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.
@@ -4,6 +4,13 @@ VALUE cKrb5Keytab, cKrb5KeytabException;
4
4
 
5
5
 
6
6
  // TypedData functions for RUBY_KRB5_KEYTAB
7
+ static void rkrb5_keytab_typed_mark(void *ptr) {
8
+ if (!ptr) return;
9
+ RUBY_KRB5_KEYTAB *kt = (RUBY_KRB5_KEYTAB *)ptr;
10
+ if (kt->rb_context != Qnil)
11
+ rb_gc_mark(kt->rb_context);
12
+ }
13
+
7
14
  void rkrb5_keytab_typed_free(void *ptr) {
8
15
  if (!ptr) return;
9
16
  RUBY_KRB5_KEYTAB *kt = (RUBY_KRB5_KEYTAB *)ptr;
@@ -11,8 +18,10 @@ void rkrb5_keytab_typed_free(void *ptr) {
11
18
  krb5_kt_close(kt->ctx, kt->keytab);
12
19
  if (kt->ctx)
13
20
  krb5_free_cred_contents(kt->ctx, &kt->creds);
14
- if (kt->ctx)
21
+ if (kt->ctx && kt->rb_context == Qnil)
15
22
  krb5_free_context(kt->ctx);
23
+ else if (kt->rb_context != Qnil)
24
+ rkrb5_context_release(kt->rb_context);
16
25
  free(kt);
17
26
  }
18
27
 
@@ -23,13 +32,14 @@ size_t rkrb5_keytab_typed_size(const void *ptr) {
23
32
  // Must NOT be static so it is exported
24
33
  const rb_data_type_t rkrb5_keytab_data_type = {
25
34
  "RUBY_KRB5_KEYTAB",
26
- {NULL, rkrb5_keytab_typed_free, rkrb5_keytab_typed_size,},
35
+ {rkrb5_keytab_typed_mark, rkrb5_keytab_typed_free, rkrb5_keytab_typed_size,},
27
36
  NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
28
37
  };
29
38
 
30
39
  VALUE rkrb5_keytab_allocate(VALUE klass){
31
40
  RUBY_KRB5_KEYTAB* ptr = ALLOC(RUBY_KRB5_KEYTAB);
32
41
  memset(ptr, 0, sizeof(RUBY_KRB5_KEYTAB));
42
+ ptr->rb_context = Qnil;
33
43
  return TypedData_Wrap_Struct(klass, &rkrb5_keytab_data_type, ptr);
34
44
  }
35
45
 
@@ -46,7 +56,7 @@ typedef struct {
46
56
  static VALUE rkrb5_keytab_each_body(VALUE arg){
47
57
  keytab_each_arg* ea = (keytab_each_arg*)arg;
48
58
  krb5_keytab_entry entry;
49
- krb5_error_code kerror;
59
+ krb5_error_code kerror, iteration_error;
50
60
  char* principal;
51
61
  VALUE v_kt_entry;
52
62
 
@@ -71,9 +81,13 @@ static VALUE rkrb5_keytab_each_body(VALUE arg){
71
81
  rb_yield(v_kt_entry);
72
82
  }
73
83
 
74
- ea->cursor_active = 0;
84
+ iteration_error = kerror;
75
85
 
76
86
  kerror = krb5_kt_end_seq_get(ea->ctx, ea->keytab, &ea->cursor);
87
+ ea->cursor_active = 0;
88
+
89
+ if(iteration_error != KRB5_KT_END)
90
+ rb_raise(cKrb5Exception, "krb5_kt_next_entry: %s", error_message(iteration_error));
77
91
 
78
92
  if(kerror)
79
93
  rb_raise(cKrb5Exception, "krb5_kt_end_seq_get: %s", error_message(kerror));
@@ -106,6 +120,9 @@ static VALUE rkrb5_keytab_each(VALUE self){
106
120
 
107
121
  TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
108
122
 
123
+ if(!ptr->ctx || !ptr->keytab)
124
+ rb_raise(cKrb5Exception, "keytab is closed");
125
+
109
126
  ea.ctx = ptr->ctx;
110
127
  ea.keytab = ptr->keytab;
111
128
 
@@ -136,6 +153,9 @@ static VALUE rkrb5_keytab_default_name(VALUE self){
136
153
 
137
154
  TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
138
155
 
156
+ if(!ptr->ctx)
157
+ rb_raise(cKrb5Exception, "no context has been established");
158
+
139
159
  kerror = krb5_kt_default_name(ptr->ctx, default_name, MAX_KEYTAB_NAME_LEN);
140
160
 
141
161
  if(kerror)
@@ -167,109 +187,192 @@ static VALUE rkrb5_keytab_close(VALUE self){
167
187
  if(ptr->ctx)
168
188
  krb5_free_cred_contents(ptr->ctx, &ptr->creds);
169
189
 
170
- if(ptr->ctx)
190
+ if(ptr->ctx && ptr->rb_context == Qnil)
171
191
  krb5_free_context(ptr->ctx);
192
+ else if(ptr->rb_context != Qnil)
193
+ rkrb5_context_release(ptr->rb_context);
172
194
 
173
195
  ptr->ctx = NULL;
196
+ ptr->rb_context = Qnil;
174
197
 
175
198
  return Qtrue;
176
199
  }
177
200
 
178
201
  /*
179
- static VALUE rkrb5_keytab_remove_entry(int argc, VALUE* argv, VALUE self){
202
+ * call-seq:
203
+ * keytab.add_entry(principal:, password:, vno: 1, enctype: 18)
204
+ *
205
+ * Add a new entry to the keytab for the given +principal+ string.
206
+ *
207
+ * A key is derived from +password+ (and the principal-based salt) using
208
+ * +krb5_c_string_to_key+, so the resulting key will match what the KDC
209
+ * would generate for the same password.
210
+ *
211
+ * Options:
212
+ * principal:: A Kerberos principal name string (required).
213
+ * password:: The password used to derive the key (required).
214
+ * vno:: Key version number (default 1).
215
+ * enctype:: Encryption type as an integer (default 18,
216
+ * aes256-cts-hmac-sha1-96).
217
+ *
218
+ * Returns +self+.
219
+ */
220
+ static VALUE rkrb5_keytab_add_entry(int argc, VALUE* argv, VALUE self){
180
221
  RUBY_KRB5_KEYTAB* ptr;
181
222
  krb5_error_code kerror;
182
223
  krb5_keytab_entry entry;
183
- char* name;
184
- VALUE v_name, v_vno, v_enctype;
224
+ krb5_data pwd_data, salt;
225
+ VALUE v_opts, v_principal, v_password, v_vno, v_enctype;
226
+ ID kw_table[4] = { rb_intern("principal"), rb_intern("password"), rb_intern("vno"), rb_intern("enctype") };
227
+ VALUE kw_vals[4];
185
228
 
186
229
  TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
187
230
 
188
- rb_scan_args(argc, argv, "12", &v_name, &v_vno, &v_enctype);
231
+ if(!ptr->ctx)
232
+ rb_raise(cKrb5Exception, "no context has been established");
189
233
 
190
- Check_Type(v_name, T_STRING);
234
+ rb_scan_args(argc, argv, "0:", &v_opts);
191
235
 
192
- name = StringValueCStr(v_name);
236
+ if(NIL_P(v_opts))
237
+ v_opts = rb_hash_new();
193
238
 
194
- if(!ptr->ctx)
195
- rb_raise(cKrb5Exception, "no context has been established");
239
+ rb_get_kwargs(v_opts, kw_table, 2, 2, kw_vals);
240
+ v_principal = kw_vals[0];
241
+ v_password = kw_vals[1];
242
+ v_vno = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
243
+ v_enctype = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
244
+
245
+ Check_Type(v_principal, T_STRING);
246
+ Check_Type(v_password, T_STRING);
247
+
248
+ memset(&entry, 0, sizeof(entry));
196
249
 
197
- kerror = krb5_parse_name(ptr->ctx, name, &entry.principal);
250
+ entry.vno = NIL_P(v_vno) ? 1 : NUM2INT(v_vno);
251
+ entry.key.enctype = NIL_P(v_enctype) ? ENCTYPE_AES256_CTS_HMAC_SHA1_96 : NUM2INT(v_enctype);
252
+
253
+ kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_principal), &entry.principal);
198
254
 
199
255
  if(kerror)
200
256
  rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
201
257
 
202
- if(NIL_P(v_vno))
203
- entry.vno = 0;
204
- else
205
- entry.vno = NUM2INT(v_vno);
258
+ entry.timestamp = time(NULL);
206
259
 
207
- if(NIL_P(v_enctype))
208
- entry.key.enctype = 0;
209
- else
210
- entry.key.enctype = NUM2INT(v_enctype);
260
+ // Derive the salt from the principal
261
+ kerror = krb5_principal2salt(ptr->ctx, entry.principal, &salt);
211
262
 
212
- entry.key.length = 16;
263
+ if(kerror){
264
+ krb5_free_principal(ptr->ctx, entry.principal);
265
+ rb_raise(cKrb5Exception, "krb5_principal2salt: %s", error_message(kerror));
266
+ }
213
267
 
214
- kerror = krb5_kt_remove_entry(
215
- ptr->ctx,
216
- ptr->keytab,
217
- &entry
218
- );
268
+ // Derive key from password + salt
269
+ pwd_data.data = StringValuePtr(v_password);
270
+ pwd_data.length = (unsigned int)RSTRING_LEN(v_password);
271
+
272
+ kerror = krb5_c_string_to_key(ptr->ctx, entry.key.enctype, &pwd_data, &salt, &entry.key);
273
+
274
+ krb5_free_data_contents(ptr->ctx, &salt);
275
+
276
+ if(kerror){
277
+ krb5_free_principal(ptr->ctx, entry.principal);
278
+ rb_raise(cKrb5Exception, "krb5_c_string_to_key: %s", error_message(kerror));
279
+ }
280
+
281
+ kerror = krb5_kt_add_entry(ptr->ctx, ptr->keytab, &entry);
282
+
283
+ krb5_free_keyblock_contents(ptr->ctx, &entry.key);
284
+ krb5_free_principal(ptr->ctx, entry.principal);
219
285
 
220
286
  if(kerror)
221
- rb_raise(cKrb5KeytabException, "krb5_kt_remove_entry: %s", error_message(kerror));
287
+ rb_raise(cKrb5KeytabException, "krb5_kt_add_entry: %s", error_message(kerror));
222
288
 
223
289
  return self;
224
290
  }
225
291
 
226
- static VALUE rkrb5_keytab_add_entry(int argc, VALUE* argv, VALUE self){
292
+ /*
293
+ * call-seq:
294
+ * keytab.remove_entry(principal:, vno: 0, enctype: 0)
295
+ *
296
+ * Remove entries from the keytab that match the given +principal+ string,
297
+ * +vno+, and +enctype+.
298
+ *
299
+ * A +vno+ of 0 (the default) matches any version number.
300
+ * An +enctype+ of 0 (the default) matches any encryption type.
301
+ *
302
+ * When both +vno+ and +enctype+ are 0 (the defaults), all entries for
303
+ * the +principal+ are removed.
304
+ *
305
+ * Options:
306
+ * principal:: A Kerberos principal name string (required).
307
+ * vno:: Key version number to match, 0 for any (default 0).
308
+ * enctype:: Encryption type to match, 0 for any (default 0).
309
+ *
310
+ * Returns +self+.
311
+ */
312
+ static VALUE rkrb5_keytab_remove_entry(int argc, VALUE* argv, VALUE self){
227
313
  RUBY_KRB5_KEYTAB* ptr;
228
314
  krb5_error_code kerror;
229
- krb5_keytab_entry entry;
230
- char* name;
231
- VALUE v_name, v_vno, v_enctype;
315
+ krb5_keytab_entry found_entry;
316
+ krb5_principal match_princ;
317
+ krb5_kvno match_vno;
318
+ krb5_enctype match_enctype;
319
+ int removed = 0;
320
+ VALUE v_opts, v_principal, v_vno, v_enctype;
321
+ ID kw_table[3] = { rb_intern("principal"), rb_intern("vno"), rb_intern("enctype") };
322
+ VALUE kw_vals[3];
232
323
 
233
324
  TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
234
325
 
235
- rb_scan_args(argc, argv, "12", &v_name, &v_vno, &v_enctype);
326
+ if(!ptr->ctx)
327
+ rb_raise(cKrb5Exception, "no context has been established");
236
328
 
237
- Check_Type(v_name, T_STRING);
329
+ rb_scan_args(argc, argv, "0:", &v_opts);
238
330
 
239
- name = StringValueCStr(v_name);
331
+ if(NIL_P(v_opts))
332
+ v_opts = rb_hash_new();
240
333
 
241
- if(!ptr->ctx)
242
- rb_raise(cKrb5Exception, "no context has been established");
334
+ rb_get_kwargs(v_opts, kw_table, 1, 2, kw_vals);
335
+ v_principal = kw_vals[0];
336
+ v_vno = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
337
+ v_enctype = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
338
+
339
+ Check_Type(v_principal, T_STRING);
243
340
 
244
- kerror = krb5_parse_name(ptr->ctx, name, &entry.principal);
341
+ match_vno = NIL_P(v_vno) ? 0 : NUM2INT(v_vno);
342
+ match_enctype = NIL_P(v_enctype) ? 0 : NUM2INT(v_enctype);
343
+
344
+ kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_principal), &match_princ);
245
345
 
246
346
  if(kerror)
247
347
  rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
248
348
 
249
- if(NIL_P(v_vno))
250
- entry.vno = 0;
251
- else
252
- entry.vno = NUM2INT(v_vno);
253
-
254
- if(NIL_P(v_enctype))
255
- entry.key.enctype = 0;
256
- else
257
- entry.key.enctype = NUM2INT(v_enctype);
349
+ // Retrieve the full entry via krb5_kt_get_entry and then pass the
350
+ // complete struct to krb5_kt_remove_entry so all fields match exactly.
351
+ // Loop to remove every matching entry when vno/enctype are wildcards.
352
+ while(1){
353
+ kerror = krb5_kt_get_entry(
354
+ ptr->ctx, ptr->keytab, match_princ,
355
+ match_vno, match_enctype, &found_entry
356
+ );
258
357
 
259
- entry.key.length = 16;
358
+ if(kerror){
359
+ krb5_free_principal(ptr->ctx, match_princ);
360
+ if(removed)
361
+ return self;
362
+ rb_raise(cKrb5KeytabException, "krb5_kt_remove_entry: %s", error_message(kerror));
363
+ }
260
364
 
261
- kerror = krb5_kt_add_entry(
262
- ptr->ctx,
263
- ptr->keytab,
264
- &entry
265
- );
365
+ kerror = krb5_kt_remove_entry(ptr->ctx, ptr->keytab, &found_entry);
366
+ krb5_kt_free_entry(ptr->ctx, &found_entry);
266
367
 
267
- if(kerror)
268
- rb_raise(cKrb5KeytabException, "krb5_kt_add_entry: %s", error_message(kerror));
368
+ if(kerror){
369
+ krb5_free_principal(ptr->ctx, match_princ);
370
+ rb_raise(cKrb5KeytabException, "krb5_kt_remove_entry: %s", error_message(kerror));
371
+ }
269
372
 
270
- return self;
373
+ removed = 1;
374
+ }
271
375
  }
272
- */
273
376
 
274
377
  /*
275
378
  * call-seq:
@@ -295,26 +398,22 @@ static VALUE rkrb5_keytab_get_entry(int argc, VALUE* argv, VALUE self){
295
398
 
296
399
  TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
297
400
 
401
+ if(!ptr->ctx || !ptr->keytab)
402
+ rb_raise(cKrb5Exception, "keytab is closed");
403
+
298
404
  rb_scan_args(argc, argv, "12", &v_principal, &v_vno, &v_enctype);
299
405
 
300
406
  Check_Type(v_principal, T_STRING);
301
407
  name = StringValueCStr(v_principal);
302
408
 
409
+ vno = NIL_P(v_vno) ? 0 : NUM2INT(v_vno);
410
+ enctype = NIL_P(v_enctype) ? 0 : NUM2INT(v_enctype);
411
+
303
412
  kerror = krb5_parse_name(ptr->ctx, name, &principal);
304
413
 
305
414
  if(kerror)
306
415
  rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
307
416
 
308
- if(NIL_P(v_vno))
309
- vno = 0;
310
- else
311
- vno = NUM2INT(v_vno);
312
-
313
- if(NIL_P(v_enctype))
314
- enctype = 0;
315
- else
316
- enctype = NUM2INT(v_enctype);
317
-
318
417
  kerror = krb5_kt_get_entry(
319
418
  ptr->ctx,
320
419
  ptr->keytab,
@@ -430,7 +529,7 @@ static VALUE rkrb5_keytab_dup(VALUE self){
430
529
 
431
530
  /*
432
531
  * call-seq:
433
- * Kerberos::Krb5::Keytab.new(name = nil)
532
+ * Kerberos::Krb5::Keytab.new(name: nil, context: nil)
434
533
  *
435
534
  * Creates and returns a new Kerberos::Krb5::Keytab object. This initializes
436
535
  * the context and keytab for future method calls on that object.
@@ -439,28 +538,56 @@ static VALUE rkrb5_keytab_dup(VALUE self){
439
538
  * name is used. If a +name+ is provided it must be in the form 'type:residual'
440
539
  * where 'type' is a type known to the Kerberos library.
441
540
  *
541
+ * An optional +context+ keyword argument may be provided. If given, it must
542
+ * be a Kerberos::Krb5::Context object and will be used instead of creating
543
+ * a new context via krb5_init_context.
544
+ *
442
545
  * Examples:
443
546
  *
444
547
  * # Using the default keytab
445
548
  * keytab = Kerberos::Krb5::Keytab.new
446
549
  *
447
550
  * # Using an explicit keytab
448
- * keytab = Kerberos::Krb5::Keytab.new('FILE:/etc/krb5.keytab')
551
+ * keytab = Kerberos::Krb5::Keytab.new(name: 'FILE:/etc/krb5.keytab')
552
+ *
553
+ * # Using a custom context
554
+ * ctx = Kerberos::Krb5::Context.new
555
+ * keytab = Kerberos::Krb5::Keytab.new(name: 'FILE:/etc/krb5.keytab', context: ctx)
449
556
  */
450
557
  static VALUE rkrb5_keytab_initialize(int argc, VALUE* argv, VALUE self){
451
558
  RUBY_KRB5_KEYTAB* ptr;
452
559
  krb5_error_code kerror;
453
560
  char keytab_name[MAX_KEYTAB_NAME_LEN];
454
561
  VALUE v_keytab_name = Qnil;
562
+ VALUE v_opts = Qnil;
563
+ VALUE v_context = Qnil;
564
+ ID kw_table[2] = { rb_intern("name"), rb_intern("context") };
565
+ VALUE kw_vals[2];
455
566
 
456
567
  TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
457
568
 
458
- rb_scan_args(argc, argv, "01", &v_keytab_name);
569
+ rb_scan_args(argc, argv, "0:", &v_opts);
459
570
 
460
- kerror = krb5_init_context(&ptr->ctx);
571
+ if(NIL_P(v_opts))
572
+ v_opts = rb_hash_new();
461
573
 
462
- if(kerror)
463
- rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
574
+ rb_get_kwargs(v_opts, kw_table, 0, 2, kw_vals);
575
+ v_keytab_name = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
576
+ v_context = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
577
+
578
+ // Initialize or borrow the context
579
+ if(!NIL_P(v_context)){
580
+ ptr->ctx = rkrb5_context_borrow(v_context);
581
+ ptr->rb_context = v_context;
582
+ }
583
+ else{
584
+ kerror = krb5_init_context(&ptr->ctx);
585
+
586
+ if(kerror)
587
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
588
+
589
+ ptr->rb_context = Qnil;
590
+ }
464
591
 
465
592
  // Use the default keytab name if one isn't provided.
466
593
  if(NIL_P(v_keytab_name)){
@@ -503,7 +630,7 @@ typedef struct {
503
630
  static VALUE rkrb5_s_keytab_foreach_body(VALUE arg){
504
631
  keytab_foreach_arg* fa = (keytab_foreach_arg*)arg;
505
632
  krb5_keytab_entry entry;
506
- krb5_error_code kerror;
633
+ krb5_error_code kerror, iteration_error;
507
634
  char* principal;
508
635
  VALUE v_kt_entry;
509
636
 
@@ -528,9 +655,13 @@ static VALUE rkrb5_s_keytab_foreach_body(VALUE arg){
528
655
  rb_yield(v_kt_entry);
529
656
  }
530
657
 
531
- fa->cursor_active = 0;
658
+ iteration_error = kerror;
532
659
 
533
660
  kerror = krb5_kt_end_seq_get(fa->ctx, fa->keytab, &fa->cursor);
661
+ fa->cursor_active = 0;
662
+
663
+ if(iteration_error != KRB5_KT_END)
664
+ rb_raise(cKrb5Exception, "krb5_kt_next_entry: %s", error_message(iteration_error));
534
665
 
535
666
  if(kerror)
536
667
  rb_raise(cKrb5Exception, "krb5_kt_end_seq_get: %s", error_message(kerror));
@@ -616,6 +747,26 @@ static VALUE rkrb5_s_keytab_foreach(int argc, VALUE* argv, VALUE klass){
616
747
  return Qnil;
617
748
  }
618
749
 
750
+ /*
751
+ * call-seq:
752
+ * keytab.have_content? -> true or false
753
+ *
754
+ * Returns true if the keytab exists and contains entries, false otherwise.
755
+ */
756
+ static VALUE rkrb5_keytab_have_content(VALUE self){
757
+ RUBY_KRB5_KEYTAB* ptr;
758
+ krb5_error_code kerror;
759
+
760
+ TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
761
+
762
+ if(!ptr->ctx)
763
+ rb_raise(cKrb5Exception, "no context has been established");
764
+
765
+ kerror = krb5_kt_have_content(ptr->ctx, ptr->keytab);
766
+
767
+ return kerror ? Qfalse : Qtrue;
768
+ }
769
+
619
770
  void Init_keytab(void){
620
771
  /* The Kerberos::Krb5::Keytab class encapsulates a Kerberos keytab. */
621
772
  cKrb5Keytab = rb_define_class_under(cKrb5, "Keytab", rb_cObject);
@@ -644,11 +795,11 @@ void Init_keytab(void){
644
795
  rb_define_method(cKrb5Keytab, "keytab_name", rkrb5_keytab_get_name, 0);
645
796
  rb_define_method(cKrb5Keytab, "keytab_type", rkrb5_keytab_get_type, 0);
646
797
  rb_define_method(cKrb5Keytab, "dup", rkrb5_keytab_dup, 0);
798
+ rb_define_method(cKrb5Keytab, "have_content?", rkrb5_keytab_have_content, 0);
647
799
  rb_define_alias(cKrb5Keytab, "clone", "dup");
648
800
 
649
- // TODO: Move these into Kadm5 and/or figure out how to set the vno properly.
650
- // rb_define_method(cKrb5Keytab, "add_entry", rkrb5_keytab_add_entry, -1);
651
- // rb_define_method(cKrb5Keytab, "remove_entry", rkrb5_keytab_remove_entry, -1);
801
+ rb_define_method(cKrb5Keytab, "add_entry", rkrb5_keytab_add_entry, -1);
802
+ rb_define_method(cKrb5Keytab, "remove_entry", rkrb5_keytab_remove_entry, -1);
652
803
 
653
804
  // Accessors
654
805
 
@@ -32,12 +32,12 @@ static VALUE rkadm5_policy_allocate(VALUE klass){
32
32
 
33
33
  /*
34
34
  * call-seq:
35
- * Kerberos::Kadm5::Policy.new(options)
35
+ * Kerberos::Kadm5::Policy.new(name:, min_life: nil, max_life: nil,
36
+ * min_length: nil, min_classes: nil, history_num: nil)
36
37
  *
37
- * Returns a new policy object using +options+ you choose to pass, where
38
- * the +options+ argument is a hash. This does NOT actually create the policy
39
- * object within Kerberos. To do that pass your Policy object to the
40
- * Kadm5.create_policy method.
38
+ * Returns a new policy object using the keyword arguments you choose to pass.
39
+ * This does NOT actually create the policy within Kerberos. To do that pass
40
+ * your Policy object to the Kadm5.create_policy method.
41
41
  *
42
42
  * The possible options are:
43
43
  *
@@ -50,32 +50,34 @@ static VALUE rkadm5_policy_allocate(VALUE klass){
50
50
  *
51
51
  * If you do not provide a :name then an ArgumentError will be raised.
52
52
  */
53
- static VALUE rkadm5_policy_init(VALUE self, VALUE v_options){
53
+ static VALUE rkadm5_policy_init(int argc, VALUE* argv, VALUE self){
54
54
  RUBY_KADM5_POLICY* ptr;
55
+ VALUE v_options;
55
56
  VALUE v_name, v_minlife, v_maxlife, v_minlength;
56
57
  VALUE v_minclasses, v_historynum;
58
+ ID kw_table[6] = {
59
+ rb_intern("name"), rb_intern("min_life"), rb_intern("max_life"),
60
+ rb_intern("min_length"), rb_intern("min_classes"), rb_intern("history_num")
61
+ };
62
+ VALUE kw_vals[6];
57
63
 
58
64
  TypedData_Get_Struct(self, RUBY_KADM5_POLICY, &rkadm5_policy_data_type, ptr);
59
65
 
60
- Check_Type(v_options, T_HASH);
66
+ rb_scan_args(argc, argv, "0:", &v_options);
61
67
 
62
- if(RTEST(rb_funcall(v_options, rb_intern("empty?"), 0)))
63
- rb_raise(rb_eArgError, "no policy options provided");
68
+ if(NIL_P(v_options))
69
+ v_options = rb_hash_new();
64
70
 
65
- v_name = rb_hash_aref2(v_options, rb_str_new_cstr("name"));
66
- v_minlife = rb_hash_aref2(v_options, rb_str_new_cstr("min_life"));
67
- v_maxlife = rb_hash_aref2(v_options, rb_str_new_cstr("max_life"));
68
- v_minlength = rb_hash_aref2(v_options, rb_str_new_cstr("min_length"));
69
- v_minclasses = rb_hash_aref2(v_options, rb_str_new_cstr("min_classes"));
70
- v_historynum = rb_hash_aref2(v_options, rb_str_new_cstr("history_num"));
71
+ rb_get_kwargs(v_options, kw_table, 1, 5, kw_vals);
72
+ v_name = kw_vals[0];
73
+ v_minlife = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
74
+ v_maxlife = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
75
+ v_minlength = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
76
+ v_minclasses = kw_vals[4] == Qundef ? Qnil : kw_vals[4];
77
+ v_historynum = kw_vals[5] == Qundef ? Qnil : kw_vals[5];
71
78
 
72
- if(NIL_P(v_name)){
73
- rb_raise(rb_eArgError, "name policy option is mandatory");
74
- }
75
- else{
76
- ptr->policy.policy = StringValueCStr(v_name);
77
- rb_iv_set(self, "@policy", v_name);
78
- }
79
+ ptr->policy.policy = StringValueCStr(v_name);
80
+ rb_iv_set(self, "@policy", v_name);
79
81
 
80
82
  if(!NIL_P(v_minlife)){
81
83
  ptr->policy.pw_min_life = NUM2LONG(v_minlife);
@@ -171,7 +173,7 @@ void Init_policy(void){
171
173
 
172
174
  // Initialization Function
173
175
 
174
- rb_define_method(cKadm5Policy, "initialize", rkadm5_policy_init, 1);
176
+ rb_define_method(cKadm5Policy, "initialize", rkadm5_policy_init, -1);
175
177
 
176
178
  // Instance methods
177
179