rkerberos 0.1.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.
@@ -0,0 +1,509 @@
1
+ #include <rkerberos.h>
2
+
3
+ VALUE cKrb5Keytab, cKrb5KeytabException;
4
+
5
+ // Free function for the Kerberos::Krb5::Keytab class.
6
+ static void rkrb5_keytab_free(RUBY_KRB5_KEYTAB* ptr){
7
+ if(!ptr)
8
+ return;
9
+
10
+ if(ptr->keytab)
11
+ krb5_kt_close(ptr->ctx, ptr->keytab);
12
+
13
+ if(ptr->ctx)
14
+ krb5_free_context(ptr->ctx);
15
+
16
+ free(ptr);
17
+ }
18
+
19
+ // Allocation function for the Kerberos::Krb5::Keytab class.
20
+ static VALUE rkrb5_keytab_allocate(VALUE klass){
21
+ RUBY_KRB5_KEYTAB* ptr = malloc(sizeof(RUBY_KRB5_KEYTAB));
22
+ memset(ptr, 0, sizeof(RUBY_KRB5_KEYTAB));
23
+ return Data_Wrap_Struct(klass, 0, rkrb5_keytab_free, ptr);
24
+ }
25
+
26
+ /*
27
+ * call-seq:
28
+ *
29
+ * keytab.each{ |entry| p entry }
30
+ *
31
+ * Iterates over each entry, and yield the principal name.
32
+ *--
33
+ * TODO: Mixin Enumerable properly.
34
+ */
35
+ static VALUE rkrb5_keytab_each(VALUE self){
36
+ RUBY_KRB5_KEYTAB* ptr;
37
+ VALUE v_kt_entry;
38
+ VALUE v_args[0];
39
+ krb5_error_code kerror;
40
+ krb5_kt_cursor cursor;
41
+ krb5_keytab_entry entry;
42
+ char* principal;
43
+
44
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
45
+
46
+ kerror = krb5_kt_start_seq_get(
47
+ ptr->ctx,
48
+ ptr->keytab,
49
+ &cursor
50
+ );
51
+
52
+ if(kerror)
53
+ rb_raise(cKrb5Exception, "krb5_kt_start_seq_get: %s", error_message(kerror));
54
+
55
+ while((kerror = krb5_kt_next_entry(ptr->ctx, ptr->keytab, &entry, &cursor)) == 0){
56
+ krb5_unparse_name(ptr->ctx, entry.principal, &principal);
57
+
58
+ v_kt_entry = rb_class_new_instance(0, v_args, cKrb5KtEntry);
59
+
60
+ rb_iv_set(v_kt_entry, "@principal", rb_str_new2(principal));
61
+ rb_iv_set(v_kt_entry, "@timestamp", rb_time_new(entry.timestamp, 0));
62
+ rb_iv_set(v_kt_entry, "@vno", INT2FIX(entry.vno));
63
+ rb_iv_set(v_kt_entry, "@key", INT2FIX(entry.key.enctype));
64
+
65
+ rb_yield(v_kt_entry);
66
+
67
+ free(principal);
68
+
69
+ krb5_kt_free_entry(ptr->ctx, &entry);
70
+ }
71
+
72
+ kerror = krb5_kt_end_seq_get(
73
+ ptr->ctx,
74
+ ptr->keytab,
75
+ &cursor
76
+ );
77
+
78
+ if(kerror)
79
+ rb_raise(cKrb5Exception, "krb5_kt_end_seq_get: %s", error_message(kerror));
80
+
81
+ return self;
82
+ }
83
+
84
+ /*
85
+ * call-seq:
86
+ *
87
+ * keytab.default_name
88
+ *
89
+ * Returns the default keytab name.
90
+ */
91
+ static VALUE rkrb5_keytab_default_name(VALUE self){
92
+ char default_name[MAX_KEYTAB_NAME_LEN];
93
+ krb5_error_code kerror;
94
+ RUBY_KRB5_KEYTAB* ptr;
95
+ VALUE v_default_name;
96
+
97
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
98
+
99
+ kerror = krb5_kt_default_name(ptr->ctx, default_name, MAX_KEYTAB_NAME_LEN);
100
+
101
+ if(kerror)
102
+ rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror));
103
+
104
+ v_default_name = rb_str_new2(default_name);
105
+
106
+ return v_default_name;
107
+ }
108
+
109
+ /*
110
+ * call-seq:
111
+ * keytab.close
112
+ *
113
+ * Close the keytab object. Internally this frees up any associated
114
+ * credential contents and the Kerberos context. Once a keytab object
115
+ * is closed it cannot be reused.
116
+ */
117
+ static VALUE rkrb5_keytab_close(VALUE self){
118
+ RUBY_KRB5_KEYTAB* ptr;
119
+
120
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
121
+
122
+ if(ptr->ctx)
123
+ krb5_free_cred_contents(ptr->ctx, &ptr->creds);
124
+
125
+ if(ptr->ctx)
126
+ krb5_free_context(ptr->ctx);
127
+
128
+ ptr->ctx = NULL;
129
+
130
+ return Qtrue;
131
+ }
132
+
133
+ /*
134
+ static VALUE rkrb5_keytab_remove_entry(int argc, VALUE* argv, VALUE self){
135
+ RUBY_KRB5_KEYTAB* ptr;
136
+ krb5_error_code kerror;
137
+ krb5_keytab_entry entry;
138
+ char* name;
139
+ VALUE v_name, v_vno, v_enctype;
140
+
141
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
142
+
143
+ rb_scan_args(argc, argv, "12", &v_name, &v_vno, &v_enctype);
144
+
145
+ Check_Type(v_name, T_STRING);
146
+
147
+ name = StringValuePtr(v_name);
148
+
149
+ if(!ptr->ctx)
150
+ rb_raise(cKrb5Exception, "no context has been established");
151
+
152
+ kerror = krb5_parse_name(ptr->ctx, name, &entry.principal);
153
+
154
+ if(kerror)
155
+ rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
156
+
157
+ if(NIL_P(v_vno))
158
+ entry.vno = 0;
159
+ else
160
+ entry.vno = NUM2INT(v_vno);
161
+
162
+ if(NIL_P(v_enctype))
163
+ entry.key.enctype = 0;
164
+ else
165
+ entry.key.enctype = NUM2INT(v_enctype);
166
+
167
+ entry.key.length = 16;
168
+
169
+ kerror = krb5_kt_remove_entry(
170
+ ptr->ctx,
171
+ ptr->keytab,
172
+ &entry
173
+ );
174
+
175
+ if(kerror)
176
+ rb_raise(cKrb5KeytabException, "krb5_kt_remove_entry: %s", error_message(kerror));
177
+
178
+ return self;
179
+ }
180
+
181
+ static VALUE rkrb5_keytab_add_entry(int argc, VALUE* argv, VALUE self){
182
+ RUBY_KRB5_KEYTAB* ptr;
183
+ krb5_error_code kerror;
184
+ krb5_keytab_entry entry;
185
+ char* name;
186
+ VALUE v_name, v_vno, v_enctype;
187
+
188
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
189
+
190
+ rb_scan_args(argc, argv, "12", &v_name, &v_vno, &v_enctype);
191
+
192
+ Check_Type(v_name, T_STRING);
193
+
194
+ name = StringValuePtr(v_name);
195
+
196
+ if(!ptr->ctx)
197
+ rb_raise(cKrb5Exception, "no context has been established");
198
+
199
+ kerror = krb5_parse_name(ptr->ctx, name, &entry.principal);
200
+
201
+ if(kerror)
202
+ rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
203
+
204
+ if(NIL_P(v_vno))
205
+ entry.vno = 0;
206
+ else
207
+ entry.vno = NUM2INT(v_vno);
208
+
209
+ if(NIL_P(v_enctype))
210
+ entry.key.enctype = 0;
211
+ else
212
+ entry.key.enctype = NUM2INT(v_enctype);
213
+
214
+ entry.key.length = 16;
215
+
216
+ kerror = krb5_kt_add_entry(
217
+ ptr->ctx,
218
+ ptr->keytab,
219
+ &entry
220
+ );
221
+
222
+ if(kerror)
223
+ rb_raise(cKrb5KeytabException, "krb5_kt_add_entry: %s", error_message(kerror));
224
+
225
+ return self;
226
+ }
227
+ */
228
+
229
+ /*
230
+ * call-seq:
231
+ * keytab.get_entry(principal, vno = 0, encoding_type = nil)
232
+ *
233
+ * Searches the keytab by +principal+, +vno+ and +encoding_type+. If the
234
+ * +vno+ is zero (the default), then the first entry that matches +principal+
235
+ * is returned.
236
+ *
237
+ * Returns a Kerberos::Krb5::KeytabEntry object if the entry is found.
238
+ *
239
+ * Raises an exception if no entry is found.
240
+ */
241
+ static VALUE rkrb5_keytab_get_entry(int argc, VALUE* argv, VALUE self){
242
+ RUBY_KRB5_KEYTAB* ptr;
243
+ krb5_error_code kerror;
244
+ krb5_principal principal;
245
+ krb5_kvno vno;
246
+ krb5_enctype enctype;
247
+ krb5_keytab_entry entry;
248
+ char* name;
249
+ VALUE v_principal, v_vno, v_enctype, v_entry;
250
+ VALUE v_args[0];
251
+
252
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
253
+
254
+ rb_scan_args(argc, argv, "12", &v_principal, &v_vno, &v_enctype);
255
+
256
+ Check_Type(v_principal, T_STRING);
257
+ name = StringValuePtr(v_principal);
258
+
259
+ kerror = krb5_parse_name(ptr->ctx, name, &principal);
260
+
261
+ if(kerror)
262
+ rb_raise(cKrb5Exception, "krb5_unparse_name: %s", error_message(kerror));
263
+
264
+ vno = 0;
265
+ enctype = 0;
266
+
267
+ kerror = krb5_kt_get_entry(
268
+ ptr->ctx,
269
+ ptr->keytab,
270
+ principal,
271
+ vno,
272
+ enctype,
273
+ &entry
274
+ );
275
+
276
+ if(kerror)
277
+ rb_raise(cKrb5Exception, "krb5_kt_get_entry: %s", error_message(kerror));
278
+
279
+ v_entry = rb_class_new_instance(0, v_args, cKrb5KtEntry);
280
+
281
+ rb_iv_set(v_entry, "@principal", rb_str_new2(name));
282
+ rb_iv_set(v_entry, "@timestamp", rb_time_new(entry.timestamp, 0));
283
+ rb_iv_set(v_entry, "@vno", INT2FIX(entry.vno));
284
+ rb_iv_set(v_entry, "@key", INT2FIX(entry.key.enctype));
285
+
286
+ krb5_kt_free_entry(ptr->ctx, &entry);
287
+
288
+ return v_entry;
289
+ }
290
+
291
+ /*
292
+ * call-seq:
293
+ * Kerberos::Krb5::Keytab.new(name = nil)
294
+ *
295
+ * Creates and returns a new Kerberos::Krb5::Keytab object. This initializes
296
+ * the context and keytab for future method calls on that object.
297
+ *
298
+ * A keytab file +name+ may be provided. If not, the system's default keytab
299
+ * name is used. If a +name+ is provided it must be in the form 'type:residual'
300
+ * where 'type' is a type known to the Kerberos library.
301
+ *
302
+ * Examples:
303
+ *
304
+ * # Using the default keytab
305
+ * keytab = Kerberos::Krb5::Keytab.new
306
+ *
307
+ * # Using an explicit keytab
308
+ * keytab = Kerberos::Krb5::Keytab.new('FILE:/etc/krb5.keytab')
309
+ */
310
+ static VALUE rkrb5_keytab_initialize(int argc, VALUE* argv, VALUE self){
311
+ RUBY_KRB5_KEYTAB* ptr;
312
+ krb5_error_code kerror;
313
+ char keytab_name[MAX_KEYTAB_NAME_LEN];
314
+ VALUE v_keytab_name = Qnil;
315
+
316
+ Data_Get_Struct(self, RUBY_KRB5_KEYTAB, ptr);
317
+
318
+ rb_scan_args(argc, argv, "01", &v_keytab_name);
319
+
320
+ kerror = krb5_init_context(&ptr->ctx);
321
+
322
+ if(kerror)
323
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
324
+
325
+ // Use the default keytab name if one isn't provided.
326
+ if(NIL_P(v_keytab_name)){
327
+ kerror = krb5_kt_default_name(ptr->ctx, keytab_name, MAX_KEYTAB_NAME_LEN);
328
+
329
+ if(kerror)
330
+ rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror));
331
+
332
+ rb_iv_set(self, "@name", rb_str_new2(keytab_name));
333
+ }
334
+ else{
335
+ Check_Type(v_keytab_name, T_STRING);
336
+ strncpy(keytab_name, StringValuePtr(v_keytab_name), MAX_KEYTAB_NAME_LEN);
337
+ rb_iv_set(self, "@name", v_keytab_name);
338
+ }
339
+
340
+ kerror = krb5_kt_resolve(
341
+ ptr->ctx,
342
+ keytab_name,
343
+ &ptr->keytab
344
+ );
345
+
346
+ if(kerror)
347
+ rb_raise(cKrb5KeytabException, "krb5_kt_resolve: %s", error_message(kerror));
348
+
349
+ return self;
350
+ }
351
+
352
+ // Singleton Methods
353
+
354
+ /*
355
+ * call-seq:
356
+ * Kerberos::Krb5::Keytab.foreach(keytab = nil){ |entry|
357
+ * puts entry.inspect
358
+ * }
359
+ *
360
+ * Iterate over each entry in the +keytab+ and yield a Krb5::Keytab::Entry
361
+ * object for each entry found.
362
+ *
363
+ * If no +keytab+ is provided, then the default keytab is used.
364
+ */
365
+ static VALUE rkrb5_s_keytab_foreach(int argc, VALUE* argv, VALUE klass){
366
+ VALUE v_kt_entry;
367
+ VALUE v_keytab_name;
368
+ VALUE v_args[0];
369
+ krb5_error_code kerror;
370
+ krb5_kt_cursor cursor;
371
+ krb5_keytab keytab;
372
+ krb5_keytab_entry entry;
373
+ krb5_context context;
374
+ char* principal;
375
+ char keytab_name[MAX_KEYTAB_NAME_LEN];
376
+
377
+ rb_scan_args(argc, argv, "01", &v_keytab_name);
378
+
379
+ kerror = krb5_init_context(&context);
380
+
381
+ if(kerror)
382
+ rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));
383
+
384
+ // Use the default keytab name if one isn't provided.
385
+ if(NIL_P(v_keytab_name)){
386
+ kerror = krb5_kt_default_name(context, keytab_name, MAX_KEYTAB_NAME_LEN);
387
+
388
+ if(kerror){
389
+ if(context)
390
+ krb5_free_context(context);
391
+
392
+ rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror));
393
+ }
394
+ }
395
+ else{
396
+ Check_Type(v_keytab_name, T_STRING);
397
+ strncpy(keytab_name, StringValuePtr(v_keytab_name), MAX_KEYTAB_NAME_LEN);
398
+ }
399
+
400
+ kerror = krb5_kt_resolve(
401
+ context,
402
+ keytab_name,
403
+ &keytab
404
+ );
405
+
406
+ if(kerror){
407
+ if(context)
408
+ krb5_free_context(context);
409
+
410
+ rb_raise(cKrb5Exception, "krb5_kt_resolve: %s", error_message(kerror));
411
+ }
412
+
413
+ kerror = krb5_kt_start_seq_get(
414
+ context,
415
+ keytab,
416
+ &cursor
417
+ );
418
+
419
+ if(kerror){
420
+ if(context)
421
+ krb5_free_context(context);
422
+
423
+ if(keytab)
424
+ krb5_kt_close(context, keytab);
425
+
426
+ rb_raise(cKrb5Exception, "krb5_kt_start_seq_get: %s", error_message(kerror));
427
+ }
428
+
429
+ while((kerror = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
430
+ krb5_unparse_name(context, entry.principal, &principal);
431
+
432
+ v_kt_entry = rb_class_new_instance(0, v_args, cKrb5KtEntry);
433
+
434
+ rb_iv_set(v_kt_entry, "@principal", rb_str_new2(principal));
435
+ rb_iv_set(v_kt_entry, "@timestamp", rb_time_new(entry.timestamp, 0));
436
+ rb_iv_set(v_kt_entry, "@vno", INT2FIX(entry.vno));
437
+ rb_iv_set(v_kt_entry, "@key", INT2FIX(entry.key.enctype));
438
+
439
+ rb_yield(v_kt_entry);
440
+
441
+ free(principal);
442
+
443
+ krb5_kt_free_entry(context, &entry);
444
+ }
445
+
446
+ kerror = krb5_kt_end_seq_get(
447
+ context,
448
+ keytab,
449
+ &cursor
450
+ );
451
+
452
+ if(kerror){
453
+ if(context)
454
+ krb5_free_context(context);
455
+
456
+ if(keytab)
457
+ krb5_kt_close(context, keytab);
458
+
459
+ rb_raise(cKrb5Exception, "krb5_kt_end_seq_get: %s", error_message(kerror));
460
+ }
461
+
462
+ if(keytab)
463
+ krb5_kt_close(context, keytab);
464
+
465
+ if(context)
466
+ krb5_free_context(context);
467
+
468
+ return Qnil;
469
+ }
470
+
471
+ void Init_keytab(){
472
+ /* The Kerberos::Krb5::Keytab class encapsulates a Kerberos keytab. */
473
+ cKrb5Keytab = rb_define_class_under(cKrb5, "Keytab", rb_cObject);
474
+
475
+ /* The Keytab::Exception is typically raised if any of the Keytab methods fail. */
476
+ cKrb5KeytabException = rb_define_class_under(cKrb5Keytab, "Exception", rb_eStandardError);
477
+
478
+ // Allocation Function
479
+
480
+ rb_define_alloc_func(cKrb5Keytab, rkrb5_keytab_allocate);
481
+
482
+ // Constructor
483
+
484
+ rb_define_method(cKrb5Keytab, "initialize", rkrb5_keytab_initialize, -1);
485
+
486
+ // Singleton Methods
487
+
488
+ rb_define_singleton_method(cKrb5Keytab, "foreach", rkrb5_s_keytab_foreach, -1);
489
+
490
+ // Instance Methods
491
+
492
+ rb_define_method(cKrb5Keytab, "default_name", rkrb5_keytab_default_name, 0);
493
+ rb_define_method(cKrb5Keytab, "close", rkrb5_keytab_close, 0);
494
+ rb_define_method(cKrb5Keytab, "each", rkrb5_keytab_each, 0);
495
+ rb_define_method(cKrb5Keytab, "get_entry", rkrb5_keytab_get_entry, -1);
496
+
497
+ // TODO: Move these into Kadm5 and/or figure out how to set the vno properly.
498
+ // rb_define_method(cKrb5Keytab, "add_entry", rkrb5_keytab_add_entry, -1);
499
+ // rb_define_method(cKrb5Keytab, "remove_entry", rkrb5_keytab_remove_entry, -1);
500
+
501
+ // Accessors
502
+
503
+ /* The name of the keytab associated with the current keytab object. */
504
+ rb_define_attr(cKrb5Keytab, "name", 1, 0);
505
+
506
+ // Aliases
507
+
508
+ rb_define_alias(cKrb5Keytab, "find", "get_entry");
509
+ }