1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/gssapi/krb5/export_cred.c - krb5 export_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 a JSON null or array value representing princ. */
38 static krb5_error_code
39 json_principal(krb5_context context, krb5_principal princ,
40 k5_json_value *val_out)
43 k5_json_string str = NULL;
48 return k5_json_null_create_val(val_out);
49 ret = krb5_unparse_name(context, princ, &princname);
52 ret = k5_json_string_create(princname, &str);
53 krb5_free_unparsed_name(context, princname);
58 /* Return a json null or array value representing etypes. */
59 static krb5_error_code
60 json_etypes(krb5_enctype *etypes, k5_json_value *val_out)
68 return k5_json_null_create_val(val_out);
69 ret = k5_json_array_create(&array);
72 for (; *etypes != 0; etypes++) {
73 ret = k5_json_number_create(*etypes, &num);
76 ret = k5_json_array_add(array, num);
84 k5_json_release(array);
88 /* Return a JSON null or array value representing name. */
89 static krb5_error_code
90 json_kgname(krb5_context context, krb5_gss_name_t name, k5_json_value *val_out)
93 k5_json_array array = NULL;
98 return k5_json_null_create_val(val_out);
99 ret = json_principal(context, name->princ, &princ);
102 ret = k5_json_array_fmt(&array, "vss", princ, name->service, name->host);
103 k5_json_release(princ);
108 /* Return a JSON null or string value representing keytab. */
109 static krb5_error_code
110 json_keytab(krb5_context context, krb5_keytab keytab, k5_json_value *val_out)
118 return k5_json_null_create_val(val_out);
119 ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
122 ret = k5_json_string_create(name, &str);
127 /* Return a JSON null or string value representing rcache. */
128 static krb5_error_code
129 json_rcache(krb5_context context, krb5_rcache rcache, k5_json_value *val_out)
132 k5_json_string str = NULL;
136 return k5_json_null_create_val(val_out);
137 if (asprintf(&name, "%s:%s", krb5_rc_get_type(context, rcache),
138 krb5_rc_get_name(context, rcache)) < 0)
140 ret = k5_json_string_create(name, &str);
146 /* Return a JSON array value representing keyblock. */
147 static krb5_error_code
148 json_keyblock(krb5_keyblock *kb, k5_json_value *val_out)
154 ret = k5_json_array_fmt(&array, "iB", kb->enctype, (void *)kb->contents,
162 /* Return a JSON array value representing addr. */
163 static krb5_error_code
164 json_address(krb5_address *addr, k5_json_value *val_out)
170 ret = k5_json_array_fmt(&array, "iB", addr->addrtype,
171 (void *)addr->contents, (size_t)addr->length);
178 /* Return a JSON null or array value representing addrs. */
179 static krb5_error_code
180 json_addresses(krb5_address **addrs, k5_json_value *val_out)
188 return k5_json_null_create_val(val_out);
189 ret = k5_json_array_create(&array);
192 for (; *addrs != NULL; addrs++) {
193 ret = json_address(*addrs, &val);
196 ret = k5_json_array_add(array, val);
197 k5_json_release(val);
204 k5_json_release(array);
208 /* Return a JSON array value representing ad. */
209 static krb5_error_code
210 json_authdata_element(krb5_authdata *ad, k5_json_value *val_out)
216 ret = k5_json_array_fmt(&array, "iB", ad->ad_type, (void *)ad->contents,
224 /* Return a JSON null or array value representing authdata. */
225 static krb5_error_code
226 json_authdata(krb5_authdata **authdata, k5_json_value *val_out)
233 if (authdata == NULL)
234 return k5_json_null_create_val(val_out);
235 ret = k5_json_array_create(&array);
238 for (; *authdata != NULL; authdata++) {
239 ret = json_authdata_element(*authdata, &val);
242 ret = k5_json_array_add(array, val);
243 k5_json_release(val);
250 k5_json_release(array);
254 /* Return a JSON array value representing creds. */
255 static krb5_error_code
256 json_creds(krb5_context context, krb5_creds *creds, k5_json_value *val_out)
260 k5_json_value client = NULL, server = NULL, keyblock = NULL, addrs = NULL;
261 k5_json_value authdata = NULL;
264 ret = json_principal(context, creds->client, &client);
267 ret = json_principal(context, creds->server, &server);
270 ret = json_keyblock(&creds->keyblock, &keyblock);
273 ret = json_addresses(creds->addresses, &addrs);
276 ret = json_authdata(creds->authdata, &authdata);
280 ret = k5_json_array_fmt(&array, "vvviiiibivBBv", client, server, keyblock,
281 creds->times.authtime, creds->times.starttime,
282 creds->times.endtime, creds->times.renew_till,
283 creds->is_skey, creds->ticket_flags, addrs,
284 (void *)creds->ticket.data,
285 (size_t)creds->ticket.length,
286 (void *)creds->second_ticket.data,
287 (size_t)creds->second_ticket.length, authdata);
293 k5_json_release(client);
294 k5_json_release(server);
295 k5_json_release(keyblock);
296 k5_json_release(addrs);
297 k5_json_release(authdata);
301 /* Return a JSON array value representing the contents of ccache. */
302 static krb5_error_code
303 json_ccache_contents(krb5_context context, krb5_ccache ccache,
304 k5_json_value *val_out)
307 krb5_principal princ;
308 krb5_cc_cursor cursor;
314 ret = k5_json_array_create(&array);
318 /* Put the principal in the first array entry. */
319 ret = krb5_cc_get_principal(context, ccache, &princ);
322 ret = json_principal(context, princ, &val);
323 krb5_free_principal(context, princ);
326 ret = k5_json_array_add(array, val);
327 k5_json_release(val);
331 /* Put credentials in the remaining array entries. */
332 ret = krb5_cc_start_seq_get(context, ccache, &cursor);
335 while ((ret = krb5_cc_next_cred(context, ccache, &cursor, &creds)) == 0) {
336 ret = json_creds(context, &creds, &val);
337 krb5_free_cred_contents(context, &creds);
340 ret = k5_json_array_add(array, val);
341 k5_json_release(val);
345 krb5_cc_end_seq_get(context, ccache, &cursor);
346 if (ret != KRB5_CC_END)
352 k5_json_release(array);
356 /* Return a JSON null, string, or array value representing ccache. */
357 static krb5_error_code
358 json_ccache(krb5_context context, krb5_ccache ccache, k5_json_value *val_out)
366 return k5_json_null_create_val(val_out);
367 if (strcmp(krb5_cc_get_type(context, ccache), "MEMORY") == 0) {
368 return json_ccache_contents(context, ccache, val_out);
370 ret = krb5_cc_get_full_name(context, ccache, &name);
373 ret = k5_json_string_create(name, &str);
380 /* Return a JSON array value representing cred. */
381 static krb5_error_code
382 json_kgcred(krb5_context context, krb5_gss_cred_id_t cred,
383 k5_json_value *val_out)
387 k5_json_value name = NULL, imp = NULL, keytab = NULL, rcache = NULL;
388 k5_json_value ccache = NULL, ckeytab = NULL, etypes = NULL;
391 ret = json_kgname(context, cred->name, &name);
394 ret = json_principal(context, cred->impersonator, &imp);
397 ret = json_keytab(context, cred->keytab, &keytab);
400 ret = json_rcache(context, cred->rcache, &rcache);
403 ret = json_ccache(context, cred->ccache, &ccache);
406 ret = json_keytab(context, cred->client_keytab, &ckeytab);
409 ret = json_etypes(cred->req_enctypes, &etypes);
413 ret = k5_json_array_fmt(&array, "ivvbbvvvvbiivs", cred->usage, name, imp,
414 cred->default_identity, cred->iakerb_mech, keytab,
415 rcache, ccache, ckeytab, cred->have_tgt,
416 cred->expire, cred->refresh_time, etypes,
423 k5_json_release(name);
424 k5_json_release(imp);
425 k5_json_release(keytab);
426 k5_json_release(rcache);
427 k5_json_release(ccache);
428 k5_json_release(ckeytab);
429 k5_json_release(etypes);
433 OM_uint32 KRB5_CALLCONV
434 krb5_gss_export_cred(OM_uint32 *minor_status, gss_cred_id_t cred_handle,
437 OM_uint32 status = GSS_S_COMPLETE;
438 krb5_context context;
440 krb5_gss_cred_id_t cred;
441 k5_json_array array = NULL;
442 k5_json_value jcred = NULL;
446 ret = krb5_gss_init_context(&context);
449 return GSS_S_FAILURE;
452 /* Validate and lock cred_handle. */
453 status = krb5_gss_validate_cred_1(minor_status, cred_handle, context);
454 if (status != GSS_S_COMPLETE)
456 cred = (krb5_gss_cred_id_t)cred_handle;
458 if (json_kgcred(context, cred, &jcred))
460 if (k5_json_array_fmt(&array, "sv", CRED_EXPORT_MAGIC, jcred))
462 if (k5_json_encode(array, &str))
464 d = string2data(str);
465 if (data_to_gss(&d, token))
471 k5_mutex_unlock(&cred->lock);
472 k5_json_release(array);
473 k5_json_release(jcred);
474 krb5_free_context(context);
478 *minor_status = ENOMEM;
479 status = GSS_S_FAILURE;