1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/krb5/import_cred.c - krb5 import_cred implementation */
4 * Copyright (C) 2012 by the Massachusetts Institute of Technology.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include "gssapiP_krb5.h"
37 /* Return the idx element of array if it is of type tid; otherwise return
38 * NULL. The caller is responsible for checking the array length. */
40 check_element(k5_json_array array, size_t idx, k5_json_tid tid)
44 v = k5_json_array_get(array, idx);
45 return (k5_json_get_tid(v) == tid) ? v : NULL;
48 /* All of the json_to_x functions return 0 on success, -1 on failure (either
49 * from running out of memory or from defective input). */
51 /* Convert a JSON value to a C string or to NULL. */
53 json_to_optional_string(k5_json_value v, char **string_out)
56 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
58 if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
60 *string_out = strdup(k5_json_string_utf8(v));
61 return (*string_out == NULL) ? -1 : 0;
64 /* Convert a JSON value to a principal or to NULL. */
66 json_to_principal(krb5_context context, k5_json_value v,
67 krb5_principal *princ_out)
70 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
72 if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
74 if (krb5_parse_name(context, k5_json_string_utf8(v), princ_out))
79 /* Convert a JSON value to a zero-terminated enctypes list or to NULL. */
81 json_to_etypes(k5_json_value v, krb5_enctype **etypes_out)
83 krb5_enctype *etypes = NULL;
89 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
91 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
94 len = k5_json_array_length(array);
95 etypes = calloc(len + 1, sizeof(*etypes));
96 for (i = 0; i < len; i++) {
97 n = check_element(array, i, K5_JSON_TID_NUMBER);
100 etypes[i] = k5_json_number_value(n);
102 *etypes_out = etypes;
110 /* Convert a JSON value to a krb5 GSS name or to NULL. */
112 json_to_kgname(krb5_context context, k5_json_value v,
113 krb5_gss_name_t *name_out)
116 krb5_gss_name_t name = NULL;
119 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
121 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
124 if (k5_json_array_length(array) != 3)
126 name = calloc(1, sizeof(*name));
129 if (k5_mutex_init(&name->lock)) {
134 if (json_to_principal(context, k5_json_array_get(array, 0), &name->princ))
136 if (json_to_optional_string(k5_json_array_get(array, 1), &name->service))
138 if (json_to_optional_string(k5_json_array_get(array, 2), &name->host))
145 kg_release_name(context, &name);
149 /* Convert a JSON value to a keytab handle or to NULL. */
151 json_to_keytab(krb5_context context, k5_json_value v, krb5_keytab *keytab_out)
154 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
156 if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
158 if (krb5_kt_resolve(context, k5_json_string_utf8(v), keytab_out))
163 /* Convert a JSON value to an rcache handle or to NULL. */
165 json_to_rcache(krb5_context context, k5_json_value v, krb5_rcache *rcache_out)
170 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
172 if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
174 if (krb5_rc_resolve_full(context, &rcache, (char *)k5_json_string_utf8(v)))
176 if (krb5_rc_recover_or_initialize(context, rcache, context->clockskew)) {
177 krb5_rc_close(context, rcache);
180 *rcache_out = rcache;
184 /* Convert a JSON value to a keyblock, filling in keyblock. */
186 json_to_keyblock(k5_json_value v, krb5_keyblock *keyblock)
193 memset(keyblock, 0, sizeof(*keyblock));
194 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
197 if (k5_json_array_length(array) != 2)
200 n = check_element(array, 0, K5_JSON_TID_NUMBER);
203 keyblock->enctype = k5_json_number_value(n);
205 s = check_element(array, 1, K5_JSON_TID_STRING);
208 if (k5_json_string_unbase64(s, &keyblock->contents, &len))
210 keyblock->length = len;
211 keyblock->magic = KV5M_KEYBLOCK;
215 /* Convert a JSON value to a krb5 address. */
217 json_to_address(k5_json_value v, krb5_address **addr_out)
220 krb5_address *addr = NULL;
226 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
229 if (k5_json_array_length(array) != 2)
232 n = check_element(array, 0, K5_JSON_TID_NUMBER);
235 s = check_element(array, 1, K5_JSON_TID_STRING);
239 addr = malloc(sizeof(*addr));
242 addr->addrtype = k5_json_number_value(n);
243 if (k5_json_string_unbase64(s, &addr->contents, &len)) {
248 addr->magic = KV5M_ADDRESS;
253 /* Convert a JSON value to a null-terminated list of krb5 addresses or to
256 json_to_addresses(krb5_context context, k5_json_value v,
257 krb5_address ***addresses_out)
260 krb5_address **addrs = NULL;
263 *addresses_out = NULL;
264 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
266 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
269 len = k5_json_array_length(array);
270 addrs = calloc(len + 1, sizeof(*addrs));
271 for (i = 0; i < len; i++) {
272 if (json_to_address(k5_json_array_get(array, i), &addrs[i]))
276 *addresses_out = addrs;
280 krb5_free_addresses(context, addrs);
284 /* Convert a JSON value to an authdata element. */
286 json_to_authdata_element(k5_json_value v, krb5_authdata **ad_out)
289 krb5_authdata *ad = NULL;
295 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
298 if (k5_json_array_length(array) != 2)
301 n = check_element(array, 0, K5_JSON_TID_NUMBER);
304 s = check_element(array, 1, K5_JSON_TID_STRING);
308 ad = malloc(sizeof(*ad));
311 ad->ad_type = k5_json_number_value(n);
312 if (k5_json_string_unbase64(s, &ad->contents, &len)) {
317 ad->magic = KV5M_AUTHDATA;
322 /* Convert a JSON value to a null-terminated authdata list or to NULL. */
324 json_to_authdata(krb5_context context, k5_json_value v,
325 krb5_authdata ***authdata_out)
328 krb5_authdata **authdata = NULL;
331 *authdata_out = NULL;
332 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
334 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
337 len = k5_json_array_length(array);
338 authdata = calloc(len + 1, sizeof(*authdata));
339 for (i = 0; i < len; i++) {
340 if (json_to_authdata_element(k5_json_array_get(array, i),
345 *authdata_out = authdata;
349 krb5_free_authdata(context, authdata);
353 /* Convert a JSON value to a krb5 credential structure, filling in creds. */
355 json_to_creds(krb5_context context, k5_json_value v, krb5_creds *creds)
364 memset(creds, 0, sizeof(*creds));
365 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
368 if (k5_json_array_length(array) != 13)
371 if (json_to_principal(context, k5_json_array_get(array, 0),
375 if (json_to_principal(context, k5_json_array_get(array, 1),
379 if (json_to_keyblock(k5_json_array_get(array, 2), &creds->keyblock))
382 n = check_element(array, 3, K5_JSON_TID_NUMBER);
385 creds->times.authtime = k5_json_number_value(n);
387 n = check_element(array, 4, K5_JSON_TID_NUMBER);
390 creds->times.starttime = k5_json_number_value(n);
392 n = check_element(array, 5, K5_JSON_TID_NUMBER);
395 creds->times.endtime = k5_json_number_value(n);
397 n = check_element(array, 6, K5_JSON_TID_NUMBER);
400 creds->times.renew_till = k5_json_number_value(n);
402 b = check_element(array, 7, K5_JSON_TID_BOOL);
405 creds->is_skey = k5_json_bool_value(b);
407 n = check_element(array, 8, K5_JSON_TID_NUMBER);
410 creds->ticket_flags = k5_json_number_value(n);
412 if (json_to_addresses(context, k5_json_array_get(array, 9),
416 s = check_element(array, 10, K5_JSON_TID_STRING);
419 if (k5_json_string_unbase64(s, &data, &len))
421 creds->ticket.data = (char *)data;
422 creds->ticket.length = len;
424 s = check_element(array, 11, K5_JSON_TID_STRING);
427 if (k5_json_string_unbase64(s, &data, &len))
429 creds->second_ticket.data = (char *)data;
430 creds->second_ticket.length = len;
432 if (json_to_authdata(context, k5_json_array_get(array, 12),
436 creds->magic = KV5M_CREDS;
440 krb5_free_cred_contents(context, creds);
441 memset(creds, 0, sizeof(*creds));
445 /* Convert a JSON value to a ccache handle or to NULL. Set *new_out to true if
446 * the ccache handle is a newly created memory ccache, false otherwise. */
448 json_to_ccache(krb5_context context, k5_json_value v, krb5_ccache *ccache_out,
449 krb5_boolean *new_out)
452 krb5_ccache ccache = NULL;
453 krb5_principal princ;
460 if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
462 if (k5_json_get_tid(v) == K5_JSON_TID_STRING) {
463 /* We got a reference to an external ccache; just resolve it. */
464 return krb5_cc_resolve(context, k5_json_string_utf8(v), ccache_out) ?
468 /* We got the contents of a memory ccache. */
469 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
472 len = k5_json_array_length(array);
476 /* Initialize a new memory ccache using the principal in the first array
478 if (krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))
480 if (json_to_principal(context, k5_json_array_get(array, 0), &princ))
482 ret = krb5_cc_initialize(context, ccache, princ);
483 krb5_free_principal(context, princ);
487 /* Add remaining array entries to the ccache as credentials. */
488 for (i = 1; i < len; i++) {
489 if (json_to_creds(context, k5_json_array_get(array, i), &creds))
491 ret = krb5_cc_store_cred(context, ccache, &creds);
492 krb5_free_cred_contents(context, &creds);
497 *ccache_out = ccache;
502 (void)krb5_cc_destroy(context, ccache);
506 /* Convert a JSON array value to a krb5 GSS credential. */
508 json_to_kgcred(krb5_context context, k5_json_array array,
509 krb5_gss_cred_id_t *cred_out)
511 krb5_gss_cred_id_t cred;
518 if (k5_json_array_length(array) != 14)
521 cred = calloc(1, sizeof(*cred));
524 if (k5_mutex_init(&cred->lock)) {
529 n = check_element(array, 0, K5_JSON_TID_NUMBER);
532 cred->usage = k5_json_number_value(n);
534 if (json_to_kgname(context, k5_json_array_get(array, 1), &cred->name))
537 if (json_to_principal(context, k5_json_array_get(array, 2),
538 &cred->impersonator))
541 b = check_element(array, 3, K5_JSON_TID_BOOL);
544 cred->default_identity = k5_json_bool_value(b);
546 b = check_element(array, 4, K5_JSON_TID_BOOL);
549 cred->iakerb_mech = k5_json_bool_value(b);
551 if (json_to_keytab(context, k5_json_array_get(array, 5), &cred->keytab))
554 if (json_to_rcache(context, k5_json_array_get(array, 6), &cred->rcache))
557 if (json_to_ccache(context, k5_json_array_get(array, 7), &cred->ccache,
560 cred->destroy_ccache = is_new;
562 if (json_to_keytab(context, k5_json_array_get(array, 8),
563 &cred->client_keytab))
566 b = check_element(array, 9, K5_JSON_TID_BOOL);
569 cred->have_tgt = k5_json_bool_value(b);
571 n = check_element(array, 10, K5_JSON_TID_NUMBER);
574 cred->expire = k5_json_number_value(n);
576 n = check_element(array, 11, K5_JSON_TID_NUMBER);
579 cred->refresh_time = k5_json_number_value(n);
581 if (json_to_etypes(k5_json_array_get(array, 12), &cred->req_enctypes))
584 if (json_to_optional_string(k5_json_array_get(array, 13), &cred->password))
591 (void)krb5_gss_release_cred(&tmp, (gss_cred_id_t *)&cred);
595 OM_uint32 KRB5_CALLCONV
596 krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
597 gss_cred_id_t *cred_handle)
599 OM_uint32 status = GSS_S_COMPLETE;
600 krb5_context context;
602 krb5_gss_cred_id_t cred;
603 k5_json_value v = NULL;
608 ret = krb5_gss_init_context(&context);
611 return GSS_S_FAILURE;
615 copy = k5memdup0(token->value, token->length, &ret);
617 status = GSS_S_FAILURE;
621 if (k5_json_decode(copy, &v))
624 /* Decode the CRED_EXPORT_MAGIC array wrapper. */
625 if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
628 if (k5_json_array_length(array) != 2)
630 str = check_element(array, 0, K5_JSON_TID_STRING);
632 strcmp(k5_json_string_utf8(str), CRED_EXPORT_MAGIC) != 0)
634 if (json_to_kgcred(context, k5_json_array_get(array, 1), &cred))
637 *cred_handle = (gss_cred_id_t)cred;
642 krb5_free_context(context);
646 status = GSS_S_DEFECTIVE_TOKEN;