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