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