1 /* $NetBSD: gss_krb5.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $ */
2
3 /*-
4 * Copyright (c) 2005 Doug Rabson
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: src/lib/libgssapi/gss_krb5.c,v 1.1 2005/12/29 14:40:20 dfr Exp $
29 */
30
31 #include "mech_locl.h"
32
33 #include <krb5/krb5.h>
34 #include <krb5/roken.h>
35
36
37 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_copy_ccache(OM_uint32 * minor_status,gss_cred_id_t cred,krb5_ccache out)38 gss_krb5_copy_ccache(OM_uint32 *minor_status,
39 gss_cred_id_t cred,
40 krb5_ccache out)
41 {
42 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
43 krb5_context context;
44 krb5_error_code kret;
45 krb5_ccache id;
46 OM_uint32 ret;
47 char *str = NULL;
48
49 ret = gss_inquire_cred_by_oid(minor_status,
50 cred,
51 GSS_KRB5_COPY_CCACHE_X,
52 &data_set);
53 if (ret)
54 return ret;
55
56 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count < 1) {
57 gss_release_buffer_set(minor_status, &data_set);
58 *minor_status = EINVAL;
59 return GSS_S_FAILURE;
60 }
61
62 kret = krb5_init_context(&context);
63 if (kret) {
64 *minor_status = kret;
65 gss_release_buffer_set(minor_status, &data_set);
66 return GSS_S_FAILURE;
67 }
68
69 kret = asprintf(&str, "%.*s", (int)data_set->elements[0].length,
70 (char *)data_set->elements[0].value);
71 gss_release_buffer_set(minor_status, &data_set);
72 if (kret < 0 || str == NULL) {
73 *minor_status = ENOMEM;
74 return GSS_S_FAILURE;
75 }
76
77 kret = krb5_cc_resolve(context, str, &id);
78 free(str);
79 if (kret) {
80 *minor_status = kret;
81 return GSS_S_FAILURE;
82 }
83
84 kret = krb5_cc_copy_cache(context, id, out);
85 krb5_cc_close(context, id);
86 krb5_free_context(context);
87 if (kret) {
88 *minor_status = kret;
89 return GSS_S_FAILURE;
90 }
91
92 return ret;
93 }
94
95 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_import_cred(OM_uint32 * minor_status,krb5_ccache id,krb5_principal keytab_principal,krb5_keytab keytab,gss_cred_id_t * cred)96 gss_krb5_import_cred(OM_uint32 *minor_status,
97 krb5_ccache id,
98 krb5_principal keytab_principal,
99 krb5_keytab keytab,
100 gss_cred_id_t *cred)
101 {
102 gss_buffer_desc buffer;
103 OM_uint32 major_status;
104 krb5_context context;
105 krb5_error_code ret;
106 krb5_storage *sp;
107 krb5_data data;
108 char *str;
109
110 *cred = GSS_C_NO_CREDENTIAL;
111
112 ret = krb5_init_context(&context);
113 if (ret) {
114 *minor_status = ret;
115 return GSS_S_FAILURE;
116 }
117
118 sp = krb5_storage_emem();
119 if (sp == NULL) {
120 *minor_status = ENOMEM;
121 major_status = GSS_S_FAILURE;
122 goto out;
123 }
124
125 if (id) {
126 ret = krb5_cc_get_full_name(context, id, &str);
127 if (ret == 0) {
128 ret = krb5_store_string(sp, str);
129 free(str);
130 }
131 } else
132 ret = krb5_store_string(sp, "");
133 if (ret) {
134 *minor_status = ret;
135 major_status = GSS_S_FAILURE;
136 goto out;
137 }
138
139 if (keytab_principal) {
140 ret = krb5_unparse_name(context, keytab_principal, &str);
141 if (ret == 0) {
142 ret = krb5_store_string(sp, str);
143 free(str);
144 }
145 } else
146 krb5_store_string(sp, "");
147 if (ret) {
148 *minor_status = ret;
149 major_status = GSS_S_FAILURE;
150 goto out;
151 }
152
153
154 if (keytab) {
155 ret = krb5_kt_get_full_name(context, keytab, &str);
156 if (ret == 0) {
157 ret = krb5_store_string(sp, str);
158 free(str);
159 }
160 } else
161 krb5_store_string(sp, "");
162 if (ret) {
163 *minor_status = ret;
164 major_status = GSS_S_FAILURE;
165 goto out;
166 }
167
168 ret = krb5_storage_to_data(sp, &data);
169 if (ret) {
170 *minor_status = ret;
171 major_status = GSS_S_FAILURE;
172 goto out;
173 }
174
175 buffer.value = data.data;
176 buffer.length = data.length;
177
178 major_status = gss_set_cred_option(minor_status,
179 cred,
180 GSS_KRB5_IMPORT_CRED_X,
181 &buffer);
182 krb5_data_free(&data);
183 out:
184 if (sp)
185 krb5_storage_free(sp);
186 krb5_free_context(context);
187 return major_status;
188 }
189
190 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_register_acceptor_identity(const char * identity)191 gsskrb5_register_acceptor_identity(const char *identity)
192 {
193 gssapi_mech_interface m;
194 gss_buffer_desc buffer;
195 OM_uint32 junk;
196
197 _gss_load_mech();
198
199 buffer.value = rk_UNCONST(identity);
200 buffer.length = strlen(identity);
201
202 m = __gss_get_mechanism(GSS_KRB5_MECHANISM);
203 if (m == NULL || m->gm_set_sec_context_option == NULL)
204 return GSS_S_FAILURE;
205
206 return m->gm_set_sec_context_option(&junk, NULL,
207 GSS_KRB5_REGISTER_ACCEPTOR_IDENTITY_X, &buffer);
208 }
209
210 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
krb5_gss_register_acceptor_identity(const char * identity)211 krb5_gss_register_acceptor_identity(const char *identity)
212 {
213 return gsskrb5_register_acceptor_identity(identity);
214 }
215
216
217 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_set_dns_canonicalize(int flag)218 gsskrb5_set_dns_canonicalize(int flag)
219 {
220 struct _gss_mech_switch *m;
221 gss_buffer_desc buffer;
222 OM_uint32 junk;
223 char b = (flag != 0);
224
225 _gss_load_mech();
226
227 buffer.value = &b;
228 buffer.length = sizeof(b);
229
230 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
231 if (m->gm_mech.gm_set_sec_context_option == NULL)
232 continue;
233 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
234 GSS_KRB5_SET_DNS_CANONICALIZE_X, &buffer);
235 }
236
237 return (GSS_S_COMPLETE);
238 }
239
240
241
242 static krb5_error_code
set_key(krb5_keyblock * keyblock,gss_krb5_lucid_key_t * key)243 set_key(krb5_keyblock *keyblock, gss_krb5_lucid_key_t *key)
244 {
245 key->type = keyblock->keytype;
246 key->length = keyblock->keyvalue.length;
247 key->data = malloc(key->length);
248 if (key->data == NULL && key->length != 0)
249 return ENOMEM;
250 memcpy(key->data, keyblock->keyvalue.data, key->length);
251 return 0;
252 }
253
254 static void
free_key(gss_krb5_lucid_key_t * key)255 free_key(gss_krb5_lucid_key_t *key)
256 {
257 memset(key->data, 0, key->length);
258 free(key->data);
259 memset(key, 0, sizeof(*key));
260 }
261
262 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_export_lucid_sec_context(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,OM_uint32 version,void ** rctx)263 gss_krb5_export_lucid_sec_context(OM_uint32 *minor_status,
264 gss_ctx_id_t *context_handle,
265 OM_uint32 version,
266 void **rctx)
267 {
268 krb5_context context = NULL;
269 krb5_error_code ret;
270 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
271 OM_uint32 major_status;
272 gss_krb5_lucid_context_v1_t *ctx = NULL;
273 krb5_storage *sp = NULL;
274 uint32_t num;
275
276 if (context_handle == NULL
277 || *context_handle == GSS_C_NO_CONTEXT
278 || version != 1)
279 {
280 *minor_status = EINVAL;
281 return GSS_S_FAILURE;
282 }
283
284 major_status =
285 gss_inquire_sec_context_by_oid (minor_status,
286 *context_handle,
287 GSS_KRB5_EXPORT_LUCID_CONTEXT_V1_X,
288 &data_set);
289 if (major_status)
290 return major_status;
291
292 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
293 gss_release_buffer_set(minor_status, &data_set);
294 *minor_status = EINVAL;
295 return GSS_S_FAILURE;
296 }
297
298 ret = krb5_init_context(&context);
299 if (ret)
300 goto out;
301
302 ctx = calloc(1, sizeof(*ctx));
303 if (ctx == NULL) {
304 ret = ENOMEM;
305 goto out;
306 }
307
308 sp = krb5_storage_from_mem(data_set->elements[0].value,
309 data_set->elements[0].length);
310 if (sp == NULL) {
311 ret = ENOMEM;
312 goto out;
313 }
314
315 ret = krb5_ret_uint32(sp, &num);
316 if (ret) goto out;
317 if (num != 1) {
318 ret = EINVAL;
319 goto out;
320 }
321 ctx->version = 1;
322 /* initiator */
323 ret = krb5_ret_uint32(sp, &ctx->initiate);
324 if (ret) goto out;
325 /* endtime */
326 ret = krb5_ret_uint32(sp, &ctx->endtime);
327 if (ret) goto out;
328 /* send_seq */
329 ret = krb5_ret_uint32(sp, &num);
330 if (ret) goto out;
331 ctx->send_seq = ((uint64_t)num) << 32;
332 ret = krb5_ret_uint32(sp, &num);
333 if (ret) goto out;
334 ctx->send_seq |= num;
335 /* recv_seq */
336 ret = krb5_ret_uint32(sp, &num);
337 if (ret) goto out;
338 ctx->recv_seq = ((uint64_t)num) << 32;
339 ret = krb5_ret_uint32(sp, &num);
340 if (ret) goto out;
341 ctx->recv_seq |= num;
342 /* protocol */
343 ret = krb5_ret_uint32(sp, &ctx->protocol);
344 if (ret) goto out;
345 if (ctx->protocol == 0) {
346 krb5_keyblock key;
347
348 /* sign_alg */
349 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.sign_alg);
350 if (ret) goto out;
351 /* seal_alg */
352 ret = krb5_ret_uint32(sp, &ctx->rfc1964_kd.seal_alg);
353 if (ret) goto out;
354 /* ctx_key */
355 ret = krb5_ret_keyblock(sp, &key);
356 if (ret) goto out;
357 ret = set_key(&key, &ctx->rfc1964_kd.ctx_key);
358 krb5_free_keyblock_contents(context, &key);
359 if (ret) goto out;
360 } else if (ctx->protocol == 1) {
361 krb5_keyblock key;
362
363 /* acceptor_subkey */
364 ret = krb5_ret_uint32(sp, &ctx->cfx_kd.have_acceptor_subkey);
365 if (ret) goto out;
366 /* ctx_key */
367 ret = krb5_ret_keyblock(sp, &key);
368 if (ret) goto out;
369 ret = set_key(&key, &ctx->cfx_kd.ctx_key);
370 krb5_free_keyblock_contents(context, &key);
371 if (ret) goto out;
372 /* acceptor_subkey */
373 if (ctx->cfx_kd.have_acceptor_subkey) {
374 ret = krb5_ret_keyblock(sp, &key);
375 if (ret) goto out;
376 ret = set_key(&key, &ctx->cfx_kd.acceptor_subkey);
377 krb5_free_keyblock_contents(context, &key);
378 if (ret) goto out;
379 }
380 } else {
381 ret = EINVAL;
382 goto out;
383 }
384
385 *rctx = ctx;
386
387 out:
388 gss_release_buffer_set(minor_status, &data_set);
389 if (sp)
390 krb5_storage_free(sp);
391 if (context)
392 krb5_free_context(context);
393
394 if (ret) {
395 if (ctx)
396 gss_krb5_free_lucid_sec_context(NULL, ctx);
397
398 *minor_status = ret;
399 return GSS_S_FAILURE;
400 }
401 *minor_status = 0;
402 return GSS_S_COMPLETE;
403 }
404
405 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_free_lucid_sec_context(OM_uint32 * minor_status,void * c)406 gss_krb5_free_lucid_sec_context(OM_uint32 *minor_status, void *c)
407 {
408 gss_krb5_lucid_context_v1_t *ctx = c;
409
410 if (ctx->version != 1) {
411 if (minor_status)
412 *minor_status = 0;
413 return GSS_S_FAILURE;
414 }
415
416 if (ctx->protocol == 0) {
417 free_key(&ctx->rfc1964_kd.ctx_key);
418 } else if (ctx->protocol == 1) {
419 free_key(&ctx->cfx_kd.ctx_key);
420 if (ctx->cfx_kd.have_acceptor_subkey)
421 free_key(&ctx->cfx_kd.acceptor_subkey);
422 }
423 free(ctx);
424 if (minor_status)
425 *minor_status = 0;
426 return GSS_S_COMPLETE;
427 }
428
429 /*
430 *
431 */
432
433 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_set_allowable_enctypes(OM_uint32 * minor_status,gss_cred_id_t cred,OM_uint32 num_enctypes,int32_t * enctypes)434 gss_krb5_set_allowable_enctypes(OM_uint32 *minor_status,
435 gss_cred_id_t cred,
436 OM_uint32 num_enctypes,
437 int32_t *enctypes)
438 {
439 krb5_error_code ret;
440 OM_uint32 maj_status;
441 gss_buffer_desc buffer;
442 krb5_storage *sp;
443 krb5_data data;
444 size_t i;
445
446 sp = krb5_storage_emem();
447 if (sp == NULL) {
448 *minor_status = ENOMEM;
449 maj_status = GSS_S_FAILURE;
450 goto out;
451 }
452
453 for (i = 0; i < num_enctypes; i++) {
454 ret = krb5_store_int32(sp, enctypes[i]);
455 if (ret) {
456 *minor_status = ret;
457 maj_status = GSS_S_FAILURE;
458 goto out;
459 }
460 }
461
462 ret = krb5_storage_to_data(sp, &data);
463 if (ret) {
464 *minor_status = ret;
465 maj_status = GSS_S_FAILURE;
466 goto out;
467 }
468
469 buffer.value = data.data;
470 buffer.length = data.length;
471
472 maj_status = gss_set_cred_option(minor_status,
473 &cred,
474 GSS_KRB5_SET_ALLOWABLE_ENCTYPES_X,
475 &buffer);
476 krb5_data_free(&data);
477 out:
478 if (sp)
479 krb5_storage_free(sp);
480 return maj_status;
481 }
482
483 /*
484 *
485 */
486
487 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc * c)488 gsskrb5_set_send_to_kdc(struct gsskrb5_send_to_kdc *c)
489 {
490 struct _gss_mech_switch *m;
491 gss_buffer_desc buffer;
492 OM_uint32 junk;
493
494 _gss_load_mech();
495
496 if (c) {
497 buffer.value = c;
498 buffer.length = sizeof(*c);
499 } else {
500 buffer.value = NULL;
501 buffer.length = 0;
502 }
503
504 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
505 if (m->gm_mech.gm_set_sec_context_option == NULL)
506 continue;
507 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
508 GSS_KRB5_SEND_TO_KDC_X, &buffer);
509 }
510
511 return (GSS_S_COMPLETE);
512 }
513
514 /*
515 *
516 */
517
518 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_ccache_name(OM_uint32 * minor_status,const char * name,const char ** out_name)519 gss_krb5_ccache_name(OM_uint32 *minor_status,
520 const char *name,
521 const char **out_name)
522 {
523 struct _gss_mech_switch *m;
524 gss_buffer_desc buffer;
525 OM_uint32 junk;
526
527 _gss_load_mech();
528
529 if (out_name)
530 *out_name = NULL;
531
532 buffer.value = rk_UNCONST(name);
533 buffer.length = strlen(name);
534
535 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
536 if (m->gm_mech.gm_set_sec_context_option == NULL)
537 continue;
538 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
539 GSS_KRB5_CCACHE_NAME_X, &buffer);
540 }
541
542 return (GSS_S_COMPLETE);
543 }
544
545
546 /*
547 *
548 */
549
550 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_extract_authtime_from_sec_context(OM_uint32 * minor_status,gss_ctx_id_t context_handle,time_t * authtime)551 gsskrb5_extract_authtime_from_sec_context(OM_uint32 *minor_status,
552 gss_ctx_id_t context_handle,
553 time_t *authtime)
554 {
555 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
556 OM_uint32 maj_stat;
557
558 if (context_handle == GSS_C_NO_CONTEXT) {
559 *minor_status = EINVAL;
560 return GSS_S_FAILURE;
561 }
562
563 maj_stat =
564 gss_inquire_sec_context_by_oid (minor_status,
565 context_handle,
566 GSS_KRB5_GET_AUTHTIME_X,
567 &data_set);
568 if (maj_stat)
569 return maj_stat;
570
571 if (data_set == GSS_C_NO_BUFFER_SET) {
572 gss_release_buffer_set(minor_status, &data_set);
573 *minor_status = EINVAL;
574 return GSS_S_FAILURE;
575 }
576
577 if (data_set->count != 1) {
578 gss_release_buffer_set(minor_status, &data_set);
579 *minor_status = EINVAL;
580 return GSS_S_FAILURE;
581 }
582
583 if (data_set->elements[0].length != 4) {
584 gss_release_buffer_set(minor_status, &data_set);
585 *minor_status = EINVAL;
586 return GSS_S_FAILURE;
587 }
588
589 {
590 unsigned char *buf = data_set->elements[0].value;
591 *authtime = (buf[3] <<24) | (buf[2] << 16) |
592 (buf[1] << 8) | (buf[0] << 0);
593 }
594
595 gss_release_buffer_set(minor_status, &data_set);
596
597 *minor_status = 0;
598 return GSS_S_COMPLETE;
599 }
600
601 /*
602 *
603 */
604
605 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_extract_authz_data_from_sec_context(OM_uint32 * minor_status,gss_ctx_id_t context_handle,int ad_type,gss_buffer_t ad_data)606 gsskrb5_extract_authz_data_from_sec_context(OM_uint32 *minor_status,
607 gss_ctx_id_t context_handle,
608 int ad_type,
609 gss_buffer_t ad_data)
610 {
611 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
612 OM_uint32 maj_stat;
613 gss_OID_desc oid_flat;
614 heim_oid baseoid, oid;
615 size_t size;
616
617 if (context_handle == GSS_C_NO_CONTEXT) {
618 *minor_status = EINVAL;
619 return GSS_S_FAILURE;
620 }
621
622 /* All this to append an integer to an oid... */
623
624 if (der_get_oid(GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->elements,
625 GSS_KRB5_EXTRACT_AUTHZ_DATA_FROM_SEC_CONTEXT_X->length,
626 &baseoid, NULL) != 0) {
627 *minor_status = EINVAL;
628 return GSS_S_FAILURE;
629 }
630
631 oid.length = baseoid.length + 1;
632 oid.components = calloc(oid.length, sizeof(*oid.components));
633 if (oid.components == NULL) {
634 der_free_oid(&baseoid);
635
636 *minor_status = ENOMEM;
637 return GSS_S_FAILURE;
638 }
639
640 memcpy(oid.components, baseoid.components,
641 baseoid.length * sizeof(*baseoid.components));
642
643 der_free_oid(&baseoid);
644
645 oid.components[oid.length - 1] = ad_type;
646
647 oid_flat.length = der_length_oid(&oid);
648 oid_flat.elements = malloc(oid_flat.length);
649 if (oid_flat.elements == NULL) {
650 free(oid.components);
651 *minor_status = ENOMEM;
652 return GSS_S_FAILURE;
653 }
654
655 if (der_put_oid((unsigned char *)oid_flat.elements + oid_flat.length - 1,
656 oid_flat.length, &oid, &size) != 0) {
657 free(oid.components);
658 free(oid_flat.elements);
659 *minor_status = EINVAL;
660 return GSS_S_FAILURE;
661 }
662 if (oid_flat.length != size)
663 abort();
664
665 free(oid.components);
666
667 /* FINALLY, we have the OID */
668
669 maj_stat = gss_inquire_sec_context_by_oid (minor_status,
670 context_handle,
671 &oid_flat,
672 &data_set);
673
674 free(oid_flat.elements);
675
676 if (maj_stat)
677 return maj_stat;
678
679 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
680 gss_release_buffer_set(minor_status, &data_set);
681 *minor_status = EINVAL;
682 return GSS_S_FAILURE;
683 }
684
685 ad_data->value = malloc(data_set->elements[0].length);
686 if (ad_data->value == NULL) {
687 gss_release_buffer_set(minor_status, &data_set);
688 *minor_status = ENOMEM;
689 return GSS_S_FAILURE;
690 }
691
692 ad_data->length = data_set->elements[0].length;
693 memcpy(ad_data->value, data_set->elements[0].value, ad_data->length);
694 gss_release_buffer_set(minor_status, &data_set);
695
696 *minor_status = 0;
697 return GSS_S_COMPLETE;
698 }
699
700 /*
701 *
702 */
703
704 static OM_uint32
gsskrb5_extract_key(OM_uint32 * minor_status,gss_ctx_id_t context_handle,const gss_OID oid,krb5_keyblock ** keyblock)705 gsskrb5_extract_key(OM_uint32 *minor_status,
706 gss_ctx_id_t context_handle,
707 const gss_OID oid,
708 krb5_keyblock **keyblock)
709 {
710 krb5_error_code ret;
711 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
712 OM_uint32 major_status;
713 krb5_context context = NULL;
714 krb5_storage *sp = NULL;
715
716 if (context_handle == GSS_C_NO_CONTEXT) {
717 *minor_status = EINVAL;
718 return GSS_S_FAILURE;
719 }
720
721 ret = krb5_init_context(&context);
722 if(ret) {
723 *minor_status = ret;
724 return GSS_S_FAILURE;
725 }
726
727 major_status =
728 gss_inquire_sec_context_by_oid (minor_status,
729 context_handle,
730 oid,
731 &data_set);
732 if (major_status)
733 return major_status;
734
735 if (data_set == GSS_C_NO_BUFFER_SET || data_set->count != 1) {
736 gss_release_buffer_set(minor_status, &data_set);
737 *minor_status = EINVAL;
738 return GSS_S_FAILURE;
739 }
740
741 sp = krb5_storage_from_mem(data_set->elements[0].value,
742 data_set->elements[0].length);
743 if (sp == NULL) {
744 ret = ENOMEM;
745 goto out;
746 }
747
748 *keyblock = calloc(1, sizeof(**keyblock));
749 if (keyblock == NULL) {
750 ret = ENOMEM;
751 goto out;
752 }
753
754 ret = krb5_ret_keyblock(sp, *keyblock);
755
756 out:
757 gss_release_buffer_set(minor_status, &data_set);
758 if (sp)
759 krb5_storage_free(sp);
760 if (ret && keyblock) {
761 krb5_free_keyblock(context, *keyblock);
762 *keyblock = NULL;
763 }
764 if (context)
765 krb5_free_context(context);
766
767 *minor_status = ret;
768 if (ret)
769 return GSS_S_FAILURE;
770
771 return GSS_S_COMPLETE;
772 }
773
774 /*
775 *
776 */
777
778 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_extract_service_keyblock(OM_uint32 * minor_status,gss_ctx_id_t context_handle,krb5_keyblock ** keyblock)779 gsskrb5_extract_service_keyblock(OM_uint32 *minor_status,
780 gss_ctx_id_t context_handle,
781 krb5_keyblock **keyblock)
782 {
783 return gsskrb5_extract_key(minor_status,
784 context_handle,
785 GSS_KRB5_GET_SERVICE_KEYBLOCK_X,
786 keyblock);
787 }
788
789 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_get_initiator_subkey(OM_uint32 * minor_status,gss_ctx_id_t context_handle,krb5_keyblock ** keyblock)790 gsskrb5_get_initiator_subkey(OM_uint32 *minor_status,
791 gss_ctx_id_t context_handle,
792 krb5_keyblock **keyblock)
793 {
794 return gsskrb5_extract_key(minor_status,
795 context_handle,
796 GSS_KRB5_GET_INITIATOR_SUBKEY_X,
797 keyblock);
798 }
799
800 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_get_subkey(OM_uint32 * minor_status,gss_ctx_id_t context_handle,krb5_keyblock ** keyblock)801 gsskrb5_get_subkey(OM_uint32 *minor_status,
802 gss_ctx_id_t context_handle,
803 krb5_keyblock **keyblock)
804 {
805 return gsskrb5_extract_key(minor_status,
806 context_handle,
807 GSS_KRB5_GET_SUBKEY_X,
808 keyblock);
809 }
810
811 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_set_default_realm(const char * realm)812 gsskrb5_set_default_realm(const char *realm)
813 {
814 struct _gss_mech_switch *m;
815 gss_buffer_desc buffer;
816 OM_uint32 junk;
817
818 _gss_load_mech();
819
820 buffer.value = rk_UNCONST(realm);
821 buffer.length = strlen(realm);
822
823 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
824 if (m->gm_mech.gm_set_sec_context_option == NULL)
825 continue;
826 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
827 GSS_KRB5_SET_DEFAULT_REALM_X, &buffer);
828 }
829
830 return (GSS_S_COMPLETE);
831 }
832
833 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gss_krb5_get_tkt_flags(OM_uint32 * minor_status,gss_ctx_id_t context_handle,OM_uint32 * tkt_flags)834 gss_krb5_get_tkt_flags(OM_uint32 *minor_status,
835 gss_ctx_id_t context_handle,
836 OM_uint32 *tkt_flags)
837 {
838
839 OM_uint32 major_status;
840 gss_buffer_set_t data_set = GSS_C_NO_BUFFER_SET;
841
842 if (context_handle == GSS_C_NO_CONTEXT) {
843 *minor_status = EINVAL;
844 return GSS_S_FAILURE;
845 }
846
847 major_status =
848 gss_inquire_sec_context_by_oid (minor_status,
849 context_handle,
850 GSS_KRB5_GET_TKT_FLAGS_X,
851 &data_set);
852 if (major_status)
853 return major_status;
854
855 if (data_set == GSS_C_NO_BUFFER_SET ||
856 data_set->count != 1 ||
857 data_set->elements[0].length < 4) {
858 gss_release_buffer_set(minor_status, &data_set);
859 *minor_status = EINVAL;
860 return GSS_S_FAILURE;
861 }
862
863 {
864 const u_char *p = data_set->elements[0].value;
865 *tkt_flags = (p[0] << 0) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
866 }
867
868 gss_release_buffer_set(minor_status, &data_set);
869 return GSS_S_COMPLETE;
870 }
871
872 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_set_time_offset(int offset)873 gsskrb5_set_time_offset(int offset)
874 {
875 struct _gss_mech_switch *m;
876 gss_buffer_desc buffer;
877 OM_uint32 junk;
878 int32_t o = offset;
879
880 _gss_load_mech();
881
882 buffer.value = &o;
883 buffer.length = sizeof(o);
884
885 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
886 if (m->gm_mech.gm_set_sec_context_option == NULL)
887 continue;
888 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
889 GSS_KRB5_SET_TIME_OFFSET_X, &buffer);
890 }
891
892 return (GSS_S_COMPLETE);
893 }
894
895 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_get_time_offset(int * offset)896 gsskrb5_get_time_offset(int *offset)
897 {
898 struct _gss_mech_switch *m;
899 gss_buffer_desc buffer;
900 OM_uint32 maj_stat, junk;
901 int32_t o;
902
903 _gss_load_mech();
904
905 buffer.value = &o;
906 buffer.length = sizeof(o);
907
908 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
909 if (m->gm_mech.gm_set_sec_context_option == NULL)
910 continue;
911 maj_stat = m->gm_mech.gm_set_sec_context_option(&junk, NULL,
912 GSS_KRB5_GET_TIME_OFFSET_X, &buffer);
913
914 if (maj_stat == GSS_S_COMPLETE) {
915 *offset = o;
916 return maj_stat;
917 }
918 }
919
920 return (GSS_S_UNAVAILABLE);
921 }
922
923 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL
gsskrb5_plugin_register(struct gsskrb5_krb5_plugin * c)924 gsskrb5_plugin_register(struct gsskrb5_krb5_plugin *c)
925 {
926 struct _gss_mech_switch *m;
927 gss_buffer_desc buffer;
928 OM_uint32 junk;
929
930 _gss_load_mech();
931
932 buffer.value = c;
933 buffer.length = sizeof(*c);
934
935 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
936 if (m->gm_mech.gm_set_sec_context_option == NULL)
937 continue;
938 m->gm_mech.gm_set_sec_context_option(&junk, NULL,
939 GSS_KRB5_PLUGIN_REGISTER_X, &buffer);
940 }
941
942 return (GSS_S_COMPLETE);
943 }
944