1 /*
2 * lib/krb5/krb/copy_auth.c
3 *
4 * Copyright 1990 by the Massachusetts Institute of Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 *
26 *
27 * krb5_copy_authdata()
28 */
29 /*
30 * Copyright (c) 2006-2008, Novell, Inc.
31 * All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions are met:
35 *
36 * * Redistributions of source code must retain the above copyright notice,
37 * this list of conditions and the following disclaimer.
38 * * Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * * The copyright holder's name is not used to endorse or promote products
42 * derived from this software without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
45 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
48 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
54 * POSSIBILITY OF SUCH DAMAGE.
55 */
56
57 #include "k5-int.h"
58
59 static krb5_error_code
krb5_copy_authdatum(krb5_context context,const krb5_authdata * inad,krb5_authdata ** outad)60 krb5_copy_authdatum(krb5_context context, const krb5_authdata *inad, krb5_authdata **outad)
61 {
62 krb5_authdata *tmpad;
63
64 if (!(tmpad = (krb5_authdata *)malloc(sizeof(*tmpad))))
65 return ENOMEM;
66 *tmpad = *inad;
67 if (!(tmpad->contents = (krb5_octet *)malloc(inad->length))) {
68 free(tmpad);
69 return ENOMEM;
70 }
71 (void) memcpy((char *)tmpad->contents, (char *)inad->contents, inad->length);
72 *outad = tmpad;
73 return 0;
74 }
75
76 /*
77 * Copy an authdata array, with fresh allocation.
78 */
79 krb5_error_code KRB5_CALLCONV
krb5_merge_authdata(krb5_context context,krb5_authdata * const * inauthdat1,krb5_authdata * const * inauthdat2,krb5_authdata *** outauthdat)80 krb5_merge_authdata(krb5_context context, krb5_authdata *const *inauthdat1, krb5_authdata * const *inauthdat2,
81 krb5_authdata ***outauthdat)
82 {
83 krb5_error_code retval;
84 krb5_authdata ** tempauthdat;
85 register unsigned int nelems = 0, nelems2 = 0;
86
87 *outauthdat = NULL;
88 if (!inauthdat1 && !inauthdat2) {
89 *outauthdat = 0;
90 return 0;
91 }
92
93 if (inauthdat1)
94 while (inauthdat1[nelems]) nelems++;
95 if (inauthdat2)
96 while (inauthdat2[nelems2]) nelems2++;
97
98 /* one more for a null terminated list */
99 if (!(tempauthdat = (krb5_authdata **) calloc(nelems+nelems2+1,
100 sizeof(*tempauthdat))))
101 return ENOMEM;
102
103 if (inauthdat1) {
104 for (nelems = 0; inauthdat1[nelems]; nelems++) {
105 retval = krb5_copy_authdatum(context, inauthdat1[nelems],
106 &tempauthdat[nelems]);
107 if (retval) {
108 krb5_free_authdata(context, tempauthdat);
109 return retval;
110 }
111 }
112 }
113
114 if (inauthdat2) {
115 for (nelems2 = 0; inauthdat2[nelems2]; nelems2++) {
116 retval = krb5_copy_authdatum(context, inauthdat2[nelems2],
117 &tempauthdat[nelems++]);
118 if (retval) {
119 krb5_free_authdata(context, tempauthdat);
120 return retval;
121 }
122 }
123 }
124
125 *outauthdat = tempauthdat;
126 return 0;
127 }
128
129 krb5_error_code KRB5_CALLCONV
krb5_copy_authdata(krb5_context context,krb5_authdata * const * in_authdat,krb5_authdata *** out)130 krb5_copy_authdata(krb5_context context,
131 krb5_authdata *const *in_authdat, krb5_authdata ***out)
132 {
133 return krb5_merge_authdata(context, in_authdat, NULL, out);
134 }
135
136 krb5_error_code KRB5_CALLCONV
krb5_decode_authdata_container(krb5_context context,krb5_authdatatype type,const krb5_authdata * container,krb5_authdata *** authdata)137 krb5_decode_authdata_container(krb5_context context,
138 krb5_authdatatype type,
139 const krb5_authdata *container,
140 krb5_authdata ***authdata)
141 {
142 krb5_error_code code;
143 krb5_data data;
144
145 *authdata = NULL;
146
147 if ((container->ad_type & AD_TYPE_FIELD_TYPE_MASK) != type)
148 return EINVAL;
149
150 data.length = container->length;
151 data.data = (char *)container->contents;
152
153 code = decode_krb5_authdata(&data, authdata);
154 if (code)
155 return code;
156
157 return 0;
158 }
159
160 krb5_error_code KRB5_CALLCONV
krb5_encode_authdata_container(krb5_context context,krb5_authdatatype type,krb5_authdata * const * authdata,krb5_authdata *** container)161 krb5_encode_authdata_container(krb5_context context,
162 krb5_authdatatype type,
163 krb5_authdata *const*authdata,
164 krb5_authdata ***container)
165 {
166 krb5_error_code code;
167 krb5_data *data;
168 krb5_authdata ad_datum;
169 krb5_authdata *ad_data[2];
170
171 *container = NULL;
172
173 code = encode_krb5_authdata((krb5_authdata * const *)authdata, &data);
174 if (code)
175 return code;
176
177 ad_datum.ad_type = type & AD_TYPE_FIELD_TYPE_MASK;
178 ad_datum.length = data->length;
179 ad_datum.contents = (unsigned char *)data->data;
180
181 ad_data[0] = &ad_datum;
182 ad_data[1] = NULL;
183
184 code = krb5_copy_authdata(context, ad_data, container);
185
186 krb5_free_data(context, data);
187
188 return code;
189 }
190
191 struct find_authdata_context {
192 krb5_authdata **out;
193 size_t space;
194 size_t length;
195 };
196
grow_find_authdata(krb5_context context,struct find_authdata_context * fctx,krb5_authdata * elem)197 static krb5_error_code grow_find_authdata
198 (krb5_context context, struct find_authdata_context *fctx,
199 krb5_authdata *elem)
200 {
201 krb5_error_code retval = 0;
202 if (fctx->length == fctx->space) {
203 krb5_authdata **new;
204 if (fctx->space >= 256) {
205 krb5_set_error_message(context, ERANGE, "More than 256 authdata matched a query");
206 return ERANGE;
207 }
208 new = realloc(fctx->out,
209 sizeof (krb5_authdata *)*(2*fctx->space+1));
210 if (new == NULL)
211 return ENOMEM;
212 fctx->out = new;
213 fctx->space *=2;
214 }
215 fctx->out[fctx->length+1] = NULL;
216 retval = krb5_copy_authdatum(context, elem,
217 &fctx->out[fctx->length]);
218 if (retval == 0)
219 fctx->length++;
220 return retval;
221 }
222
223
224
225
find_authdata_1(krb5_context context,krb5_authdata * const * in_authdat,krb5_authdatatype ad_type,struct find_authdata_context * fctx)226 static krb5_error_code find_authdata_1
227 (krb5_context context, krb5_authdata *const *in_authdat, krb5_authdatatype ad_type,
228 struct find_authdata_context *fctx)
229 {
230 int i = 0;
231 krb5_error_code retval=0;
232
233 for (i = 0; in_authdat[i]; i++) {
234 krb5_authdata *ad = in_authdat[i];
235 if (ad->ad_type == ad_type && retval ==0)
236 retval = grow_find_authdata(context, fctx, ad);
237 else switch (ad->ad_type) {
238 krb5_authdata **decoded_container;
239 case KRB5_AUTHDATA_IF_RELEVANT:
240 if (retval == 0)
241 retval = krb5_decode_authdata_container( context, ad->ad_type, ad, &decoded_container);
242 if (retval == 0) {
243 retval = find_authdata_1(context,
244 decoded_container, ad_type, fctx);
245 krb5_free_authdata(context, decoded_container);
246 }
247 break;
248 default:
249 break;
250 }
251 }
252 return retval;
253 }
254
255
krb5int_find_authdata(krb5_context context,krb5_authdata * const * ticket_authdata,krb5_authdata * const * ap_req_authdata,krb5_authdatatype ad_type,krb5_authdata *** results)256 krb5_error_code krb5int_find_authdata
257 (krb5_context context, krb5_authdata *const * ticket_authdata,
258 krb5_authdata * const *ap_req_authdata,
259 krb5_authdatatype ad_type,
260 krb5_authdata ***results)
261 {
262 krb5_error_code retval = 0;
263 struct find_authdata_context fctx;
264 fctx.length = 0;
265 fctx.space = 2;
266 fctx.out = calloc(fctx.space+1, sizeof (krb5_authdata *));
267 *results = NULL;
268 if (fctx.out == NULL)
269 return ENOMEM;
270 if (ticket_authdata)
271 retval = find_authdata_1( context, ticket_authdata, ad_type, &fctx);
272 if ((retval==0) && ap_req_authdata)
273 retval = find_authdata_1( context, ap_req_authdata, ad_type, &fctx);
274 if ((retval== 0) && fctx.length)
275 *results = fctx.out;
276 else krb5_free_authdata(context, fctx.out);
277 return retval;
278 }
279