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.
- checksums.yaml +4 -4
- data/CHANGES.md +15 -0
- data/EXAMPLES.md +1015 -0
- data/MANIFEST.md +17 -12
- data/README.md +5 -5
- data/ext/rkerberos/ccache.c +101 -26
- data/ext/rkerberos/config.c +53 -7
- data/ext/rkerberos/context.c +70 -7
- data/ext/rkerberos/kadm5.c +280 -87
- data/ext/rkerberos/keytab.c +210 -64
- data/ext/rkerberos/policy.c +25 -23
- data/ext/rkerberos/principal.c +108 -10
- data/ext/rkerberos/rkerberos.c +229 -28
- data/ext/rkerberos/rkerberos.h +8 -0
- data/rkerberos.gemspec +10 -7
- data/spec/config_spec.rb +33 -0
- data/spec/context_spec.rb +51 -0
- data/spec/credentials_cache_spec.rb +79 -26
- data/spec/kadm5_spec.rb +278 -5
- data/spec/krb5_keytab_spec.rb +224 -20
- data/spec/krb5_spec.rb +131 -20
- data/spec/policy_spec.rb +4 -0
- data/spec/principal_spec.rb +90 -10
- metadata +9 -8
data/ext/rkerberos/keytab.c
CHANGED
|
@@ -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,7 +18,7 @@ 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);
|
|
16
23
|
free(kt);
|
|
17
24
|
}
|
|
@@ -23,13 +30,14 @@ size_t rkrb5_keytab_typed_size(const void *ptr) {
|
|
|
23
30
|
// Must NOT be static so it is exported
|
|
24
31
|
const rb_data_type_t rkrb5_keytab_data_type = {
|
|
25
32
|
"RUBY_KRB5_KEYTAB",
|
|
26
|
-
{
|
|
33
|
+
{rkrb5_keytab_typed_mark, rkrb5_keytab_typed_free, rkrb5_keytab_typed_size,},
|
|
27
34
|
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
|
|
28
35
|
};
|
|
29
36
|
|
|
30
37
|
VALUE rkrb5_keytab_allocate(VALUE klass){
|
|
31
38
|
RUBY_KRB5_KEYTAB* ptr = ALLOC(RUBY_KRB5_KEYTAB);
|
|
32
39
|
memset(ptr, 0, sizeof(RUBY_KRB5_KEYTAB));
|
|
40
|
+
ptr->rb_context = Qnil;
|
|
33
41
|
return TypedData_Wrap_Struct(klass, &rkrb5_keytab_data_type, ptr);
|
|
34
42
|
}
|
|
35
43
|
|
|
@@ -167,109 +175,189 @@ static VALUE rkrb5_keytab_close(VALUE self){
|
|
|
167
175
|
if(ptr->ctx)
|
|
168
176
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
169
177
|
|
|
170
|
-
if(ptr->ctx)
|
|
178
|
+
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
171
179
|
krb5_free_context(ptr->ctx);
|
|
172
180
|
|
|
173
181
|
ptr->ctx = NULL;
|
|
182
|
+
ptr->rb_context = Qnil;
|
|
174
183
|
|
|
175
184
|
return Qtrue;
|
|
176
185
|
}
|
|
177
186
|
|
|
178
187
|
/*
|
|
179
|
-
|
|
188
|
+
* call-seq:
|
|
189
|
+
* keytab.add_entry(principal:, password:, vno: 1, enctype: 18)
|
|
190
|
+
*
|
|
191
|
+
* Add a new entry to the keytab for the given +principal+ string.
|
|
192
|
+
*
|
|
193
|
+
* A key is derived from +password+ (and the principal-based salt) using
|
|
194
|
+
* +krb5_c_string_to_key+, so the resulting key will match what the KDC
|
|
195
|
+
* would generate for the same password.
|
|
196
|
+
*
|
|
197
|
+
* Options:
|
|
198
|
+
* principal:: A Kerberos principal name string (required).
|
|
199
|
+
* password:: The password used to derive the key (required).
|
|
200
|
+
* vno:: Key version number (default 1).
|
|
201
|
+
* enctype:: Encryption type as an integer (default 18,
|
|
202
|
+
* aes256-cts-hmac-sha1-96).
|
|
203
|
+
*
|
|
204
|
+
* Returns +self+.
|
|
205
|
+
*/
|
|
206
|
+
static VALUE rkrb5_keytab_add_entry(int argc, VALUE* argv, VALUE self){
|
|
180
207
|
RUBY_KRB5_KEYTAB* ptr;
|
|
181
208
|
krb5_error_code kerror;
|
|
182
209
|
krb5_keytab_entry entry;
|
|
183
|
-
|
|
184
|
-
VALUE
|
|
210
|
+
krb5_data pwd_data, salt;
|
|
211
|
+
VALUE v_opts, v_principal, v_password, v_vno, v_enctype;
|
|
212
|
+
ID kw_table[4] = { rb_intern("principal"), rb_intern("password"), rb_intern("vno"), rb_intern("enctype") };
|
|
213
|
+
VALUE kw_vals[4];
|
|
185
214
|
|
|
186
215
|
TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
|
|
187
216
|
|
|
188
|
-
|
|
217
|
+
if(!ptr->ctx)
|
|
218
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
189
219
|
|
|
190
|
-
|
|
220
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
191
221
|
|
|
192
|
-
|
|
222
|
+
if(NIL_P(v_opts))
|
|
223
|
+
v_opts = rb_hash_new();
|
|
193
224
|
|
|
194
|
-
|
|
195
|
-
|
|
225
|
+
rb_get_kwargs(v_opts, kw_table, 2, 2, kw_vals);
|
|
226
|
+
v_principal = kw_vals[0];
|
|
227
|
+
v_password = kw_vals[1];
|
|
228
|
+
v_vno = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
229
|
+
v_enctype = kw_vals[3] == Qundef ? Qnil : kw_vals[3];
|
|
230
|
+
|
|
231
|
+
Check_Type(v_principal, T_STRING);
|
|
232
|
+
Check_Type(v_password, T_STRING);
|
|
196
233
|
|
|
197
|
-
|
|
234
|
+
memset(&entry, 0, sizeof(entry));
|
|
235
|
+
|
|
236
|
+
kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_principal), &entry.principal);
|
|
198
237
|
|
|
199
238
|
if(kerror)
|
|
200
239
|
rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
201
240
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
entry.vno = NUM2INT(v_vno);
|
|
241
|
+
entry.vno = NIL_P(v_vno) ? 1 : NUM2INT(v_vno);
|
|
242
|
+
entry.key.enctype = NIL_P(v_enctype) ? ENCTYPE_AES256_CTS_HMAC_SHA1_96 : NUM2INT(v_enctype);
|
|
243
|
+
entry.timestamp = time(NULL);
|
|
206
244
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
else
|
|
210
|
-
entry.key.enctype = NUM2INT(v_enctype);
|
|
245
|
+
// Derive the salt from the principal
|
|
246
|
+
kerror = krb5_principal2salt(ptr->ctx, entry.principal, &salt);
|
|
211
247
|
|
|
212
|
-
|
|
248
|
+
if(kerror){
|
|
249
|
+
krb5_free_principal(ptr->ctx, entry.principal);
|
|
250
|
+
rb_raise(cKrb5Exception, "krb5_principal2salt: %s", error_message(kerror));
|
|
251
|
+
}
|
|
213
252
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
);
|
|
253
|
+
// Derive key from password + salt
|
|
254
|
+
pwd_data.data = StringValuePtr(v_password);
|
|
255
|
+
pwd_data.length = (unsigned int)RSTRING_LEN(v_password);
|
|
256
|
+
|
|
257
|
+
kerror = krb5_c_string_to_key(ptr->ctx, entry.key.enctype, &pwd_data, &salt, &entry.key);
|
|
258
|
+
|
|
259
|
+
krb5_free_data_contents(ptr->ctx, &salt);
|
|
260
|
+
|
|
261
|
+
if(kerror){
|
|
262
|
+
krb5_free_principal(ptr->ctx, entry.principal);
|
|
263
|
+
rb_raise(cKrb5Exception, "krb5_c_string_to_key: %s", error_message(kerror));
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
kerror = krb5_kt_add_entry(ptr->ctx, ptr->keytab, &entry);
|
|
267
|
+
|
|
268
|
+
krb5_free_keyblock_contents(ptr->ctx, &entry.key);
|
|
269
|
+
krb5_free_principal(ptr->ctx, entry.principal);
|
|
219
270
|
|
|
220
271
|
if(kerror)
|
|
221
|
-
rb_raise(cKrb5KeytabException, "
|
|
272
|
+
rb_raise(cKrb5KeytabException, "krb5_kt_add_entry: %s", error_message(kerror));
|
|
222
273
|
|
|
223
274
|
return self;
|
|
224
275
|
}
|
|
225
276
|
|
|
226
|
-
|
|
277
|
+
/*
|
|
278
|
+
* call-seq:
|
|
279
|
+
* keytab.remove_entry(principal:, vno: 0, enctype: 0)
|
|
280
|
+
*
|
|
281
|
+
* Remove entries from the keytab that match the given +principal+ string,
|
|
282
|
+
* +vno+, and +enctype+.
|
|
283
|
+
*
|
|
284
|
+
* A +vno+ of 0 (the default) matches any version number.
|
|
285
|
+
* An +enctype+ of 0 (the default) matches any encryption type.
|
|
286
|
+
*
|
|
287
|
+
* When both +vno+ and +enctype+ are 0 (the defaults), all entries for
|
|
288
|
+
* the +principal+ are removed.
|
|
289
|
+
*
|
|
290
|
+
* Options:
|
|
291
|
+
* principal:: A Kerberos principal name string (required).
|
|
292
|
+
* vno:: Key version number to match, 0 for any (default 0).
|
|
293
|
+
* enctype:: Encryption type to match, 0 for any (default 0).
|
|
294
|
+
*
|
|
295
|
+
* Returns +self+.
|
|
296
|
+
*/
|
|
297
|
+
static VALUE rkrb5_keytab_remove_entry(int argc, VALUE* argv, VALUE self){
|
|
227
298
|
RUBY_KRB5_KEYTAB* ptr;
|
|
228
299
|
krb5_error_code kerror;
|
|
229
|
-
krb5_keytab_entry
|
|
230
|
-
|
|
231
|
-
|
|
300
|
+
krb5_keytab_entry found_entry;
|
|
301
|
+
krb5_principal match_princ;
|
|
302
|
+
krb5_kvno match_vno;
|
|
303
|
+
krb5_enctype match_enctype;
|
|
304
|
+
int removed = 0;
|
|
305
|
+
VALUE v_opts, v_principal, v_vno, v_enctype;
|
|
306
|
+
ID kw_table[3] = { rb_intern("principal"), rb_intern("vno"), rb_intern("enctype") };
|
|
307
|
+
VALUE kw_vals[3];
|
|
232
308
|
|
|
233
309
|
TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
|
|
234
310
|
|
|
235
|
-
|
|
311
|
+
if(!ptr->ctx)
|
|
312
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
236
313
|
|
|
237
|
-
|
|
314
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
238
315
|
|
|
239
|
-
|
|
316
|
+
if(NIL_P(v_opts))
|
|
317
|
+
v_opts = rb_hash_new();
|
|
240
318
|
|
|
241
|
-
|
|
242
|
-
|
|
319
|
+
rb_get_kwargs(v_opts, kw_table, 1, 2, kw_vals);
|
|
320
|
+
v_principal = kw_vals[0];
|
|
321
|
+
v_vno = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
322
|
+
v_enctype = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
243
323
|
|
|
244
|
-
|
|
324
|
+
Check_Type(v_principal, T_STRING);
|
|
325
|
+
|
|
326
|
+
kerror = krb5_parse_name(ptr->ctx, StringValueCStr(v_principal), &match_princ);
|
|
245
327
|
|
|
246
328
|
if(kerror)
|
|
247
329
|
rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
248
330
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
else
|
|
252
|
-
entry.vno = NUM2INT(v_vno);
|
|
331
|
+
match_vno = NIL_P(v_vno) ? 0 : NUM2INT(v_vno);
|
|
332
|
+
match_enctype = NIL_P(v_enctype) ? 0 : NUM2INT(v_enctype);
|
|
253
333
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
334
|
+
// Retrieve the full entry via krb5_kt_get_entry and then pass the
|
|
335
|
+
// complete struct to krb5_kt_remove_entry so all fields match exactly.
|
|
336
|
+
// Loop to remove every matching entry when vno/enctype are wildcards.
|
|
337
|
+
while(1){
|
|
338
|
+
kerror = krb5_kt_get_entry(
|
|
339
|
+
ptr->ctx, ptr->keytab, match_princ,
|
|
340
|
+
match_vno, match_enctype, &found_entry
|
|
341
|
+
);
|
|
258
342
|
|
|
259
|
-
|
|
343
|
+
if(kerror){
|
|
344
|
+
krb5_free_principal(ptr->ctx, match_princ);
|
|
345
|
+
if(removed)
|
|
346
|
+
return self;
|
|
347
|
+
rb_raise(cKrb5KeytabException, "krb5_kt_remove_entry: %s", error_message(kerror));
|
|
348
|
+
}
|
|
260
349
|
|
|
261
|
-
|
|
262
|
-
ptr->ctx,
|
|
263
|
-
ptr->keytab,
|
|
264
|
-
&entry
|
|
265
|
-
);
|
|
350
|
+
kerror = krb5_kt_remove_entry(ptr->ctx, ptr->keytab, &found_entry);
|
|
351
|
+
krb5_kt_free_entry(ptr->ctx, &found_entry);
|
|
266
352
|
|
|
267
|
-
|
|
268
|
-
|
|
353
|
+
if(kerror){
|
|
354
|
+
krb5_free_principal(ptr->ctx, match_princ);
|
|
355
|
+
rb_raise(cKrb5KeytabException, "krb5_kt_remove_entry: %s", error_message(kerror));
|
|
356
|
+
}
|
|
269
357
|
|
|
270
|
-
|
|
358
|
+
removed = 1;
|
|
359
|
+
}
|
|
271
360
|
}
|
|
272
|
-
*/
|
|
273
361
|
|
|
274
362
|
/*
|
|
275
363
|
* call-seq:
|
|
@@ -430,7 +518,7 @@ static VALUE rkrb5_keytab_dup(VALUE self){
|
|
|
430
518
|
|
|
431
519
|
/*
|
|
432
520
|
* call-seq:
|
|
433
|
-
* Kerberos::Krb5::Keytab.new(name
|
|
521
|
+
* Kerberos::Krb5::Keytab.new(name: nil, context: nil)
|
|
434
522
|
*
|
|
435
523
|
* Creates and returns a new Kerberos::Krb5::Keytab object. This initializes
|
|
436
524
|
* the context and keytab for future method calls on that object.
|
|
@@ -439,28 +527,66 @@ static VALUE rkrb5_keytab_dup(VALUE self){
|
|
|
439
527
|
* name is used. If a +name+ is provided it must be in the form 'type:residual'
|
|
440
528
|
* where 'type' is a type known to the Kerberos library.
|
|
441
529
|
*
|
|
530
|
+
* An optional +context+ keyword argument may be provided. If given, it must
|
|
531
|
+
* be a Kerberos::Krb5::Context object and will be used instead of creating
|
|
532
|
+
* a new context via krb5_init_context.
|
|
533
|
+
*
|
|
442
534
|
* Examples:
|
|
443
535
|
*
|
|
444
536
|
* # Using the default keytab
|
|
445
537
|
* keytab = Kerberos::Krb5::Keytab.new
|
|
446
538
|
*
|
|
447
539
|
* # Using an explicit keytab
|
|
448
|
-
* keytab = Kerberos::Krb5::Keytab.new('FILE:/etc/krb5.keytab')
|
|
540
|
+
* keytab = Kerberos::Krb5::Keytab.new(name: 'FILE:/etc/krb5.keytab')
|
|
541
|
+
*
|
|
542
|
+
* # Using a custom context
|
|
543
|
+
* ctx = Kerberos::Krb5::Context.new
|
|
544
|
+
* keytab = Kerberos::Krb5::Keytab.new(name: 'FILE:/etc/krb5.keytab', context: ctx)
|
|
449
545
|
*/
|
|
450
546
|
static VALUE rkrb5_keytab_initialize(int argc, VALUE* argv, VALUE self){
|
|
451
547
|
RUBY_KRB5_KEYTAB* ptr;
|
|
452
548
|
krb5_error_code kerror;
|
|
453
549
|
char keytab_name[MAX_KEYTAB_NAME_LEN];
|
|
454
550
|
VALUE v_keytab_name = Qnil;
|
|
551
|
+
VALUE v_opts = Qnil;
|
|
552
|
+
VALUE v_context = Qnil;
|
|
553
|
+
ID kw_table[2] = { rb_intern("name"), rb_intern("context") };
|
|
554
|
+
VALUE kw_vals[2];
|
|
455
555
|
|
|
456
556
|
TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
|
|
457
557
|
|
|
458
|
-
rb_scan_args(argc, argv, "
|
|
558
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
459
559
|
|
|
460
|
-
|
|
560
|
+
if(NIL_P(v_opts))
|
|
561
|
+
v_opts = rb_hash_new();
|
|
461
562
|
|
|
462
|
-
|
|
463
|
-
|
|
563
|
+
rb_get_kwargs(v_opts, kw_table, 0, 2, kw_vals);
|
|
564
|
+
v_keytab_name = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
565
|
+
v_context = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
566
|
+
|
|
567
|
+
// Initialize or borrow the context
|
|
568
|
+
if(!NIL_P(v_context)){
|
|
569
|
+
RUBY_KRB5_CONTEXT* ctx_ptr;
|
|
570
|
+
|
|
571
|
+
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
572
|
+
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
573
|
+
|
|
574
|
+
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
575
|
+
|
|
576
|
+
if(!ctx_ptr->ctx)
|
|
577
|
+
rb_raise(cKrb5Exception, "context is closed");
|
|
578
|
+
|
|
579
|
+
ptr->ctx = ctx_ptr->ctx;
|
|
580
|
+
ptr->rb_context = v_context;
|
|
581
|
+
}
|
|
582
|
+
else{
|
|
583
|
+
kerror = krb5_init_context(&ptr->ctx);
|
|
584
|
+
|
|
585
|
+
if(kerror)
|
|
586
|
+
rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
|
|
587
|
+
|
|
588
|
+
ptr->rb_context = Qnil;
|
|
589
|
+
}
|
|
464
590
|
|
|
465
591
|
// Use the default keytab name if one isn't provided.
|
|
466
592
|
if(NIL_P(v_keytab_name)){
|
|
@@ -616,6 +742,26 @@ static VALUE rkrb5_s_keytab_foreach(int argc, VALUE* argv, VALUE klass){
|
|
|
616
742
|
return Qnil;
|
|
617
743
|
}
|
|
618
744
|
|
|
745
|
+
/*
|
|
746
|
+
* call-seq:
|
|
747
|
+
* keytab.have_content? -> true or false
|
|
748
|
+
*
|
|
749
|
+
* Returns true if the keytab exists and contains entries, false otherwise.
|
|
750
|
+
*/
|
|
751
|
+
static VALUE rkrb5_keytab_have_content(VALUE self){
|
|
752
|
+
RUBY_KRB5_KEYTAB* ptr;
|
|
753
|
+
krb5_error_code kerror;
|
|
754
|
+
|
|
755
|
+
TypedData_Get_Struct(self, RUBY_KRB5_KEYTAB, &rkrb5_keytab_data_type, ptr);
|
|
756
|
+
|
|
757
|
+
if(!ptr->ctx)
|
|
758
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
759
|
+
|
|
760
|
+
kerror = krb5_kt_have_content(ptr->ctx, ptr->keytab);
|
|
761
|
+
|
|
762
|
+
return kerror ? Qfalse : Qtrue;
|
|
763
|
+
}
|
|
764
|
+
|
|
619
765
|
void Init_keytab(void){
|
|
620
766
|
/* The Kerberos::Krb5::Keytab class encapsulates a Kerberos keytab. */
|
|
621
767
|
cKrb5Keytab = rb_define_class_under(cKrb5, "Keytab", rb_cObject);
|
|
@@ -644,11 +790,11 @@ void Init_keytab(void){
|
|
|
644
790
|
rb_define_method(cKrb5Keytab, "keytab_name", rkrb5_keytab_get_name, 0);
|
|
645
791
|
rb_define_method(cKrb5Keytab, "keytab_type", rkrb5_keytab_get_type, 0);
|
|
646
792
|
rb_define_method(cKrb5Keytab, "dup", rkrb5_keytab_dup, 0);
|
|
793
|
+
rb_define_method(cKrb5Keytab, "have_content?", rkrb5_keytab_have_content, 0);
|
|
647
794
|
rb_define_alias(cKrb5Keytab, "clone", "dup");
|
|
648
795
|
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
// rb_define_method(cKrb5Keytab, "remove_entry", rkrb5_keytab_remove_entry, -1);
|
|
796
|
+
rb_define_method(cKrb5Keytab, "add_entry", rkrb5_keytab_add_entry, -1);
|
|
797
|
+
rb_define_method(cKrb5Keytab, "remove_entry", rkrb5_keytab_remove_entry, -1);
|
|
652
798
|
|
|
653
799
|
// Accessors
|
|
654
800
|
|
data/ext/rkerberos/policy.c
CHANGED
|
@@ -32,12 +32,12 @@ static VALUE rkadm5_policy_allocate(VALUE klass){
|
|
|
32
32
|
|
|
33
33
|
/*
|
|
34
34
|
* call-seq:
|
|
35
|
-
* Kerberos::Kadm5::Policy.new(
|
|
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
|
|
38
|
-
*
|
|
39
|
-
*
|
|
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
|
|
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
|
-
|
|
66
|
+
rb_scan_args(argc, argv, "0:", &v_options);
|
|
61
67
|
|
|
62
|
-
if(
|
|
63
|
-
|
|
68
|
+
if(NIL_P(v_options))
|
|
69
|
+
v_options = rb_hash_new();
|
|
64
70
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
|
data/ext/rkerberos/principal.c
CHANGED
|
@@ -4,12 +4,19 @@ VALUE cKrb5Principal;
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
// TypedData functions for RUBY_KRB5_PRINC
|
|
7
|
+
static void rkrb5_princ_typed_mark(void *ptr) {
|
|
8
|
+
if (!ptr) return;
|
|
9
|
+
RUBY_KRB5_PRINC *p = (RUBY_KRB5_PRINC *)ptr;
|
|
10
|
+
if (p->rb_context != Qnil)
|
|
11
|
+
rb_gc_mark(p->rb_context);
|
|
12
|
+
}
|
|
13
|
+
|
|
7
14
|
static void rkrb5_princ_typed_free(void *ptr) {
|
|
8
15
|
if (!ptr) return;
|
|
9
16
|
RUBY_KRB5_PRINC *p = (RUBY_KRB5_PRINC *)ptr;
|
|
10
17
|
if (p->principal)
|
|
11
18
|
krb5_free_principal(p->ctx, p->principal);
|
|
12
|
-
if (p->ctx)
|
|
19
|
+
if (p->ctx && p->rb_context == Qnil)
|
|
13
20
|
krb5_free_context(p->ctx);
|
|
14
21
|
free(p);
|
|
15
22
|
}
|
|
@@ -20,7 +27,7 @@ static size_t rkrb5_princ_typed_size(const void *ptr) {
|
|
|
20
27
|
|
|
21
28
|
static const rb_data_type_t rkrb5_princ_data_type = {
|
|
22
29
|
"RUBY_KRB5_PRINC",
|
|
23
|
-
{
|
|
30
|
+
{rkrb5_princ_typed_mark, rkrb5_princ_typed_free, rkrb5_princ_typed_size,},
|
|
24
31
|
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
|
|
25
32
|
};
|
|
26
33
|
|
|
@@ -28,34 +35,78 @@ static const rb_data_type_t rkrb5_princ_data_type = {
|
|
|
28
35
|
static VALUE rkrb5_princ_allocate(VALUE klass){
|
|
29
36
|
RUBY_KRB5_PRINC* ptr = ALLOC(RUBY_KRB5_PRINC);
|
|
30
37
|
memset(ptr, 0, sizeof(RUBY_KRB5_PRINC));
|
|
38
|
+
ptr->rb_context = Qnil;
|
|
31
39
|
return TypedData_Wrap_Struct(klass, &rkrb5_princ_data_type, ptr);
|
|
32
40
|
}
|
|
33
41
|
|
|
34
42
|
/*
|
|
35
43
|
* call-seq:
|
|
36
|
-
* Kerberos::Krb5::Principal.new(name)
|
|
44
|
+
* Kerberos::Krb5::Principal.new(name: nil, context: nil)
|
|
37
45
|
*
|
|
38
46
|
* Creates and returns a new Krb5::Principal object. If a block is provided
|
|
39
47
|
* then it yields itself.
|
|
40
48
|
*
|
|
49
|
+
* A principal +name+ may be provided as a keyword argument. If not provided
|
|
50
|
+
* or nil, the principal attribute will be nil.
|
|
51
|
+
*
|
|
52
|
+
* An optional +context+ keyword argument may be provided. If given, it must
|
|
53
|
+
* be a Kerberos::Krb5::Context object and will be used instead of creating
|
|
54
|
+
* a new context via krb5_init_context.
|
|
55
|
+
*
|
|
41
56
|
* Example:
|
|
42
57
|
*
|
|
43
|
-
* principal1 = Kerberos::Krb5::Principal.new('Jon')
|
|
58
|
+
* principal1 = Kerberos::Krb5::Principal.new(name: 'Jon')
|
|
44
59
|
*
|
|
45
|
-
* principal2 = Kerberos::Krb5::Principal.new('Jon') do |pr|
|
|
60
|
+
* principal2 = Kerberos::Krb5::Principal.new(name: 'Jon') do |pr|
|
|
46
61
|
* pr.expire_time = Time.now + 20000
|
|
47
62
|
* end
|
|
63
|
+
*
|
|
64
|
+
* ctx = Kerberos::Krb5::Context.new
|
|
65
|
+
* principal3 = Kerberos::Krb5::Principal.new(name: 'Jon', context: ctx)
|
|
48
66
|
*/
|
|
49
|
-
static VALUE rkrb5_princ_initialize(VALUE
|
|
67
|
+
static VALUE rkrb5_princ_initialize(int argc, VALUE* argv, VALUE self){
|
|
50
68
|
RUBY_KRB5_PRINC* ptr;
|
|
51
69
|
krb5_error_code kerror;
|
|
70
|
+
VALUE v_opts = Qnil;
|
|
71
|
+
VALUE v_name = Qnil;
|
|
72
|
+
VALUE v_context = Qnil;
|
|
73
|
+
ID kw_table[2] = { rb_intern("name"), rb_intern("context") };
|
|
74
|
+
VALUE kw_vals[2];
|
|
52
75
|
|
|
53
76
|
TypedData_Get_Struct(self, RUBY_KRB5_PRINC, &rkrb5_princ_data_type, ptr);
|
|
54
77
|
|
|
55
|
-
|
|
78
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
79
|
+
|
|
80
|
+
if(NIL_P(v_opts))
|
|
81
|
+
v_opts = rb_hash_new();
|
|
82
|
+
|
|
83
|
+
rb_get_kwargs(v_opts, kw_table, 0, 2, kw_vals);
|
|
84
|
+
v_name = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
85
|
+
v_context = kw_vals[1] == Qundef ? Qnil : kw_vals[1];
|
|
86
|
+
|
|
87
|
+
// Initialize or borrow the context
|
|
88
|
+
if(!NIL_P(v_context)){
|
|
89
|
+
RUBY_KRB5_CONTEXT* ctx_ptr;
|
|
90
|
+
|
|
91
|
+
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
92
|
+
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
93
|
+
|
|
94
|
+
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
56
95
|
|
|
57
|
-
|
|
58
|
-
|
|
96
|
+
if(!ctx_ptr->ctx)
|
|
97
|
+
rb_raise(cKrb5Exception, "context is closed");
|
|
98
|
+
|
|
99
|
+
ptr->ctx = ctx_ptr->ctx;
|
|
100
|
+
ptr->rb_context = v_context;
|
|
101
|
+
}
|
|
102
|
+
else{
|
|
103
|
+
kerror = krb5_init_context(&ptr->ctx);
|
|
104
|
+
|
|
105
|
+
if(kerror)
|
|
106
|
+
rb_raise(cKrb5Exception, "krb5_init_context failed: %s", error_message(kerror));
|
|
107
|
+
|
|
108
|
+
ptr->rb_context = Qnil;
|
|
109
|
+
}
|
|
59
110
|
|
|
60
111
|
if(NIL_P(v_name)){
|
|
61
112
|
rb_iv_set(self, "@principal", Qnil);
|
|
@@ -233,6 +284,51 @@ static VALUE rkrb5_princ_inspect(VALUE self){
|
|
|
233
284
|
return v_str;
|
|
234
285
|
}
|
|
235
286
|
|
|
287
|
+
/*
|
|
288
|
+
* call-seq:
|
|
289
|
+
* principal.principal_type -> Integer
|
|
290
|
+
*
|
|
291
|
+
* Returns the type of the principal as an integer, e.g.
|
|
292
|
+
* KRB5_NT_PRINCIPAL (1), KRB5_NT_SRV_HST (2), etc.
|
|
293
|
+
*/
|
|
294
|
+
static VALUE rkrb5_princ_get_type(VALUE self){
|
|
295
|
+
RUBY_KRB5_PRINC* ptr;
|
|
296
|
+
|
|
297
|
+
TypedData_Get_Struct(self, RUBY_KRB5_PRINC, &rkrb5_princ_data_type, ptr);
|
|
298
|
+
|
|
299
|
+
if(!ptr->principal)
|
|
300
|
+
rb_raise(cKrb5Exception, "no principal has been established");
|
|
301
|
+
|
|
302
|
+
return INT2FIX(krb5_princ_type(ptr->ctx, ptr->principal));
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/*
|
|
306
|
+
* call-seq:
|
|
307
|
+
* principal.components -> Array
|
|
308
|
+
*
|
|
309
|
+
* Returns an array of the component strings that make up this principal
|
|
310
|
+
* name (excluding the realm). For example, "admin/instance@REALM" would
|
|
311
|
+
* return ["admin", "instance"].
|
|
312
|
+
*/
|
|
313
|
+
static VALUE rkrb5_princ_components(VALUE self){
|
|
314
|
+
RUBY_KRB5_PRINC* ptr;
|
|
315
|
+
|
|
316
|
+
TypedData_Get_Struct(self, RUBY_KRB5_PRINC, &rkrb5_princ_data_type, ptr);
|
|
317
|
+
|
|
318
|
+
if(!ptr->principal)
|
|
319
|
+
rb_raise(cKrb5Exception, "no principal has been established");
|
|
320
|
+
|
|
321
|
+
int n = krb5_princ_size(ptr->ctx, ptr->principal);
|
|
322
|
+
VALUE v_array = rb_ary_new_capa(n);
|
|
323
|
+
|
|
324
|
+
for(int i = 0; i < n; i++){
|
|
325
|
+
krb5_data* component = krb5_princ_component(ptr->ctx, ptr->principal, i);
|
|
326
|
+
rb_ary_push(v_array, rb_str_new(component->data, component->length));
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
return v_array;
|
|
330
|
+
}
|
|
331
|
+
|
|
236
332
|
void Init_principal(void){
|
|
237
333
|
/* The Kerberos::Krb5::Principal class encapsulates a Kerberos principal. */
|
|
238
334
|
cKrb5Principal = rb_define_class_under(cKrb5, "Principal", rb_cObject);
|
|
@@ -243,7 +339,7 @@ void Init_principal(void){
|
|
|
243
339
|
|
|
244
340
|
// Constructor
|
|
245
341
|
|
|
246
|
-
rb_define_method(cKrb5Principal, "initialize", rkrb5_princ_initialize, 1);
|
|
342
|
+
rb_define_method(cKrb5Principal, "initialize", rkrb5_princ_initialize, -1);
|
|
247
343
|
|
|
248
344
|
// Instance Methods
|
|
249
345
|
|
|
@@ -251,6 +347,8 @@ void Init_principal(void){
|
|
|
251
347
|
rb_define_method(cKrb5Principal, "realm", rkrb5_princ_get_realm, 0);
|
|
252
348
|
rb_define_method(cKrb5Principal, "realm=", rkrb5_princ_set_realm, 1);
|
|
253
349
|
rb_define_method(cKrb5Principal, "==", rkrb5_princ_equal, 1);
|
|
350
|
+
rb_define_method(cKrb5Principal, "principal_type", rkrb5_princ_get_type, 0);
|
|
351
|
+
rb_define_method(cKrb5Principal, "components", rkrb5_princ_components, 0);
|
|
254
352
|
|
|
255
353
|
// Attributes
|
|
256
354
|
|