rkerberos 0.2.3 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGES.md +30 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +17 -6
- data/ext/rkerberos/ccache.c +99 -26
- data/ext/rkerberos/config.c +62 -10
- data/ext/rkerberos/context.c +132 -14
- data/ext/rkerberos/kadm5.c +332 -116
- data/ext/rkerberos/keytab.c +230 -79
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +139 -11
- data/ext/rkerberos/rkerberos.c +269 -52
- data/ext/rkerberos/rkerberos.h +14 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +41 -0
- data/spec/context_spec.rb +96 -0
- data/spec/credentials_cache_spec.rb +82 -26
- data/spec/kadm5_spec.rb +319 -5
- data/spec/krb5_keytab_spec.rb +275 -20
- data/spec/krb5_spec.rb +186 -21
- data/spec/policy_spec.rb +4 -0
- data/spec/principal_spec.rb +116 -10
- metadata +9 -8
data/ext/rkerberos/kadm5.c
CHANGED
|
@@ -8,6 +8,7 @@ VALUE cKadm5PrincipalNotFoundException;
|
|
|
8
8
|
|
|
9
9
|
// Prototype
|
|
10
10
|
static VALUE rkadm5_close(VALUE);
|
|
11
|
+
static void rkadm5_check_open(RUBY_KADM5 *);
|
|
11
12
|
static void free_tl_data(krb5_tl_data *);
|
|
12
13
|
static void free_db_args(char**);
|
|
13
14
|
char** parse_db_args(VALUE v_db_args);
|
|
@@ -17,6 +18,13 @@ void add_tl_data(krb5_int16 *, krb5_tl_data **,
|
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
// TypedData functions for RUBY_KADM5
|
|
21
|
+
static void rkadm5_typed_mark(void *ptr) {
|
|
22
|
+
if (!ptr) return;
|
|
23
|
+
RUBY_KADM5 *k = (RUBY_KADM5 *)ptr;
|
|
24
|
+
if (k->rb_context != Qnil)
|
|
25
|
+
rb_gc_mark(k->rb_context);
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
static void rkadm5_typed_free(void *ptr) {
|
|
21
29
|
if (!ptr) return;
|
|
22
30
|
RUBY_KADM5 *k = (RUBY_KADM5 *)ptr;
|
|
@@ -24,8 +32,10 @@ static void rkadm5_typed_free(void *ptr) {
|
|
|
24
32
|
kadm5_destroy(k->handle);
|
|
25
33
|
if (k->princ)
|
|
26
34
|
krb5_free_principal(k->ctx, k->princ);
|
|
27
|
-
if (k->ctx)
|
|
35
|
+
if (k->ctx && k->rb_context == Qnil)
|
|
28
36
|
krb5_free_context(k->ctx);
|
|
37
|
+
else if (k->rb_context != Qnil)
|
|
38
|
+
rkrb5_context_release(k->rb_context);
|
|
29
39
|
free_db_args(k->db_args);
|
|
30
40
|
free(k);
|
|
31
41
|
}
|
|
@@ -36,7 +46,7 @@ static size_t rkadm5_typed_size(const void *ptr) {
|
|
|
36
46
|
|
|
37
47
|
static const rb_data_type_t rkadm5_data_type = {
|
|
38
48
|
"RUBY_KADM5",
|
|
39
|
-
{
|
|
49
|
+
{rkadm5_typed_mark, rkadm5_typed_free, rkadm5_typed_size,},
|
|
40
50
|
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
|
|
41
51
|
};
|
|
42
52
|
|
|
@@ -44,34 +54,53 @@ static const rb_data_type_t rkadm5_data_type = {
|
|
|
44
54
|
static VALUE rkadm5_allocate(VALUE klass){
|
|
45
55
|
RUBY_KADM5* ptr = ALLOC(RUBY_KADM5);
|
|
46
56
|
memset(ptr, 0, sizeof(RUBY_KADM5));
|
|
57
|
+
ptr->rb_context = Qnil;
|
|
47
58
|
return TypedData_Wrap_Struct(klass, &rkadm5_data_type, ptr);
|
|
48
59
|
}
|
|
49
60
|
|
|
61
|
+
static void rkadm5_check_open(RUBY_KADM5 *ptr){
|
|
62
|
+
if(!ptr->ctx || !ptr->handle)
|
|
63
|
+
rb_raise(cKadm5Exception, "no administrative context has been established");
|
|
64
|
+
}
|
|
65
|
+
|
|
50
66
|
/*
|
|
51
67
|
* call-seq:
|
|
52
|
-
* Kerberos::Kadm5.new(:
|
|
53
|
-
* Kerberos::Kadm5.new(:
|
|
54
|
-
* Kerberos::Kadm5.new(:
|
|
68
|
+
* Kerberos::Kadm5.new(principal: 'name', password: 'xxxxx')
|
|
69
|
+
* Kerberos::Kadm5.new(principal: 'name', keytab: '/path/to/your/keytab')
|
|
70
|
+
* Kerberos::Kadm5.new(principal: 'name', keytab: true)
|
|
71
|
+
* Kerberos::Kadm5.new(principal: 'name', ccache: ccache_object)
|
|
55
72
|
*
|
|
56
|
-
* Creates and returns a new Kerberos::Kadm5 object.
|
|
57
|
-
*
|
|
58
|
-
*
|
|
73
|
+
* Creates and returns a new Kerberos::Kadm5 object. Keyword arguments allow
|
|
74
|
+
* you to specify a principal and a password, a keytab file, or a credentials
|
|
75
|
+
* cache.
|
|
59
76
|
*
|
|
60
77
|
* If you pass a string as the :keytab value it will attempt to use that file
|
|
61
78
|
* for the keytab. If you pass true as the value it will attempt to use the
|
|
62
79
|
* default keytab file, typically /etc/krb5.keytab.
|
|
63
80
|
*
|
|
81
|
+
* If you pass a Kerberos::Krb5::CredentialsCache object as the :ccache value,
|
|
82
|
+
* it will authenticate using the credentials stored in that cache via
|
|
83
|
+
* kadm5_init_with_creds.
|
|
84
|
+
*
|
|
64
85
|
* You may also pass the :service option to specify the service name. The
|
|
65
86
|
* default is kadmin/admin.
|
|
66
87
|
*
|
|
67
88
|
* There is also a :db_args option, which is a single string or array of strings
|
|
68
89
|
* containing options usually passed to kadmin with the -x switch. For a list of
|
|
69
|
-
* available options, see the kadmin manpage
|
|
90
|
+
* available options, see the kadmin manpage.
|
|
91
|
+
*
|
|
92
|
+
* Only one of :password, :keytab, or :ccache may be specified.
|
|
70
93
|
*
|
|
71
94
|
*/
|
|
72
|
-
static VALUE rkadm5_initialize(VALUE
|
|
95
|
+
static VALUE rkadm5_initialize(int argc, VALUE* argv, VALUE self){
|
|
73
96
|
RUBY_KADM5* ptr;
|
|
74
|
-
VALUE v_principal, v_password, v_keytab, v_service, v_db_args;
|
|
97
|
+
VALUE v_opts, v_principal, v_password, v_keytab, v_service, v_db_args, v_context, v_ccache;
|
|
98
|
+
ID kw_table[7] = {
|
|
99
|
+
rb_intern("principal"), rb_intern("password"), rb_intern("keytab"),
|
|
100
|
+
rb_intern("ccache"), rb_intern("service"), rb_intern("db_args"),
|
|
101
|
+
rb_intern("context")
|
|
102
|
+
};
|
|
103
|
+
VALUE kw_vals[7];
|
|
75
104
|
char* user;
|
|
76
105
|
char* pass = NULL;
|
|
77
106
|
char* keytab = NULL;
|
|
@@ -80,35 +109,56 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
|
|
|
80
109
|
krb5_error_code kerror;
|
|
81
110
|
|
|
82
111
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
83
|
-
|
|
112
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
113
|
+
|
|
114
|
+
if(NIL_P(v_opts))
|
|
115
|
+
v_opts = rb_hash_new();
|
|
116
|
+
|
|
117
|
+
rb_get_kwargs(v_opts, kw_table, 0, 7, kw_vals);
|
|
118
|
+
v_principal = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
119
|
+
v_password = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
120
|
+
v_keytab = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
121
|
+
v_ccache = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
|
|
122
|
+
v_service = kw_vals[4] == Qundef ? Qnil : kw_vals[4];
|
|
123
|
+
v_db_args = kw_vals[5] == Qundef ? Qnil : kw_vals[5];
|
|
124
|
+
v_context = kw_vals[6] == Qundef ? Qnil : kw_vals[6];
|
|
125
|
+
|
|
126
|
+
// Validate mutual exclusivity
|
|
127
|
+
{
|
|
128
|
+
int auth_count = 0;
|
|
129
|
+
if(RTEST(v_password)) auth_count++;
|
|
130
|
+
if(RTEST(v_keytab)) auth_count++;
|
|
131
|
+
if(RTEST(v_ccache)) auth_count++;
|
|
132
|
+
|
|
133
|
+
if(auth_count > 1)
|
|
134
|
+
rb_raise(rb_eArgError, "only one of password, keytab, or ccache may be specified");
|
|
135
|
+
|
|
136
|
+
if(auth_count == 0)
|
|
137
|
+
rb_raise(rb_eArgError, "one of password, keytab, or ccache must be specified");
|
|
138
|
+
}
|
|
84
139
|
|
|
85
|
-
//
|
|
86
|
-
|
|
87
|
-
|
|
140
|
+
// Principal must be specified if using a password
|
|
141
|
+
if(RTEST(v_password)){
|
|
142
|
+
if(NIL_P(v_principal))
|
|
143
|
+
rb_raise(rb_eArgError, "principal must be specified");
|
|
88
144
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
rb_raise(rb_eArgError, "principal must be specified");
|
|
145
|
+
Check_Type(v_password, T_STRING);
|
|
146
|
+
Check_Type(v_principal, T_STRING);
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
|
|
148
|
+
pass = StringValueCStr(v_password);
|
|
149
|
+
}
|
|
95
150
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
v_keytab = rb_hash_aref2(v_opts, rb_str_new_cstr("keytab"));
|
|
99
|
-
if (NIL_P(v_keytab)) v_keytab = rb_hash_aref2(v_opts, ID2SYM(rb_intern("keytab")));
|
|
151
|
+
if(RTEST(v_keytab) && NIL_P(v_principal))
|
|
152
|
+
rb_raise(rb_eArgError, "principal must be specified when using a keytab");
|
|
100
153
|
|
|
101
|
-
if(RTEST(
|
|
102
|
-
rb_raise(
|
|
154
|
+
if(RTEST(v_ccache) && !rb_obj_is_kind_of(v_ccache, cKrb5CCache))
|
|
155
|
+
rb_raise(rb_eTypeError, "ccache must be a Kerberos::Krb5::CredentialsCache object");
|
|
103
156
|
|
|
104
|
-
if(RTEST(
|
|
105
|
-
|
|
106
|
-
pass = StringValueCStr(v_password);
|
|
157
|
+
if(RTEST(v_ccache) && NIL_P(v_principal)){
|
|
158
|
+
v_principal = rb_funcall(v_ccache, rb_intern("principal"), 0);
|
|
107
159
|
}
|
|
108
160
|
|
|
109
|
-
|
|
110
|
-
if (NIL_P(v_service)) v_service = rb_hash_aref2(v_opts, ID2SYM(rb_intern("service")));
|
|
111
|
-
|
|
161
|
+
user = StringValueCStr(v_principal);
|
|
112
162
|
if(NIL_P(v_service)){
|
|
113
163
|
service = (char *) "kadmin/admin";
|
|
114
164
|
}
|
|
@@ -117,16 +167,21 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
|
|
|
117
167
|
service = StringValueCStr(v_service);
|
|
118
168
|
}
|
|
119
169
|
|
|
120
|
-
v_db_args = rb_hash_aref2(v_opts, rb_str_new_cstr("db_args"));
|
|
121
|
-
if (NIL_P(v_db_args)) v_db_args = rb_hash_aref2(v_opts, ID2SYM(rb_intern("db_args")));
|
|
122
170
|
ptr->db_args = parse_db_args(v_db_args);
|
|
123
171
|
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
172
|
+
// Initialize or borrow the context
|
|
173
|
+
if(!NIL_P(v_context)){
|
|
174
|
+
ptr->ctx = rkrb5_context_borrow(v_context);
|
|
175
|
+
ptr->rb_context = v_context;
|
|
176
|
+
}
|
|
177
|
+
else{
|
|
178
|
+
kerror = krb5_init_context(&ptr->ctx);
|
|
127
179
|
|
|
128
|
-
|
|
129
|
-
|
|
180
|
+
if(kerror)
|
|
181
|
+
rb_raise(cKadm5Exception, "krb5_init_context: %s", error_message(kerror));
|
|
182
|
+
|
|
183
|
+
ptr->rb_context = Qnil;
|
|
184
|
+
}
|
|
130
185
|
|
|
131
186
|
// The docs say I can use NULL to get the default, but reality appears to be otherwise.
|
|
132
187
|
if(RTEST(v_keytab)){
|
|
@@ -176,8 +231,28 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
|
|
|
176
231
|
if(kerror)
|
|
177
232
|
rb_raise(cKadm5Exception, "kadm5_init_with_skey: %s", error_message(kerror));
|
|
178
233
|
}
|
|
179
|
-
else{
|
|
180
|
-
|
|
234
|
+
else if(RTEST(v_ccache)){
|
|
235
|
+
RUBY_KRB5_CCACHE* cc_ptr;
|
|
236
|
+
|
|
237
|
+
TypedData_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, &rkrb5_ccache_data_type, cc_ptr);
|
|
238
|
+
|
|
239
|
+
if(!cc_ptr->ctx || !cc_ptr->ccache)
|
|
240
|
+
rb_raise(cKrb5Exception, "credentials cache is closed or destroyed");
|
|
241
|
+
|
|
242
|
+
kerror = kadm5_init_with_creds(
|
|
243
|
+
ptr->ctx,
|
|
244
|
+
user,
|
|
245
|
+
cc_ptr->ccache,
|
|
246
|
+
service,
|
|
247
|
+
NULL,
|
|
248
|
+
KADM5_STRUCT_VERSION,
|
|
249
|
+
KADM5_API_VERSION_3,
|
|
250
|
+
ptr->db_args,
|
|
251
|
+
&ptr->handle
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
if(kerror)
|
|
255
|
+
rb_raise(cKadm5Exception, "kadm5_init_with_creds: %s", error_message(kerror));
|
|
181
256
|
}
|
|
182
257
|
|
|
183
258
|
if(rb_block_given_p()){
|
|
@@ -206,8 +281,7 @@ static VALUE rkadm5_set_password(VALUE self, VALUE v_user, VALUE v_pass){
|
|
|
206
281
|
user = StringValueCStr(v_user);
|
|
207
282
|
pass = StringValueCStr(v_pass);
|
|
208
283
|
|
|
209
|
-
|
|
210
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
284
|
+
rkadm5_check_open(ptr);
|
|
211
285
|
|
|
212
286
|
if(ptr->princ){
|
|
213
287
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -244,8 +318,7 @@ static VALUE rkadm5_set_pwexpire(VALUE self, VALUE v_user, VALUE v_pwexpire){
|
|
|
244
318
|
|
|
245
319
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
246
320
|
|
|
247
|
-
|
|
248
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
321
|
+
rkadm5_check_open(ptr);
|
|
249
322
|
|
|
250
323
|
if(ptr->princ){
|
|
251
324
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -281,50 +354,147 @@ static VALUE rkadm5_set_pwexpire(VALUE self, VALUE v_user, VALUE v_pwexpire){
|
|
|
281
354
|
|
|
282
355
|
/*
|
|
283
356
|
* call-seq:
|
|
284
|
-
* kadm5.create_principal(name
|
|
285
|
-
* kadm5.create_principal(principal)
|
|
357
|
+
* kadm5.create_principal(name:, password:, db_args: nil)
|
|
358
|
+
* kadm5.create_principal(principal:, password:, db_args: nil)
|
|
359
|
+
*
|
|
360
|
+
* Creates a new principal with an initial password of +password+.
|
|
361
|
+
*
|
|
362
|
+
* The principal may be specified either as a +name+ string or as a
|
|
363
|
+
* +principal+ object (a Kerberos::Krb5::Principal). When a Principal
|
|
364
|
+
* object is provided, any non-nil writable attributes on that object
|
|
365
|
+
* are forwarded to the KDC:
|
|
366
|
+
*
|
|
367
|
+
* * +policy+
|
|
368
|
+
* * +expire_time+
|
|
369
|
+
* * +password_expiration+
|
|
370
|
+
* * +max_life+
|
|
371
|
+
* * +max_renewable_life+
|
|
372
|
+
* * +attributes+
|
|
286
373
|
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
* in the add_principal section.
|
|
291
|
-
*--
|
|
292
|
-
* TODO: Allow a Principal object to be passed in as an argument.
|
|
374
|
+
* +db_args+ is an optional string or array of strings containing options
|
|
375
|
+
* that are usually passed to add_principal with the -x option. For a
|
|
376
|
+
* list of options, see the kadmin manpage, in the add_principal section.
|
|
293
377
|
*/
|
|
294
378
|
static VALUE rkadm5_create_principal(int argc, VALUE* argv, VALUE self){
|
|
295
379
|
RUBY_KADM5* ptr;
|
|
296
|
-
char* user;
|
|
297
380
|
char* pass;
|
|
298
381
|
char** db_args;
|
|
299
382
|
int mask;
|
|
300
383
|
kadm5_principal_ent_rec princ;
|
|
301
384
|
krb5_error_code kerror;
|
|
302
|
-
VALUE
|
|
385
|
+
VALUE v_opts, v_name, v_principal, v_pass, v_db_args;
|
|
386
|
+
ID kw_table[4] = { rb_intern("name"), rb_intern("principal"), rb_intern("password"), rb_intern("db_args") };
|
|
387
|
+
VALUE kw_vals[4];
|
|
303
388
|
|
|
304
389
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
305
390
|
|
|
306
|
-
|
|
307
|
-
|
|
391
|
+
rkadm5_check_open(ptr);
|
|
392
|
+
|
|
393
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
394
|
+
|
|
395
|
+
if(NIL_P(v_opts))
|
|
396
|
+
v_opts = rb_hash_new();
|
|
397
|
+
|
|
398
|
+
rb_get_kwargs(v_opts, kw_table, 0, 4, kw_vals);
|
|
399
|
+
v_name = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
400
|
+
v_principal = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
401
|
+
v_pass = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
402
|
+
v_db_args = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
|
|
403
|
+
|
|
404
|
+
if(NIL_P(v_pass))
|
|
405
|
+
rb_raise(rb_eArgError, "password: is required");
|
|
406
|
+
|
|
308
407
|
Check_Type(v_pass, T_STRING);
|
|
309
408
|
|
|
409
|
+
if(NIL_P(v_name) && NIL_P(v_principal))
|
|
410
|
+
rb_raise(rb_eArgError, "name: or principal: is required");
|
|
411
|
+
|
|
412
|
+
if(RTEST(v_name) && RTEST(v_principal))
|
|
413
|
+
rb_raise(rb_eArgError, "name: and principal: are mutually exclusive");
|
|
414
|
+
|
|
310
415
|
memset(&princ, 0, sizeof(princ));
|
|
311
416
|
|
|
312
417
|
mask = KADM5_PRINCIPAL | KADM5_TL_DATA;
|
|
313
|
-
user = StringValueCStr(v_user);
|
|
314
418
|
pass = StringValueCStr(v_pass);
|
|
315
419
|
|
|
316
420
|
db_args = parse_db_args(v_db_args);
|
|
317
421
|
add_db_args(&princ, db_args);
|
|
318
422
|
free_db_args(db_args);
|
|
319
423
|
|
|
320
|
-
|
|
321
|
-
|
|
424
|
+
// Determine the principal name and populate mask from the principal object
|
|
425
|
+
if(RTEST(v_principal)){
|
|
426
|
+
VALUE v_princ_name, v_policy, v_expire, v_pw_expire, v_max_life, v_max_renew, v_attrs;
|
|
322
427
|
|
|
323
|
-
|
|
428
|
+
if(!rb_obj_is_kind_of(v_principal, cKrb5Principal))
|
|
429
|
+
rb_raise(rb_eTypeError, "principal: must be a Kerberos::Krb5::Principal object");
|
|
324
430
|
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
431
|
+
v_princ_name = rb_iv_get(v_principal, "@principal");
|
|
432
|
+
|
|
433
|
+
if(NIL_P(v_princ_name))
|
|
434
|
+
rb_raise(rb_eArgError, "principal object has no name set");
|
|
435
|
+
|
|
436
|
+
Check_Type(v_princ_name, T_STRING);
|
|
437
|
+
|
|
438
|
+
kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_princ_name), &princ.principal);
|
|
439
|
+
|
|
440
|
+
if(kerror){
|
|
441
|
+
free_tl_data(princ.tl_data);
|
|
442
|
+
rb_raise(cKadm5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Forward optional attributes from the Principal object
|
|
446
|
+
v_policy = rb_iv_get(v_principal, "@policy");
|
|
447
|
+
|
|
448
|
+
if(RTEST(v_policy)){
|
|
449
|
+
Check_Type(v_policy, T_STRING);
|
|
450
|
+
princ.policy = StringValueCStr(v_policy);
|
|
451
|
+
mask |= KADM5_POLICY;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
v_expire = rb_iv_get(v_principal, "@expire_time");
|
|
455
|
+
|
|
456
|
+
if(RTEST(v_expire)){
|
|
457
|
+
princ.princ_expire_time = (krb5_timestamp)NUM2LONG(rb_funcall(v_expire, rb_intern("to_i"), 0));
|
|
458
|
+
mask |= KADM5_PRINC_EXPIRE_TIME;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
v_pw_expire = rb_iv_get(v_principal, "@password_expiration");
|
|
462
|
+
|
|
463
|
+
if(RTEST(v_pw_expire)){
|
|
464
|
+
princ.pw_expiration = (krb5_timestamp)NUM2LONG(rb_funcall(v_pw_expire, rb_intern("to_i"), 0));
|
|
465
|
+
mask |= KADM5_PW_EXPIRATION;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
v_max_life = rb_iv_get(v_principal, "@max_life");
|
|
469
|
+
|
|
470
|
+
if(RTEST(v_max_life)){
|
|
471
|
+
princ.max_life = NUM2LONG(v_max_life);
|
|
472
|
+
mask |= KADM5_MAX_LIFE;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
v_max_renew = rb_iv_get(v_principal, "@max_renewable_life");
|
|
476
|
+
|
|
477
|
+
if(RTEST(v_max_renew)){
|
|
478
|
+
princ.max_renewable_life = NUM2LONG(v_max_renew);
|
|
479
|
+
mask |= KADM5_MAX_RLIFE;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
v_attrs = rb_iv_get(v_principal, "@attributes");
|
|
483
|
+
|
|
484
|
+
if(RTEST(v_attrs)){
|
|
485
|
+
princ.attributes = NUM2LONG(v_attrs);
|
|
486
|
+
mask |= KADM5_ATTRIBUTES;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
else{
|
|
490
|
+
Check_Type(v_name, T_STRING);
|
|
491
|
+
|
|
492
|
+
kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_name), &princ.principal);
|
|
493
|
+
|
|
494
|
+
if(kerror){
|
|
495
|
+
free_tl_data(princ.tl_data);
|
|
496
|
+
rb_raise(cKadm5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
497
|
+
}
|
|
328
498
|
}
|
|
329
499
|
|
|
330
500
|
kerror = kadm5_create_principal(ptr->handle, &princ, mask, pass);
|
|
@@ -355,8 +525,7 @@ static VALUE rkadm5_delete_principal(VALUE self, VALUE v_user){
|
|
|
355
525
|
Check_Type(v_user, T_STRING);
|
|
356
526
|
user = StringValueCStr(v_user);
|
|
357
527
|
|
|
358
|
-
|
|
359
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
528
|
+
rkadm5_check_open(ptr);
|
|
360
529
|
|
|
361
530
|
if(ptr->princ){
|
|
362
531
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -396,8 +565,10 @@ static VALUE rkadm5_close(VALUE self){
|
|
|
396
565
|
if(ptr->princ)
|
|
397
566
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
398
567
|
|
|
399
|
-
if(ptr->ctx)
|
|
568
|
+
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
400
569
|
krb5_free_context(ptr->ctx);
|
|
570
|
+
else if(ptr->rb_context != Qnil)
|
|
571
|
+
rkrb5_context_release(ptr->rb_context);
|
|
401
572
|
|
|
402
573
|
free_db_args(ptr->db_args);
|
|
403
574
|
|
|
@@ -405,6 +576,7 @@ static VALUE rkadm5_close(VALUE self){
|
|
|
405
576
|
ptr->ctx = NULL;
|
|
406
577
|
ptr->princ = NULL;
|
|
407
578
|
ptr->handle = NULL;
|
|
579
|
+
ptr->rb_context = Qnil;
|
|
408
580
|
|
|
409
581
|
return self;
|
|
410
582
|
}
|
|
@@ -413,11 +585,11 @@ static VALUE rkadm5_close(VALUE self){
|
|
|
413
585
|
static VALUE create_principal_from_entry(VALUE v_name, RUBY_KADM5* ptr, kadm5_principal_ent_rec* ent){
|
|
414
586
|
krb5_error_code kerror;
|
|
415
587
|
VALUE v_principal;
|
|
416
|
-
VALUE
|
|
588
|
+
VALUE v_opts = rb_hash_new();
|
|
417
589
|
|
|
418
|
-
|
|
590
|
+
rb_hash_aset(v_opts, ID2SYM(rb_intern("name")), v_name);
|
|
419
591
|
|
|
420
|
-
v_principal =
|
|
592
|
+
v_principal = rb_class_new_instance_kw(1, &v_opts, cKrb5Principal, RB_PASS_KEYWORDS);
|
|
421
593
|
|
|
422
594
|
rb_iv_set(v_principal, "@attributes", LONG2FIX(ent->attributes));
|
|
423
595
|
rb_iv_set(v_principal, "@aux_attributes", INT2FIX(ent->aux_attributes));
|
|
@@ -492,8 +664,7 @@ static VALUE rkadm5_find_principal(VALUE self, VALUE v_user){
|
|
|
492
664
|
|
|
493
665
|
memset(&ent, 0, sizeof(ent));
|
|
494
666
|
|
|
495
|
-
|
|
496
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
667
|
+
rkadm5_check_open(ptr);
|
|
497
668
|
|
|
498
669
|
if(ptr->princ){
|
|
499
670
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -553,8 +724,7 @@ static VALUE rkadm5_get_principal(VALUE self, VALUE v_user){
|
|
|
553
724
|
|
|
554
725
|
memset(&ent, 0, sizeof(ent));
|
|
555
726
|
|
|
556
|
-
|
|
557
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
727
|
+
rkadm5_check_open(ptr);
|
|
558
728
|
|
|
559
729
|
if(ptr->princ){
|
|
560
730
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
@@ -596,28 +766,41 @@ static VALUE rkadm5_get_principal(VALUE self, VALUE v_user){
|
|
|
596
766
|
* Example:
|
|
597
767
|
*
|
|
598
768
|
* # Using a Policy object
|
|
599
|
-
* policy = Kerberos::Kadm5::Policy.new(:
|
|
769
|
+
* policy = Kerberos::Kadm5::Policy.new(name: 'test', min_length: 5)
|
|
600
770
|
* kadm5.create_policy(policy)
|
|
601
771
|
*
|
|
602
|
-
* # Using
|
|
603
|
-
* kadm5.create_policy(:
|
|
772
|
+
* # Using keywords
|
|
773
|
+
* kadm5.create_policy(name: 'test', min_length: 5)
|
|
604
774
|
*/
|
|
605
|
-
static VALUE rkadm5_create_policy(VALUE
|
|
775
|
+
static VALUE rkadm5_create_policy(int argc, VALUE* argv, VALUE self){
|
|
606
776
|
RUBY_KADM5* ptr;
|
|
607
777
|
kadm5_ret_t kerror;
|
|
608
778
|
kadm5_policy_ent_rec ent;
|
|
609
779
|
long mask = KADM5_POLICY;
|
|
780
|
+
VALUE v_policy, v_kwargs;
|
|
610
781
|
VALUE v_name, v_min_classes, v_min_life, v_max_life, v_min_length, v_history_num;
|
|
611
782
|
|
|
612
783
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
613
784
|
|
|
614
|
-
|
|
615
|
-
|
|
785
|
+
rkadm5_check_open(ptr);
|
|
786
|
+
|
|
787
|
+
rb_scan_args(argc, argv, "01:", &v_policy, &v_kwargs);
|
|
788
|
+
|
|
789
|
+
if(!NIL_P(v_kwargs)){
|
|
616
790
|
VALUE v_args[1];
|
|
617
|
-
|
|
618
|
-
|
|
791
|
+
if(!NIL_P(v_policy))
|
|
792
|
+
rb_raise(rb_eArgError, "provide a Policy object or keyword arguments, not both");
|
|
793
|
+
|
|
794
|
+
v_args[0] = v_kwargs;
|
|
795
|
+
v_policy = rb_class_new_instance_kw(1, v_args, cKadm5Policy, RB_PASS_KEYWORDS);
|
|
619
796
|
}
|
|
620
797
|
|
|
798
|
+
if(NIL_P(v_policy))
|
|
799
|
+
rb_raise(rb_eArgError, "a Policy object or policy keywords are required");
|
|
800
|
+
|
|
801
|
+
if(!rb_obj_is_kind_of(v_policy, cKadm5Policy))
|
|
802
|
+
rb_raise(rb_eTypeError, "expected a Kerberos::Kadm5::Policy object or policy keywords");
|
|
803
|
+
|
|
621
804
|
v_name = rb_iv_get(v_policy, "@policy");
|
|
622
805
|
v_min_classes = rb_iv_get(v_policy, "@min_classes");
|
|
623
806
|
v_min_length = rb_iv_get(v_policy, "@min_length");
|
|
@@ -678,6 +861,8 @@ static VALUE rkadm5_delete_policy(VALUE self, VALUE v_policy){
|
|
|
678
861
|
|
|
679
862
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
680
863
|
|
|
864
|
+
rkadm5_check_open(ptr);
|
|
865
|
+
|
|
681
866
|
policy = StringValueCStr(v_policy);
|
|
682
867
|
|
|
683
868
|
kerror = kadm5_delete_policy(ptr->handle, policy);
|
|
@@ -708,8 +893,7 @@ static VALUE rkadm5_get_policy(VALUE self, VALUE v_name){
|
|
|
708
893
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
709
894
|
memset(&ent, 0, sizeof(ent));
|
|
710
895
|
|
|
711
|
-
|
|
712
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
896
|
+
rkadm5_check_open(ptr);
|
|
713
897
|
|
|
714
898
|
policy_name = StringValueCStr(v_name);
|
|
715
899
|
|
|
@@ -725,16 +909,16 @@ static VALUE rkadm5_get_policy(VALUE self, VALUE v_name){
|
|
|
725
909
|
VALUE v_arg[1];
|
|
726
910
|
VALUE v_hash = rb_hash_new();
|
|
727
911
|
|
|
728
|
-
rb_hash_aset(v_hash,
|
|
729
|
-
rb_hash_aset(v_hash,
|
|
730
|
-
rb_hash_aset(v_hash,
|
|
731
|
-
rb_hash_aset(v_hash,
|
|
732
|
-
rb_hash_aset(v_hash,
|
|
733
|
-
rb_hash_aset(v_hash,
|
|
912
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("name")), rb_str_new2(ent.policy));
|
|
913
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_life")), LONG2FIX(ent.pw_min_life));
|
|
914
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("max_life")), LONG2FIX(ent.pw_max_life));
|
|
915
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_length")), LONG2FIX(ent.pw_min_length));
|
|
916
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_classes")), LONG2FIX(ent.pw_min_classes));
|
|
917
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("history_num")), LONG2FIX(ent.pw_history_num));
|
|
734
918
|
|
|
735
919
|
v_arg[0] = v_hash;
|
|
736
920
|
|
|
737
|
-
v_policy =
|
|
921
|
+
v_policy = rb_class_new_instance_kw(1, v_arg, cKadm5Policy, RB_PASS_KEYWORDS);
|
|
738
922
|
|
|
739
923
|
kadm5_free_policy_ent(ptr->handle, &ent);
|
|
740
924
|
}
|
|
@@ -762,8 +946,7 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
|
|
|
762
946
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
763
947
|
memset(&ent, 0, sizeof(ent));
|
|
764
948
|
|
|
765
|
-
|
|
766
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
949
|
+
rkadm5_check_open(ptr);
|
|
767
950
|
|
|
768
951
|
policy_name = StringValueCStr(v_name);
|
|
769
952
|
|
|
@@ -782,16 +965,16 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
|
|
|
782
965
|
VALUE v_arg[1];
|
|
783
966
|
VALUE v_hash = rb_hash_new();
|
|
784
967
|
|
|
785
|
-
rb_hash_aset(v_hash,
|
|
786
|
-
rb_hash_aset(v_hash,
|
|
787
|
-
rb_hash_aset(v_hash,
|
|
788
|
-
rb_hash_aset(v_hash,
|
|
789
|
-
rb_hash_aset(v_hash,
|
|
790
|
-
rb_hash_aset(v_hash,
|
|
968
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("name")), rb_str_new2(ent.policy));
|
|
969
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_life")), LONG2FIX(ent.pw_min_life));
|
|
970
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("max_life")), LONG2FIX(ent.pw_max_life));
|
|
971
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_length")), LONG2FIX(ent.pw_min_length));
|
|
972
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_classes")), LONG2FIX(ent.pw_min_classes));
|
|
973
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("history_num")), LONG2FIX(ent.pw_history_num));
|
|
791
974
|
|
|
792
975
|
v_arg[0] = v_hash;
|
|
793
976
|
|
|
794
|
-
v_policy =
|
|
977
|
+
v_policy = rb_class_new_instance_kw(1, v_arg, cKadm5Policy, RB_PASS_KEYWORDS);
|
|
795
978
|
|
|
796
979
|
kadm5_free_policy_ent(ptr->handle, &ent);
|
|
797
980
|
}
|
|
@@ -808,34 +991,59 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
|
|
|
808
991
|
* Example:
|
|
809
992
|
*
|
|
810
993
|
* policy = Kerberos::Kadm5::Policy.find('test')
|
|
811
|
-
* policy.
|
|
994
|
+
* policy.max_life = 1024
|
|
812
995
|
* kadm5.modify_policy(policy)
|
|
813
996
|
*/
|
|
814
997
|
static VALUE rkadm5_modify_policy(VALUE self, VALUE v_policy){
|
|
815
998
|
RUBY_KADM5* ptr;
|
|
816
|
-
RUBY_KADM5_POLICY* pptr;
|
|
817
999
|
kadm5_ret_t kerror;
|
|
818
|
-
|
|
1000
|
+
kadm5_policy_ent_rec ent;
|
|
1001
|
+
long mask = 0;
|
|
1002
|
+
VALUE v_name, v_min_classes, v_min_life, v_max_life, v_min_length, v_history_num;
|
|
819
1003
|
|
|
820
1004
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
821
|
-
TypedData_Get_Struct(v_policy, RUBY_KADM5_POLICY, &rkadm5_policy_data_type, pptr);
|
|
822
1005
|
|
|
823
|
-
|
|
824
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
1006
|
+
rkadm5_check_open(ptr);
|
|
825
1007
|
|
|
826
|
-
if(
|
|
1008
|
+
if(!rb_obj_is_kind_of(v_policy, cKadm5Policy))
|
|
1009
|
+
rb_raise(rb_eTypeError, "expected a Kerberos::Kadm5::Policy object");
|
|
1010
|
+
|
|
1011
|
+
v_name = rb_iv_get(v_policy, "@policy");
|
|
1012
|
+
v_min_classes = rb_iv_get(v_policy, "@min_classes");
|
|
1013
|
+
v_min_length = rb_iv_get(v_policy, "@min_length");
|
|
1014
|
+
v_min_life = rb_iv_get(v_policy, "@min_life");
|
|
1015
|
+
v_max_life = rb_iv_get(v_policy, "@max_life");
|
|
1016
|
+
v_history_num = rb_iv_get(v_policy, "@history_num");
|
|
1017
|
+
|
|
1018
|
+
memset(&ent, 0, sizeof(ent));
|
|
1019
|
+
ent.policy = StringValueCStr(v_name);
|
|
1020
|
+
|
|
1021
|
+
if(!NIL_P(v_min_classes)){
|
|
827
1022
|
mask |= KADM5_PW_MIN_CLASSES;
|
|
1023
|
+
ent.pw_min_classes = NUM2LONG(v_min_classes);
|
|
1024
|
+
}
|
|
828
1025
|
|
|
829
|
-
if(
|
|
1026
|
+
if(!NIL_P(v_min_length)){
|
|
830
1027
|
mask |= KADM5_PW_MIN_LENGTH;
|
|
1028
|
+
ent.pw_min_length = NUM2LONG(v_min_length);
|
|
1029
|
+
}
|
|
831
1030
|
|
|
832
|
-
if(
|
|
1031
|
+
if(!NIL_P(v_min_life)){
|
|
833
1032
|
mask |= KADM5_PW_MIN_LIFE;
|
|
1033
|
+
ent.pw_min_life = NUM2LONG(v_min_life);
|
|
1034
|
+
}
|
|
834
1035
|
|
|
835
|
-
if(
|
|
1036
|
+
if(!NIL_P(v_max_life)){
|
|
836
1037
|
mask |= KADM5_PW_MAX_LIFE;
|
|
1038
|
+
ent.pw_max_life = NUM2LONG(v_max_life);
|
|
1039
|
+
}
|
|
837
1040
|
|
|
838
|
-
|
|
1041
|
+
if(!NIL_P(v_history_num)){
|
|
1042
|
+
mask |= KADM5_PW_HISTORY_NUM;
|
|
1043
|
+
ent.pw_history_num = NUM2LONG(v_history_num);
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
kerror = kadm5_modify_policy(ptr->handle, &ent, mask);
|
|
839
1047
|
|
|
840
1048
|
if(kerror)
|
|
841
1049
|
rb_raise(cKadm5Exception, "kadm5_modify_policy: %s (%li)", error_message(kerror), kerror);
|
|
@@ -866,6 +1074,8 @@ static VALUE rkadm5_get_policies(int argc, VALUE* argv, VALUE self){
|
|
|
866
1074
|
|
|
867
1075
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
868
1076
|
|
|
1077
|
+
rkadm5_check_open(ptr);
|
|
1078
|
+
|
|
869
1079
|
rb_scan_args(argc, argv, "01", &v_expr);
|
|
870
1080
|
|
|
871
1081
|
if(NIL_P(v_expr))
|
|
@@ -914,6 +1124,8 @@ static VALUE rkadm5_get_principals(int argc, VALUE* argv, VALUE self){
|
|
|
914
1124
|
|
|
915
1125
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
916
1126
|
|
|
1127
|
+
rkadm5_check_open(ptr);
|
|
1128
|
+
|
|
917
1129
|
rb_scan_args(argc, argv, "01", &v_expr);
|
|
918
1130
|
|
|
919
1131
|
if(NIL_P(v_expr))
|
|
@@ -962,6 +1174,8 @@ static VALUE rkadm5_get_privs(int argc, VALUE* argv, VALUE self){
|
|
|
962
1174
|
|
|
963
1175
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
964
1176
|
|
|
1177
|
+
rkadm5_check_open(ptr);
|
|
1178
|
+
|
|
965
1179
|
rb_scan_args(argc, argv, "01", &v_strings);
|
|
966
1180
|
|
|
967
1181
|
kerror = kadm5_get_privs(ptr->handle, &privs);
|
|
@@ -1007,8 +1221,7 @@ static VALUE rkadm5_randkey_principal(VALUE self, VALUE v_user){
|
|
|
1007
1221
|
|
|
1008
1222
|
user = StringValueCStr(v_user);
|
|
1009
1223
|
|
|
1010
|
-
|
|
1011
|
-
rb_raise(cKadm5Exception, "no context has been established");
|
|
1224
|
+
rkadm5_check_open(ptr);
|
|
1012
1225
|
|
|
1013
1226
|
kerror = krb5_parse_name(ptr->ctx, user, &princ);
|
|
1014
1227
|
|
|
@@ -1047,10 +1260,13 @@ char** parse_db_args(VALUE v_db_args){
|
|
|
1047
1260
|
case T_ARRAY:
|
|
1048
1261
|
// Multiple arguments
|
|
1049
1262
|
array_length = RARRAY_LEN(v_db_args);
|
|
1263
|
+
|
|
1264
|
+
for(long i = 0; i < array_length; ++i)
|
|
1265
|
+
Check_Type(rb_ary_entry(v_db_args, i), T_STRING);
|
|
1266
|
+
|
|
1050
1267
|
db_args = (char **) malloc((array_length + 1) * sizeof(char *));
|
|
1051
1268
|
for(long i = 0; i < array_length; ++i){
|
|
1052
1269
|
VALUE elem = rb_ary_entry(v_db_args, i);
|
|
1053
|
-
Check_Type(elem, T_STRING);
|
|
1054
1270
|
db_args[i] = strdup(StringValueCStr(elem));
|
|
1055
1271
|
}
|
|
1056
1272
|
db_args[array_length] = NULL;
|
|
@@ -1137,12 +1353,12 @@ void Init_kadm5(void){
|
|
|
1137
1353
|
|
|
1138
1354
|
// Initialization Method
|
|
1139
1355
|
|
|
1140
|
-
rb_define_method(cKadm5, "initialize", rkadm5_initialize, 1);
|
|
1356
|
+
rb_define_method(cKadm5, "initialize", rkadm5_initialize, -1);
|
|
1141
1357
|
|
|
1142
1358
|
// Instance Methods
|
|
1143
1359
|
|
|
1144
1360
|
rb_define_method(cKadm5, "close", rkadm5_close, 0);
|
|
1145
|
-
rb_define_method(cKadm5, "create_policy", rkadm5_create_policy, 1);
|
|
1361
|
+
rb_define_method(cKadm5, "create_policy", rkadm5_create_policy, -1);
|
|
1146
1362
|
rb_define_method(cKadm5, "create_principal", rkadm5_create_principal, -1);
|
|
1147
1363
|
rb_define_method(cKadm5, "delete_policy", rkadm5_delete_policy, 1);
|
|
1148
1364
|
rb_define_method(cKadm5, "delete_principal", rkadm5_delete_principal, 1);
|