1#pragma ident	"%Z%%M%	%I%	%E% SMI"
2
3/*
4 * lib/kdb/kdb_xdr.c
5 *
6 * Copyright 1995 by the Massachusetts Institute of Technology.
7 * All Rights Reserved.
8 *
9 * Export of this software from the United States of America may
10 *   require a specific license from the United States Government.
11 *   It is the responsibility of any person or organization contemplating
12 *   export to obtain such a license before exporting.
13 *
14 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
15 * distribute this software and its documentation for any purpose and
16 * without fee is hereby granted, provided that the above copyright
17 * notice appear in all copies and that both that copyright notice and
18 * this permission notice appear in supporting documentation, and that
19 * the name of M.I.T. not be used in advertising or publicity pertaining
20 * to distribution of the software without specific, written prior
21 * permission.  Furthermore if you modify this software you must label
22 * your software as modified software and not distribute it in such a
23 * fashion that it might be confused with the original M.I.T. software.
24 * M.I.T. makes no representations about the suitability of
25 * this software for any purpose.  It is provided "as is" without express
26 * or implied warranty.
27 *
28 */
29
30#include "k5-int.h"
31#include <string.h>
32#include <stdio.h>
33#include <errno.h>
34#include "kdb_xdr.h"
35
36krb5_error_code
37krb5_encode_princ_dbkey(context, key, principal)
38    krb5_context context;
39    krb5_data  *key;
40    krb5_const_principal principal;
41{
42    char *princ_name;
43    krb5_error_code retval;
44
45    if (!(retval = krb5_unparse_name(context, principal, &princ_name))) {
46        /* need to store the NULL for decoding */
47        key->length = strlen(princ_name)+1;
48        key->data = princ_name;
49    }
50    return(retval);
51}
52
53void
54krb5_free_princ_dbkey(context, key)
55    krb5_context context;
56    krb5_data  *key;
57{
58    (void) krb5_free_data_contents(context, key);
59}
60
61krb5_error_code
62krb5_encode_princ_contents(context, content, entry)
63    krb5_context 	  context;
64    krb5_data  		* content;
65    krb5_db_entry 	* entry;
66{
67    int 		  i, j;
68    unsigned int	  unparse_princ_size;
69    char 		* unparse_princ;
70    char		* nextloc;
71    krb5_tl_data	* tl_data;
72    krb5_error_code 	  retval;
73    krb5_int16		  psize16;
74
75    /*
76     * Generate one lump of data from the krb5_db_entry.
77     * This data must be independent of byte order of the machine,
78     * compact and extensible.
79     */
80
81    /*
82     * First allocate enough space for all the data.
83     * Need  2 bytes for the length of the base structure
84     * then 36 [ 8 * 4 + 2 * 2] bytes for the base information
85     *         [ attributes, max_life, max_renewable_life, expiration,
86     *	  	 pw_expiration, last_success, last_failed, fail_auth_count ]
87     *         [ n_key_data, n_tl_data ]
88     * then XX bytes [ e_length ] for the extra data [ e_data ]
89     * then XX bytes [ 2 for length + length for string ] for the principal,
90     * then (4 [type + length] + tl_data_length) bytes per tl_data
91     * then (4 + (4 + key_data_length) per key_data_contents) bytes per key_data
92     */
93    content->length = entry->len + entry->e_length;
94
95    if ((retval = krb5_unparse_name(context, entry->princ, &unparse_princ)))
96	return(retval);
97
98    unparse_princ_size = strlen(unparse_princ) + 1;
99    content->length += unparse_princ_size;
100    content->length += 2;
101
102    i = 0;
103    /* tl_data is a linked list */
104    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
105	content->length += tl_data->tl_data_length;
106	content->length += 4; /* type, length */
107	i++;
108    }
109
110    if (i != entry->n_tl_data) {
111	retval = KRB5_KDB_TRUNCATED_RECORD;
112	goto epc_error;
113    }
114
115    /* key_data is an array */
116    for (i = 0; i < entry->n_key_data; i++) {
117	content->length += 4; /* Version, KVNO */
118	for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
119	    content->length += entry->key_data[i].key_data_length[j];
120	    content->length += 4; /* type + length */
121	}
122    }
123
124    if ((content->data = malloc(content->length)) == NULL) {
125	retval = ENOMEM;
126	goto epc_error;
127    }
128
129    /*
130     * Now we go through entry again, this time copying data
131     * These first entries are always saved regardless of version
132     */
133    nextloc = content->data;
134
135	/* Base Length */
136    krb5_kdb_encode_int16(entry->len, nextloc);
137    nextloc += 2;
138
139	/* Attributes */
140    krb5_kdb_encode_int32(entry->attributes, nextloc);
141    nextloc += 4;
142
143	/* Max Life */
144    krb5_kdb_encode_int32(entry->max_life, nextloc);
145    nextloc += 4;
146
147	/* Max Renewable Life */
148    krb5_kdb_encode_int32(entry->max_renewable_life, nextloc);
149    nextloc += 4;
150
151	/* When the client expires */
152    krb5_kdb_encode_int32(entry->expiration, nextloc);
153    nextloc += 4;
154
155	/* When its passwd expires */
156    krb5_kdb_encode_int32(entry->pw_expiration, nextloc);
157    nextloc += 4;
158
159	/* Last successful passwd */
160    krb5_kdb_encode_int32(entry->last_success, nextloc);
161    nextloc += 4;
162
163	/* Last failed passwd attempt */
164    krb5_kdb_encode_int32(entry->last_failed, nextloc);
165    nextloc += 4;
166
167	/* # of failed passwd attempt */
168    krb5_kdb_encode_int32(entry->fail_auth_count, nextloc);
169    nextloc += 4;
170
171	/* # tl_data strutures */
172    krb5_kdb_encode_int16(entry->n_tl_data, nextloc);
173    nextloc += 2;
174
175	/* # key_data strutures */
176    krb5_kdb_encode_int16(entry->n_key_data, nextloc);
177    nextloc += 2;
178
179    	/* Put extended fields here */
180    if (entry->len != KRB5_KDB_V1_BASE_LENGTH)
181	abort();
182
183	/* Any extra data that this version doesn't understand. */
184    if (entry->e_length) {
185	memcpy(nextloc, entry->e_data, entry->e_length);
186	nextloc += entry->e_length;
187    }
188
189	/*
190	 * Now we get to the principal.
191	 * To squeze a few extra bytes out it is always assumed to come
192	 * after the base type.
193	 */
194    psize16 = (krb5_int16) unparse_princ_size;
195    krb5_kdb_encode_int16(psize16, nextloc);
196    nextloc += 2;
197    (void) memcpy(nextloc, unparse_princ, unparse_princ_size);
198    nextloc += unparse_princ_size;
199
200    	/* tl_data is a linked list, of type, legth, contents */
201    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
202	krb5_kdb_encode_int16(tl_data->tl_data_type, nextloc);
203	nextloc += 2;
204	krb5_kdb_encode_int16(tl_data->tl_data_length, nextloc);
205	nextloc += 2;
206
207	memcpy(nextloc, tl_data->tl_data_contents, tl_data->tl_data_length);
208	nextloc += tl_data->tl_data_length;
209    }
210
211    	/* key_data is an array */
212    for (i = 0; i < entry->n_key_data; i++) {
213	krb5_kdb_encode_int16(entry->key_data[i].key_data_ver, nextloc);
214	nextloc += 2;
215	krb5_kdb_encode_int16(entry->key_data[i].key_data_kvno, nextloc);
216	nextloc += 2;
217
218	for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
219	    krb5_int16 type = entry->key_data[i].key_data_type[j];
220	    krb5_ui_2  length = entry->key_data[i].key_data_length[j];
221
222    	    krb5_kdb_encode_int16(type, nextloc);
223	    nextloc += 2;
224    	    krb5_kdb_encode_int16(length, nextloc);
225	    nextloc += 2;
226
227	    if (length) {
228	        memcpy(nextloc, entry->key_data[i].key_data_contents[j],length);
229	        nextloc += length;
230	    }
231	}
232    }
233
234epc_error:;
235    free(unparse_princ);
236    return retval;
237}
238
239void
240krb5_free_princ_contents(context, contents)
241    krb5_context 	  context;
242    krb5_data *contents;
243{
244    krb5_free_data_contents(context, contents);
245    return;
246}
247
248krb5_error_code
249krb5_decode_princ_contents(context, content, entry)
250    krb5_context 	  context;
251    krb5_data  		* content;
252    krb5_db_entry 	* entry;
253{
254    int			  sizeleft, i;
255    char 		* nextloc;
256    krb5_tl_data       ** tl_data;
257    krb5_int16		  i16;
258
259    krb5_error_code retval;
260
261    /* Zero out entry and NULL pointers */
262    memset(entry, 0, sizeof(krb5_db_entry));
263
264    /*
265     * undo the effects of encode_princ_contents.
266     *
267     * The first part is decoding the base type. If the base type is
268     * bigger than the original base type then the additional fields
269     * need to be filled in. If the base type is larger than any
270     * known base type the additional data goes in e_data.
271     */
272
273    /* First do the easy stuff */
274    nextloc = content->data;
275    sizeleft = content->length;
276    if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0)
277	return KRB5_KDB_TRUNCATED_RECORD;
278
279	/* Base Length */
280    krb5_kdb_decode_int16(nextloc, entry->len);
281    nextloc += 2;
282
283	/* Attributes */
284    krb5_kdb_decode_int32(nextloc, entry->attributes);
285    nextloc += 4;
286
287	/* Max Life */
288    krb5_kdb_decode_int32(nextloc, entry->max_life);
289    nextloc += 4;
290
291	/* Max Renewable Life */
292    krb5_kdb_decode_int32(nextloc, entry->max_renewable_life);
293    nextloc += 4;
294
295	/* When the client expires */
296    krb5_kdb_decode_int32(nextloc, entry->expiration);
297    nextloc += 4;
298
299	/* When its passwd expires */
300    krb5_kdb_decode_int32(nextloc, entry->pw_expiration);
301    nextloc += 4;
302
303	/* Last successful passwd */
304    krb5_kdb_decode_int32(nextloc, entry->last_success);
305    nextloc += 4;
306
307	/* Last failed passwd attempt */
308    krb5_kdb_decode_int32(nextloc, entry->last_failed);
309    nextloc += 4;
310
311	/* # of failed passwd attempt */
312    krb5_kdb_decode_int32(nextloc, entry->fail_auth_count);
313    nextloc += 4;
314
315	/* # tl_data strutures */
316    krb5_kdb_decode_int16(nextloc, entry->n_tl_data);
317    nextloc += 2;
318
319    if (entry->n_tl_data < 0)
320	return KRB5_KDB_TRUNCATED_RECORD;
321
322	/* # key_data strutures */
323    krb5_kdb_decode_int16(nextloc, entry->n_key_data);
324    nextloc += 2;
325
326    if (entry->n_key_data < 0)
327	return KRB5_KDB_TRUNCATED_RECORD;
328
329	/* Check for extra data */
330    if (entry->len > KRB5_KDB_V1_BASE_LENGTH) {
331	entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH;
332	if ((entry->e_data = (krb5_octet *)malloc(entry->e_length))) {
333	    memcpy(entry->e_data, nextloc, entry->e_length);
334	    nextloc += entry->e_length;
335	} else {
336	    return ENOMEM;
337	}
338    }
339
340    /*
341     * Get the principal name for the entry
342     * (stored as a string which gets unparsed.)
343     */
344    if ((sizeleft -= 2) < 0) {
345	retval = KRB5_KDB_TRUNCATED_RECORD;
346	goto error_out;
347    }
348
349    i = 0;
350    krb5_kdb_decode_int16(nextloc, i16);
351    i = (int) i16;
352    nextloc += 2;
353
354    if ((retval = krb5_parse_name(context, nextloc, &(entry->princ))))
355	goto error_out;
356    if (((size_t) i != (strlen(nextloc) + 1)) || (sizeleft < i)) {
357	retval = KRB5_KDB_TRUNCATED_RECORD;
358	goto error_out;
359    }
360    sizeleft -= i;
361    nextloc += i;
362
363    	/* tl_data is a linked list */
364    tl_data = &entry->tl_data;
365    for (i = 0; i < entry->n_tl_data; i++) {
366    	if ((sizeleft -= 4) < 0) {
367	    retval = KRB5_KDB_TRUNCATED_RECORD;
368	    goto error_out;
369	}
370	if ((*tl_data = (krb5_tl_data *)
371	  malloc(sizeof(krb5_tl_data))) == NULL) {
372	    retval = ENOMEM;
373	    goto error_out;
374	}
375	(*tl_data)->tl_data_next = NULL;
376	(*tl_data)->tl_data_contents = NULL;
377	krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type);
378	nextloc += 2;
379	krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length);
380	nextloc += 2;
381
382    	if ((sizeleft -= (*tl_data)->tl_data_length) < 0) {
383	    retval = KRB5_KDB_TRUNCATED_RECORD;
384	    goto error_out;
385	}
386	if (((*tl_data)->tl_data_contents = (krb5_octet *)
387	  malloc((*tl_data)->tl_data_length)) == NULL) {
388	    retval = ENOMEM;
389	    goto error_out;
390	}
391	memcpy((*tl_data)->tl_data_contents,nextloc,(*tl_data)->tl_data_length);
392	nextloc += (*tl_data)->tl_data_length;
393	tl_data = &((*tl_data)->tl_data_next);
394    }
395
396    	/* key_data is an array */
397    if (entry->n_key_data && ((entry->key_data = (krb5_key_data *)
398      malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) {
399        retval = ENOMEM;
400	goto error_out;
401    }
402    for (i = 0; i < entry->n_key_data; i++) {
403	krb5_key_data * key_data;
404        int j;
405
406    	if ((sizeleft -= 4) < 0) {
407	    retval = KRB5_KDB_TRUNCATED_RECORD;
408	    goto error_out;
409	}
410	key_data = entry->key_data + i;
411	memset(key_data, 0, sizeof(krb5_key_data));
412	krb5_kdb_decode_int16(nextloc, key_data->key_data_ver);
413	nextloc += 2;
414	krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno);
415	nextloc += 2;
416
417	/* key_data_ver determins number of elements and how to unparse them. */
418	if (key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) {
419	    for (j = 0; j < key_data->key_data_ver; j++) {
420    	        if ((sizeleft -= 4) < 0) {
421	            retval = KRB5_KDB_TRUNCATED_RECORD;
422	            goto error_out;
423	        }
424		krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]);
425		nextloc += 2;
426		krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]);
427		nextloc += 2;
428
429    	        if ((sizeleft -= key_data->key_data_length[j]) < 0) {
430	            retval = KRB5_KDB_TRUNCATED_RECORD;
431	            goto error_out;
432	        }
433	        if (key_data->key_data_length[j]) {
434	    	    if ((key_data->key_data_contents[j] = (krb5_octet *)
435	    	      malloc(key_data->key_data_length[j])) == NULL) {
436	                retval = ENOMEM;
437	                goto error_out;
438	            }
439	            memcpy(key_data->key_data_contents[j], nextloc,
440		           key_data->key_data_length[j]);
441	            nextloc += key_data->key_data_length[j];
442		}
443	    }
444	} else {
445	    /* This isn't right. I'll fix it later */
446	    abort();
447	}
448    }
449    return 0;
450
451error_out:;
452    krb5_dbe_free_contents(context, entry);
453    return retval;
454}
455
456void
457krb5_dbe_free_contents(context, entry)
458     krb5_context 	  context;
459     krb5_db_entry 	* entry;
460{
461    krb5_tl_data 	* tl_data_next;
462    krb5_tl_data 	* tl_data;
463    int i, j;
464
465    if (entry->e_data)
466	free(entry->e_data);
467    if (entry->princ)
468	krb5_free_principal(context, entry->princ);
469    for (tl_data = entry->tl_data; tl_data; tl_data = tl_data_next) {
470	tl_data_next = tl_data->tl_data_next;
471	if (tl_data->tl_data_contents)
472	    free(tl_data->tl_data_contents);
473	free(tl_data);
474    }
475    if (entry->key_data) {
476    	for (i = 0; i < entry->n_key_data; i++) {
477	    for (j = 0; j < entry->key_data[i].key_data_ver; j++) {
478	    	if (entry->key_data[i].key_data_length[j]) {
479		    if (entry->key_data[i].key_data_contents[j]) {
480		        memset(entry->key_data[i].key_data_contents[j],
481			       0,
482			       (unsigned) entry->key_data[i].key_data_length[j]);
483		    	free (entry->key_data[i].key_data_contents[j]);
484		    }
485		}
486		entry->key_data[i].key_data_contents[j] = NULL;
487		entry->key_data[i].key_data_length[j] = 0;
488		entry->key_data[i].key_data_type[j] = 0;
489	    }
490	}
491	free(entry->key_data);
492    }
493    memset(entry, 0, sizeof(*entry));
494    return;
495}
496