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