Mention ITP#.
[krb5dissect.git] / ccache.c
blob2d88fb298a3b2a56a28d7686ca0b4a733ce55ca4
1 /* ccache.c --- Read MIT style Kerberos Credential Cache file.
2 * Copyright (C) 2006, 2007 Simon Josefsson
4 * This file is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
9 * This file is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this file; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA
21 #include "ccache.h"
22 #include <stdio.h>
24 /* See ccache.txt for a description of the file format.
26 * This implementation do not support addresses nor auth-data right
27 * now, see XXX below.
30 static int
31 get_uint8 (const char **data, size_t * len, uint8_t * i)
33 const char *p = *data;
34 if (*len < 1)
35 return -1;
36 *i = p[0];
37 *data += 1;
38 *len -= 1;
39 return 0;
42 static int
43 get_uint16 (const char **data, size_t * len, uint16_t * i)
45 const char *p = *data;
46 if (*len < 2)
47 return -1;
48 *i = p[0] << 8 | p[1];
49 *data += 2;
50 *len -= 2;
51 return 0;
54 static int
55 get_uint32 (const char **data, size_t * len, uint32_t * i)
57 const char *p = *data;
58 if (*len < 4)
59 return -1;
60 *i = ((p[0] << 24) & 0xFF000000)
61 | ((p[1] << 16) & 0xFF0000) | ((p[2] << 8) & 0xFF00) | (p[3] & 0xFF);
62 *data += 4;
63 *len -= 4;
64 return 0;
67 static int
68 get_uint32_swapped (const char **data, size_t * len, uint32_t * i)
70 const char *p = *data;
71 if (*len < 4)
72 return -1;
73 *i = ((p[3] << 24) & 0xFF000000)
74 | ((p[2] << 16) & 0xFF0000) | ((p[1] << 8) & 0xFF00) | (p[0] & 0xFF);
75 *data += 4;
76 *len -= 4;
77 return 0;
80 static int
81 put_uint8 (uint8_t i, char **data, size_t * len)
83 if (*len < 1)
84 return -1;
85 *(*data)++ = i;
86 *len -= 1;
87 return 0;
90 static int
91 put_uint16 (uint16_t i, char **data, size_t * len)
93 if (*len < 2)
94 return -1;
95 *(*data)++ = (i >> 8) & 0xFF;
96 *(*data)++ = i;
97 *len -= 2;
98 return 0;
101 static int
102 put_uint32 (uint32_t i, char **data, size_t * len)
104 if (*len < 4)
105 return -1;
106 *(*data)++ = (i >> 24) & 0xFF;
107 *(*data)++ = (i >> 16) & 0xFF;
108 *(*data)++ = (i >> 8) & 0xFF;
109 *(*data)++ = i;
110 *len -= 4;
111 return 0;
114 static int
115 put_uint32_swapped (uint32_t i, char **data, size_t * len)
117 if (*len < 4)
118 return -1;
119 *(*data)++ = i;
120 *(*data)++ = (i >> 8) & 0xFF;
121 *(*data)++ = (i >> 16) & 0xFF;
122 *(*data)++ = (i >> 24) & 0xFF;
123 *len -= 4;
124 return 0;
127 static int
128 parse_principal (const char **data, size_t * len,
129 struct ccache_principal *out)
131 size_t n;
132 int rc;
134 rc = get_uint32 (data, len, &out->name_type);
135 if (rc < 0)
136 return rc;
138 rc = get_uint32 (data, len, &out->num_components);
139 if (rc < 0)
140 return rc;
142 if (out->num_components >= CCACHE_MAX_COMPONENTS)
143 return -1;
145 rc = get_uint32 (data, len, &out->realm.length);
146 if (rc < 0)
147 return rc;
149 if (*len < out->realm.length)
150 return -1;
151 out->realm.data = *data;
152 *data += out->realm.length;
153 *len -= out->realm.length;
155 /* Make sure realm will be zero terminated. This limits component
156 lengths to 2^24 bytes. */
157 if (**(char**)data != '\0')
158 return -1;
160 for (n = 0; n < out->num_components; n++)
162 rc = get_uint32 (data, len, &out->components[n].length);
163 if (rc < 0)
164 return rc;
166 if (*len < out->components[n].length)
167 return -1;
168 out->components[n].data = *data;
169 *data += out->components[n].length;
170 *len -= out->components[n].length;
172 /* Make sure component is zero terminated. This limits the
173 length of the next component to 2^24 bytes. Note that you'll
174 have to test after the last component elsewhere. */
175 if (*len > 0 && **(char**)data != '\0')
176 return -1;
179 return 0;
182 static int
183 skip_address (const char **data, size_t * len)
185 uint16_t addrtype;
186 uint32_t addrlen;
187 int rc;
189 rc = get_uint16 (data, len, &addrtype);
190 if (rc < 0)
191 return rc;
193 rc = get_uint32 (data, len, &addrlen);
194 if (rc < 0)
195 return rc;
197 if (*len < addrlen)
198 return -1;
199 *data += addrlen;
200 *len -= addrlen;
202 return 0;
205 static int
206 skip_authdata (const char **data, size_t * len)
208 uint16_t authdatatype;
209 uint32_t authdatalen;
210 int rc;
212 rc = get_uint16 (data, len, &authdatatype);
213 if (rc < 0)
214 return rc;
216 rc = get_uint32 (data, len, &authdatalen);
217 if (rc < 0)
218 return rc;
220 if (*len < authdatalen)
221 return -1;
222 *data += authdatalen;
223 *len -= authdatalen;
225 return 0;
228 static int
229 parse_credential (const char **data, size_t * len,
230 struct ccache_credential *out)
232 struct ccache_principal princ;
233 uint32_t num_address;
234 uint32_t num_authdata;
235 int rc;
237 rc = parse_principal (data, len, &out->client);
238 if (rc < 0)
239 return rc;
241 /* Make sure the last component is zero terminated. This limits the
242 next name-type to 2^24 bytes. */
243 if (*len > 0 && **(char**)data != '\0')
244 return -1;
246 rc = parse_principal (data, len, &out->server);
247 if (rc < 0)
248 return rc;
250 /* Make sure the last component is zero terminated. This limits the
251 next key-type to lower 1 byte. */
252 if (*len > 0 && **(char**)data != '\0')
253 return -1;
255 rc = get_uint16 (data, len, &out->key.keytype);
256 if (rc < 0)
257 return rc;
259 rc = get_uint16 (data, len, &out->key.etype);
260 if (rc < 0)
261 return rc;
263 rc = get_uint16 (data, len, &out->key.keylen);
264 if (rc < 0)
265 return rc;
267 if (*len < out->key.keylen)
268 return -1;
270 out->key.keyvalue = *data;
272 *data += out->key.keylen;
273 *len -= out->key.keylen;
275 rc = get_uint32 (data, len, &out->authtime);
276 if (rc < 0)
277 return rc;
279 rc = get_uint32 (data, len, &out->starttime);
280 if (rc < 0)
281 return rc;
283 rc = get_uint32 (data, len, &out->endtime);
284 if (rc < 0)
285 return rc;
287 rc = get_uint32 (data, len, &out->renew_till);
288 if (rc < 0)
289 return rc;
291 rc = get_uint8 (data, len, &out->is_skey);
292 if (rc < 0)
293 return rc;
295 rc = get_uint32_swapped (data, len, &out->tktflags);
296 if (rc < 0)
297 return rc;
299 rc = get_uint32 (data, len, &num_address);
300 if (rc < 0)
301 return rc;
303 for (; num_address; num_address--)
305 /* XXX Don't just skip data. */
306 rc = skip_address (data, len);
307 if (rc < 0)
308 return rc;
311 rc = get_uint32 (data, len, &num_authdata);
312 if (rc < 0)
313 return rc;
315 for (; num_authdata; num_authdata--)
317 /* XXX Don't just skip data. */
318 rc = skip_authdata (data, len);
319 if (rc < 0)
320 return rc;
323 rc = get_uint32 (data, len, &out->ticket.length);
324 if (rc < 0)
325 return rc;
327 if (*len < out->ticket.length)
328 return -1;
329 out->ticket.data = *data;
330 *data += out->ticket.length;
331 *len -= out->ticket.length;
333 rc = get_uint32 (data, len, &out->second_ticket.length);
334 if (rc < 0)
335 return rc;
337 if (*len < out->second_ticket.length)
338 return -1;
339 out->second_ticket.data = *data;
340 *data += out->second_ticket.length;
341 *len -= out->second_ticket.length;
343 return 0;
347 ccache_parse (const char *data, size_t len, struct ccache *out)
349 size_t pos = 0;
350 int rc;
352 rc = get_uint16 (&data, &len, &out->file_format_version);
353 if (rc < 0)
354 return rc;
356 rc = get_uint16 (&data, &len, &out->headerlen);
357 if (rc < 0)
358 return rc;
360 if (len < out->headerlen)
361 return -1;
362 out->header = data;
363 data += out->headerlen;
364 len -= out->headerlen;
366 rc = parse_principal (&data, &len, &out->default_principal);
367 if (rc < 0)
368 return rc;
370 out->credentials = data;
371 out->credentialslen = len;
373 return 0;
377 ccache_parse_credential (const char *data, size_t len,
378 struct ccache_credential *out, size_t * n)
380 size_t savelen = len;
381 int rc = parse_credential (&data, &len, out);
383 if (rc < 0)
384 return rc;
386 *n = savelen - len;
387 return 0;
390 static int
391 pack_principal (struct ccache_principal *princ,
392 char **out, size_t * len)
395 size_t n;
396 int rc;
398 rc = put_uint32 (princ->name_type, out, len);
399 if (rc < 0)
400 return rc;
402 rc = put_uint32 (princ->num_components, out, len);
403 if (rc < 0)
404 return rc;
406 if (princ->num_components >= CCACHE_MAX_COMPONENTS)
407 return -1;
409 rc = put_uint32 (princ->realm.length, out, len);
410 if (rc < 0)
411 return rc;
413 if (*len < princ->realm.length)
414 return -1;
415 memcpy (*out, princ->realm.data, princ->realm.length);
416 *out += princ->realm.length;
417 *len -= princ->realm.length;
419 for (n = 0; n < princ->num_components; n++)
421 rc = put_uint32 (princ->components[n].length, out, len);
422 if (rc < 0)
423 return rc;
425 if (*len < princ->components[n].length)
426 return -1;
427 memcpy (*out, princ->components[n].data, princ->components[n].length);
428 *out += princ->components[n].length;
429 *len -= princ->components[n].length;
432 return 0;
435 static int
436 pack_credential (struct ccache_credential *cred,
437 char **out, size_t *len)
439 struct ccache_principal princ;
440 uint32_t num_address;
441 uint32_t num_authdata;
442 int rc;
444 rc = pack_principal (&cred->client, out, len);
445 if (rc < 0)
446 return rc;
448 rc = pack_principal (&cred->server, out, len);
449 if (rc < 0)
450 return rc;
452 rc = put_uint16 (cred->key.keytype, out, len);
453 if (rc < 0)
454 return rc;
456 rc = put_uint16 (cred->key.etype, out, len);
457 if (rc < 0)
458 return rc;
460 rc = put_uint16 (cred->key.keylen, out, len);
461 if (rc < 0)
462 return rc;
464 if (*len < cred->key.keylen)
465 return -1;
467 memcpy (*out, cred->key.keyvalue, cred->key.keylen);
469 *out += cred->key.keylen;
470 *len -= cred->key.keylen;
472 rc = put_uint32 (cred->authtime, out, len);
473 if (rc < 0)
474 return rc;
476 rc = put_uint32 (cred->starttime, out, len);
477 if (rc < 0)
478 return rc;
480 rc = put_uint32 (cred->endtime, out, len);
481 if (rc < 0)
482 return rc;
484 rc = put_uint32 (cred->renew_till, out, len);
485 if (rc < 0)
486 return rc;
488 rc = put_uint8 (0, out, len);
489 if (rc < 0)
490 return rc;
492 rc = put_uint32_swapped (cred->tktflags, out, len);
493 if (rc < 0)
494 return rc;
496 /* XXX Write addresses. */
497 rc = put_uint32 (0, out, len);
498 if (rc < 0)
499 return rc;
501 /* XXX Write auth-data. */
502 rc = put_uint32 (0, out, len);
503 if (rc < 0)
504 return rc;
506 rc = put_uint32 (cred->ticket.length, out, len);
507 if (rc < 0)
508 return rc;
510 if (*len < cred->ticket.length)
511 return -1;
512 memcpy (*out, cred->ticket.data, cred->ticket.length);
513 *out += cred->ticket.length;
514 *len -= cred->ticket.length;
516 rc = put_uint32 (cred->second_ticket.length, out, len);
517 if (rc < 0)
518 return rc;
520 if (*len < cred->second_ticket.length)
521 return -1;
522 memcpy (*out, cred->second_ticket.data, cred->second_ticket.length);
523 *out += cred->second_ticket.length;
524 *len -= cred->second_ticket.length;
526 return 0;
530 ccache_pack_credential (struct ccache_credential *cred,
531 char *out, size_t *len)
533 size_t savelen = *len;
534 int rc = pack_credential (cred, &out, len);
536 if (rc < 0)
537 return rc;
539 *len = savelen - *len;
540 return 0;
544 ccache_pack (struct ccache *info, char *data, size_t *len)
546 size_t savelen = *len;
547 int rc;
549 rc = put_uint16 (info->file_format_version
550 ? info->file_format_version : 0x0504, &data, len);
551 if (rc < 0)
552 return rc;
554 rc = put_uint16 (info->headerlen, &data, len);
555 if (rc < 0)
556 return rc;
558 if (*len < info->headerlen)
559 return -1;
560 memcpy (data, info->header, info->headerlen);
561 data += info->headerlen;
562 *len -= info->headerlen;
564 rc = pack_principal (&info->default_principal, &data, len);
565 if (rc < 0)
566 return rc;
568 *len = savelen - *len;
569 return 0;
572 #if defined (TEST) || defined (ENABLE_PRINT)
573 void
574 ccache_print (struct ccache *ccache)
576 size_t n;
578 printf ("file_format_version %04x\n", ccache->file_format_version);
579 printf ("headerlen %04x\n", ccache->headerlen);
580 printf ("default_principal\n");
581 ccache_print_principal (&ccache->default_principal);
584 void
585 ccache_print_principal (struct ccache_principal *princ)
587 size_t n;
589 printf ("\tname_type %04x\n", princ->name_type);
590 printf ("\tnum_components %04x\n", princ->num_components);
591 printf ("\trealmlen %04x\n", princ->realm.length);
592 printf ("\trealm %.*s\n", princ->realm.length, princ->realm.data);
594 for (n = 0; n < princ->num_components; n++)
596 printf ("\t\tcomponentlen %04x\n", princ->components[n].length);
597 printf ("\t\tcomponent %.*s\n", princ->components[n].length,
598 princ->components[n].data);
602 void
603 ccache_print_credential (struct ccache_credential *cred)
605 size_t i;
606 printf ("\tclient:\n");
607 ccache_print_principal (&cred->client);
608 printf ("\tserver:\n");
609 ccache_print_principal (&cred->server);
610 printf ("\tkey:\n");
611 printf ("\t\tkeytype %04x\n", cred->key.keytype);
612 printf ("\t\tetype %04x\n", cred->key.etype);
613 printf ("\t\tkeylen %04x\n", cred->key.keylen);
614 printf ("\t\tkey value: ");
615 for (i = 0; i < cred->key.keylen; i++)
616 printf ("%02x", ((char *) cred->key.keyvalue)[i] & 0xFF);
617 printf ("\n");
618 printf ("\ttimes:\n");
619 printf ("\t\tauthtime %04x\n", cred->authtime);
620 printf ("\t\tstarttime %04x\n", cred->starttime);
621 printf ("\t\tendtime %04x\n", cred->endtime);
622 printf ("\t\trenew_till %04x\n", cred->renew_till);
623 printf ("\tis_skey %04x\n", cred->is_skey);
624 printf ("\ttktflags %04x\n", cred->tktflags);
625 printf ("\tticketlen %04x\n", cred->ticket.length);
626 printf ("\tsecond_ticketlen %04x\n", cred->second_ticket.length);
628 #endif
630 #ifdef TEST
632 main (int argc, char *argv[])
634 char buf[10240];
635 size_t len;
636 FILE *fh;
637 int rc;
638 struct ccache ccache;
639 struct ccache_credential cred;
640 size_t i = 0;
642 if (argc <= 1)
644 printf ("Usage: %s <krb5ccache-file>\n", argv[0]);
645 return 1;
648 fh = fopen (argv[1], "rb");
649 if (!fh)
651 puts ("Error: cannot open file");
652 return 1;
655 len = fread (buf, 1, sizeof (buf), fh);
657 if (len >= sizeof (buf))
659 puts ("Error: file too large");
660 return 1;
663 rc = ccache_parse (buf, len, &ccache);
664 if (rc < 0)
666 puts ("Error: syntax error");
667 return 1;
670 ccache_print (&ccache);
672 while (ccache.credentialslen)
674 size_t n;
676 rc = ccache_parse_credential (ccache.credentials,
677 ccache.credentialslen, &cred, &n);
678 if (rc < 0)
680 printf ("Error: cannot parse credential %d\n", i);
681 return rc;
684 printf ("\nCredential %d:\n", i++);
686 ccache_print_credential (&cred);
688 ccache.credentials += n;
689 ccache.credentialslen -= n;
692 if (fclose (fh))
694 puts ("Error: cannot close file");
695 return 1;
698 return 0;
700 #endif