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
36 krb5_error_code
krb5_encode_princ_dbkey(context,key,principal)37 krb5_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
53 void
krb5_free_princ_dbkey(context,key)54 krb5_free_princ_dbkey(context, key)
55 krb5_context context;
56 krb5_data *key;
57 {
58 (void) krb5_free_data_contents(context, key);
59 }
60
61 krb5_error_code
krb5_encode_princ_contents(context,content,entry)62 krb5_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
234 epc_error:;
235 free(unparse_princ);
236 return retval;
237 }
238
239 void
krb5_free_princ_contents(context,contents)240 krb5_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
248 krb5_error_code
krb5_decode_princ_contents(context,content,entry)249 krb5_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
451 error_out:;
452 krb5_dbe_free_contents(context, entry);
453 return retval;
454 }
455
456 void
krb5_dbe_free_contents(context,entry)457 krb5_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