rkerberos 0.2.3 → 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.
@@ -17,6 +17,13 @@ void add_tl_data(krb5_int16 *, krb5_tl_data **,
17
17
 
18
18
 
19
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
+
20
27
  static void rkadm5_typed_free(void *ptr) {
21
28
  if (!ptr) return;
22
29
  RUBY_KADM5 *k = (RUBY_KADM5 *)ptr;
@@ -24,7 +31,7 @@ static void rkadm5_typed_free(void *ptr) {
24
31
  kadm5_destroy(k->handle);
25
32
  if (k->princ)
26
33
  krb5_free_principal(k->ctx, k->princ);
27
- if (k->ctx)
34
+ if (k->ctx && k->rb_context == Qnil)
28
35
  krb5_free_context(k->ctx);
29
36
  free_db_args(k->db_args);
30
37
  free(k);
@@ -36,7 +43,7 @@ static size_t rkadm5_typed_size(const void *ptr) {
36
43
 
37
44
  static const rb_data_type_t rkadm5_data_type = {
38
45
  "RUBY_KADM5",
39
- {NULL, rkadm5_typed_free, rkadm5_typed_size,},
46
+ {rkadm5_typed_mark, rkadm5_typed_free, rkadm5_typed_size,},
40
47
  NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
41
48
  };
42
49
 
@@ -44,34 +51,48 @@ static const rb_data_type_t rkadm5_data_type = {
44
51
  static VALUE rkadm5_allocate(VALUE klass){
45
52
  RUBY_KADM5* ptr = ALLOC(RUBY_KADM5);
46
53
  memset(ptr, 0, sizeof(RUBY_KADM5));
54
+ ptr->rb_context = Qnil;
47
55
  return TypedData_Wrap_Struct(klass, &rkadm5_data_type, ptr);
48
56
  }
49
57
 
50
58
  /*
51
59
  * call-seq:
52
- * Kerberos::Kadm5.new(:principal => 'name', :password => 'xxxxx')
53
- * Kerberos::Kadm5.new(:principal => 'name', :keytab => '/path/to/your/keytab')
54
- * Kerberos::Kadm5.new(:principal => 'name', :keytab => true)
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)
55
64
  *
56
- * Creates and returns a new Kerberos::Kadm5 object. A hash argument is
57
- * accepted that allows you to specify a principal and a password, or
58
- * a keytab file.
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.
59
68
  *
60
69
  * If you pass a string as the :keytab value it will attempt to use that file
61
70
  * for the keytab. If you pass true as the value it will attempt to use the
62
71
  * default keytab file, typically /etc/krb5.keytab.
63
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
+ *
64
77
  * You may also pass the :service option to specify the service name. The
65
78
  * default is kadmin/admin.
66
79
  *
67
80
  * There is also a :db_args option, which is a single string or array of strings
68
81
  * containing options usually passed to kadmin with the -x switch. For a list of
69
- * 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.
70
85
  *
71
86
  */
72
- static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
87
+ static VALUE rkadm5_initialize(int argc, VALUE* argv, VALUE self){
73
88
  RUBY_KADM5* ptr;
74
- 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];
75
96
  char* user;
76
97
  char* pass = NULL;
77
98
  char* keytab = NULL;
@@ -80,35 +101,59 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
80
101
  krb5_error_code kerror;
81
102
 
82
103
  TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
83
- Check_Type(v_opts, T_HASH);
84
-
85
- // Accept both string and symbol keys
86
- v_principal = rb_hash_aref2(v_opts, rb_str_new_cstr("principal"));
87
- if (NIL_P(v_principal)) v_principal = rb_hash_aref2(v_opts, ID2SYM(rb_intern("principal")));
88
-
89
- // Principal must be specified
90
- if(NIL_P(v_principal))
91
- rb_raise(rb_eArgError, "principal must be specified");
92
-
93
- Check_Type(v_principal, T_STRING);
94
- user = StringValueCStr(v_principal);
95
-
96
- v_password = rb_hash_aref2(v_opts, rb_str_new_cstr("password"));
97
- if (NIL_P(v_password)) v_password = rb_hash_aref2(v_opts, ID2SYM(rb_intern("password")));
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")));
100
-
101
- if(RTEST(v_password) && RTEST(v_keytab))
102
- rb_raise(rb_eArgError, "cannot use both a password and a keytab");
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
+ }
103
131
 
132
+ // Principal must be specified if using a password
104
133
  if(RTEST(v_password)){
134
+ if(NIL_P(v_principal))
135
+ rb_raise(rb_eArgError, "principal must be specified");
136
+
105
137
  Check_Type(v_password, T_STRING);
138
+ Check_Type(v_principal, T_STRING);
139
+
106
140
  pass = StringValueCStr(v_password);
107
141
  }
108
142
 
109
- v_service = rb_hash_aref2(v_opts, rb_str_new_cstr("service"));
110
- if (NIL_P(v_service)) v_service = rb_hash_aref2(v_opts, ID2SYM(rb_intern("service")));
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
+ }
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
+ }
111
155
 
156
+ user = StringValueCStr(v_principal);
112
157
  if(NIL_P(v_service)){
113
158
  service = (char *) "kadmin/admin";
114
159
  }
@@ -117,16 +162,31 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
117
162
  service = StringValueCStr(v_service);
118
163
  }
119
164
 
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
165
  ptr->db_args = parse_db_args(v_db_args);
123
166
 
124
- // Normally I would wait to initialize the context, but we might need it
125
- // to get the default keytab file name.
126
- kerror = krb5_init_context(&ptr->ctx);
167
+ // Initialize or borrow the context
168
+ if(!NIL_P(v_context)){
169
+ RUBY_KRB5_CONTEXT* ctx_ptr;
127
170
 
128
- if(kerror)
129
- rb_raise(cKadm5Exception, "krb5_init_context: %s", error_message(kerror));
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
+ }
130
190
 
131
191
  // The docs say I can use NULL to get the default, but reality appears to be otherwise.
132
192
  if(RTEST(v_keytab)){
@@ -176,8 +236,31 @@ static VALUE rkadm5_initialize(VALUE self, VALUE v_opts){
176
236
  if(kerror)
177
237
  rb_raise(cKadm5Exception, "kadm5_init_with_skey: %s", error_message(kerror));
178
238
  }
179
- else{
180
- // TODO: Credentials cache.
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));
181
264
  }
