1#pragma ident	"%Z%%M%	%I%	%E% SMI"
2
3/*
4 * Copyright (C) 1998 by the FundsXpress, INC.
5 *
6 * All rights reserved.
7 *
8 * Export of this software from the United States of America may require
9 * a specific license from the United States Government.  It is the
10 * responsibility of any person or organization contemplating export to
11 * obtain such a license before exporting.
12 *
13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14 * distribute this software and its documentation for any purpose and
15 * without fee is hereby granted, provided that the above copyright
16 * notice appear in all copies and that both that copyright notice and
17 * this permission notice appear in supporting documentation, and that
18 * the name of FundsXpress. not be used in advertising or publicity pertaining
19 * to distribution of the software without specific, written prior
20 * permission.  FundsXpress makes no representations about the suitability of
21 * this software for any purpose.  It is provided "as is" without express
22 * or implied warranty.
23 *
24 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
25 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
26 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27 */
28
29#include <gssapiP_krb5.h>
30
31/* from the token, flags is stored directly. nctypes/ctypes is
32   allocated and returns the length and list of ctypes in the token.
33   noptions/options lists all the options which the caller cares
34   about.  Those which are present in the token are filled in; the
35   order and length are not changed.  If an error is returned, the
36   option list is in an indeterminate state. */
37
38OM_uint32
39kg2_parse_token(minor_status, ptr, token_length, flags, nctypes, ctypes,
40		noptions, options, kmsg, mic)
41     OM_uint32 *minor_status;
42     unsigned char *ptr;
43     int token_length;
44     krb5_ui_4 *flags;
45     int *nctypes; /* OUT */
46     krb5_cksumtype **ctypes; /* OUT */
47     int noptions;
48     struct kg2_option *options; /* INOUT */
49     krb5_data *kmsg;
50     krb5_data *mic;
51{
52    int field_length, i;
53    int opt_id;
54
55    *ctypes = 0;
56
57    /* read the flags */
58
59    if (token_length < 4)
60	goto defective;
61    *flags = (ptr[0]<<24) | (ptr[1]<<16) | (ptr[2]<<8) | ptr[3];
62    ptr += 4;
63    token_length -= 4;
64
65    /* read out the token list */
66
67    if (token_length < 2)
68	goto defective;
69    field_length = (ptr[0]<<8) | ptr[1];
70    ptr += 2;
71    token_length -= 2;
72
73    *nctypes = field_length;
74
75    if (*nctypes == 0) {
76	*minor_status = 0;
77	return(GSS_S_DEFECTIVE_TOKEN);
78    }
79
80    if ((*ctypes = (krb5_cksumtype *)
81	 malloc((*nctypes) * sizeof(krb5_cksumtype))) == NULL) {
82	*minor_status = ENOMEM;
83	return(GSS_S_FAILURE);
84    }
85
86    for (i=0; i<field_length; i++) {
87	if (token_length < 4)
88	    goto defective;
89
90	(*ctypes)[i] = (krb5_cksumtype) ((ptr[0]<<24) | (ptr[1]<<16) |
91				      (ptr[2]<<8) | ptr[3]);
92	ptr += 4;
93	token_length -= 4;
94    }
95
96    do {
97	if (token_length < 4)
98	    goto defective;
99	opt_id = (ptr[0]<<8) | ptr[1];
100	field_length = (ptr[2]<<8) | ptr[3];
101	ptr += 4;
102	token_length -= 4;
103
104	if (token_length < field_length)
105	    goto defective;
106
107	for (i=0; i<noptions; i++) {
108	    if (options[i].option_id = opt_id) {
109		options[i].length = field_length;
110		options[i].data = ptr;
111	    	break;
112	    }
113	}
114
115	ptr += field_length;
116	token_length -= field_length;
117    } while (opt_id);
118
119    if (token_length < 2)
120	goto defective;
121    field_length = (ptr[0]<<8) | ptr[1];
122    ptr += 2;
123    token_length -= 2;
124
125    if (token_length < field_length)
126	goto defective;
127
128    kmsg->length = field_length;
129    kmsg->data = (char *) ptr;
130
131    ptr += field_length;
132    token_length -= field_length;
133
134    /* if there's anything left, assume it's a mic.  the mic isn't
135       necessarily present */
136
137    if (mic && token_length) {
138	if (token_length < 2)
139	    goto defective;
140	field_length = (ptr[0]<<8) | ptr[1];
141	ptr += 2;
142	token_length -= 2;
143
144	if (token_length < field_length)
145	    goto defective;
146
147	mic->length = field_length;
148	mic->data = (char *) ptr;
149
150	ptr += field_length;
151	token_length -= field_length;
152    } else if (mic) {
153	mic->length = 0;
154	mic->data = (char *) ptr;
155    }
156
157    if (token_length)
158	goto defective;
159
160    return(GSS_S_COMPLETE);
161
162defective:
163    if (*ctypes)
164	free(*ctypes);
165
166    *minor_status = 0;
167    return(GSS_S_DEFECTIVE_TOKEN);
168}
169
170/* nc1/c1 will be modified to contain the intersection of the
171   two lists. */
172
173void
174kg2_intersect_ctypes(nc1, c1, nc2, c2)
175     int *nc1;
176     krb5_cksumtype *c1;
177     int nc2;
178     const krb5_cksumtype *c2;
179{
180    int i, j, count;
181    krb5_cksumtype tmp;
182
183    count = 0;
184
185    for (i=0; i<*nc1; i++) {
186	/* first, check to make sure that c1[i] isn't a duplicate in c1 */
187	for (j=0; j<i; j++)
188	    if (c1[i] == c1[j])
189		break;
190	if (j<i)
191	    continue;
192	/* check if c1[i] is in c2.  If it is, keep it by swapping
193	   it into c1[count] and incrementing count.  If count < i, then
194	   that field has already been looked at and skipped as
195	   not intersecting, which is ok. */
196
197	for (j=0; j<nc2; j++)
198	    if (c1[i] == c2[j])
199		break;
200	if ((j<nc2) && (count != i)) {
201	    tmp = c1[count];
202	    c1[count] = c1[i];
203	    c1[i] = tmp;
204	}
205	count++;
206    }
207
208    *nc1 = count;
209}
210
211