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/rkerberos.c
CHANGED
|
@@ -25,6 +25,13 @@ VALUE rb_hash_aref2(VALUE v_hash, VALUE v_key){
|
|
|
25
25
|
|
|
26
26
|
|
|
27
27
|
// TypedData functions for RUBY_KRB5
|
|
28
|
+
static void rkrb5_typed_mark(void *ptr) {
|
|
29
|
+
if (!ptr) return;
|
|
30
|
+
RUBY_KRB5 *r = (RUBY_KRB5 *)ptr;
|
|
31
|
+
if (r->rb_context != Qnil)
|
|
32
|
+
rb_gc_mark(r->rb_context);
|
|
33
|
+
}
|
|
34
|
+
|
|
28
35
|
static void rkrb5_typed_free(void *ptr) {
|
|
29
36
|
if (!ptr) return;
|
|
30
37
|
RUBY_KRB5 *r = (RUBY_KRB5 *)ptr;
|
|
@@ -34,7 +41,7 @@ static void rkrb5_typed_free(void *ptr) {
|
|
|
34
41
|
krb5_free_cred_contents(r->ctx, &r->creds);
|
|
35
42
|
if (r->princ)
|
|
36
43
|
krb5_free_principal(r->ctx, r->princ);
|
|
37
|
-
if (r->ctx)
|
|
44
|
+
if (r->ctx && r->rb_context == Qnil)
|
|
38
45
|
krb5_free_context(r->ctx);
|
|
39
46
|
free(r);
|
|
40
47
|
}
|
|
@@ -43,9 +50,9 @@ static size_t rkrb5_typed_size(const void *ptr) {
|
|
|
43
50
|
return sizeof(RUBY_KRB5);
|
|
44
51
|
}
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
const rb_data_type_t rkrb5_data_type = {
|
|
47
54
|
"RUBY_KRB5",
|
|
48
|
-
{
|
|
55
|
+
{rkrb5_typed_mark, rkrb5_typed_free, rkrb5_typed_size,},
|
|
49
56
|
NULL, NULL, RUBY_TYPED_FREE_IMMEDIATELY
|
|
50
57
|
};
|
|
51
58
|
|
|
@@ -53,26 +60,63 @@ static const rb_data_type_t rkrb5_data_type = {
|
|
|
53
60
|
static VALUE rkrb5_allocate(VALUE klass){
|
|
54
61
|
RUBY_KRB5* ptr = ALLOC(RUBY_KRB5);
|
|
55
62
|
memset(ptr, 0, sizeof(RUBY_KRB5));
|
|
63
|
+
ptr->rb_context = Qnil;
|
|
56
64
|
return TypedData_Wrap_Struct(klass, &rkrb5_data_type, ptr);
|
|
57
65
|
}
|
|
58
66
|
|
|
59
67
|
/*
|
|
60
68
|
* call-seq:
|
|
61
|
-
* Kerberos::Krb5.new
|
|
69
|
+
* Kerberos::Krb5.new(context: nil)
|
|
62
70
|
*
|
|
63
71
|
* Creates and returns a new Kerberos::Krb5 object. This initializes the
|
|
64
72
|
* context for future method calls on that object.
|
|
73
|
+
*
|
|
74
|
+
* If a +context+ keyword argument is provided, it must be a
|
|
75
|
+
* Kerberos::Krb5::Context object. The context will be borrowed rather than
|
|
76
|
+
* creating a new one internally via krb5_init_context. The caller is
|
|
77
|
+
* responsible for keeping the Context object alive for the lifetime of
|
|
78
|
+
* this Krb5 instance.
|
|
79
|
+
*
|
|
80
|
+
* A block form is also supported. If a block is given, the object is
|
|
81
|
+
* yielded to the block and automatically closed when the block returns.
|
|
65
82
|
*/
|
|
66
|
-
static VALUE rkrb5_initialize(VALUE self){
|
|
83
|
+
static VALUE rkrb5_initialize(int argc, VALUE* argv, VALUE self){
|
|
67
84
|
RUBY_KRB5* ptr;
|
|
85
|
+
VALUE v_opts, v_context;
|
|
86
|
+
ID kw_table[1] = { rb_intern("context") };
|
|
87
|
+
VALUE kw_vals[1];
|
|
68
88
|
krb5_error_code kerror;
|
|
69
89
|
|
|
70
90
|
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
71
91
|
|
|
72
|
-
|
|
92
|
+
rb_scan_args(argc, argv, "0:", &v_opts);
|
|
73
93
|
|
|
74
|
-
if(
|
|
75
|
-
|
|
94
|
+
if(NIL_P(v_opts))
|
|
95
|
+
v_opts = rb_hash_new();
|
|
96
|
+
|
|
97
|
+
rb_get_kwargs(v_opts, kw_table, 0, 1, kw_vals);
|
|
98
|
+
v_context = kw_vals[0] == Qundef ? Qnil : kw_vals[0];
|
|
99
|
+
|
|
100
|
+
if(!NIL_P(v_context)){
|
|
101
|
+
RUBY_KRB5_CONTEXT* ctx_ptr;
|
|
102
|
+
|
|
103
|
+
if(!rb_obj_is_kind_of(v_context, cKrb5Context))
|
|
104
|
+
rb_raise(rb_eTypeError, "context must be a Kerberos::Krb5::Context object");
|
|
105
|
+
|
|
106
|
+
TypedData_Get_Struct(v_context, RUBY_KRB5_CONTEXT, &rkrb5_context_data_type, ctx_ptr);
|
|
107
|
+
|
|
108
|
+
if(!ctx_ptr->ctx)
|
|
109
|
+
rb_raise(cKrb5Exception, "context is closed");
|
|
110
|
+
|
|
111
|
+
ptr->ctx = ctx_ptr->ctx;
|
|
112
|
+
ptr->rb_context = v_context;
|
|
113
|
+
}
|
|
114
|
+
else{
|
|
115
|
+
kerror = krb5_init_context(&ptr->ctx);
|
|
116
|
+
|
|
117
|
+
if(kerror)
|
|
118
|
+
rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
|
|
119
|
+
}
|
|
76
120
|
|
|
77
121
|
if(rb_block_given_p()){
|
|
78
122
|
rb_ensure(rb_yield, self, rkrb5_close, self);
|
|
@@ -140,7 +184,7 @@ static VALUE rkrb5_set_default_realm(int argc, VALUE* argv, VALUE self){
|
|
|
140
184
|
}
|
|
141
185
|
|
|
142
186
|
/* call-seq:
|
|
143
|
-
* krb5.get_init_creds_keytab(principal
|
|
187
|
+
* krb5.get_init_creds_keytab(principal: nil, keytab: nil, service: nil, ccache: nil)
|
|
144
188
|
*
|
|
145
189
|
* Acquire credentials for +principal+ from +keytab+ using +service+. If
|
|
146
190
|
* no principal is specified, then a principal is derived from the service
|
|
@@ -154,7 +198,10 @@ static VALUE rkrb5_set_default_realm(int argc, VALUE* argv, VALUE self){
|
|
|
154
198
|
*/
|
|
155
199
|
static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
156
200
|
RUBY_KRB5* ptr;
|
|
157
|
-
VALUE v_user, v_keytab_name, v_service, v_ccache;
|
|
201
|
+
VALUE v_user = Qnil, v_keytab_name = Qnil, v_service = Qnil, v_ccache = Qnil;
|
|
202
|
+
VALUE v_kwargs = Qnil;
|
|
203
|
+
ID kw_table[4] = { rb_intern("principal"), rb_intern("keytab"), rb_intern("service"), rb_intern("ccache") };
|
|
204
|
+
VALUE kw_vals[4];
|
|
158
205
|
char* user;
|
|
159
206
|
char* service;
|
|
160
207
|
char keytab_name[MAX_KEYTAB_NAME_LEN];
|
|
@@ -181,18 +228,36 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
|
181
228
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
182
229
|
memset(&ptr->creds, 0, sizeof(ptr->creds));
|
|
183
230
|
|
|
231
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
232
|
+
|
|
233
|
+
if(NIL_P(v_kwargs))
|
|
234
|
+
v_kwargs = rb_hash_new();
|
|
235
|
+
|
|
236
|
+
rb_get_kwargs(v_kwargs, kw_table, 0, 4, kw_vals);
|
|
237
|
+
if(kw_vals[0] != Qundef) v_user = kw_vals[0];
|
|
238
|
+
if(kw_vals[1] != Qundef) v_keytab_name = kw_vals[1];
|
|
239
|
+
if(kw_vals[2] != Qundef) v_service = kw_vals[2];
|
|
240
|
+
if(kw_vals[3] != Qundef) v_ccache = kw_vals[3];
|
|
241
|
+
|
|
242
|
+
// Validate argument types before allocating opt, so type errors don't leak it.
|
|
243
|
+
if(!NIL_P(v_user))
|
|
244
|
+
Check_Type(v_user, T_STRING);
|
|
245
|
+
|
|
246
|
+
if(!NIL_P(v_keytab_name))
|
|
247
|
+
Check_Type(v_keytab_name, T_STRING);
|
|
248
|
+
|
|
249
|
+
if(!NIL_P(v_service))
|
|
250
|
+
Check_Type(v_service, T_STRING);
|
|
251
|
+
|
|
184
252
|
kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt);
|
|
185
253
|
if(kerror)
|
|
186
254
|
rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror));
|
|
187
255
|
|
|
188
|
-
rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache);
|
|
189
|
-
|
|
190
256
|
// We need the service information for later.
|
|
191
257
|
if(NIL_P(v_service)){
|
|
192
258
|
service = NULL;
|
|
193
259
|
}
|
|
194
260
|
else{
|
|
195
|
-
Check_Type(v_service, T_STRING);
|
|
196
261
|
service = StringValueCStr(v_service);
|
|
197
262
|
}
|
|
198
263
|
|
|
@@ -212,7 +277,6 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
|
212
277
|
}
|
|
213
278
|
}
|
|
214
279
|
else{
|
|
215
|
-
Check_Type(v_user, T_STRING);
|
|
216
280
|
user = StringValueCStr(v_user);
|
|
217
281
|
|
|
218
282
|
kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ);
|
|
@@ -233,7 +297,6 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
|
233
297
|
}
|
|
234
298
|
}
|
|
235
299
|
else{
|
|
236
|
-
Check_Type(v_keytab_name, T_STRING);
|
|
237
300
|
strncpy(keytab_name, StringValueCStr(v_keytab_name), MAX_KEYTAB_NAME_LEN - 1);
|
|
238
301
|
keytab_name[MAX_KEYTAB_NAME_LEN - 1] = '\0';
|
|
239
302
|
}
|
|
@@ -293,7 +356,7 @@ static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
|
|
|
293
356
|
*
|
|
294
357
|
* Example:
|
|
295
358
|
*
|
|
296
|
-
* krb5.get_init_creds_password('foo', 'XXXXXX') # Authenticate 'foo' user
|
|
359
|
+
* krb5.get_init_creds_password(principal: 'foo', password: 'XXXXXX') # Authenticate 'foo' user
|
|
297
360
|
* krb5.change_password('XXXXXX', 'YYYYYY') # Change password for 'foo'
|
|
298
361
|
*/
|
|
299
362
|
static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){
|
|
@@ -371,19 +434,26 @@ static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){
|
|
|
371
434
|
|
|
372
435
|
/*
|
|
373
436
|
* call-seq:
|
|
374
|
-
* krb5.get_init_creds_password(
|
|
437
|
+
* krb5.get_init_creds_password(principal: nil, password: nil, service: nil, ccache: nil)
|
|
375
438
|
*
|
|
376
|
-
* Authenticates the credentials of +
|
|
439
|
+
* Authenticates the credentials of +principal+ using +password+ against +service+,
|
|
377
440
|
* and has the effect of setting the principal and context internally. This method
|
|
378
441
|
* must typically be called before using other methods.
|
|
442
|
+
*
|
|
443
|
+
* When +ccache+ is given, the acquired credentials will be written into the
|
|
444
|
+
* provided Kerberos::Krb5::CredentialsCache.
|
|
379
445
|
*/
|
|
380
446
|
static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
381
447
|
RUBY_KRB5* ptr;
|
|
382
|
-
VALUE v_user, v_pass, v_service;
|
|
448
|
+
VALUE v_user = Qnil, v_pass = Qnil, v_service = Qnil, v_ccache = Qnil;
|
|
449
|
+
VALUE v_kwargs = Qnil;
|
|
450
|
+
ID kw_table[4] = { rb_intern("principal"), rb_intern("password"), rb_intern("service"), rb_intern("ccache") };
|
|
451
|
+
VALUE kw_vals[4];
|
|
383
452
|
char* user;
|
|
384
453
|
char* pass;
|
|
385
454
|
char* service;
|
|
386
455
|
krb5_error_code kerror;
|
|
456
|
+
krb5_get_init_creds_opt* opt = NULL;
|
|
387
457
|
|
|
388
458
|
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
389
459
|
|
|
@@ -399,7 +469,19 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
399
469
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
400
470
|
memset(&ptr->creds, 0, sizeof(ptr->creds));
|
|
401
471
|
|
|
402
|
-
rb_scan_args(argc, argv, "
|
|
472
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
473
|
+
|
|
474
|
+
if(NIL_P(v_kwargs))
|
|
475
|
+
v_kwargs = rb_hash_new();
|
|
476
|
+
|
|
477
|
+
rb_get_kwargs(v_kwargs, kw_table, 0, 4, kw_vals);
|
|
478
|
+
if(kw_vals[0] != Qundef) v_user = kw_vals[0];
|
|
479
|
+
if(kw_vals[1] != Qundef) v_pass = kw_vals[1];
|
|
480
|
+
if(kw_vals[2] != Qundef) v_service = kw_vals[2];
|
|
481
|
+
if(kw_vals[3] != Qundef) v_ccache = kw_vals[3];
|
|
482
|
+
|
|
483
|
+
if(NIL_P(v_user) || NIL_P(v_pass))
|
|
484
|
+
rb_raise(rb_eArgError, "principal and password are required");
|
|
403
485
|
|
|
404
486
|
Check_Type(v_user, T_STRING);
|
|
405
487
|
Check_Type(v_pass, T_STRING);
|
|
@@ -419,6 +501,21 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
419
501
|
if(kerror)
|
|
420
502
|
rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
|
|
421
503
|
|
|
504
|
+
if(!NIL_P(v_ccache)){
|
|
505
|
+
RUBY_KRB5_CCACHE* ccptr;
|
|
506
|
+
TypedData_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, &rkrb5_ccache_data_type, ccptr);
|
|
507
|
+
|
|
508
|
+
kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt);
|
|
509
|
+
if(kerror)
|
|
510
|
+
rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror));
|
|
511
|
+
|
|
512
|
+
kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache);
|
|
513
|
+
if(kerror){
|
|
514
|
+
krb5_get_init_creds_opt_free(ptr->ctx, opt);
|
|
515
|
+
rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror));
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
|
|
422
519
|
kerror = krb5_get_init_creds_password(
|
|
423
520
|
ptr->ctx,
|
|
424
521
|
&ptr->creds,
|
|
@@ -428,9 +525,12 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
428
525
|
NULL,
|
|
429
526
|
0,
|
|
430
527
|
service,
|
|
431
|
-
|
|
528
|
+
opt
|
|
432
529
|
);
|
|
433
530
|
|
|
531
|
+
if(opt)
|
|
532
|
+
krb5_get_init_creds_opt_free(ptr->ctx, opt);
|
|
533
|
+
|
|
434
534
|
if(kerror)
|
|
435
535
|
rb_raise(cKrb5Exception, "krb5_get_init_creds_password: %s", error_message(kerror));
|
|
436
536
|
|
|
@@ -439,7 +539,7 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
439
539
|
|
|
440
540
|
/*
|
|
441
541
|
* call-seq:
|
|
442
|
-
* krb5.authenticate!(
|
|
542
|
+
* krb5.authenticate!(principal:, password:, service: nil)
|
|
443
543
|
*
|
|
444
544
|
* Convenience method that: acquires initial credentials via password and
|
|
445
545
|
* immediately verifies those credentials using `verify_init_creds` with
|
|
@@ -451,7 +551,9 @@ static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
|
|
|
451
551
|
*/
|
|
452
552
|
static VALUE rkrb5_authenticate_bang(int argc, VALUE* argv, VALUE self){
|
|
453
553
|
RUBY_KRB5* ptr;
|
|
454
|
-
VALUE v_user, v_pass, v_service;
|
|
554
|
+
VALUE v_kwargs, v_user, v_pass, v_service;
|
|
555
|
+
ID kw_table[3] = { rb_intern("principal"), rb_intern("password"), rb_intern("service") };
|
|
556
|
+
VALUE kw_vals[3];
|
|
455
557
|
char* user;
|
|
456
558
|
char* pass;
|
|
457
559
|
char* service;
|
|
@@ -472,8 +574,15 @@ static VALUE rkrb5_authenticate_bang(int argc, VALUE* argv, VALUE self){
|
|
|
472
574
|
krb5_free_cred_contents(ptr->ctx, &ptr->creds);
|
|
473
575
|
memset(&ptr->creds, 0, sizeof(ptr->creds));
|
|
474
576
|
|
|
475
|
-
|
|
476
|
-
|
|
577
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
578
|
+
|
|
579
|
+
if(NIL_P(v_kwargs))
|
|
580
|
+
v_kwargs = rb_hash_new();
|
|
581
|
+
|
|
582
|
+
rb_get_kwargs(v_kwargs, kw_table, 2, 1, kw_vals);
|
|
583
|
+
v_user = kw_vals[0];
|
|
584
|
+
v_pass = kw_vals[1];
|
|
585
|
+
v_service = kw_vals[2] == Qundef ? Qnil : kw_vals[2];
|
|
477
586
|
|
|
478
587
|
Check_Type(v_user, T_STRING);
|
|
479
588
|
Check_Type(v_pass, T_STRING);
|
|
@@ -573,11 +682,12 @@ static VALUE rkrb5_close(VALUE self){
|
|
|
573
682
|
if(ptr->princ)
|
|
574
683
|
krb5_free_principal(ptr->ctx, ptr->princ);
|
|
575
684
|
|
|
576
|
-
if(ptr->ctx)
|
|
685
|
+
if(ptr->ctx && ptr->rb_context == Qnil)
|
|
577
686
|
krb5_free_context(ptr->ctx);
|
|
578
687
|
|
|
579
688
|
ptr->ctx = NULL;
|
|
580
689
|
ptr->princ = NULL;
|
|
690
|
+
ptr->rb_context = Qnil;
|
|
581
691
|
|
|
582
692
|
return Qtrue;
|
|
583
693
|
}
|
|
@@ -678,8 +788,10 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
|
|
|
678
788
|
v_enctypes = rb_hash_new();
|
|
679
789
|
|
|
680
790
|
for(i = 0; ktypes[i]; i++){
|
|
681
|
-
|
|
682
|
-
|
|
791
|
+
krb5_error_code enc_err = krb5_enctype_to_string(ktypes[i], encoding, 128);
|
|
792
|
+
if(enc_err){
|
|
793
|
+
krb5_free_enctypes(ptr->ctx, ktypes);
|
|
794
|
+
rb_raise(cKrb5Exception, "krb5_enctype_to_string: %s", error_message(enc_err));
|
|
683
795
|
}
|
|
684
796
|
rb_hash_aset(v_enctypes, INT2FIX(ktypes[i]), rb_str_new2(encoding));
|
|
685
797
|
}
|
|
@@ -692,7 +804,7 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
|
|
|
692
804
|
|
|
693
805
|
/*
|
|
694
806
|
* call-seq:
|
|
695
|
-
* krb5.verify_init_creds(server
|
|
807
|
+
* krb5.verify_init_creds(server: nil, keytab: nil, ccache: nil)
|
|
696
808
|
*
|
|
697
809
|
* Verifies the initial credentials currently stored in the internal
|
|
698
810
|
* credentials structure. Optionally a server principal string, a
|
|
@@ -702,7 +814,10 @@ static VALUE rkrb5_get_permitted_enctypes(VALUE self){
|
|
|
702
814
|
*/
|
|
703
815
|
static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
|
|
704
816
|
RUBY_KRB5* ptr;
|
|
705
|
-
VALUE v_server, v_keytab, v_ccache;
|
|
817
|
+
VALUE v_server = Qnil, v_keytab = Qnil, v_ccache = Qnil;
|
|
818
|
+
VALUE v_kwargs = Qnil;
|
|
819
|
+
ID kw_table[3] = { rb_intern("server"), rb_intern("keytab"), rb_intern("ccache") };
|
|
820
|
+
VALUE kw_vals[3];
|
|
706
821
|
krb5_error_code kerror;
|
|
707
822
|
krb5_principal server_princ = NULL;
|
|
708
823
|
RUBY_KRB5_KEYTAB* ktptr = NULL;
|
|
@@ -710,7 +825,15 @@ static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
|
|
|
710
825
|
krb5_keytab keytab = NULL;
|
|
711
826
|
krb5_ccache *ccache_ptr = NULL;
|
|
712
827
|
|
|
713
|
-
rb_scan_args(argc, argv, "
|
|
828
|
+
rb_scan_args(argc, argv, "0:", &v_kwargs);
|
|
829
|
+
|
|
830
|
+
if(NIL_P(v_kwargs))
|
|
831
|
+
v_kwargs = rb_hash_new();
|
|
832
|
+
|
|
833
|
+
rb_get_kwargs(v_kwargs, kw_table, 0, 3, kw_vals);
|
|
834
|
+
if(kw_vals[0] != Qundef) v_server = kw_vals[0];
|
|
835
|
+
if(kw_vals[1] != Qundef) v_keytab = kw_vals[1];
|
|
836
|
+
if(kw_vals[2] != Qundef) v_ccache = kw_vals[2];
|
|
714
837
|
|
|
715
838
|
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
716
839
|
|
|
@@ -772,6 +895,83 @@ static VALUE rkrb5_verify_init_creds(int argc, VALUE* argv, VALUE self){
|
|
|
772
895
|
return Qtrue;
|
|
773
896
|
}
|
|
774
897
|
|
|
898
|
+
/*
|
|
899
|
+
* call-seq:
|
|
900
|
+
* krb5.get_host_realm(hostname) -> Array
|
|
901
|
+
*
|
|
902
|
+
* Returns an array of realm names associated with +hostname+.
|
|
903
|
+
* Uses the Kerberos library's host-to-realm mapping (krb5.conf
|
|
904
|
+
* [domain_realm] section, DNS lookups, etc.).
|
|
905
|
+
*/
|
|
906
|
+
static VALUE rkrb5_get_host_realm(VALUE self, VALUE v_host){
|
|
907
|
+
RUBY_KRB5* ptr;
|
|
908
|
+
char** realms;
|
|
909
|
+
char** p;
|
|
910
|
+
krb5_error_code kerror;
|
|
911
|
+
|
|
912
|
+
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
913
|
+
|
|
914
|
+
if(!ptr->ctx)
|
|
915
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
916
|
+
|
|
917
|
+
Check_Type(v_host, T_STRING);
|
|
918
|
+
|
|
919
|
+
kerror = krb5_get_host_realm(ptr->ctx, StringValueCStr(v_host), &realms);
|
|
920
|
+
|
|
921
|
+
if(kerror)
|
|
922
|
+
rb_raise(cKrb5Exception, "krb5_get_host_realm: %s", error_message(kerror));
|
|
923
|
+
|
|
924
|
+
VALUE v_array = rb_ary_new();
|
|
925
|
+
|
|
926
|
+
for(p = realms; p && *p; p++)
|
|
927
|
+
rb_ary_push(v_array, rb_str_new2(*p));
|
|
928
|
+
|
|
929
|
+
krb5_free_host_realm(ptr->ctx, realms);
|
|
930
|
+
|
|
931
|
+
return v_array;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/*
|
|
935
|
+
* call-seq:
|
|
936
|
+
* krb5.expand_hostname(hostname) -> String
|
|
937
|
+
*
|
|
938
|
+
* Canonicalizes +hostname+ by performing a forward DNS lookup followed
|
|
939
|
+
* by a reverse lookup, returning the canonical hostname.
|
|
940
|
+
*/
|
|
941
|
+
static VALUE rkrb5_expand_hostname(VALUE self, VALUE v_host){
|
|
942
|
+
RUBY_KRB5* ptr;
|
|
943
|
+
char* canonical;
|
|
944
|
+
krb5_error_code kerror;
|
|
945
|
+
|
|
946
|
+
TypedData_Get_Struct(self, RUBY_KRB5, &rkrb5_data_type, ptr);
|
|
947
|
+
|
|
948
|
+
if(!ptr->ctx)
|
|
949
|
+
rb_raise(cKrb5Exception, "no context has been established");
|
|
950
|
+
|
|
951
|
+
Check_Type(v_host, T_STRING);
|
|
952
|
+
|
|
953
|
+
kerror = krb5_expand_hostname(ptr->ctx, StringValueCStr(v_host), &canonical);
|
|
954
|
+
|
|
955
|
+
if(kerror)
|
|
956
|
+
rb_raise(cKrb5Exception, "krb5_expand_hostname: %s", error_message(kerror));
|
|
957
|
+
|
|
958
|
+
VALUE v_result = rb_str_new2(canonical);
|
|
959
|
+
krb5_free_string(ptr->ctx, canonical);
|
|
960
|
+
|
|
961
|
+
return v_result;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/*
|
|
965
|
+
* call-seq:
|
|
966
|
+
* Kerberos::Krb5.thread_safe?
|
|
967
|
+
*
|
|
968
|
+
* Returns true if the Kerberos library was built with multithread support,
|
|
969
|
+
* false otherwise.
|
|
970
|
+
*/
|
|
971
|
+
static VALUE rkrb5_s_thread_safe(VALUE klass){
|
|
972
|
+
return krb5_is_thread_safe() ? Qtrue : Qfalse;
|
|
973
|
+
}
|
|
974
|
+
|
|
775
975
|
void Init_rkerberos(void){
|
|
776
976
|
mKerberos = rb_define_module("Kerberos");
|
|
777
977
|
cKrb5 = rb_define_class_under(mKerberos, "Krb5", rb_cObject);
|
|
@@ -781,7 +981,10 @@ void Init_rkerberos(void){
|
|
|
781
981
|
rb_define_alloc_func(cKrb5, rkrb5_allocate);
|
|
782
982
|
|
|
783
983
|
// Initializers
|
|
784
|
-
rb_define_method(cKrb5, "initialize", rkrb5_initialize,
|
|
984
|
+
rb_define_method(cKrb5, "initialize", rkrb5_initialize, -1);
|
|
985
|
+
|
|
986
|
+
// Singleton Methods
|
|
987
|
+
rb_define_singleton_method(cKrb5, "thread_safe?", rkrb5_s_thread_safe, 0);
|
|
785
988
|
|
|
786
989
|
// Krb5 Methods
|
|
787
990
|
rb_define_method(cKrb5, "authenticate!", rkrb5_authenticate_bang, -1);
|
|
@@ -794,13 +997,20 @@ void Init_rkerberos(void){
|
|
|
794
997
|
rb_define_method(cKrb5, "get_permitted_enctypes", rkrb5_get_permitted_enctypes, 0);
|
|
795
998
|
rb_define_method(cKrb5, "set_default_realm", rkrb5_set_default_realm, -1);
|
|
796
999
|
rb_define_method(cKrb5, "verify_init_creds", rkrb5_verify_init_creds, -1);
|
|
1000
|
+
rb_define_method(cKrb5, "get_host_realm", rkrb5_get_host_realm, 1);
|
|
1001
|
+
rb_define_method(cKrb5, "expand_hostname", rkrb5_expand_hostname, 1);
|
|
797
1002
|
|
|
798
1003
|
// Aliases
|
|
799
1004
|
rb_define_alias(cKrb5, "default_realm", "get_default_realm");
|
|
1005
|
+
rb_define_alias(cKrb5, "default_realm=", "set_default_realm");
|
|
800
1006
|
rb_define_alias(cKrb5, "default_principal", "get_default_principal");
|
|
1007
|
+
rb_define_alias(cKrb5, "host_realm", "get_host_realm");
|
|
1008
|
+
rb_define_alias(cKrb5, "init_creds_password", "get_init_creds_password");
|
|
1009
|
+
rb_define_alias(cKrb5, "init_creds_keytab", "get_init_creds_keytab");
|
|
1010
|
+
rb_define_alias(cKrb5, "permitted_enctypes", "get_permitted_enctypes");
|
|
801
1011
|
|
|
802
|
-
/* 0.
|
|
803
|
-
rb_define_const(cKrb5, "VERSION", rb_str_new2("0.
|
|
1012
|
+
/* 0.3.0: The version of the custom rkerberos library */
|
|
1013
|
+
rb_define_const(cKrb5, "VERSION", rb_str_new2("0.3.0"));
|
|
804
1014
|
|
|
805
1015
|
// Encoding type constants
|
|
806
1016
|
|
data/ext/rkerberos/rkerberos.h
CHANGED
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
|
|
9
9
|
// Make the context data type visible to other C files
|
|
10
10
|
extern const rb_data_type_t rkrb5_context_data_type;
|
|
11
|
+
// Make the Krb5 data type visible to other C files
|
|
12
|
+
extern const rb_data_type_t rkrb5_data_type;
|
|
11
13
|
// Make the config data type visible to other C files
|
|
12
14
|
extern const rb_data_type_t rkadm5_config_data_type;
|
|
13
15
|
|
|
@@ -67,6 +69,7 @@ typedef struct {
|
|
|
67
69
|
krb5_creds creds;
|
|
68
70
|
krb5_principal princ;
|
|
69
71
|
krb5_keytab keytab;
|
|
72
|
+
VALUE rb_context;
|
|
70
73
|
} RUBY_KRB5;
|
|
71
74
|
|
|
72
75
|
// Kerberos::Context
|
|
@@ -81,6 +84,7 @@ typedef struct {
|
|
|
81
84
|
krb5_principal princ;
|
|
82
85
|
void* handle;
|
|
83
86
|
char** db_args;
|
|
87
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
84
88
|
} RUBY_KADM5;
|
|
85
89
|
|
|
86
90
|
// Kerberos::Krb5::Keytab::Entry
|
|
@@ -96,23 +100,27 @@ typedef struct {
|
|
|
96
100
|
krb5_context ctx;
|
|
97
101
|
krb5_creds creds;
|
|
98
102
|
krb5_keytab keytab;
|
|
103
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
99
104
|
} RUBY_KRB5_KEYTAB;
|
|
100
105
|
|
|
101
106
|
typedef struct {
|
|
102
107
|
krb5_context ctx;
|
|
103
108
|
krb5_principal principal;
|
|
109
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
104
110
|
} RUBY_KRB5_PRINC;
|
|
105
111
|
|
|
106
112
|
typedef struct {
|
|
107
113
|
krb5_context ctx;
|
|
108
114
|
krb5_ccache ccache;
|
|
109
115
|
krb5_principal principal;
|
|
116
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
110
117
|
} RUBY_KRB5_CCACHE;
|
|
111
118
|
|
|
112
119
|
#ifdef HAVE_KADM5_ADMIN_H
|
|
113
120
|
typedef struct {
|
|
114
121
|
krb5_context ctx;
|
|
115
122
|
kadm5_config_params config;
|
|
123
|
+
VALUE rb_context; // Ruby Context object when borrowed, Qnil if ctx is owned
|
|
116
124
|
} RUBY_KADM5_CONFIG;
|
|
117
125
|
|
|
118
126
|
typedef struct {
|
data/rkerberos.gemspec
CHANGED
|
@@ -2,15 +2,18 @@ require 'rubygems'
|
|
|
2
2
|
|
|
3
3
|
Gem::Specification.new do |spec|
|
|
4
4
|
spec.name = 'rkerberos'
|
|
5
|
-
spec.version = '0.
|
|
5
|
+
spec.version = '0.3.0'
|
|
6
6
|
spec.authors = ['Daniel Berger', 'Dominic Cleal', 'Simon Levermann']
|
|
7
7
|
spec.license = 'Artistic-2.0'
|
|
8
8
|
spec.email = ['djberg96@gmail.com', 'dominic@cleal.org', 'simon-rubygems@slevermann.de']
|
|
9
|
-
spec.homepage = '
|
|
10
|
-
spec.summary = 'A Ruby interface for the
|
|
9
|
+
spec.homepage = 'https://github.com/rkerberos/rkerberos'
|
|
10
|
+
spec.summary = 'A Ruby interface for the Kerberos library'
|
|
11
|
+
spec.required_ruby_version = '>= 3.2'
|
|
11
12
|
spec.test_files = Dir['spec/**/*_spec.rb']
|
|
12
13
|
spec.extensions = ['ext/rkerberos/extconf.rb']
|
|
13
|
-
spec.files = Dir['**/*']
|
|
14
|
+
spec.files = Dir['**/*']
|
|
15
|
+
.select { |file| File.file?(file) }
|
|
16
|
+
.grep_v(%r{\A(?:\.git|docker|Dockerfile|Gemfile\.lock\z|tmp(?:/|\z))|\.gem\z})
|
|
14
17
|
|
|
15
18
|
spec.add_development_dependency('rake-compiler')
|
|
16
19
|
spec.add_development_dependency('rspec', '>= 3.0')
|
|
@@ -22,13 +25,13 @@ Gem::Specification.new do |spec|
|
|
|
22
25
|
EOF
|
|
23
26
|
|
|
24
27
|
spec.metadata = {
|
|
25
|
-
'homepage_uri' => 'https://github.com/rkerberos/rkerberos',
|
|
26
28
|
'bug_tracker_uri' => 'https://github.com/rkerberos/rkerberos/issues',
|
|
27
|
-
'changelog_uri' => 'https://github.com/rkerberos/rkerberos/blob/
|
|
29
|
+
'changelog_uri' => 'https://github.com/rkerberos/rkerberos/blob/master/CHANGES.md',
|
|
28
30
|
'documentation_uri' => 'https://github.com/rkerberos/rkerberos/wiki',
|
|
31
|
+
'homepage_uri' => 'https://github.com/rkerberos/rkerberos',
|
|
29
32
|
'source_code_uri' => 'https://github.com/rkerberos/rkerberos',
|
|
30
33
|
'wiki_uri' => 'https://github.com/rkerberos/rkerberos/wiki',
|
|
31
|
-
'github_repo' => 'https://github.com/
|
|
34
|
+
'github_repo' => 'https://github.com/rkerberos/rkerberos',
|
|
32
35
|
'funding_uri' => 'https://github.com/sponsors/rkerberos',
|
|
33
36
|
'rubygems_mfa_required' => 'true'
|
|
34
37
|
}
|