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