Class: Kerberos::Krb5

Inherits:
Object
  • Object
show all
Defined in:
ext/rkerberos/rkerberos.c

Defined Under Namespace

Classes: Context, CredentialsCache, Exception, Keytab, Principal

Constant Summary collapse

VERSION =

The version of the custom rkerberos library

0.1.0
ENCTYPE_NULL =

None

0
ENCTYPE_DES_CBC_CRC =

DES cbc mode with CRC-32

1
ENCTYPE_DES_CBC_MD4 =

DES cbc mode with RSA-MD4

2
ENCTYPE_DES_CBC_MD5 =

DES cbc mode with RSA-MD5

3
ENCTYPE_DES_CBC_RAW =

DES cbc mode raw

4
ENCTYPE_DES3_CBC_SHA =

DES-3 cbc mode with NIST-SHA

5
ENCTYPE_DES3_CBC_RAW =

DES-3 cbc mode raw

6
ENCTYPE_DES_HMAC_SHA1 =

HMAC SHA1

8
ENCTYPE_DSA_SHA1_CMS =

DSA with SHA1, CMS signature

9
ENCTYPE_MD5_RSA_CMS =

MD5 with RSA, CMS signature

10
ENCTYPE_SHA1_RSA_CMS =

SHA1 with RSA, CMS signature

11
ENCTYPE_RC2_CBC_ENV =

RC2 cbc mode, CMS enveloped data

12
ENCTYPE_RSA_ENV =

RSA encryption, CMS enveloped data

13
ENCTYPE_RSA_ES_OAEP_ENV =

RSA w/OEAP encryption, CMS enveloped data

14
ENCTYPE_DES3_CBC_ENV =

DES-3 cbc mode, CMS enveloped data

15
ENCTYPE_DES3_CBC_SHA1 =

DES3 CBC SHA1

16
ENCTYPE_AES128_CTS_HMAC_SHA1_96 =

AES128 CTS HMAC SHA1 96

17
ENCTYPE_AES256_CTS_HMAC_SHA1_96 =

AES256 CTS HMAC SHA1 96

18
ENCTYPE_ARCFOUR_HMAC =

ARCFOUR HMAC

23
ENCTYPE_ARCFOUR_HMAC_EXP =

ARCFOUR HMAC EXP

24
ENCTYPE_UNKNOWN =

Unknown

511

Instance Method Summary collapse

Constructor Details

#Kerberos::Krb5.newObject

Creates and returns a new Kerberos::Krb5 object. This initializes the context for future method calls on that object.


56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'ext/rkerberos/rkerberos.c', line 56

static VALUE rkrb5_initialize(VALUE self){
  RUBY_KRB5* ptr;
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  kerror = krb5_init_context(&ptr->ctx); 

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_init_context: %s", error_message(kerror));

  if(rb_block_given_p()){
    rb_ensure(rb_yield, self, rkrb5_close, self);
    return Qnil;
  }

  return self;
}

Instance Method Details

#change_password(old, new) ⇒ Object

Changes the password for the principal from old to new. The principal is defined as whoever the last principal was authenticated via the Krb5#get_init_creds_password method.

Attempting to change a password before a principal has been established will raise an error.

Example:

krb5.get_init_creds_password('foo', 'XXXXXX') # Authenticate 'foo' user krb5.change_password('XXXXXX', 'YYYYYY') # Change password for 'foo'


272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
# File 'ext/rkerberos/rkerberos.c', line 272

static VALUE rkrb5_change_password(VALUE self, VALUE v_old, VALUE v_new){

  RUBY_KRB5* ptr;
  krb5_data result_string;
  krb5_data pw_result_string;
  krb5_error_code kerror;
  char *old_passwd;
  char *new_passwd;

  int pw_result;

  Check_Type(v_old, T_STRING);
  Check_Type(v_new, T_STRING);

  old_passwd = StringValueCStr(v_old);
  new_passwd = StringValueCStr(v_new);

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  if(!ptr->ctx)
    rb_raise(cKrb5Exception, "no context has been established"); 

  if(!ptr->princ)
    rb_raise(cKrb5Exception, "no principal has been established"); 

  kerror = krb5_get_init_creds_password(
    ptr->ctx,
    &ptr->creds,
    ptr->princ,
    old_passwd,
    NULL,
    NULL,
    0,
    "kadmin/changepw",
    NULL
  );

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_get_init_creds_password: %s", error_message(kerror));

  kerror = krb5_change_password(
    ptr->ctx,
    &ptr->creds,
    new_passwd,
    &pw_result,
    &pw_result_string,
    &result_string
  );

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_change_password: %s", error_message(kerror));

  return Qtrue;
}

#closeObject

Handles cleanup of the Krb5 object, freeing any credentials, principal or context associated with the object.


393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
# File 'ext/rkerberos/rkerberos.c', line 393

static VALUE rkrb5_close(VALUE self){
  RUBY_KRB5* ptr;

  Data_Get_Struct(self, RUBY_KRB5, ptr);

  if(ptr->ctx)
    krb5_free_cred_contents(ptr->ctx, &ptr->creds);

  if(ptr->princ)
    krb5_free_principal(ptr->ctx, ptr->princ);

  if(ptr->ctx)
    krb5_free_context(ptr->ctx);

  ptr->ctx = NULL;
  ptr->princ = NULL;

  return Qtrue;
}

