1 /*
2  * lib/krb5/krb/ser_auth.c
3  *
4  * Copyright 1995 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 
28 /*
29  * ser_auth.c - Serialize krb5_authenticator structure.
30  */
31 #include "k5-int.h"
32 #include "int-proto.h"
33 
34 /*
35  * Routines to deal with externalizing the krb5_authenticator:
36  *	krb5_authenticator_size();
37  *	krb5_authenticator_externalize();
38  *	krb5_authenticator_internalize();
39  */
40 static krb5_error_code krb5_authenticator_size
41 	(krb5_context, krb5_pointer, size_t *);
42 static krb5_error_code krb5_authenticator_externalize
43 	(krb5_context, krb5_pointer, krb5_octet **, size_t *);
44 static krb5_error_code krb5_authenticator_internalize
45 	(krb5_context,krb5_pointer *, krb5_octet **, size_t *);
46 
47 /* Local data */
48 static const krb5_ser_entry krb5_authenticator_ser_entry = {
49     KV5M_AUTHENTICATOR,			/* Type			*/
50     krb5_authenticator_size,		/* Sizer routine	*/
51     krb5_authenticator_externalize,	/* Externalize routine	*/
52     krb5_authenticator_internalize	/* Internalize routine	*/
53 };
54 
55 /*
56  * krb5_authenticator_size()	- Determine the size required to externalize
57  *				  the krb5_authenticator.
58  */
59 static krb5_error_code
krb5_authenticator_size(krb5_context kcontext,krb5_pointer arg,size_t * sizep)60 krb5_authenticator_size(krb5_context kcontext, krb5_pointer arg, size_t *sizep)
61 {
62     krb5_error_code	kret;
63     krb5_authenticator	*authenticator;
64     size_t		required;
65 
66     /*
67      * krb5_authenticator requires at minimum:
68      *	krb5_int32		for KV5M_AUTHENTICATOR
69      *	krb5_int32		for seconds
70      *	krb5_int32		for cusec
71      *	krb5_int32		for seq_number
72      *	krb5_int32		for number in authorization_data array.
73      *	krb5_int32		for KV5M_AUTHENTICATOR
74      */
75     kret = EINVAL;
76     /* Solaris Kerberos */
77     authenticator = (krb5_authenticator *) arg;
78     if (authenticator) {
79 	required = sizeof(krb5_int32)*6;
80 
81 	/* Calculate size required by client, if appropriate */
82 	if (authenticator->client)
83 	    kret = krb5_size_opaque(kcontext,
84 				    KV5M_PRINCIPAL,
85 				    (krb5_pointer) authenticator->client,
86 				    &required);
87 	else
88 	    kret = 0;
89 
90 	/* Calculate size required by checksum, if appropriate */
91 	if (!kret && authenticator->checksum)
92 	    kret = krb5_size_opaque(kcontext,
93 				    KV5M_CHECKSUM,
94 				    (krb5_pointer) authenticator->checksum,
95 				    &required);
96 
97 	/* Calculate size required by subkey, if appropriate */
98 	if (!kret && authenticator->subkey)
99 	    kret = krb5_size_opaque(kcontext,
100 				    KV5M_KEYBLOCK,
101 				    (krb5_pointer) authenticator->subkey,
102 				    &required);
103 
104 	/* Calculate size required by authorization_data, if appropriate */
105 	if (!kret && authenticator->authorization_data) {
106 	    int i;
107 
108 	    for (i=0; !kret && authenticator->authorization_data[i]; i++) {
109 		kret = krb5_size_opaque(kcontext,
110 					KV5M_AUTHDATA,
111 					(krb5_pointer) authenticator->
112 					authorization_data[i],
113 					&required);
114 	    }
115 	}
116     }
117     if (!kret)
118 	*sizep += required;
119     return(kret);
120 }
121 
122 /*
123  * krb5_authenticator_externalize()	- Externalize the krb5_authenticator.
124  */
125 static krb5_error_code
krb5_authenticator_externalize(krb5_context kcontext,krb5_pointer arg,krb5_octet ** buffer,size_t * lenremain)126 krb5_authenticator_externalize(krb5_context kcontext, krb5_pointer arg, krb5_octet **buffer, size_t *lenremain)
127 {
128     krb5_error_code	kret;
129     krb5_authenticator	*authenticator;
130     size_t		required;
131     krb5_octet		*bp;
132     size_t		remain;
133     int			i;
134 
135     required = 0;
136     bp = *buffer;
137     remain = *lenremain;
138     kret = EINVAL;
139     /* Solaris Kerberos */
140     authenticator = (krb5_authenticator *) arg;
141     if (authenticator) {
142 	kret = ENOMEM;
143 	if (!krb5_authenticator_size(kcontext, arg, &required) &&
144 	    (required <= remain)) {
145 	    /* First write our magic number */
146 	    (void) krb5_ser_pack_int32(KV5M_AUTHENTICATOR, &bp, &remain);
147 
148 	    /* Now ctime */
149 	    (void) krb5_ser_pack_int32((krb5_int32) authenticator->ctime,
150 				       &bp, &remain);
151 
152 	    /* Now cusec */
153 	    (void) krb5_ser_pack_int32((krb5_int32) authenticator->cusec,
154 				       &bp, &remain);
155 
156 	    /* Now seq_number */
157 	    (void) krb5_ser_pack_int32(authenticator->seq_number,
158 				       &bp, &remain);
159 
160 	    /* Now handle client, if appropriate */
161 	    if (authenticator->client)
162 		kret = krb5_externalize_opaque(kcontext,
163 					       KV5M_PRINCIPAL,
164 					       (krb5_pointer)
165 					       authenticator->client,
166 					       &bp,
167 					       &remain);
168 	    else
169 		kret = 0;
170 
171 	    /* Now handle checksum, if appropriate */
172 	    if (!kret && authenticator->checksum)
173 		kret = krb5_externalize_opaque(kcontext,
174 					       KV5M_CHECKSUM,
175 					       (krb5_pointer)
176 					       authenticator->checksum,
177 					       &bp,
178 					       &remain);
179 
180 	    /* Now handle subkey, if appropriate */
181 	    if (!kret && authenticator->subkey)
182 		kret = krb5_externalize_opaque(kcontext,
183 					       KV5M_KEYBLOCK,
184 					       (krb5_pointer)
185 					       authenticator->subkey,
186 					       &bp,
187 					       &remain);
188 
189 	    /* Now handle authorization_data, if appropriate */
190 	    if (!kret) {
191 		if (authenticator->authorization_data)
192 		    for (i=0; authenticator->authorization_data[i]; i++);
193 		else
194 		    i = 0;
195 		(void) krb5_ser_pack_int32((krb5_int32) i, &bp, &remain);
196 
197 		/* Now pound out the authorization_data */
198 		if (authenticator->authorization_data) {
199 		    for (i=0; !kret && authenticator->authorization_data[i];
200 			 i++)
201 			kret = krb5_externalize_opaque(kcontext,
202 						       KV5M_AUTHDATA,
203 						       (krb5_pointer)
204 						       authenticator->
205 						       authorization_data[i],
206 						       &bp,
207 						       &remain);
208 		}
209 	    }
210 
211 	    /*
212 	     * If we were successful, write trailer then update the pointer and
213 	     * remaining length;
214 	     */
215 	    if (!kret) {
216 		/* Write our trailer */
217 		(void) krb5_ser_pack_int32(KV5M_AUTHENTICATOR, &bp, &remain);
218 		*buffer = bp;
219 		*lenremain = remain;
220 	    }
221 	}
222     }
223     return(kret);
224 }
225 
226 /*
227  * krb5_authenticator_internalize()	- Internalize the krb5_authenticator.
228  */
229 static krb5_error_code
krb5_authenticator_internalize(krb5_context kcontext,krb5_pointer * argp,krb5_octet ** buffer,size_t * lenremain)230 krb5_authenticator_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
231 {
232     krb5_error_code	kret;
233     krb5_authenticator	*authenticator;
234     krb5_int32		ibuf;
235     krb5_octet		*bp;
236     size_t		remain;
237     int			i;
238     krb5_int32		nadata;
239     size_t		len;
240 
241     bp = *buffer;
242     remain = *lenremain;
243     kret = EINVAL;
244     /* Read our magic number */
245     if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
246 	ibuf = 0;
247     if (ibuf == KV5M_AUTHENTICATOR) {
248 	kret = ENOMEM;
249 
250 	/* Get memory for the authenticator */
251 	if ((remain >= (3*sizeof(krb5_int32))) &&
252 	    (authenticator = (krb5_authenticator *)
253 	     MALLOC(sizeof(krb5_authenticator)))) {
254 	    (void) memset(authenticator, 0, sizeof(krb5_authenticator));
255 
256 	    /* Get ctime */
257 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
258 	    authenticator->ctime = (krb5_timestamp) ibuf;
259 
260 	    /* Get cusec */
261 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
262 	    authenticator->cusec = ibuf;
263 
264 	    /* Get seq_number */
265 	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
266 	    authenticator->seq_number = ibuf;
267 
268 	    kret = 0;
269 
270 	    /* Attempt to read in the client */
271 	    kret = krb5_internalize_opaque(kcontext,
272 					   KV5M_PRINCIPAL,
273 					   (krb5_pointer *)
274 					   &authenticator->client,
275 					   &bp,
276 					   &remain);
277 	    if (kret == EINVAL)
278 		kret = 0;
279 
280 	    /* Attempt to read in the checksum */
281 	    if (!kret) {
282 		kret = krb5_internalize_opaque(kcontext,
283 					       KV5M_CHECKSUM,
284 					       (krb5_pointer *)
285 					       &authenticator->checksum,
286 					       &bp,
287 					       &remain);
288 		if (kret == EINVAL)
289 		    kret = 0;
290 	    }
291 
292 	    /* Attempt to read in the subkey */
293 	    if (!kret) {
294 		kret = krb5_internalize_opaque(kcontext,
295 					       KV5M_KEYBLOCK,
296 					       (krb5_pointer *)
297 					       &authenticator->subkey,
298 					       &bp,
299 					       &remain);
300 		if (kret == EINVAL)
301 		    kret = 0;
302 	    }
303 
304 	    /* Attempt to read in the authorization data count */
305 	    if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
306 		nadata = ibuf;
307 		len = (size_t) (nadata + 1);
308 
309 		/* Get memory for the authorization data pointers */
310 		if ((authenticator->authorization_data = (krb5_authdata **)
311 		     MALLOC(sizeof(krb5_authdata *) * len))) {
312 		    (void) memset(authenticator->authorization_data, 0,
313 			   sizeof(krb5_authdata *) * len);
314 
315 		    for (i=0; !kret && (i<nadata); i++) {
316 			kret = krb5_internalize_opaque(kcontext,
317 						       KV5M_AUTHDATA,
318 						       (krb5_pointer *)
319 						       &authenticator->
320 						       authorization_data[i],
321 						       &bp,
322 						       &remain);
323 		    }
324 
325 		    /* Finally, find the trailer */
326 		    if (!kret) {
327 			kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
328 			if (!kret && (ibuf == KV5M_AUTHENTICATOR))
329 			    authenticator->magic = KV5M_AUTHENTICATOR;
330 			else
331 			    kret = EINVAL;
332 		    }
333 		}
334 	    }
335 	    if (!kret) {
336 		*buffer = bp;
337 		*lenremain = remain;
338 		*argp = (krb5_pointer) authenticator;
339 	    }
340 	    else
341 		krb5_free_authenticator(kcontext, authenticator);
342 	}
343     }
344     return(kret);
345 }
346 
347 /*
348  * Register the authenticator serializer.
349  */
350 krb5_error_code
krb5_ser_authenticator_init(krb5_context kcontext)351 krb5_ser_authenticator_init(krb5_context kcontext)
352 {
353     return(krb5_register_serializer(kcontext, &krb5_authenticator_ser_entry));
354 }
355