rkerberos 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }