1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* lib/gssapi/krb5/import_cred.c - krb5 import_cred implementation */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert * Copyright (C) 2012 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert * All rights reserved.
6*7f2fe78bSCy Schubert *
7*7f2fe78bSCy Schubert * Redistribution and use in source and binary forms, with or without
8*7f2fe78bSCy Schubert * modification, are permitted provided that the following conditions
9*7f2fe78bSCy Schubert * are met:
10*7f2fe78bSCy Schubert *
11*7f2fe78bSCy Schubert * * Redistributions of source code must retain the above copyright
12*7f2fe78bSCy Schubert * notice, this list of conditions and the following disclaimer.
13*7f2fe78bSCy Schubert *
14*7f2fe78bSCy Schubert * * Redistributions in binary form must reproduce the above copyright
15*7f2fe78bSCy Schubert * notice, this list of conditions and the following disclaimer in
16*7f2fe78bSCy Schubert * the documentation and/or other materials provided with the
17*7f2fe78bSCy Schubert * distribution.
18*7f2fe78bSCy Schubert *
19*7f2fe78bSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*7f2fe78bSCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*7f2fe78bSCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22*7f2fe78bSCy Schubert * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23*7f2fe78bSCy Schubert * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24*7f2fe78bSCy Schubert * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25*7f2fe78bSCy Schubert * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26*7f2fe78bSCy Schubert * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27*7f2fe78bSCy Schubert * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28*7f2fe78bSCy Schubert * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29*7f2fe78bSCy Schubert * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30*7f2fe78bSCy Schubert * OF THE POSSIBILITY OF SUCH DAMAGE.
31*7f2fe78bSCy Schubert */
32*7f2fe78bSCy Schubert
33*7f2fe78bSCy Schubert #include "k5-int.h"
34*7f2fe78bSCy Schubert #include "k5-json.h"
35*7f2fe78bSCy Schubert #include "gssapiP_krb5.h"
36*7f2fe78bSCy Schubert
37*7f2fe78bSCy Schubert /* Return the idx element of array if it is of type tid; otherwise return
38*7f2fe78bSCy Schubert * NULL. The caller is responsible for checking the array length. */
39*7f2fe78bSCy Schubert static k5_json_value
check_element(k5_json_array array,size_t idx,k5_json_tid tid)40*7f2fe78bSCy Schubert check_element(k5_json_array array, size_t idx, k5_json_tid tid)
41*7f2fe78bSCy Schubert {
42*7f2fe78bSCy Schubert k5_json_value v;
43*7f2fe78bSCy Schubert
44*7f2fe78bSCy Schubert v = k5_json_array_get(array, idx);
45*7f2fe78bSCy Schubert return (k5_json_get_tid(v) == tid) ? v : NULL;
46*7f2fe78bSCy Schubert }
47*7f2fe78bSCy Schubert
48*7f2fe78bSCy Schubert /* All of the json_to_x functions return 0 on success, -1 on failure (either
49*7f2fe78bSCy Schubert * from running out of memory or from defective input). */
50*7f2fe78bSCy Schubert
51*7f2fe78bSCy Schubert /* Convert a JSON value to a C string or to NULL. */
52*7f2fe78bSCy Schubert static int
json_to_optional_string(k5_json_value v,char ** string_out)53*7f2fe78bSCy Schubert json_to_optional_string(k5_json_value v, char **string_out)
54*7f2fe78bSCy Schubert {
55*7f2fe78bSCy Schubert *string_out = NULL;
56*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
57*7f2fe78bSCy Schubert return 0;
58*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
59*7f2fe78bSCy Schubert return -1;
60*7f2fe78bSCy Schubert *string_out = strdup(k5_json_string_utf8(v));
61*7f2fe78bSCy Schubert return (*string_out == NULL) ? -1 : 0;
62*7f2fe78bSCy Schubert }
63*7f2fe78bSCy Schubert
64*7f2fe78bSCy Schubert /* Convert a JSON value to a principal or to NULL. */
65*7f2fe78bSCy Schubert static int
json_to_principal(krb5_context context,k5_json_value v,krb5_principal * princ_out)66*7f2fe78bSCy Schubert json_to_principal(krb5_context context, k5_json_value v,
67*7f2fe78bSCy Schubert krb5_principal *princ_out)
68*7f2fe78bSCy Schubert {
69*7f2fe78bSCy Schubert *princ_out = NULL;
70*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
71*7f2fe78bSCy Schubert return 0;
72*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
73*7f2fe78bSCy Schubert return -1;
74*7f2fe78bSCy Schubert if (krb5_parse_name(context, k5_json_string_utf8(v), princ_out))
75*7f2fe78bSCy Schubert return -1;
76*7f2fe78bSCy Schubert return 0;
77*7f2fe78bSCy Schubert }
78*7f2fe78bSCy Schubert
79*7f2fe78bSCy Schubert /* Convert a JSON value to a zero-terminated enctypes list or to NULL. */
80*7f2fe78bSCy Schubert static int
json_to_etypes(k5_json_value v,krb5_enctype ** etypes_out)81*7f2fe78bSCy Schubert json_to_etypes(k5_json_value v, krb5_enctype **etypes_out)
82*7f2fe78bSCy Schubert {
83*7f2fe78bSCy Schubert krb5_enctype *etypes = NULL;
84*7f2fe78bSCy Schubert k5_json_array array;
85*7f2fe78bSCy Schubert k5_json_number n;
86*7f2fe78bSCy Schubert size_t len, i;
87*7f2fe78bSCy Schubert
88*7f2fe78bSCy Schubert *etypes_out = NULL;
89*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
90*7f2fe78bSCy Schubert return 0;
91*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
92*7f2fe78bSCy Schubert return -1;
93*7f2fe78bSCy Schubert array = v;
94*7f2fe78bSCy Schubert len = k5_json_array_length(array);
95*7f2fe78bSCy Schubert etypes = calloc(len + 1, sizeof(*etypes));
96*7f2fe78bSCy Schubert for (i = 0; i < len; i++) {
97*7f2fe78bSCy Schubert n = check_element(array, i, K5_JSON_TID_NUMBER);
98*7f2fe78bSCy Schubert if (n == NULL)
99*7f2fe78bSCy Schubert goto invalid;
100*7f2fe78bSCy Schubert etypes[i] = k5_json_number_value(n);
101*7f2fe78bSCy Schubert }
102*7f2fe78bSCy Schubert *etypes_out = etypes;
103*7f2fe78bSCy Schubert return 0;
104*7f2fe78bSCy Schubert
105*7f2fe78bSCy Schubert invalid:
106*7f2fe78bSCy Schubert free(etypes);
107*7f2fe78bSCy Schubert return -1;
108*7f2fe78bSCy Schubert }
109*7f2fe78bSCy Schubert
110*7f2fe78bSCy Schubert /* Convert a JSON value to a krb5 GSS name or to NULL. */
111*7f2fe78bSCy Schubert static int
json_to_kgname(krb5_context context,k5_json_value v,krb5_gss_name_t * name_out)112*7f2fe78bSCy Schubert json_to_kgname(krb5_context context, k5_json_value v,
113*7f2fe78bSCy Schubert krb5_gss_name_t *name_out)
114*7f2fe78bSCy Schubert {
115*7f2fe78bSCy Schubert k5_json_array array;
116*7f2fe78bSCy Schubert krb5_gss_name_t name = NULL;
117*7f2fe78bSCy Schubert
118*7f2fe78bSCy Schubert *name_out = NULL;
119*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
120*7f2fe78bSCy Schubert return 0;
121*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
122*7f2fe78bSCy Schubert return -1;
123*7f2fe78bSCy Schubert array = v;
124*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 3)
125*7f2fe78bSCy Schubert return -1;
126*7f2fe78bSCy Schubert name = calloc(1, sizeof(*name));
127*7f2fe78bSCy Schubert if (name == NULL)
128*7f2fe78bSCy Schubert return -1;
129*7f2fe78bSCy Schubert if (k5_mutex_init(&name->lock)) {
130*7f2fe78bSCy Schubert free(name);
131*7f2fe78bSCy Schubert return -1;
132*7f2fe78bSCy Schubert }
133*7f2fe78bSCy Schubert
134*7f2fe78bSCy Schubert if (json_to_principal(context, k5_json_array_get(array, 0), &name->princ))
135*7f2fe78bSCy Schubert goto invalid;
136*7f2fe78bSCy Schubert if (json_to_optional_string(k5_json_array_get(array, 1), &name->service))
137*7f2fe78bSCy Schubert goto invalid;
138*7f2fe78bSCy Schubert if (json_to_optional_string(k5_json_array_get(array, 2), &name->host))
139*7f2fe78bSCy Schubert goto invalid;
140*7f2fe78bSCy Schubert
141*7f2fe78bSCy Schubert *name_out = name;
142*7f2fe78bSCy Schubert return 0;
143*7f2fe78bSCy Schubert
144*7f2fe78bSCy Schubert invalid:
145*7f2fe78bSCy Schubert kg_release_name(context, &name);
146*7f2fe78bSCy Schubert return -1;
147*7f2fe78bSCy Schubert }
148*7f2fe78bSCy Schubert
149*7f2fe78bSCy Schubert /* Convert a JSON value to a keytab handle or to NULL. */
150*7f2fe78bSCy Schubert static int
json_to_keytab(krb5_context context,k5_json_value v,krb5_keytab * keytab_out)151*7f2fe78bSCy Schubert json_to_keytab(krb5_context context, k5_json_value v, krb5_keytab *keytab_out)
152*7f2fe78bSCy Schubert {
153*7f2fe78bSCy Schubert *keytab_out = NULL;
154*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
155*7f2fe78bSCy Schubert return 0;
156*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
157*7f2fe78bSCy Schubert return -1;
158*7f2fe78bSCy Schubert if (krb5_kt_resolve(context, k5_json_string_utf8(v), keytab_out))
159*7f2fe78bSCy Schubert return -1;
160*7f2fe78bSCy Schubert return 0;
161*7f2fe78bSCy Schubert }
162*7f2fe78bSCy Schubert
163*7f2fe78bSCy Schubert /* Convert a JSON value to an rcache handle or to NULL. */
164*7f2fe78bSCy Schubert static int
json_to_rcache(krb5_context context,k5_json_value v,krb5_rcache * rcache_out)165*7f2fe78bSCy Schubert json_to_rcache(krb5_context context, k5_json_value v, krb5_rcache *rcache_out)
166*7f2fe78bSCy Schubert {
167*7f2fe78bSCy Schubert krb5_rcache rcache;
168*7f2fe78bSCy Schubert
169*7f2fe78bSCy Schubert *rcache_out = NULL;
170*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
171*7f2fe78bSCy Schubert return 0;
172*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_STRING)
173*7f2fe78bSCy Schubert return -1;
174*7f2fe78bSCy Schubert if (k5_rc_resolve(context, (char *)k5_json_string_utf8(v), &rcache))
175*7f2fe78bSCy Schubert return -1;
176*7f2fe78bSCy Schubert *rcache_out = rcache;
177*7f2fe78bSCy Schubert return 0;
178*7f2fe78bSCy Schubert }
179*7f2fe78bSCy Schubert
180*7f2fe78bSCy Schubert /* Convert a JSON value to a keyblock, filling in keyblock. */
181*7f2fe78bSCy Schubert static int
json_to_keyblock(k5_json_value v,krb5_keyblock * keyblock)182*7f2fe78bSCy Schubert json_to_keyblock(k5_json_value v, krb5_keyblock *keyblock)
183*7f2fe78bSCy Schubert {
184*7f2fe78bSCy Schubert k5_json_array array;
185*7f2fe78bSCy Schubert k5_json_number n;
186*7f2fe78bSCy Schubert k5_json_string s;
187*7f2fe78bSCy Schubert size_t len;
188*7f2fe78bSCy Schubert
189*7f2fe78bSCy Schubert memset(keyblock, 0, sizeof(*keyblock));
190*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
191*7f2fe78bSCy Schubert return -1;
192*7f2fe78bSCy Schubert array = v;
193*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 2)
194*7f2fe78bSCy Schubert return -1;
195*7f2fe78bSCy Schubert
196*7f2fe78bSCy Schubert n = check_element(array, 0, K5_JSON_TID_NUMBER);
197*7f2fe78bSCy Schubert if (n == NULL)
198*7f2fe78bSCy Schubert return -1;
199*7f2fe78bSCy Schubert keyblock->enctype = k5_json_number_value(n);
200*7f2fe78bSCy Schubert
201*7f2fe78bSCy Schubert s = check_element(array, 1, K5_JSON_TID_STRING);
202*7f2fe78bSCy Schubert if (s == NULL)
203*7f2fe78bSCy Schubert return -1;
204*7f2fe78bSCy Schubert if (k5_json_string_unbase64(s, &keyblock->contents, &len))
205*7f2fe78bSCy Schubert return -1;
206*7f2fe78bSCy Schubert keyblock->length = len;
207*7f2fe78bSCy Schubert keyblock->magic = KV5M_KEYBLOCK;
208*7f2fe78bSCy Schubert return 0;
209*7f2fe78bSCy Schubert }
210*7f2fe78bSCy Schubert
211*7f2fe78bSCy Schubert /* Convert a JSON value to a krb5 address. */
212*7f2fe78bSCy Schubert static int
json_to_address(k5_json_value v,krb5_address ** addr_out)213*7f2fe78bSCy Schubert json_to_address(k5_json_value v, krb5_address **addr_out)
214*7f2fe78bSCy Schubert {
215*7f2fe78bSCy Schubert k5_json_array array;
216*7f2fe78bSCy Schubert krb5_address *addr = NULL;
217*7f2fe78bSCy Schubert k5_json_number n;
218*7f2fe78bSCy Schubert k5_json_string s;
219*7f2fe78bSCy Schubert size_t len;
220*7f2fe78bSCy Schubert
221*7f2fe78bSCy Schubert *addr_out = NULL;
222*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
223*7f2fe78bSCy Schubert return -1;
224*7f2fe78bSCy Schubert array = v;
225*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 2)
226*7f2fe78bSCy Schubert return -1;
227*7f2fe78bSCy Schubert
228*7f2fe78bSCy Schubert n = check_element(array, 0, K5_JSON_TID_NUMBER);
229*7f2fe78bSCy Schubert if (n == NULL)
230*7f2fe78bSCy Schubert return -1;
231*7f2fe78bSCy Schubert s = check_element(array, 1, K5_JSON_TID_STRING);
232*7f2fe78bSCy Schubert if (s == NULL)
233*7f2fe78bSCy Schubert return -1;
234*7f2fe78bSCy Schubert
235*7f2fe78bSCy Schubert addr = malloc(sizeof(*addr));
236*7f2fe78bSCy Schubert if (addr == NULL)
237*7f2fe78bSCy Schubert return -1;
238*7f2fe78bSCy Schubert addr->addrtype = k5_json_number_value(n);
239*7f2fe78bSCy Schubert if (k5_json_string_unbase64(s, &addr->contents, &len)) {
240*7f2fe78bSCy Schubert free(addr);
241*7f2fe78bSCy Schubert return -1;
242*7f2fe78bSCy Schubert }
243*7f2fe78bSCy Schubert addr->length = len;
244*7f2fe78bSCy Schubert addr->magic = KV5M_ADDRESS;
245*7f2fe78bSCy Schubert *addr_out = addr;
246*7f2fe78bSCy Schubert return 0;
247*7f2fe78bSCy Schubert }
248*7f2fe78bSCy Schubert
249*7f2fe78bSCy Schubert /* Convert a JSON value to a null-terminated list of krb5 addresses or to
250*7f2fe78bSCy Schubert * NULL. */
251*7f2fe78bSCy Schubert static int
json_to_addresses(krb5_context context,k5_json_value v,krb5_address *** addresses_out)252*7f2fe78bSCy Schubert json_to_addresses(krb5_context context, k5_json_value v,
253*7f2fe78bSCy Schubert krb5_address ***addresses_out)
254*7f2fe78bSCy Schubert {
255*7f2fe78bSCy Schubert k5_json_array array;
256*7f2fe78bSCy Schubert krb5_address **addrs = NULL;
257*7f2fe78bSCy Schubert size_t len, i;
258*7f2fe78bSCy Schubert
259*7f2fe78bSCy Schubert *addresses_out = NULL;
260*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
261*7f2fe78bSCy Schubert return 0;
262*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
263*7f2fe78bSCy Schubert return -1;
264*7f2fe78bSCy Schubert array = v;
265*7f2fe78bSCy Schubert len = k5_json_array_length(array);
266*7f2fe78bSCy Schubert addrs = calloc(len + 1, sizeof(*addrs));
267*7f2fe78bSCy Schubert for (i = 0; i < len; i++) {
268*7f2fe78bSCy Schubert if (json_to_address(k5_json_array_get(array, i), &addrs[i]))
269*7f2fe78bSCy Schubert goto invalid;
270*7f2fe78bSCy Schubert }
271*7f2fe78bSCy Schubert addrs[i] = NULL;
272*7f2fe78bSCy Schubert *addresses_out = addrs;
273*7f2fe78bSCy Schubert return 0;
274*7f2fe78bSCy Schubert
275*7f2fe78bSCy Schubert invalid:
276*7f2fe78bSCy Schubert krb5_free_addresses(context, addrs);
277*7f2fe78bSCy Schubert return -1;
278*7f2fe78bSCy Schubert }
279*7f2fe78bSCy Schubert
280*7f2fe78bSCy Schubert /* Convert a JSON value to an authdata element. */
281*7f2fe78bSCy Schubert static int
json_to_authdata_element(k5_json_value v,krb5_authdata ** ad_out)282*7f2fe78bSCy Schubert json_to_authdata_element(k5_json_value v, krb5_authdata **ad_out)
283*7f2fe78bSCy Schubert {
284*7f2fe78bSCy Schubert k5_json_array array;
285*7f2fe78bSCy Schubert krb5_authdata *ad = NULL;
286*7f2fe78bSCy Schubert k5_json_number n;
287*7f2fe78bSCy Schubert k5_json_string s;
288*7f2fe78bSCy Schubert size_t len;
289*7f2fe78bSCy Schubert
290*7f2fe78bSCy Schubert *ad_out = NULL;
291*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
292*7f2fe78bSCy Schubert return -1;
293*7f2fe78bSCy Schubert array = v;
294*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 2)
295*7f2fe78bSCy Schubert return -1;
296*7f2fe78bSCy Schubert
297*7f2fe78bSCy Schubert n = check_element(array, 0, K5_JSON_TID_NUMBER);
298*7f2fe78bSCy Schubert if (n == NULL)
299*7f2fe78bSCy Schubert return -1;
300*7f2fe78bSCy Schubert s = check_element(array, 1, K5_JSON_TID_STRING);
301*7f2fe78bSCy Schubert if (s == NULL)
302*7f2fe78bSCy Schubert return -1;
303*7f2fe78bSCy Schubert
304*7f2fe78bSCy Schubert ad = malloc(sizeof(*ad));
305*7f2fe78bSCy Schubert if (ad == NULL)
306*7f2fe78bSCy Schubert return -1;
307*7f2fe78bSCy Schubert ad->ad_type = k5_json_number_value(n);
308*7f2fe78bSCy Schubert if (k5_json_string_unbase64(s, &ad->contents, &len)) {
309*7f2fe78bSCy Schubert free(ad);
310*7f2fe78bSCy Schubert return -1;
311*7f2fe78bSCy Schubert }
312*7f2fe78bSCy Schubert ad->length = len;
313*7f2fe78bSCy Schubert ad->magic = KV5M_AUTHDATA;
314*7f2fe78bSCy Schubert *ad_out = ad;
315*7f2fe78bSCy Schubert return 0;
316*7f2fe78bSCy Schubert }
317*7f2fe78bSCy Schubert
318*7f2fe78bSCy Schubert /* Convert a JSON value to a null-terminated authdata list or to NULL. */
319*7f2fe78bSCy Schubert static int
json_to_authdata(krb5_context context,k5_json_value v,krb5_authdata *** authdata_out)320*7f2fe78bSCy Schubert json_to_authdata(krb5_context context, k5_json_value v,
321*7f2fe78bSCy Schubert krb5_authdata ***authdata_out)
322*7f2fe78bSCy Schubert {
323*7f2fe78bSCy Schubert k5_json_array array;
324*7f2fe78bSCy Schubert krb5_authdata **authdata = NULL;
325*7f2fe78bSCy Schubert size_t len, i;
326*7f2fe78bSCy Schubert
327*7f2fe78bSCy Schubert *authdata_out = NULL;
328*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
329*7f2fe78bSCy Schubert return 0;
330*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
331*7f2fe78bSCy Schubert return -1;
332*7f2fe78bSCy Schubert array = v;
333*7f2fe78bSCy Schubert len = k5_json_array_length(array);
334*7f2fe78bSCy Schubert authdata = calloc(len + 1, sizeof(*authdata));
335*7f2fe78bSCy Schubert for (i = 0; i < len; i++) {
336*7f2fe78bSCy Schubert if (json_to_authdata_element(k5_json_array_get(array, i),
337*7f2fe78bSCy Schubert &authdata[i]))
338*7f2fe78bSCy Schubert goto invalid;
339*7f2fe78bSCy Schubert }
340*7f2fe78bSCy Schubert authdata[i] = NULL;
341*7f2fe78bSCy Schubert *authdata_out = authdata;
342*7f2fe78bSCy Schubert return 0;
343*7f2fe78bSCy Schubert
344*7f2fe78bSCy Schubert invalid:
345*7f2fe78bSCy Schubert krb5_free_authdata(context, authdata);
346*7f2fe78bSCy Schubert return -1;
347*7f2fe78bSCy Schubert }
348*7f2fe78bSCy Schubert
349*7f2fe78bSCy Schubert /* Convert a JSON value to a krb5 credential structure, filling in creds. */
350*7f2fe78bSCy Schubert static int
json_to_creds(krb5_context context,k5_json_value v,krb5_creds * creds)351*7f2fe78bSCy Schubert json_to_creds(krb5_context context, k5_json_value v, krb5_creds *creds)
352*7f2fe78bSCy Schubert {
353*7f2fe78bSCy Schubert k5_json_array array;
354*7f2fe78bSCy Schubert k5_json_number n;
355*7f2fe78bSCy Schubert k5_json_bool b;
356*7f2fe78bSCy Schubert k5_json_string s;
357*7f2fe78bSCy Schubert unsigned char *data;
358*7f2fe78bSCy Schubert size_t len;
359*7f2fe78bSCy Schubert
360*7f2fe78bSCy Schubert memset(creds, 0, sizeof(*creds));
361*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
362*7f2fe78bSCy Schubert return -1;
363*7f2fe78bSCy Schubert array = v;
364*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 13)
365*7f2fe78bSCy Schubert return -1;
366*7f2fe78bSCy Schubert
367*7f2fe78bSCy Schubert if (json_to_principal(context, k5_json_array_get(array, 0),
368*7f2fe78bSCy Schubert &creds->client))
369*7f2fe78bSCy Schubert goto invalid;
370*7f2fe78bSCy Schubert
371*7f2fe78bSCy Schubert if (json_to_principal(context, k5_json_array_get(array, 1),
372*7f2fe78bSCy Schubert &creds->server))
373*7f2fe78bSCy Schubert goto invalid;
374*7f2fe78bSCy Schubert
375*7f2fe78bSCy Schubert if (json_to_keyblock(k5_json_array_get(array, 2), &creds->keyblock))
376*7f2fe78bSCy Schubert goto invalid;
377*7f2fe78bSCy Schubert
378*7f2fe78bSCy Schubert n = check_element(array, 3, K5_JSON_TID_NUMBER);
379*7f2fe78bSCy Schubert if (n == NULL)
380*7f2fe78bSCy Schubert goto invalid;
381*7f2fe78bSCy Schubert creds->times.authtime = k5_json_number_value(n);
382*7f2fe78bSCy Schubert
383*7f2fe78bSCy Schubert n = check_element(array, 4, K5_JSON_TID_NUMBER);
384*7f2fe78bSCy Schubert if (n == NULL)
385*7f2fe78bSCy Schubert goto invalid;
386*7f2fe78bSCy Schubert creds->times.starttime = k5_json_number_value(n);
387*7f2fe78bSCy Schubert
388*7f2fe78bSCy Schubert n = check_element(array, 5, K5_JSON_TID_NUMBER);
389*7f2fe78bSCy Schubert if (n == NULL)
390*7f2fe78bSCy Schubert goto invalid;
391*7f2fe78bSCy Schubert creds->times.endtime = k5_json_number_value(n);
392*7f2fe78bSCy Schubert
393*7f2fe78bSCy Schubert n = check_element(array, 6, K5_JSON_TID_NUMBER);
394*7f2fe78bSCy Schubert if (n == NULL)
395*7f2fe78bSCy Schubert goto invalid;
396*7f2fe78bSCy Schubert creds->times.renew_till = k5_json_number_value(n);
397*7f2fe78bSCy Schubert
398*7f2fe78bSCy Schubert b = check_element(array, 7, K5_JSON_TID_BOOL);
399*7f2fe78bSCy Schubert if (b == NULL)
400*7f2fe78bSCy Schubert goto invalid;
401*7f2fe78bSCy Schubert creds->is_skey = k5_json_bool_value(b);
402*7f2fe78bSCy Schubert
403*7f2fe78bSCy Schubert n = check_element(array, 8, K5_JSON_TID_NUMBER);
404*7f2fe78bSCy Schubert if (n == NULL)
405*7f2fe78bSCy Schubert goto invalid;
406*7f2fe78bSCy Schubert creds->ticket_flags = k5_json_number_value(n);
407*7f2fe78bSCy Schubert
408*7f2fe78bSCy Schubert if (json_to_addresses(context, k5_json_array_get(array, 9),
409*7f2fe78bSCy Schubert &creds->addresses))
410*7f2fe78bSCy Schubert goto invalid;
411*7f2fe78bSCy Schubert
412*7f2fe78bSCy Schubert s = check_element(array, 10, K5_JSON_TID_STRING);
413*7f2fe78bSCy Schubert if (s == NULL)
414*7f2fe78bSCy Schubert goto invalid;
415*7f2fe78bSCy Schubert if (k5_json_string_unbase64(s, &data, &len))
416*7f2fe78bSCy Schubert goto invalid;
417*7f2fe78bSCy Schubert creds->ticket.data = (char *)data;
418*7f2fe78bSCy Schubert creds->ticket.length = len;
419*7f2fe78bSCy Schubert
420*7f2fe78bSCy Schubert s = check_element(array, 11, K5_JSON_TID_STRING);
421*7f2fe78bSCy Schubert if (s == NULL)
422*7f2fe78bSCy Schubert goto invalid;
423*7f2fe78bSCy Schubert if (k5_json_string_unbase64(s, &data, &len))
424*7f2fe78bSCy Schubert goto invalid;
425*7f2fe78bSCy Schubert creds->second_ticket.data = (char *)data;
426*7f2fe78bSCy Schubert creds->second_ticket.length = len;
427*7f2fe78bSCy Schubert
428*7f2fe78bSCy Schubert if (json_to_authdata(context, k5_json_array_get(array, 12),
429*7f2fe78bSCy Schubert &creds->authdata))
430*7f2fe78bSCy Schubert goto invalid;
431*7f2fe78bSCy Schubert
432*7f2fe78bSCy Schubert creds->magic = KV5M_CREDS;
433*7f2fe78bSCy Schubert return 0;
434*7f2fe78bSCy Schubert
435*7f2fe78bSCy Schubert invalid:
436*7f2fe78bSCy Schubert krb5_free_cred_contents(context, creds);
437*7f2fe78bSCy Schubert memset(creds, 0, sizeof(*creds));
438*7f2fe78bSCy Schubert return -1;
439*7f2fe78bSCy Schubert }
440*7f2fe78bSCy Schubert
441*7f2fe78bSCy Schubert /* Convert a JSON value to a ccache handle or to NULL. Set *new_out to true if
442*7f2fe78bSCy Schubert * the ccache handle is a newly created memory ccache, false otherwise. */
443*7f2fe78bSCy Schubert static int
json_to_ccache(krb5_context context,k5_json_value v,krb5_ccache * ccache_out,krb5_boolean * new_out)444*7f2fe78bSCy Schubert json_to_ccache(krb5_context context, k5_json_value v, krb5_ccache *ccache_out,
445*7f2fe78bSCy Schubert krb5_boolean *new_out)
446*7f2fe78bSCy Schubert {
447*7f2fe78bSCy Schubert krb5_error_code ret;
448*7f2fe78bSCy Schubert krb5_ccache ccache = NULL;
449*7f2fe78bSCy Schubert krb5_principal princ;
450*7f2fe78bSCy Schubert krb5_creds creds;
451*7f2fe78bSCy Schubert k5_json_array array;
452*7f2fe78bSCy Schubert size_t i, len;
453*7f2fe78bSCy Schubert
454*7f2fe78bSCy Schubert *ccache_out = NULL;
455*7f2fe78bSCy Schubert *new_out = FALSE;
456*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_NULL)
457*7f2fe78bSCy Schubert return 0;
458*7f2fe78bSCy Schubert if (k5_json_get_tid(v) == K5_JSON_TID_STRING) {
459*7f2fe78bSCy Schubert /* We got a reference to an external ccache; just resolve it. */
460*7f2fe78bSCy Schubert return krb5_cc_resolve(context, k5_json_string_utf8(v), ccache_out) ?
461*7f2fe78bSCy Schubert -1 : 0;
462*7f2fe78bSCy Schubert }
463*7f2fe78bSCy Schubert
464*7f2fe78bSCy Schubert /* We got the contents of a memory ccache. */
465*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
466*7f2fe78bSCy Schubert return -1;
467*7f2fe78bSCy Schubert array = v;
468*7f2fe78bSCy Schubert len = k5_json_array_length(array);
469*7f2fe78bSCy Schubert if (len < 1)
470*7f2fe78bSCy Schubert return -1;
471*7f2fe78bSCy Schubert
472*7f2fe78bSCy Schubert /* Initialize a new memory ccache using the principal in the first array
473*7f2fe78bSCy Schubert * entry.*/
474*7f2fe78bSCy Schubert if (krb5_cc_new_unique(context, "MEMORY", NULL, &ccache))
475*7f2fe78bSCy Schubert return -1;
476*7f2fe78bSCy Schubert if (json_to_principal(context, k5_json_array_get(array, 0), &princ))
477*7f2fe78bSCy Schubert goto invalid;
478*7f2fe78bSCy Schubert ret = krb5_cc_initialize(context, ccache, princ);
479*7f2fe78bSCy Schubert krb5_free_principal(context, princ);
480*7f2fe78bSCy Schubert if (ret)
481*7f2fe78bSCy Schubert goto invalid;
482*7f2fe78bSCy Schubert
483*7f2fe78bSCy Schubert /* Add remaining array entries to the ccache as credentials. */
484*7f2fe78bSCy Schubert for (i = 1; i < len; i++) {
485*7f2fe78bSCy Schubert if (json_to_creds(context, k5_json_array_get(array, i), &creds))
486*7f2fe78bSCy Schubert goto invalid;
487*7f2fe78bSCy Schubert ret = krb5_cc_store_cred(context, ccache, &creds);
488*7f2fe78bSCy Schubert krb5_free_cred_contents(context, &creds);
489*7f2fe78bSCy Schubert if (ret)
490*7f2fe78bSCy Schubert goto invalid;
491*7f2fe78bSCy Schubert }
492*7f2fe78bSCy Schubert
493*7f2fe78bSCy Schubert *ccache_out = ccache;
494*7f2fe78bSCy Schubert *new_out = TRUE;
495*7f2fe78bSCy Schubert return 0;
496*7f2fe78bSCy Schubert
497*7f2fe78bSCy Schubert invalid:
498*7f2fe78bSCy Schubert (void)krb5_cc_destroy(context, ccache);
499*7f2fe78bSCy Schubert return -1;
500*7f2fe78bSCy Schubert }
501*7f2fe78bSCy Schubert
502*7f2fe78bSCy Schubert /* Convert a JSON array value to a krb5 GSS credential. */
503*7f2fe78bSCy Schubert static int
json_to_kgcred(krb5_context context,k5_json_array array,krb5_gss_cred_id_t * cred_out)504*7f2fe78bSCy Schubert json_to_kgcred(krb5_context context, k5_json_array array,
505*7f2fe78bSCy Schubert krb5_gss_cred_id_t *cred_out)
506*7f2fe78bSCy Schubert {
507*7f2fe78bSCy Schubert krb5_gss_cred_id_t cred;
508*7f2fe78bSCy Schubert k5_json_number n;
509*7f2fe78bSCy Schubert k5_json_bool b;
510*7f2fe78bSCy Schubert krb5_boolean is_new;
511*7f2fe78bSCy Schubert OM_uint32 tmp;
512*7f2fe78bSCy Schubert
513*7f2fe78bSCy Schubert *cred_out = NULL;
514*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 14)
515*7f2fe78bSCy Schubert return -1;
516*7f2fe78bSCy Schubert
517*7f2fe78bSCy Schubert cred = calloc(1, sizeof(*cred));
518*7f2fe78bSCy Schubert if (cred == NULL)
519*7f2fe78bSCy Schubert return -1;
520*7f2fe78bSCy Schubert if (k5_mutex_init(&cred->lock)) {
521*7f2fe78bSCy Schubert free(cred);
522*7f2fe78bSCy Schubert return -1;
523*7f2fe78bSCy Schubert }
524*7f2fe78bSCy Schubert
525*7f2fe78bSCy Schubert n = check_element(array, 0, K5_JSON_TID_NUMBER);
526*7f2fe78bSCy Schubert if (n == NULL)
527*7f2fe78bSCy Schubert goto invalid;
528*7f2fe78bSCy Schubert cred->usage = k5_json_number_value(n);
529*7f2fe78bSCy Schubert
530*7f2fe78bSCy Schubert if (json_to_kgname(context, k5_json_array_get(array, 1), &cred->name))
531*7f2fe78bSCy Schubert goto invalid;
532*7f2fe78bSCy Schubert
533*7f2fe78bSCy Schubert if (json_to_principal(context, k5_json_array_get(array, 2),
534*7f2fe78bSCy Schubert &cred->impersonator))
535*7f2fe78bSCy Schubert goto invalid;
536*7f2fe78bSCy Schubert
537*7f2fe78bSCy Schubert b = check_element(array, 3, K5_JSON_TID_BOOL);
538*7f2fe78bSCy Schubert if (b == NULL)
539*7f2fe78bSCy Schubert goto invalid;
540*7f2fe78bSCy Schubert cred->default_identity = k5_json_bool_value(b);
541*7f2fe78bSCy Schubert
542*7f2fe78bSCy Schubert b = check_element(array, 4, K5_JSON_TID_BOOL);
543*7f2fe78bSCy Schubert if (b == NULL)
544*7f2fe78bSCy Schubert goto invalid;
545*7f2fe78bSCy Schubert cred->iakerb_mech = k5_json_bool_value(b);
546*7f2fe78bSCy Schubert
547*7f2fe78bSCy Schubert if (json_to_keytab(context, k5_json_array_get(array, 5), &cred->keytab))
548*7f2fe78bSCy Schubert goto invalid;
549*7f2fe78bSCy Schubert
550*7f2fe78bSCy Schubert if (json_to_rcache(context, k5_json_array_get(array, 6), &cred->rcache))
551*7f2fe78bSCy Schubert goto invalid;
552*7f2fe78bSCy Schubert
553*7f2fe78bSCy Schubert if (json_to_ccache(context, k5_json_array_get(array, 7), &cred->ccache,
554*7f2fe78bSCy Schubert &is_new))
555*7f2fe78bSCy Schubert goto invalid;
556*7f2fe78bSCy Schubert cred->destroy_ccache = is_new;
557*7f2fe78bSCy Schubert
558*7f2fe78bSCy Schubert if (json_to_keytab(context, k5_json_array_get(array, 8),
559*7f2fe78bSCy Schubert &cred->client_keytab))
560*7f2fe78bSCy Schubert goto invalid;
561*7f2fe78bSCy Schubert
562*7f2fe78bSCy Schubert b = check_element(array, 9, K5_JSON_TID_BOOL);
563*7f2fe78bSCy Schubert if (b == NULL)
564*7f2fe78bSCy Schubert goto invalid;
565*7f2fe78bSCy Schubert cred->have_tgt = k5_json_bool_value(b);
566*7f2fe78bSCy Schubert
567*7f2fe78bSCy Schubert n = check_element(array, 10, K5_JSON_TID_NUMBER);
568*7f2fe78bSCy Schubert if (n == NULL)
569*7f2fe78bSCy Schubert goto invalid;
570*7f2fe78bSCy Schubert cred->expire = k5_json_number_value(n);
571*7f2fe78bSCy Schubert
572*7f2fe78bSCy Schubert n = check_element(array, 11, K5_JSON_TID_NUMBER);
573*7f2fe78bSCy Schubert if (n == NULL)
574*7f2fe78bSCy Schubert goto invalid;
575*7f2fe78bSCy Schubert cred->refresh_time = k5_json_number_value(n);
576*7f2fe78bSCy Schubert
577*7f2fe78bSCy Schubert if (json_to_etypes(k5_json_array_get(array, 12), &cred->req_enctypes))
578*7f2fe78bSCy Schubert goto invalid;
579*7f2fe78bSCy Schubert
580*7f2fe78bSCy Schubert if (json_to_optional_string(k5_json_array_get(array, 13), &cred->password))
581*7f2fe78bSCy Schubert goto invalid;
582*7f2fe78bSCy Schubert
583*7f2fe78bSCy Schubert *cred_out = cred;
584*7f2fe78bSCy Schubert return 0;
585*7f2fe78bSCy Schubert
586*7f2fe78bSCy Schubert invalid:
587*7f2fe78bSCy Schubert (void)krb5_gss_release_cred(&tmp, (gss_cred_id_t *)&cred);
588*7f2fe78bSCy Schubert return -1;
589*7f2fe78bSCy Schubert }
590*7f2fe78bSCy Schubert
591*7f2fe78bSCy Schubert OM_uint32 KRB5_CALLCONV
krb5_gss_import_cred(OM_uint32 * minor_status,gss_buffer_t token,gss_cred_id_t * cred_handle)592*7f2fe78bSCy Schubert krb5_gss_import_cred(OM_uint32 *minor_status, gss_buffer_t token,
593*7f2fe78bSCy Schubert gss_cred_id_t *cred_handle)
594*7f2fe78bSCy Schubert {
595*7f2fe78bSCy Schubert OM_uint32 status = GSS_S_COMPLETE;
596*7f2fe78bSCy Schubert krb5_context context;
597*7f2fe78bSCy Schubert krb5_error_code ret;
598*7f2fe78bSCy Schubert krb5_gss_cred_id_t cred;
599*7f2fe78bSCy Schubert k5_json_value v = NULL;
600*7f2fe78bSCy Schubert k5_json_array array;
601*7f2fe78bSCy Schubert k5_json_string str;
602*7f2fe78bSCy Schubert char *copy = NULL;
603*7f2fe78bSCy Schubert
604*7f2fe78bSCy Schubert ret = krb5_gss_init_context(&context);
605*7f2fe78bSCy Schubert if (ret) {
606*7f2fe78bSCy Schubert *minor_status = ret;
607*7f2fe78bSCy Schubert return GSS_S_FAILURE;
608*7f2fe78bSCy Schubert }
609*7f2fe78bSCy Schubert
610*7f2fe78bSCy Schubert /* Decode token. */
611*7f2fe78bSCy Schubert copy = k5memdup0(token->value, token->length, &ret);
612*7f2fe78bSCy Schubert if (copy == NULL) {
613*7f2fe78bSCy Schubert status = GSS_S_FAILURE;
614*7f2fe78bSCy Schubert *minor_status = ret;
615*7f2fe78bSCy Schubert goto cleanup;
616*7f2fe78bSCy Schubert }
617*7f2fe78bSCy Schubert if (k5_json_decode(copy, &v))
618*7f2fe78bSCy Schubert goto invalid;
619*7f2fe78bSCy Schubert
620*7f2fe78bSCy Schubert /* Decode the CRED_EXPORT_MAGIC array wrapper. */
621*7f2fe78bSCy Schubert if (k5_json_get_tid(v) != K5_JSON_TID_ARRAY)
622*7f2fe78bSCy Schubert goto invalid;
623*7f2fe78bSCy Schubert array = v;
624*7f2fe78bSCy Schubert if (k5_json_array_length(array) != 2)
625*7f2fe78bSCy Schubert goto invalid;
626*7f2fe78bSCy Schubert str = check_element(array, 0, K5_JSON_TID_STRING);
627*7f2fe78bSCy Schubert if (str == NULL ||
628*7f2fe78bSCy Schubert strcmp(k5_json_string_utf8(str), CRED_EXPORT_MAGIC) != 0)
629*7f2fe78bSCy Schubert goto invalid;
630*7f2fe78bSCy Schubert if (json_to_kgcred(context, k5_json_array_get(array, 1), &cred))
631*7f2fe78bSCy Schubert goto invalid;
632*7f2fe78bSCy Schubert
633*7f2fe78bSCy Schubert *cred_handle = (gss_cred_id_t)cred;
634*7f2fe78bSCy Schubert
635*7f2fe78bSCy Schubert cleanup:
636*7f2fe78bSCy Schubert free(copy);
637*7f2fe78bSCy Schubert k5_json_release(v);
638*7f2fe78bSCy Schubert krb5_free_context(context);
639*7f2fe78bSCy Schubert return status;
640*7f2fe78bSCy Schubert
641*7f2fe78bSCy Schubert invalid:
642*7f2fe78bSCy Schubert status = GSS_S_DEFECTIVE_TOKEN;
643*7f2fe78bSCy Schubert goto cleanup;
644*7f2fe78bSCy Schubert }
645