rkerberos 0.2.2 → 0.3.0
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 +22 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +5 -5
- data/ext/rkerberos/ccache.c +105 -26
- data/ext/rkerberos/config.c +59 -10
- data/ext/rkerberos/context.c +76 -7
- data/ext/rkerberos/extconf.rb +16 -3
- data/ext/rkerberos/kadm5.c +301 -96
- data/ext/rkerberos/keytab.c +222 -66
- data/ext/rkerberos/keytab_entry.c +2 -1
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +136 -10
- data/ext/rkerberos/rkerberos.c +244 -34
- data/ext/rkerberos/rkerberos.h +8 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +58 -3
- data/spec/context_spec.rb +57 -7
- data/spec/credentials_cache_spec.rb +106 -39
- data/spec/kadm5_spec.rb +292 -17
- data/spec/krb5_keytab_spec.rb +229 -24
- data/spec/krb5_spec.rb +142 -29
- data/spec/policy_spec.rb +12 -7
- data/spec/principal_spec.rb +102 -4
- data/spec/spec_helper.rb +34 -0
- metadata +10 -8
data/ext/rkerberos/kadm5.c
CHANGED
|
@@ -9,6 +9,7 @@ VALUE cKadm5PrincipalNotFoundException;
|
|
|
9
9
|
// Prototype
|
|
10
10
|
static VALUE rkadm5_close(VALUE);
|
|
11
11
|
static void free_tl_data(krb5_tl_data *);
|
|
12
|
+
static void free_db_args(char**);
|
|
12
13
|
char** parse_db_args(VALUE v_db_args);
|
|
13
14
|
void add_db_args(kadm5_principal_ent_rec*, char**);
|
|
14
15
|
void add_tl_data(krb5_int16 *, krb5_tl_data **,
|
|
@@ -16,6 +17,13 @@ void add_tl_data(krb5_int16 *, krb5_tl_data **,
|
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
// TypedData functions for RUBY_KADM5
|
|
20
|
+
static void rkadm5_typed_mark(void *ptr) {
|
|
21
|
+
if (!ptr) return;
|
|
22
|
+
RUBY_KADM5 *k = (RUBY_KADM5 *)ptr;
|
|
23
|
+
if (k->rb_context != Qnil)
|
|
24
|
+
rb_gc_mark(k->rb_context);
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
static void rkadm5_typed_free(void *ptr) {
|
|
20
28
|
if (!ptr) return;
|
|
21
29
|
RUBY_KADM5 *k = (RUBY_KADM5 *)ptr;
|
|
@@ -23,9 +31,9 @@ static void rkadm5_typed_free(void *ptr) {
|
|
|
23
31
|
kadm5_destroy(k->handle);
|
|
24
32
|
if (k->princ)
|
|
25
33
|
krb5_free_principal(k->ctx, k->princ);
|
|
26
|
-
if (k->ctx)
|
|
34
|
+
if (k->ctx && k->rb_context == Qnil)
|
|
27
35
|
krb5_free_context(k->ctx);
|
|
28
|
-
|
|
36
|
+
free_db_args(k->db_args);
|
|
29
37
|
free(k);
|
|
30
38
|
}
|
|
31
39
|
|
|
@@ -35,7 +43,7 @@ static size_t rkadm5_typed_size(const void *ptr) {
|
|
|
35
43
|
|
|
36
44
|
static const rb_data_type_t rkadm5_data_type = {
|
|
37
45
|
"RUBY_KADM5",
|
|
38
|
-
{
|
|
46
|
+
{rkadm5_typed_mark, rkadm5_typed_free, rkadm5_typed_size,},
|
|
39
47
|
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
|
|
40
48
|
};
|
|
41
49
|
|
|
@@ -43,34 +51,48 @@ static const rb_data_type_t rkadm5_data_type = {
|
|
|
43
51
|
static VALUE rkadm5_allocate(VALUE klass){
|
|
44
52
|
RUBY_KADM5* ptr = ALLOC(RUBY_KADM5);
|
|
45
53
|
memset(ptr, 0, sizeof(RUBY_KADM5));
|
|
54
|
+
ptr->rb_context = Qnil;
|
|
46
55
|
return TypedData_Wrap_Struct(klass, &rkadm5_data_type, ptr);
|
|
47
56
|
}
|
|
48
57
|
|
|
49
58
|
/*
|
|
50
59
|
* call-seq:
|
|
51
|
-
* Kerberos::Kadm5.new(:
|
|
52
|
-
* Kerberos::Kadm5.new(:
|
|
53
|
-
* Kerberos::Kadm5.new(:
|
|
60
|
+
* Kerberos::Kadm5.new(principal: 'name', password: 'xxxxx')
|
|
61
|
+
* Kerberos::Kadm5.new(principal: 'name', keytab: '/path/to/your/keytab')
|
|
62
|
+
* Kerberos::Kadm5.new(principal: 'name', keytab: true)
|
|
63
|
+
* Kerberos::Kadm5.new(principal: 'name', ccache: ccache_object)
|
|
54
64
|
*
|
|
55
|
-
* Creates and returns a new Kerberos::Kadm5 object.
|
|
56
|
-
*
|
|
57
|
-
*
|
|
65
|
+
* Creates and returns a new Kerberos::Kadm5 object. Keyword arguments allow
|
|
66
|
+
* you to specify a principal and a password, a keytab file, or a credentials
|
|
67
|
+
* cache.
|
|
58
68
|
*
|
|
59
69
|
* If you pass a string as the :keytab value it will attempt to use that file
|
|
60
70
|
* for the keytab. If you pass true as the value it will attempt to use the
|
|
61
71
|
* default keytab file, typically /etc/krb5.keytab.
|
|
62
72
|
*
|
|
73
|
+
* If you pass a Kerberos::Krb5::CredentialsCache object as the :ccache value,
|
|
74
|
+
* it will authenticate using the credentials stored in that cache via
|
|
75
|
+
* kadm5_init_with_creds.
|
|
76
|
+
*
|
|
63
77
|
* You may also pass the :service option to specify the service name. The
|
|
64
78
|
* default is kadmin/admin.
|
|
65
79
|
*
|
|
66
80
|
* There is also a :db_args option, which is a single string or array of strings
|
|
67
81
|
* containing options usually passed to kadmin with the -x switch. For a list of
|
|
68
|
-
* available options, see the kadmin manpage
|
|
82
|
+
* available options, see the kadmin manpage.
|
|
83
|
+
*
|
|
84
|
+
* Only one of :password, :keytab, or :ccache may be specified.
|
|
69
85
|
*
|
|
70
86
|
*/
|
|
71
|
-
static VALUE rkadm5_initialize(VALUE
|
|
87
|
+
static VALUE rkadm5_initialize(int argc, VALUE* argv, VALUE self){
|
|
72
88
|
RUBY_KADM5* ptr;
|
|
73
|
-
VALUE v_principal, v_password, v_keytab, v_service, v_db_args;
|
|
89
|
+
VALUE v_opts, v_principal, v_password, v_keytab, v_service, v_db_args, v_context, v_ccache;
|
|
90
|
+
ID kw_table[7] = {
|
|
91
|
+
rb_intern("principal"), rb_intern("password"), rb_intern("keytab"),
|
|
92
|
+
rb_intern("ccache"), rb_intern("service"), rb_intern("db_args"),
|
|
93
|
+
rb_intern("context")
|
|
94
|
+
};
|
|
95
|
+
VALUE kw_vals[7];
|
|
74
96
|
char* user;
|
|
75
97
|
char* pass = NULL;
|
|
76
98
|
char* keytab = NULL;
|
|
@@ -79,35 +101,59 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
|
|
|
79
101
|
krb5_error_code kerror;
|
|
80
102
|
|
|
81
103
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
104
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
105
|
+
|
|
106
|
+
if(NIL_P(v_opts))
|
|
107
|
+
v_opts = rb_hash_new();
|
|
108
|
+
|
|
109
|
+
rb_get_kwargs(v_opts, kw_table, 0, 7, kw_vals);
|
|
110
|
+
v_principal = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
111
|
+
v_password = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
112
|
+
v_keytab = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
113
|
+
v_ccache = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
|
|
114
|
+
v_service = kw_vals[4] == Qundef ? Qnil : kw_vals[4];
|
|
115
|
+
v_db_args = kw_vals[5] == Qundef ? Qnil : kw_vals[5];
|
|
116
|
+
v_context = kw_vals[6] == Qundef ? Qnil : kw_vals[6];
|
|
117
|
+
|
|
118
|
+
// Validate mutual exclusivity
|
|
119
|
+
{
|
|
120
|
+
int auth_count = 0;
|
|
121
|
+
if(RTEST(v_password)) auth_count++;
|
|
122
|
+
if(RTEST(v_keytab)) auth_count++;
|
|
123
|
+
if(RTEST(v_ccache)) auth_count++;
|
|
124
|
+
|
|
125
|
+
if(auth_count > 1)
|
|
126
|
+
rb_raise(rb_eArgError, "only one of password, keytab, or ccache may be specified");
|
|
127
|
+
|
|
128
|
+
if(auth_count == 0)
|
|
129
|
+
rb_raise(rb_eArgError, "one of password, keytab, or ccache must be specified");
|
|
130
|
+
}
|
|
102
131
|
|
|
132
|
+
// Principal must be specified if using a password
|
|
103
133
|
if(RTEST(v_password)){
|
|
134
|
+
if(NIL_P(v_principal))
|
|
135
|
+
rb_raise(rb_eArgError, "principal must be specified");
|
|
136
|
+
|
|
104
137
|
Check_Type(v_password, T_STRING);
|
|
138
|
+
Check_Type(v_principal, T_STRING);
|
|
139
|
+
|
|
105
140
|
pass = StringValueCStr(v_password);
|
|
106
141
|
}
|
|
107
142
|
|
|
108
|
-
|
|
109
|
-
|
|
143
|
+
if(RTEST(v_ccache) && NIL_P(v_principal)){
|
|
144
|
+
if(NIL_P(v_principal))
|
|
145
|
+
v_principal = rb_funcall(v_ccache, rb_intern("principal"), 0);
|
|
146
|
+
}
|
|
110
147
|
|
|
148
|
+
// For a keytab use the first entry's principal
|
|
149
|
+
if(RTEST(v_keytab) && NIL_P(v_principal)) {
|
|
150
|
+
VALUE v_enum, v_first;
|
|
151
|
+
v_enum = rb_funcall(v_keytab, rb_intern("each"), 0);
|
|
152
|
+
v_first = rb_funcall(v_enum, rb_intern("first"), 0);
|
|
153
|
+
v_principal = rb_iv_get(v_first, "@principal");
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
user = StringValueCStr(v_principal);
|
|
111
157
|
if(NIL_P(v_service)){
|
|
112
158
|
service = (char *) "kadmin/admin";
|
|
113
159
|
}
|
|
@@ -116,16 +162,31 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
|
|
|
116
162
|
service = StringValueCStr(v_service);
|
|
117
163
|
}
|
|
118
164
|
|
|
119
|
-
v_db_args = rb_hash_aref2(v_opts, rb_str_new_cstr("db_args"));
|
|
120
|
-
if (NIL_P(v_db_args)) v_db_args = rb_hash_aref2(v_opts, ID2SYM(rb_intern("db_args")));
|
|
121
165
|
ptr->db_args = parse_db_args(v_db_args);
|
|
122
166
|
|
|
123
|
-
//
|
|
124
|
-
|
|
125
|
-
|
|
167
|
+
// Initialize or borrow the context
|
|
168
|
+
if(!NIL_P(v_context)){
|
|
169
|
+
RUBY_KRB5_CONTEXT* ctx_ptr;
|
|
126
170
|
|
|
127
|
-
|
|
128
|
-
|
|
171
|
+
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
172
|
+
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
173
|
+
|
|
174
|
+
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
175
|
+
|
|
176
|
+
if(!ctx_ptr->ctx)
|
|
177
|
+
rb_raise(cKrb5Exception, "context is closed");
|
|
178
|
+
|
|
179
|
+
ptr->ctx = ctx_ptr->ctx;
|
|
180
|
+
ptr->rb_context = v_context;
|
|
181
|
+
}
|
|
182
|
+
else{
|
|
183
|
+
kerror = krb5_init_context(&ptr->ctx);
|
|
184
|
+
|
|
185
|
+
if(kerror)
|
|
186
|
+
rb_raise(cKadm5Exception, "krb5_init_context: %s", error_message(kerror));
|
|
187
|
+
|
|
188
|
+
ptr->rb_context = Qnil;
|
|
189
|
+
}
|
|
129
190
|
|
|
130
191
|
// The docs say I can use NULL to get the default, but reality appears to be otherwise.
|
|
131
192
|
if(RTEST(v_keytab)){
|
|
@@ -175,8 +236,31 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
|
|
|
175
236
|
if(kerror)
|
|
176
237
|
rb_raise(cKadm5Exception, "kadm5_init_with_skey: %s", error_message(kerror));
|
|
177
238
|
}
|
|
178
|
-
else{
|
|
179
|
-
|
|
239
|
+
else if(RTEST(v_ccache)){
|
|
240
|
+
RUBY_KRB5_CCACHE* cc_ptr;
|
|
241
|
+
|
|
242
|
+
if(!rb_obj_is_kind_of(v_ccache, cKrb5CCache))
|
|
243
|
+
rb_raise(rb_eTypeError, "ccache must be a Kerberos::Krb5::CredentialsCache object");
|
|
244
|
+
|
|
245
|
+
TypedData_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, &rkrb5_ccache_data_type, cc_ptr);
|
|
246
|
+
|
|
247
|
+
if(!cc_ptr->ccache)
|
|
248
|
+
rb_raise(cKrb5Exception, "credentials cache is closed or destroyed");
|
|
249
|
+
|
|
250
|
+
kerror = kadm5_init_with_creds(
|
|
251
|
+
ptr->ctx,
|
|
252
|
+
user,
|
|
253
|
+
cc_ptr->ccache,
|
|
254
|
+
service,
|
|
255
|
+
NULL,
|
|
256
|
+
KADM5_STRUCT_VERSION,
|
|
257
|
+
KADM5_API_VERSION_3,
|
|
258
|
+
ptr->db_args,
|
|
259
|
+
&ptr->handle
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
if(kerror)
|
|
263
|
+
rb_raise(cKadm5Exception, "kadm5_init_with_creds: %s", error_message(kerror));
|
|
180
264
|
}
|
|
181
265
|
|
|
182
266
|
if(rb_block_given_p()){
|
|
@@ -280,50 +364,148 @@ static VALUE rkadm5_set_pwexpire(VALUE self, VALUE v_user, VALUE v_pwexpire){
|
|
|
280
364
|
|
|
281
365
|
/*
|
|
282
366
|
* call-seq:
|
|
283
|
-
* kadm5.create_principal(name
|
|
284
|
-
* kadm5.create_principal(principal)
|
|
367
|
+
* kadm5.create_principal(name:, password:, db_args: nil)
|
|
368
|
+
* kadm5.create_principal(principal:, password:, db_args: nil)
|
|
369
|
+
*
|
|
370
|
+
* Creates a new principal with an initial password of +password+.
|
|
285
371
|
*
|
|
286
|
-
*
|
|
287
|
-
* +
|
|
288
|
-
*
|
|
289
|
-
*
|
|
290
|
-
|
|
291
|
-
*
|
|
372
|
+
* The principal may be specified either as a +name+ string or as a
|
|
373
|
+
* +principal+ object (a Kerberos::Krb5::Principal). When a Principal
|
|
374
|
+
* object is provided, any non-nil writable attributes on that object
|
|
375
|
+
* are forwarded to the KDC:
|
|
376
|
+
*
|
|
377
|
+
* * +policy+
|
|
378
|
+
* * +expire_time+
|
|
379
|
+
* * +password_expiration+
|
|
380
|
+
* * +max_life+
|
|
381
|
+
* * +max_renewable_life+
|
|
382
|
+
* * +attributes+
|
|
383
|
+
*
|
|
384
|
+
* +db_args+ is an optional string or array of strings containing options
|
|
385
|
+
* that are usually passed to add_principal with the -x option. For a
|
|
386
|
+
* list of options, see the kadmin manpage, in the add_principal section.
|
|
292
387
|
*/
|
|
293
388
|
static VALUE rkadm5_create_principal(int argc, VALUE* argv, VALUE self){
|
|
294
389
|
RUBY_KADM5* ptr;
|
|
295
|
-
char* user;
|
|
296
390
|
char* pass;
|
|
297
391
|
char** db_args;
|
|
298
392
|
int mask;
|
|
299
393
|
kadm5_principal_ent_rec princ;
|
|
300
394
|
krb5_error_code kerror;
|
|
301
|
-
VALUE
|
|
395
|
+
VALUE v_opts, v_name, v_principal, v_pass, v_db_args;
|
|
396
|
+
ID kw_table[4] = { rb_intern("name"), rb_intern("principal"), rb_intern("password"), rb_intern("db_args") };
|
|
397
|
+
VALUE kw_vals[4];
|
|
302
398
|
|
|
303
399
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
304
400
|
|
|
305
|
-
rb_scan_args(argc, argv, "
|
|
306
|
-
|
|
401
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
402
|
+
|
|
403
|
+
if(NIL_P(v_opts))
|
|
404
|
+
v_opts = rb_hash_new();
|
|
405
|
+
|
|
406
|
+
rb_get_kwargs(v_opts, kw_table, 0, 4, kw_vals);
|
|
407
|
+
v_name = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
408
|
+
v_principal = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
409
|
+
v_pass = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
410
|
+
v_db_args = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
|
|
411
|
+
|
|
412
|
+
if(NIL_P(v_pass))
|
|
413
|
+
rb_raise(rb_eArgError, "password: is required");
|
|
414
|
+
|
|
307
415
|
Check_Type(v_pass, T_STRING);
|
|
308
416
|
|
|
417
|
+
if(NIL_P(v_name) && NIL_P(v_principal))
|
|
418
|
+
rb_raise(rb_eArgError, "name: or principal: is required");
|
|
419
|
+
|
|
420
|
+
if(RTEST(v_name) && RTEST(v_principal))
|
|
421
|
+
rb_raise(rb_eArgError, "name: and principal: are mutually exclusive");
|
|
422
|
+
|
|
309
423
|
memset(&princ, 0, sizeof(princ));
|
|
310
424
|
|
|
311
425
|
mask = KADM5_PRINCIPAL | KADM5_TL_DATA;
|
|
312
|
-
user = StringValueCStr(v_user);
|
|
313
426
|
pass = StringValueCStr(v_pass);
|
|
314
427
|
|
|
315
428
|
db_args = parse_db_args(v_db_args);
|
|
316
429
|
add_db_args(&princ, db_args);
|
|
317
|
-
|
|
430
|
+
free_db_args(db_args);
|
|
318
431
|
|
|
319
432
|
if(!ptr->ctx)
|
|
320
433
|
rb_raise(cKadm5Exception, "no context has been established");
|
|
321
434
|
|
|
322
|
-
|
|
435
|
+
// Determine the principal name and populate mask from the principal object
|
|
436
|
+
if(RTEST(v_principal)){
|
|
437
|
+
VALUE v_princ_name, v_policy, v_expire, v_pw_expire, v_max_life, v_max_renew, v_attrs;
|
|
323
438
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
439
|
+
if(!rb_obj_is_kind_of(v_principal, cKrb5Principal))
|
|
440
|
+
rb_raise(rb_eTypeError, "principal: must be a Kerberos::Krb5::Principal object");
|
|
441
|
+
|
|
442
|
+
v_princ_name = rb_iv_get(v_principal, "@principal");
|
|
443
|
+
|
|
444
|
+
if(NIL_P(v_princ_name))
|
|
445
|
+
rb_raise(rb_eArgError, "principal object has no name set");
|
|
446
|
+
|
|
447
|
+
Check_Type(v_princ_name, T_STRING);
|
|
448
|
+
|
|
449
|
+
kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_princ_name), &princ.principal);
|
|
450
|
+
|
|
451
|
+
if(kerror){
|
|
452
|
+
free_tl_data(princ.tl_data);
|
|
453
|
+
rb_raise(cKadm5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// Forward optional attributes from the Principal object
|
|
457
|
+
v_policy = rb_iv_get(v_principal, "@policy");
|
|
458
|
+
|
|
459
|
+
if(RTEST(v_policy)){
|
|
460
|
+
Check_Type(v_policy, T_STRING);
|
|
461
|
+
princ.policy = StringValueCStr(v_policy);
|
|
462
|
+
mask |= KADM5_POLICY;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
v_expire = rb_iv_get(v_principal, "@expire_time");
|
|
466
|
+
|
|
467
|
+
if(RTEST(v_expire)){
|
|
468
|
+
princ.princ_expire_time = (krb5_timestamp)NUM2LONG(rb_funcall(v_expire, rb_intern("to_i"), 0));
|
|
469
|
+
mask |= KADM5_PRINC_EXPIRE_TIME;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
v_pw_expire = rb_iv_get(v_principal, "@password_expiration");
|
|
473
|
+
|
|
474
|
+
if(RTEST(v_pw_expire)){
|
|
475
|
+
princ.pw_expiration = (krb5_timestamp)NUM2LONG(rb_funcall(v_pw_expire, rb_intern("to_i"), 0));
|
|
476
|
+
mask |= KADM5_PW_EXPIRATION;
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
v_max_life = rb_iv_get(v_principal, "@max_life");
|
|
480
|
+
|
|
481
|
+
if(RTEST(v_max_life)){
|
|
482
|
+
princ.max_life = NUM2LONG(v_max_life);
|
|
483
|
+
mask |= KADM5_MAX_LIFE;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
v_max_renew = rb_iv_get(v_principal, "@max_renewable_life");
|
|
487
|
+
|
|
488
|
+
if(RTEST(v_max_renew)){
|
|
489
|
+
princ.max_renewable_life = NUM2LONG(v_max_renew);
|
|
490
|
+
mask |= KADM5_MAX_RLIFE;
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
v_attrs = rb_iv_get(v_principal, "@attributes");
|
|
494
|
+
|
|
495
|
+
if(RTEST(v_attrs)){
|
|
496
|
+
princ.attributes = NUM2LONG(v_attrs);
|
|
497
|
+
mask |= KADM5_ATTRIBUTES;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
else{
|
|
501
|
+
Check_Type(v_name, T_STRING);
|
|
502
|
+
|
|
503
|
+
kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_name), &princ.principal);
|
|
504
|
+
|
|
505
|
+
if(kerror){
|
|
506
|
+
free_tl_data(princ.tl_data);
|
|
507
|
+
rb_raise(cKadm5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
508
|
+
}
|
|
327
509
|
}
|
|
328
510
|
|
|
329
511
|
kerror = kadm5_create_principal(ptr->handle, &princ, mask, pass);
|
|
@@ -395,15 +577,16 @@ static VALUE rkadm5_close(VALUE self){
|
|
|
395
577
|
if(ptr->princ)
|
|
396
578
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
397
579
|
|
|
398
|
-
if(ptr->ctx)
|
|
580
|
+
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
399
581
|
krb5_free_context(ptr->ctx);
|
|
400
582
|
|
|
401
|
-
|
|
583
|
+
free_db_args(ptr->db_args);
|
|
402
584
|
|
|
403
585
|
ptr->db_args = NULL;
|
|
404
586
|
ptr->ctx = NULL;
|
|
405
587
|
ptr->princ = NULL;
|
|
406
588
|
ptr->handle = NULL;
|
|
589
|
+
ptr->rb_context = Qnil;
|
|
407
590
|
|
|
408
591
|
return self;
|
|
409
592
|
}
|
|
@@ -412,11 +595,11 @@ static VALUE rkadm5_close(VALUE self){
|
|
|
412
595
|
static VALUE create_principal_from_entry(VALUE v_name, RUBY_KADM5* ptr, kadm5_principal_ent_rec* ent){
|
|
413
596
|
krb5_error_code kerror;
|
|
414
597
|
VALUE v_principal;
|
|
415
|
-
VALUE
|
|
598
|
+
VALUE v_opts = rb_hash_new();
|
|
416
599
|
|
|
417
|
-
|
|
600
|
+
rb_hash_aset(v_opts, ID2SYM(rb_intern("name")), v_name);
|
|
418
601
|
|
|
419
|
-
v_principal =
|
|
602
|
+
v_principal = rb_class_new_instance_kw(1, &v_opts, cKrb5Principal, RB_PASS_KEYWORDS);
|
|
420
603
|
|
|
421
604
|
rb_iv_set(v_principal, "@attributes", LONG2FIX(ent->attributes));
|
|
422
605
|
rb_iv_set(v_principal, "@aux_attributes", INT2FIX(ent->aux_attributes));
|
|
@@ -446,8 +629,10 @@ static VALUE create_principal_from_entry(VALUE v_name, RUBY_KADM5* ptr, kadm5_pr
|
|
|
446
629
|
char* mod_name;
|
|
447
630
|
kerror = krb5_unparse_name(ptr->ctx, ent->mod_name, &mod_name);
|
|
448
631
|
|
|
449
|
-
if(kerror)
|
|
632
|
+
if(kerror){
|
|
633
|
+
kadm5_free_principal_ent(ptr->handle, ent);
|
|
450
634
|
rb_raise(cKadm5Exception, "krb5_unparse_name: %s", error_message(kerror));
|
|
635
|
+
}
|
|
451
636
|
|
|
452
637
|
rb_iv_set(v_principal, "@mod_name", rb_str_new2(mod_name));
|
|
453
638
|
krb5_free_unparsed_name(ptr->ctx, mod_name);
|
|
@@ -459,6 +644,8 @@ static VALUE create_principal_from_entry(VALUE v_name, RUBY_KADM5* ptr, kadm5_pr
|
|
|
459
644
|
if(ent->policy)
|
|
460
645
|
rb_iv_set(v_principal, "@policy", rb_str_new2(ent->policy));
|
|
461
646
|
|
|
647
|
+
kadm5_free_principal_ent(ptr->handle, ent);
|
|
648
|
+
|
|
462
649
|
return v_principal;
|
|
463
650
|
}
|
|
464
651
|
|
|
@@ -518,7 +705,6 @@ static VALUE rkadm5_find_principal(VALUE self, VALUE v_user){
|
|
|
518
705
|
}
|
|
519
706
|
else{
|
|
520
707
|
v_principal = create_principal_from_entry(v_user, ptr, &ent);
|
|
521
|
-
kadm5_free_principal_ent(ptr->handle, &ent);
|
|
522
708
|
}
|
|
523
709
|
|
|
524
710
|
return v_principal;
|
|
@@ -580,8 +766,6 @@ static VALUE rkadm5_get_principal(VALUE self, VALUE v_user){
|
|
|
580
766
|
|
|
581
767
|
v_principal = create_principal_from_entry(v_user, ptr, &ent);
|
|
582
768
|
|
|
583
|
-
kadm5_free_principal_ent(ptr->handle, &ent);
|
|
584
|
-
|
|
585
769
|
return v_principal;
|
|
586
770
|
}
|
|
587
771
|
|
|
@@ -594,28 +778,39 @@ static VALUE rkadm5_get_principal(VALUE self, VALUE v_user){
|
|
|
594
778
|
* Example:
|
|
595
779
|
*
|
|
596
780
|
* # Using a Policy object
|
|
597
|
-
* policy = Kerberos::Kadm5::Policy.new(:
|
|
781
|
+
* policy = Kerberos::Kadm5::Policy.new(name: 'test', min_length: 5)
|
|
598
782
|
* kadm5.create_policy(policy)
|
|
599
783
|
*
|
|
600
|
-
* # Using
|
|
601
|
-
* kadm5.create_policy(:
|
|
784
|
+
* # Using keywords
|
|
785
|
+
* kadm5.create_policy(name: 'test', min_length: 5)
|
|
602
786
|
*/
|
|
603
|
-
static VALUE rkadm5_create_policy(VALUE
|
|
787
|
+
static VALUE rkadm5_create_policy(int argc, VALUE* argv, VALUE self){
|
|
604
788
|
RUBY_KADM5* ptr;
|
|
605
789
|
kadm5_ret_t kerror;
|
|
606
790
|
kadm5_policy_ent_rec ent;
|
|
607
791
|
long mask = KADM5_POLICY;
|
|
792
|
+
VALUE v_policy, v_kwargs;
|
|
608
793
|
VALUE v_name, v_min_classes, v_min_life, v_max_life, v_min_length, v_history_num;
|
|
609
794
|
|
|
610
795
|
TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
|
|
611
796
|
|
|
612
|
-
|
|
613
|
-
|
|
797
|
+
rb_scan_args(argc, argv, "01:", &v_policy, &v_kwargs);
|
|
798
|
+
|
|
799
|
+
if(!NIL_P(v_kwargs)){
|
|
614
800
|
VALUE v_args[1];
|
|
615
|
-
|
|
616
|
-
|
|
801
|
+
if(!NIL_P(v_policy))
|
|
802
|
+
rb_raise(rb_eArgError, "provide a Policy object or keyword arguments, not both");
|
|
803
|
+
|
|
804
|
+
v_args[0] = v_kwargs;
|
|
805
|
+
v_policy = rb_class_new_instance_kw(1, v_args, cKadm5Policy, RB_PASS_KEYWORDS);
|
|
617
806
|
}
|
|
618
807
|
|
|
808
|
+
if(NIL_P(v_policy))
|
|
809
|
+
rb_raise(rb_eArgError, "a Policy object or policy keywords are required");
|
|
810
|
+
|
|
811
|
+
if(!rb_obj_is_kind_of(v_policy, cKadm5Policy))
|
|
812
|
+
rb_raise(rb_eTypeError, "expected a Kerberos::Kadm5::Policy object or policy keywords");
|
|
813
|
+
|
|
619
814
|
v_name = rb_iv_get(v_policy, "@policy");
|
|
620
815
|
v_min_classes = rb_iv_get(v_policy, "@min_classes");
|
|
621
816
|
v_min_length = rb_iv_get(v_policy, "@min_length");
|
|
@@ -723,16 +918,16 @@ static VALUE rkadm5_get_policy(VALUE self, VALUE v_name){
|
|
|
723
918
|
VALUE v_arg[1];
|
|
724
919
|
VALUE v_hash = rb_hash_new();
|
|
725
920
|
|
|
726
|
-
rb_hash_aset(v_hash,
|
|
727
|
-
rb_hash_aset(v_hash,
|
|
728
|
-
rb_hash_aset(v_hash,
|
|
729
|
-
rb_hash_aset(v_hash,
|
|
730
|
-
rb_hash_aset(v_hash,
|
|
731
|
-
rb_hash_aset(v_hash,
|
|
921
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("name")), rb_str_new2(ent.policy));
|
|
922
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_life")), LONG2FIX(ent.pw_min_life));
|
|
923
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("max_life")), LONG2FIX(ent.pw_max_life));
|
|
924
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_length")), LONG2FIX(ent.pw_min_length));
|
|
925
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_classes")), LONG2FIX(ent.pw_min_classes));
|
|
926
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("history_num")), LONG2FIX(ent.pw_history_num));
|
|
732
927
|
|
|
733
928
|
v_arg[0] = v_hash;
|
|
734
929
|
|
|
735
|
-
v_policy =
|
|
930
|
+
v_policy = rb_class_new_instance_kw(1, v_arg, cKadm5Policy, RB_PASS_KEYWORDS);
|
|
736
931
|
|
|
737
932
|
kadm5_free_policy_ent(ptr->handle, &ent);
|
|
738
933
|
}
|
|
@@ -780,16 +975,16 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
|
|
|
780
975
|
VALUE v_arg[1];
|
|
781
976
|
VALUE v_hash = rb_hash_new();
|
|
782
977
|
|
|
783
|
-
rb_hash_aset(v_hash,
|
|
784
|
-
rb_hash_aset(v_hash,
|
|
785
|
-
rb_hash_aset(v_hash,
|
|
786
|
-
rb_hash_aset(v_hash,
|
|
787
|
-
rb_hash_aset(v_hash,
|
|
788
|
-
rb_hash_aset(v_hash,
|
|
978
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("name")), rb_str_new2(ent.policy));
|
|
979
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_life")), LONG2FIX(ent.pw_min_life));
|
|
980
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("max_life")), LONG2FIX(ent.pw_max_life));
|
|
981
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_length")), LONG2FIX(ent.pw_min_length));
|
|
982
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("min_classes")), LONG2FIX(ent.pw_min_classes));
|
|
983
|
+
rb_hash_aset(v_hash, ID2SYM(rb_intern("history_num")), LONG2FIX(ent.pw_history_num));
|
|
789
984
|
|
|
790
985
|
v_arg[0] = v_hash;
|
|
791
986
|
|
|
792
|
-
v_policy =
|
|
987
|
+
v_policy = rb_class_new_instance_kw(1, v_arg, cKadm5Policy, RB_PASS_KEYWORDS);
|
|
793
988
|
|
|
794
989
|
kadm5_free_policy_ent(ptr->handle, &ent);
|
|
795
990
|
}
|
|
@@ -1039,7 +1234,7 @@ char** parse_db_args(VALUE v_db_args){
|
|
|
1039
1234
|
switch(TYPE(v_db_args)){
|
|
1040
1235
|
case T_STRING:
|
|
1041
1236
|
db_args = (char **) malloc(2 * sizeof(char *));
|
|
1042
|
-
db_args[0] = StringValueCStr(v_db_args);
|
|
1237
|
+
db_args[0] = strdup(StringValueCStr(v_db_args));
|
|
1043
1238
|
db_args[1] = NULL;
|
|
1044
1239
|
break;
|
|
1045
1240
|
case T_ARRAY:
|
|
@@ -1049,7 +1244,7 @@ char** parse_db_args(VALUE v_db_args){
|
|
|
1049
1244
|
for(long i = 0; i < array_length; ++i){
|
|
1050
1245
|
VALUE elem = rb_ary_entry(v_db_args, i);
|
|
1051
1246
|
Check_Type(elem, T_STRING);
|
|
1052
|
-
db_args[i] = StringValueCStr(elem);
|
|
1247
|
+
db_args[i] = strdup(StringValueCStr(elem));
|
|
1053
1248
|
}
|
|
1054
1249
|
db_args[array_length] = NULL;
|
|
1055
1250
|
break;
|
|
@@ -1062,6 +1257,16 @@ char** parse_db_args(VALUE v_db_args){
|
|
|
1062
1257
|
return db_args;
|
|
1063
1258
|
}
|
|
1064
1259
|
|
|
1260
|
+
/**
|
|
1261
|
+
* Free a NULL-terminated array of strings returned by parse_db_args.
|
|
1262
|
+
*/
|
|
1263
|
+
static void free_db_args(char** db_args){
|
|
1264
|
+
if(!db_args) return;
|
|
1265
|
+
for(int i = 0; db_args[i] != NULL; i++)
|
|
1266
|
+
free(db_args[i]);
|
|
1267
|
+
free(db_args);
|
|
1268
|
+
}
|
|
1269
|
+
|
|
1065
1270
|
/**
|
|
1066
1271
|
* Add parsed db-args to principal entry
|
|
1067
1272
|
*/
|
|
@@ -1125,12 +1330,12 @@ void Init_kadm5(void){
|
|
|
1125
1330
|
|
|
1126
1331
|
// Initialization Method
|
|
1127
1332
|
|
|
1128
|
-
rb_define_method(cKadm5, "initialize", rkadm5_initialize, 1);
|
|
1333
|
+
rb_define_method(cKadm5, "initialize", rkadm5_initialize, -1);
|
|
1129
1334
|
|
|
1130
1335
|
// Instance Methods
|
|
1131
1336
|
|
|
1132
1337
|
rb_define_method(cKadm5, "close", rkadm5_close, 0);
|
|
1133
|
-
rb_define_method(cKadm5, "create_policy", rkadm5_create_policy, 1);
|
|
1338
|
+
rb_define_method(cKadm5, "create_policy", rkadm5_create_policy, -1);
|
|
1134
1339
|
rb_define_method(cKadm5, "create_principal", rkadm5_create_principal, -1);
|
|
1135
1340
|
rb_define_method(cKadm5, "delete_policy", rkadm5_delete_policy, 1);
|
|
1136
1341
|
rb_define_method(cKadm5, "delete_principal", rkadm5_delete_principal, 1);
|