182
265
 
183
266
  if(rb_block_given_p()){
@@ -281,36 +364,65 @@ static VALUE rkadm5_set_pwexpire(VALUE self, VALUE v_user, VALUE v_pwexpire){
281
364
 
282
365
  /*
283
366
  * call-seq:
284
- * kadm5.create_principal(name, password, db_args=nil)
285
- * 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+.
371
+ *
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+
286
383
  *
287
- * Creates a new principal +name+ with an initial password of +password+.
288
- * +db_args+ is an optional string or array of strings containing options that are usually
289
- * passed to add_principal with the -x option. For a list of options, see the kadmin manpage,
290
- * in the add_principal section.
291
- *--
292
- * TODO: Allow a Principal object to be passed in as an argument.
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.
293
387
  */
294
388
  static VALUE rkadm5_create_principal(int argc, VALUE* argv, VALUE self){
295
389
  RUBY_KADM5* ptr;
296
- char* user;
297
390
  char* pass;
298
391
  char** db_args;
299
392
  int mask;
300
393
  kadm5_principal_ent_rec princ;
301
394
  krb5_error_code kerror;
302
- VALUE v_user, v_pass, v_db_args;
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];
303
398
 
304
399
  TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
305
400
 
306
- rb_scan_args(argc, argv, "21", &v_user, &v_pass, &v_db_args);
307
- Check_Type(v_user, T_STRING);
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
+
308
415
  Check_Type(v_pass, T_STRING);
309
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
+
310
423
  memset(&princ, 0, sizeof(princ));
311
424
 
312
425
  mask = KADM5_PRINCIPAL | KADM5_TL_DATA;
313
- user = StringValueCStr(v_user);
314
426
  pass = StringValueCStr(v_pass);
315
427
 
316
428
  db_args = parse_db_args(v_db_args);
@@ -320,11 +432,80 @@ static VALUE rkadm5_create_principal(int argc, VALUE* argv, VALUE self){
320
432
  if(!ptr->ctx)
321
433
  rb_raise(cKadm5Exception, "no context has been established");
322
434
 
323
- kerror = krb5_parse_name(ptr->ctx, user, &princ.principal);
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;
324
438
 
325
- if(kerror){
326
- free_tl_data(princ.tl_data);
327
- rb_raise(cKadm5Exception, "krb5_parse_name: %s", error_message(kerror));
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
+ }
328
509
  }
329
510
 
330
511
  kerror = kadm5_create_principal(ptr->handle, &princ, mask, pass);
@@ -396,7 +577,7 @@ static VALUE rkadm5_close(VALUE self){
396
577
  if(ptr->princ)
397
578
  krb5_free_principal(ptr->ctx, ptr->princ);
398
579
 
399
- if(ptr->ctx)
580
+ if(ptr->ctx && ptr->rb_context == Qnil)
400
581
  krb5_free_context(ptr->ctx);
401
582
 
402
583
  free_db_args(ptr->db_args);
@@ -405,6 +586,7 @@ static VALUE rkadm5_close(VALUE self){
405
586
  ptr->ctx = NULL;
406
587
  ptr->princ = NULL;
407
588
  ptr->handle = NULL;
589
+ ptr->rb_context = Qnil;
408
590
 
409
591
  return self;
410
592
  }
@@ -413,11 +595,11 @@ static VALUE rkadm5_close(VALUE self){
413
595
  static VALUE create_principal_from_entry(VALUE v_name, RUBY_KADM5* ptr, kadm5_principal_ent_rec* ent){
414
596
  krb5_error_code kerror;
415
597
  VALUE v_principal;
416
- VALUE v_args[1];
598
+ VALUE v_opts = rb_hash_new();
417
599
 
418
- v_args[0] = v_name;
600
+ rb_hash_aset(v_opts, ID2SYM(rb_intern("name")), v_name);
419
601
 
420
- v_principal = rb_class_new_instance(1, v_args, cKrb5Principal);
602
+ v_principal = rb_class_new_instance_kw(1, &v_opts, cKrb5Principal, RB_PASS_KEYWORDS);
421
603
 
422
604
  rb_iv_set(v_principal, "@attributes", LONG2FIX(ent->attributes));
423
605
  rb_iv_set(v_principal, "@aux_attributes", INT2FIX(ent->aux_attributes));
@@ -596,28 +778,39 @@ static VALUE rkadm5_get_principal(VALUE self, VALUE v_user){
596
778
  * Example:
597
779
  *
598
780
  * # Using a Policy object
599
- * policy = Kerberos::Kadm5::Policy.new(:name => 'test', :min_length => 5)
781
+ * policy = Kerberos::Kadm5::Policy.new(name: 'test', min_length: 5)
600
782
  * kadm5.create_policy(policy)
601
783
  *
602
- * # Using a hash
603
- * kadm5.create_policy(:name => 'test', :min_length => 5)
784
+ * # Using keywords
785
+ * kadm5.create_policy(name: 'test', min_length: 5)
604
786
  */
605
- static VALUE rkadm5_create_policy(VALUE self, VALUE v_policy){
787
+ static VALUE rkadm5_create_policy(int argc, VALUE* argv, VALUE self){
606
788
  RUBY_KADM5* ptr;
607
789
  kadm5_ret_t kerror;
608
790
  kadm5_policy_ent_rec ent;
609
791
  long mask = KADM5_POLICY;
792
+ VALUE v_policy, v_kwargs;
610
793
  VALUE v_name, v_min_classes, v_min_life, v_max_life, v_min_length, v_history_num;
611
794
 
612
795
  TypedData_Get_Struct(self, RUBY_KADM5, &rkadm5_data_type, ptr);
613
796
 
614
- // Allow a hash or a Policy object
615
- if(rb_obj_is_kind_of(v_policy, rb_cHash)){
797
+ rb_scan_args(argc, argv, "01:", &v_policy, &v_kwargs);
798
+
799
+ if(!NIL_P(v_kwargs)){
616
800
  VALUE v_args[1];
617
- v_args[0] = v_policy;
618
- v_policy = rb_class_new_instance(1, v_args, cKadm5Policy);
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);
619
806
  }
620
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
+
621
814
  v_name = rb_iv_get(v_policy, "@policy");
622
815
  v_min_classes = rb_iv_get(v_policy, "@min_classes");
623
816
  v_min_length = rb_iv_get(v_policy, "@min_length");
@@ -725,16 +918,16 @@ static VALUE rkadm5_get_policy(VALUE self, VALUE v_name){
725
918
  VALUE v_arg[1];
726
919
  VALUE v_hash = rb_hash_new();
727
920
 
728
- rb_hash_aset(v_hash, rb_str_new2("name"), rb_str_new2(ent.policy));
729
- rb_hash_aset(v_hash, rb_str_new2("min_life"), LONG2FIX(ent.pw_min_life));
730
- rb_hash_aset(v_hash, rb_str_new2("max_life"), LONG2FIX(ent.pw_max_life));
731
- rb_hash_aset(v_hash, rb_str_new2("min_length"), LONG2FIX(ent.pw_min_length));
732
- rb_hash_aset(v_hash, rb_str_new2("min_classes"), LONG2FIX(ent.pw_min_classes));
733
- rb_hash_aset(v_hash, rb_str_new2("history_num"), LONG2FIX(ent.pw_history_num));
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));
734
927
 
735
928
  v_arg[0] = v_hash;
736
929
 
737
- v_policy = rb_class_new_instance(1, v_arg, cKadm5Policy);
930
+ v_policy = rb_class_new_instance_kw(1, v_arg, cKadm5Policy, RB_PASS_KEYWORDS);
738
931
 
739
932
  kadm5_free_policy_ent(ptr->handle, &ent);
740
933
  }
@@ -782,16 +975,16 @@ static VALUE rkadm5_find_policy(VALUE self, VALUE v_name){
782
975
  VALUE v_arg[1];
783
976
  VALUE v_hash = rb_hash_new();
784
977
 
785
- rb_hash_aset(v_hash, rb_str_new2("name"), rb_str_new2(ent.policy));
786
- rb_hash_aset(v_hash, rb_str_new2("min_life"), LONG2FIX(ent.pw_min_life));
787
- rb_hash_aset(v_hash, rb_str_new2("max_life"), LONG2FIX(ent.pw_max_life));
788
- rb_hash_aset(v_hash, rb_str_new2("min_length"), LONG2FIX(ent.pw_min_length));
789
- rb_hash_aset(v_hash, rb_str_new2("min_classes"), LONG2FIX(ent.pw_min_classes));
790
- rb_hash_aset(v_hash, rb_str_new2("history_num"), LONG2FIX(ent.pw_history_num));
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));
791
984
 
792
985
  v_arg[0] = v_hash;
793
986
 
794
- v_policy = rb_class_new_instance(1, v_arg, cKadm5Policy);
987
+ v_policy = rb_class_new_instance_kw(1, v_arg, cKadm5Policy, RB_PASS_KEYWORDS);
795
988
 
796
989
  kadm5_free_policy_ent(ptr->handle, &ent);
797
990
  }
@@ -1137,12 +1330,12 @@ void Init_kadm5(void){
1137
1330
 
1138
1331
  // Initialization Method
1139
1332
 
1140
- rb_define_method(cKadm5, "initialize", rkadm5_initialize, 1);
1333
+ rb_define_method(cKadm5, "initialize", rkadm5_initialize, -1);
1141
1334
 
1142
1335
  // Instance Methods
1143
1336
 
1144
1337
  rb_define_method(cKadm5, "close", rkadm5_close, 0);
1145
- rb_define_method(cKadm5, "create_policy", rkadm5_create_policy, 1);
1338
+ rb_define_method(cKadm5, "create_policy", rkadm5_create_policy, -1);
1146
1339
  rb_define_method(cKadm5, "create_principal", rkadm5_create_principal, -1);
1147
1340
  rb_define_method(cKadm5, "delete_policy", rkadm5_delete_policy, 1);
1148
1341
  rb_define_method(cKadm5, "delete_principal", rkadm5_delete_principal, 1);