#get_default_principalObject Also known as: default_principal

Returns the default principal for the current realm based on the current credentials cache.

If no credentials cache is found then an error is raised.


422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
# File 'ext/rkerberos/rkerberos.c', line 422

static VALUE rkrb5_get_default_principal(VALUE self){
  char* princ_name;
  RUBY_KRB5* ptr;
  krb5_ccache ccache;  
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  if(!ptr->ctx)
    rb_raise(cKrb5Exception, "no context has been established");

  // Get the default credentials cache
  kerror = krb5_cc_default(ptr->ctx, &ccache);

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_cc_default: %s", error_message(kerror));

  kerror = krb5_cc_get_principal(ptr->ctx, ccache, &ptr->princ);

  if(kerror){
    krb5_cc_close(ptr->ctx, ccache);
    rb_raise(cKrb5Exception, "krb5_cc_get_principal: %s", error_message(kerror));
  }

  krb5_cc_close(ptr->ctx, ccache);

  kerror = krb5_unparse_name(ptr->ctx, ptr->princ, &princ_name);

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_cc_default: %s", error_message(kerror));

  return rb_str_new2(princ_name);
}

#get_default_realmObject Also known as: default_realm

Returns the default Kerberos realm on your system.


81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'ext/rkerberos/rkerberos.c', line 81

static VALUE rkrb5_get_default_realm(VALUE self){
  RUBY_KRB5* ptr;
  char* realm;
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  kerror = krb5_get_default_realm(ptr->ctx, &realm);

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_get_default_realm: %s", error_message(kerror));

  return rb_str_new2(realm);
}

#get_init_creds_keytab(principal = nil, keytab = nil, service = nil, ccache = nil) ⇒ Object

Acquire credentials for principal from keytab using service. If no principal is specified, then a principal is derived from the service name. If no service name is specified, kerberos defaults to “host”.

If no keytab file is provided, the default keytab file is used. This is typically /etc/krb5.keytab.

If ccache is supplied and is a Kerberos::Krb5::CredentialsCache, the resulting credentials will be stored in the credential cache.


142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'ext/rkerberos/rkerberos.c', line 142

static VALUE rkrb5_get_init_creds_keytab(int argc, VALUE* argv, VALUE self){
  RUBY_KRB5* ptr;
  VALUE v_user, v_keytab_name, v_service, v_ccache;
  char* user;
  char* service;
  char keytab_name[MAX_KEYTAB_NAME_LEN];

  krb5_error_code kerror;
  krb5_get_init_creds_opt* opt;
  krb5_creds cred;

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  if(!ptr->ctx)
    rb_raise(cKrb5Exception, "no context has been established");

  kerror = krb5_get_init_creds_opt_alloc(ptr->ctx, &opt);
  if(kerror)
    rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_alloc: %s", error_message(kerror));

  rb_scan_args(argc, argv, "04", &v_user, &v_keytab_name, &v_service, &v_ccache);

  // We need the service information for later.
  if(NIL_P(v_service)){
    service = NULL;
  }
  else{
    Check_Type(v_service, T_STRING);
    service = StringValueCStr(v_service);
  }

  // Convert the name (or service name) to a kerberos principal.
  if(NIL_P(v_user)){
    kerror = krb5_sname_to_principal(
      ptr->ctx,
      NULL,
      service,
      KRB5_NT_SRV_HST,
      &ptr->princ
    );

    if(kerror) {
      krb5_get_init_creds_opt_free(ptr->ctx, opt);
      rb_raise(cKrb5Exception, "krb5_sname_to_principal: %s", error_message(kerror));
    }
  }
  else{
    Check_Type(v_user, T_STRING);
    user = StringValueCStr(v_user);

    kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ); 

    if(kerror) {
      krb5_get_init_creds_opt_free(ptr->ctx, opt);
      rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));
    }
  }

  // Use the default keytab if none is specified.
  if(NIL_P(v_keytab_name)){
    kerror = krb5_kt_default_name(ptr->ctx, keytab_name, MAX_KEYTAB_NAME_LEN);

    if(kerror) {
      krb5_get_init_creds_opt_free(ptr->ctx, opt);
      rb_raise(cKrb5Exception, "krb5_kt_default_name: %s", error_message(kerror));
    }
  }
  else{
    Check_Type(v_keytab_name, T_STRING);
    strncpy(keytab_name, StringValueCStr(v_keytab_name), MAX_KEYTAB_NAME_LEN);
  }

  kerror = krb5_kt_resolve(
    ptr->ctx,
    keytab_name,
    &ptr->keytab
  );

  if(kerror) {
    krb5_get_init_creds_opt_free(ptr->ctx, opt);
    rb_raise(cKrb5Exception, "krb5_kt_resolve: %s", error_message(kerror));
  }

  // Set the credential cache from the supplied Kerberos::Krb5::CredentialsCache
  if(!NIL_P(v_ccache)){
    RUBY_KRB5_CCACHE* ccptr;
    Data_Get_Struct(v_ccache, RUBY_KRB5_CCACHE, ccptr);

    kerror = krb5_get_init_creds_opt_set_out_ccache(ptr->ctx, opt, ccptr->ccache);
    if(kerror) {
      krb5_get_init_creds_opt_free(ptr->ctx, opt);
      rb_raise(cKrb5Exception, "krb5_get_init_creds_opt_set_out_ccache: %s", error_message(kerror));
    }
  }

  kerror = krb5_get_init_creds_keytab(
    ptr->ctx,
    &cred,
    ptr->princ,
    ptr->keytab,
    0,
    service,
    opt
  );

  if(kerror) {
    krb5_get_init_creds_opt_free(ptr->ctx, opt);
    rb_raise(cKrb5Exception, "krb5_get_init_creds_keytab: %s", error_message(kerror));
  }

  krb5_get_init_creds_opt_free(ptr->ctx, opt);

  return self; 
}

#get_init_creds_password(user, password, service = nil) ⇒ Object

Authenticates the credentials of user using password against service, and has the effect of setting the principal and context internally. This method must typically be called before using other methods.


335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
# File 'ext/rkerberos/rkerberos.c', line 335

static VALUE rkrb5_get_init_creds_passwd(int argc, VALUE* argv, VALUE self){
  RUBY_KRB5* ptr;
  VALUE v_user, v_pass, v_service;
  char* user;
  char* pass;
  char* service;
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  if(!ptr->ctx)
    rb_raise(cKrb5Exception, "no context has been established");

  rb_scan_args(argc, argv, "21", &v_user, &v_pass, &v_service);

  Check_Type(v_user, T_STRING);
  Check_Type(v_pass, T_STRING);
  user = StringValueCStr(v_user);
  pass = StringValueCStr(v_pass);

  if(NIL_P(v_service)){
    service = NULL;
  }
  else{
    Check_Type(v_service, T_STRING);
    service = StringValueCStr(v_service);
  }

  kerror = krb5_parse_name(ptr->ctx, user, &ptr->princ); 

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_parse_name: %s", error_message(kerror));

  kerror = krb5_get_init_creds_password(
    ptr->ctx,
    &ptr->creds,
    ptr->princ,
    pass,
    0,
    NULL,
    0,
    service,
    NULL
  );

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_get_init_creds_password: %s", error_message(kerror));

  return Qtrue;
}

#get_permitted_enctypesObject

Returns a hash containing the permitted encoding types. The key is the numeric constant, with a string description as its value.

Example:

krb.get_permitted_enctypes

# Results:
{
   1  => "DES cbc mode with CRC-32",
   2  => "DES cbc mode with RSA-MD4",
   3  => "DES cbc mode with RSA-MD5"}
   16 => "Triple DES cbc mode with HMAC/sha1",
   17 => "AES-128 CTS mode with 96-bit SHA-1 HMAC",
   18 => "AES-256 CTS mode with 96-bit SHA-1 HMAC",
   23 => "ArcFour with HMAC/md5"
}

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
# File 'ext/rkerberos/rkerberos.c', line 478

static VALUE rkrb5_get_permitted_enctypes(VALUE self){
  RUBY_KRB5* ptr;
  VALUE v_enctypes;
  krb5_enctype* ktypes;
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KRB5, ptr);

  if(!ptr->ctx)
    rb_raise(cKrb5Exception, "no context has been established");

  kerror = krb5_get_permitted_enctypes(ptr->ctx, &ktypes);

  if(kerror){
    rb_raise(cKrb5Exception, "krb5_get_permitted_types: %s", error_message(kerror));
  }
  else{
    int i;
    char encoding[128];
    v_enctypes = rb_hash_new();

    for(i = 0; ktypes[i]; i++){
      if(krb5_enctype_to_string(ktypes[i], encoding, 128)){
        rb_raise(cKrb5Exception, "krb5_enctype_to_string: %s", error_message(kerror));
      }
      rb_hash_aset(v_enctypes, INT2FIX(ktypes[i]), rb_str_new2(encoding));
    }
  }

  return v_enctypes;
}

#set_default_realm(realm = nil) ⇒ Object

Sets the default realm to realm. If no argument is provided, then the default realm in your krb5.conf file is used.


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'ext/rkerberos/rkerberos.c', line 103

static VALUE rkrb5_set_default_realm(int argc, VALUE* argv, VALUE self){
  RUBY_KRB5* ptr;
  VALUE v_realm;
  char* realm;
  krb5_error_code kerror;

  Data_Get_Struct(self, RUBY_KRB5, ptr); 

  rb_scan_args(argc, argv, "01", &v_realm); 

  if(NIL_P(v_realm)){
    realm = NULL;
  }
  else{
    Check_Type(v_realm, T_STRING);
    realm = StringValueCStr(v_realm);
  }

  kerror = krb5_set_default_realm(ptr->ctx, realm);

  if(kerror)
    rb_raise(cKrb5Exception, "krb5_set_default_realm: %s", error_message(kerror));

  return self;
}