1 /* ccache.c --- Read MIT style Kerberos Credential Cache file.
2 * Copyright (C) 2006-2013 Simon Josefsson
3 *
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 3 of the License,
7 * or (at your option) any later version.
8 *
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.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this file; if not, see http://www.gnu.org/licenses or
16 * write to the Free Software Foundation, Inc., 51 Franklin Street,
17 * Fifth Floor, Boston, MA 02110-1301, USA
18 *
19 */
20
21 #include "ccache.h"
22 #include <stdio.h>
23
24 /* See ccache.txt for a description of the file format. Currently
25 this implementation do not support addresses nor auth-data. */
26
27 static int
get_uint8(const char ** data,size_t * len,uint8_t * i)28 get_uint8 (const char **data, size_t * len, uint8_t * i)
29 {
30 const char *p = *data;
31 if (*len < 1)
32 return -1;
33 *i = p[0];
34 *data += 1;
35 *len -= 1;
36 return 0;
37 }
38
39 static int
get_uint16(const char ** data,size_t * len,uint16_t * i)40 get_uint16 (const char **data, size_t * len, uint16_t * i)
41 {
42 const char *p = *data;
43 if (*len < 2)
44 return -1;
45 *i = p[0] << 8 | p[1];
46 *data += 2;
47 *len -= 2;
48 return 0;
49 }
50
51 static int
get_uint32(const char ** data,size_t * len,uint32_t * i)52 get_uint32 (const char **data, size_t * len, uint32_t * i)
53 {
54 const char *p = *data;
55 if (*len < 4)
56 return -1;
57 *i = ((p[0] << 24) & 0xFF000000)
58 | ((p[1] << 16) & 0xFF0000) | ((p[2] << 8) & 0xFF00) | (p[3] & 0xFF);
59 *data += 4;
60 *len -= 4;
61 return 0;
62 }
63
64 static int
get_uint32_swapped(const char ** data,size_t * len,uint32_t * i)65 get_uint32_swapped (const char **data, size_t * len, uint32_t * i)
66 {
67 const char *p = *data;
68 if (*len < 4)
69 return -1;
70 *i = ((p[3] << 24) & 0xFF000000)
71 | ((p[2] << 16) & 0xFF0000) | ((p[1] << 8) & 0xFF00) | (p[0] & 0xFF);
72 *data += 4;
73 *len -= 4;
74 return 0;
75 }
76
77 static int
put_uint8(uint8_t i,char ** data,size_t * len)78 put_uint8 (uint8_t i, char **data, size_t * len)
79 {
80 if (*len < 1)
81 return -1;
82 *(*data)++ = i;
83 *len -= 1;
84 return 0;
85 }
86
87 static int
put_uint16(uint16_t i,char ** data,size_t * len)88 put_uint16 (uint16_t i, char **data, size_t * len)
89 {
90 if (*len < 2)
91 return -1;
92 *(*data)++ = (i >> 8) & 0xFF;
93 *(*data)++ = i;
94 *len -= 2;
95 return 0;
96 }
97
98 static int
put_uint32(uint32_t i,char ** data,size_t * len)99 put_uint32 (uint32_t i, char **data, size_t * len)
100 {
101 if (*len < 4)
102 return -1;
103 *(*data)++ = (i >> 24) & 0xFF;
104 *(*data)++ = (i >> 16) & 0xFF;
105 *(*data)++ = (i >> 8) & 0xFF;
106 *(*data)++ = i;
107 *len -= 4;
108 return 0;
109 }
110
111 static int
put_uint32_swapped(uint32_t i,char ** data,size_t * len)112 put_uint32_swapped (uint32_t i, char **data, size_t * len)
113 {
114 if (*len < 4)
115 return -1;
116 *(*data)++ = i;
117 *(*data)++ = (i >> 8) & 0xFF;
118 *(*data)++ = (i >> 16) & 0xFF;
119 *(*data)++ = (i >> 24) & 0xFF;
120 *len -= 4;
121 return 0;
122 }
123
124 static int
parse_principal(const char ** data,size_t * len,struct ccache_principal * out)125 parse_principal (const char **data, size_t * len,
126 struct ccache_principal *out)
127 {
128 size_t n;
129 int rc;
130
131 rc = get_uint32 (data, len, &out->name_type);
132 if (rc < 0)
133 return rc;
134
135 rc = get_uint32 (data, len, &out->num_components);
136 if (rc < 0)
137 return rc;
138
139 if (out->num_components >= CCACHE_MAX_COMPONENTS)
140 return -1;
141
142 rc = get_uint32 (data, len, &out->realm.length);
143 if (rc < 0)
144 return rc;
145
146 if (*len < out->realm.length)
147 return -1;
148 out->realm.data = (char *) *data;
149 *data += out->realm.length;
150 *len -= out->realm.length;
151
152 /* Make sure realm will be zero terminated. This limits component
153 lengths to 2^24 bytes. */
154 if (**(char **) data != '\0')
155 return -1;
156
157 for (n = 0; n < out->num_components; n++)
158 {
159 rc = get_uint32 (data, len, &out->components[n].length);
160 if (rc < 0)
161 return rc;
162
163 if (*len < out->components[n].length)
164 return -1;
165 out->components[n].data = (char *) *data;
166 *data += out->components[n].length;
167 *len -= out->components[n].length;
168
169 /* Make sure component is zero terminated. This limits the
170 length of the next component to 2^24 bytes. Note that you'll
171 have to test after the last component elsewhere. */
172 if (*len > 0 && **(char **) data != '\0')
173 return -1;
174 }
175
176 return 0;
177 }
178
179 static int
skip_address(const char ** data,size_t * len)180 skip_address (const char **data, size_t * len)
181 {
182 uint16_t addrtype;
183 uint32_t addrlen;
184 int rc;
185
186 rc = get_uint16 (data, len, &addrtype);
187 if (rc < 0)
188 return rc;
189
190 rc = get_uint32 (data, len, &addrlen);
191 if (rc < 0)
192 return rc;
193
194 if (*len < addrlen)
195 return -1;
196 *data += addrlen;
197 *len -= addrlen;
198
199 return 0;
200 }
201
202 static int
skip_authdata(const char ** data,size_t * len)203 skip_authdata (const char **data, size_t * len)
204 {
205 uint16_t authdatatype;
206 uint32_t authdatalen;
207 int rc;
208
209 rc = get_uint16 (data, len, &authdatatype);
210 if (rc < 0)
211 return rc;
212
213 rc = get_uint32 (data, len, &authdatalen);
214 if (rc < 0)
215 return rc;
216
217 if (*len < authdatalen)
218 return -1;
219 *data += authdatalen;
220 *len -= authdatalen;
221
222 return 0;
223 }
224
225 static int
parse_credential(const char ** data,size_t * len,struct ccache_credential * out)226 parse_credential (const char **data, size_t * len,
227 struct ccache_credential *out)
228 {
229 uint32_t num_address;
230 uint32_t num_authdata;
231 int rc;
232
233 rc = parse_principal (data, len, &out->client);
234 if (rc < 0)
235 return rc;
236
237 /* Make sure the last component is zero terminated. This limits the
238 next name-type to 2^24 bytes. */
239 if (*len > 0 && **(char **) data != '\0')
240 return -1;
241
242 rc = parse_principal (data, len, &out->server);
243 if (rc < 0)
244 return rc;
245
246 /* Make sure the last component is zero terminated. This limits the
247 next key-type to lower 1 byte. */
248 if (*len > 0 && **(char **) data != '\0')
249 return -1;
250
251 rc = get_uint16 (data, len, &out->key.keytype);
252 if (rc < 0)
253 return rc;
254
255 rc = get_uint16 (data, len, &out->key.etype);
256 if (rc < 0)
257 return rc;
258
259 rc = get_uint16 (data, len, &out->key.keylen);
260 if (rc < 0)
261 return rc;
262
263 if (*len < out->key.keylen)
264 return -1;
265
266 out->key.keyvalue = (char *) *data;
267
268 *data += out->key.keylen;
269 *len -= out->key.keylen;
270
271 rc = get_uint32 (data, len, &out->authtime);
272 if (rc < 0)
273 return rc;
274
275 rc = get_uint32 (data, len, &out->starttime);
276 if (rc < 0)
277 return rc;
278
279 rc = get_uint32 (data, len, &out->endtime);
280 if (rc < 0)
281 return rc;
282
283 rc = get_uint32 (data, len, &out->renew_till);
284 if (rc < 0)
285 return rc;
286
287 rc = get_uint8 (data, len, &out->is_skey);
288 if (rc < 0)
289 return rc;
290
291 rc = get_uint32_swapped (data, len, &out->tktflags);
292 if (rc < 0)
293 return rc;
294
295 rc = get_uint32 (data, len, &num_address);
296 if (rc < 0)
297 return rc;
298
299 for (; num_address; num_address--)
300 {
301 /* XXX Don't just skip data. */
302 rc = skip_address (data, len);
303 if (rc < 0)
304 return rc;
305 }
306
307 rc = get_uint32 (data, len, &num_authdata);
308 if (rc < 0)
309 return rc;
310
311 for (; num_authdata; num_authdata--)
312 {
313 /* XXX Don't just skip data. */
314 rc = skip_authdata (data, len);
315 if (rc < 0)
316 return rc;
317 }
318
319 rc = get_uint32 (data, len, &out->ticket.length);
320 if (rc < 0)
321 return rc;
322
323 if (*len < out->ticket.length)
324 return -1;
325 out->ticket.data = (char *) *data;
326 *data += out->ticket.length;
327 *len -= out->ticket.length;
328
329 rc = get_uint32 (data, len, &out->second_ticket.length);
330 if (rc < 0)
331 return rc;
332
333 if (*len < out->second_ticket.length)
334 return -1;
335 out->second_ticket.data = (char *) *data;
336 *data += out->second_ticket.length;
337 *len -= out->second_ticket.length;
338
339 return 0;
340 }
341
342 int
ccache_parse(const char * data,size_t len,struct ccache * out)343 ccache_parse (const char *data, size_t len, struct ccache *out)
344 {
345 int rc;
346
347 rc = get_uint16 (&data, &len, &out->file_format_version);
348 if (rc < 0)
349 return rc;
350
351 rc = get_uint16 (&data, &len, &out->headerlen);
352 if (rc < 0)
353 return rc;
354
355 if (len < out->headerlen)
356 return -1;
357 out->header = (char *) data;
358 data += out->headerlen;
359 len -= out->headerlen;
360
361 rc = parse_principal (&data, &len, &out->default_principal);
362 if (rc < 0)
363 return rc;
364
365 out->credentials = (char *) data;
366 out->credentialslen = len;
367
368 return 0;
369 }
370
371 int
ccache_parse_credential(const char * data,size_t len,struct ccache_credential * out,size_t * n)372 ccache_parse_credential (const char *data, size_t len,
373 struct ccache_credential *out, size_t * n)
374 {
375 size_t savelen = len;
376 int rc = parse_credential (&data, &len, out);
377
378 if (rc < 0)
379 return rc;
380
381 *n = savelen - len;
382 return 0;
383 }
384
385 static int
pack_principal(struct ccache_principal * princ,char ** out,size_t * len)386 pack_principal (struct ccache_principal *princ, char **out, size_t * len)
387 {
388 size_t n;
389 int rc;
390
391 rc = put_uint32 (princ->name_type, out, len);
392 if (rc < 0)
393 return rc;
394
395 rc = put_uint32 (princ->num_components, out, len);
396 if (rc < 0)
397 return rc;
398
399 if (princ->num_components >= CCACHE_MAX_COMPONENTS)
400 return -1;
401
402 rc = put_uint32 (princ->realm.length, out, len);
403 if (rc < 0)
404 return rc;
405
406 if (*len < princ->realm.length)
407 return -1;
408 memcpy (*out, princ->realm.data, princ->realm.length);
409 *out += princ->realm.length;
410 *len -= princ->realm.length;
411
412 for (n = 0; n < princ->num_components; n++)
413 {
414 rc = put_uint32 (princ->components[n].length, out, len);
415 if (rc < 0)
416 return rc;
417
418 if (*len < princ->components[n].length)
419 return -1;
420 memcpy (*out, princ->components[n].data, princ->components[n].length);
421 *out += princ->components[n].length;
422 *len -= princ->components[n].length;
423 }
424
425 return 0;
426 }
427
428 static int
pack_credential(struct ccache_credential * cred,char ** out,size_t * len)429 pack_credential (struct ccache_credential *cred, char **out, size_t * len)
430 {
431 int rc;
432
433 rc = pack_principal (&cred->client, out, len);
434 if (rc < 0)
435 return rc;
436
437 rc = pack_principal (&cred->server, out, len);
438 if (rc < 0)
439 return rc;
440
441 rc = put_uint16 (cred->key.keytype, out, len);
442 if (rc < 0)
443 return rc;
444
445 rc = put_uint16 (cred->key.etype, out, len);
446 if (rc < 0)
447 return rc;
448
449 rc = put_uint16 (cred->key.keylen, out, len);
450 if (rc < 0)
451 return rc;
452
453 if (*len < cred->key.keylen)
454 return -1;
455
456 memcpy (*out, cred->key.keyvalue, cred->key.keylen);
457
458 *out += cred->key.keylen;
459 *len -= cred->key.keylen;
460
461 rc = put_uint32 (cred->authtime, out, len);
462 if (rc < 0)
463 return rc;
464
465 rc = put_uint32 (cred->starttime, out, len);
466 if (rc < 0)
467 return rc;
468
469 rc = put_uint32 (cred->endtime, out, len);
470 if (rc < 0)
471 return rc;
472
473 rc = put_uint32 (cred->renew_till, out, len);
474 if (rc < 0)
475 return rc;
476
477 rc = put_uint8 (0, out, len);
478 if (rc < 0)
479 return rc;
480
481 rc = put_uint32_swapped (cred->tktflags, out, len);
482 if (rc < 0)
483 return rc;
484
485 /* XXX Write addresses. */
486 rc = put_uint32 (0, out, len);
487 if (rc < 0)
488 return rc;
489
490 /* XXX Write auth-data. */
491 rc = put_uint32 (0, out, len);
492 if (rc < 0)
493 return rc;
494
495 rc = put_uint32 (cred->ticket.length, out, len);
496 if (rc < 0)
497 return rc;
498
499 if (*len < cred->ticket.length)
500 return -1;
501 memcpy (*out, cred->ticket.data, cred->ticket.length);
502 *out += cred->ticket.length;
503 *len -= cred->ticket.length;
504
505 rc = put_uint32 (cred->second_ticket.length, out, len);
506 if (rc < 0)
507 return rc;
508
509 if (*len < cred->second_ticket.length)
510 return -1;
511 memcpy (*out, cred->second_ticket.data, cred->second_ticket.length);
512 *out += cred->second_ticket.length;
513 *len -= cred->second_ticket.length;
514
515 return 0;
516 }
517
518 int
ccache_pack_credential(struct ccache_credential * cred,char * out,size_t * len)519 ccache_pack_credential (struct ccache_credential *cred,
520 char *out, size_t * len)
521 {
522 size_t savelen = *len;
523 int rc = pack_credential (cred, &out, len);
524
525 if (rc < 0)
526 return rc;
527
528 *len = savelen - *len;
529 return 0;
530 }
531
532 int
ccache_pack(struct ccache * info,char * data,size_t * len)533 ccache_pack (struct ccache *info, char *data, size_t * len)
534 {
535 size_t savelen = *len;
536 int rc;
537
538 rc = put_uint16 (info->file_format_version
539 ? info->file_format_version : 0x0504, &data, len);
540 if (rc < 0)
541 return rc;
542
543 rc = put_uint16 (info->headerlen, &data, len);
544 if (rc < 0)
545 return rc;
546
547 if (*len < info->headerlen)
548 return -1;
549 memcpy (data, info->header, info->headerlen);
550 data += info->headerlen;
551 *len -= info->headerlen;
552
553 rc = pack_principal (&info->default_principal, &data, len);
554 if (rc < 0)
555 return rc;
556
557 *len = savelen - *len;
558 return 0;
559 }
560
561 void
ccache_print(struct ccache * ccache)562 ccache_print (struct ccache *ccache)
563 {
564 printf ("file_format_version %04x\n", ccache->file_format_version);
565 printf ("headerlen %04x\n", ccache->headerlen);
566 printf ("default_principal\n");
567 ccache_print_principal (&ccache->default_principal);
568 }
569
570 void
ccache_print_principal(struct ccache_principal * princ)571 ccache_print_principal (struct ccache_principal *princ)
572 {
573 size_t n;
574
575 printf ("\tname_type %04x\n", princ->name_type);
576 printf ("\tnum_components %04x\n", princ->num_components);
577 printf ("\trealmlen %04x\n", princ->realm.length);
578 printf ("\trealm %.*s\n", princ->realm.length, princ->realm.data);
579
580 for (n = 0; n < princ->num_components; n++)
581 {
582 printf ("\t\tcomponentlen %04x\n", princ->components[n].length);
583 printf ("\t\tcomponent %.*s\n", princ->components[n].length,
584 princ->components[n].data);
585 }
586 }
587
588 void
ccache_print_credential(struct ccache_credential * cred)589 ccache_print_credential (struct ccache_credential *cred)
590 {
591 size_t i;
592 printf ("\tclient:\n");
593 ccache_print_principal (&cred->client);
594 printf ("\tserver:\n");
595 ccache_print_principal (&cred->server);
596 printf ("\tkey:\n");
597 printf ("\t\tkeytype %04x\n", cred->key.keytype);
598 printf ("\t\tetype %04x\n", cred->key.etype);
599 printf ("\t\tkeylen %04x\n", cred->key.keylen);
600 printf ("\t\tkey value: ");
601 for (i = 0; i < cred->key.keylen; i++)
602 printf ("%02x", ((char *) cred->key.keyvalue)[i] & 0xFF);
603 printf ("\n");
604 printf ("\ttimes:\n");
605 printf ("\t\tauthtime %04x\n", cred->authtime);
606 printf ("\t\tstarttime %04x\n", cred->starttime);
607 printf ("\t\tendtime %04x\n", cred->endtime);
608 printf ("\t\trenew_till %04x\n", cred->renew_till);
609 printf ("\tis_skey %04x\n", cred->is_skey);
610 printf ("\ttktflags %04x\n", cred->tktflags);
611 printf ("\tticketlen %04x\n", cred->ticket.length);
612 printf ("\tsecond_ticketlen %04x\n", cred->second_ticket.length);
613 }
614
615 #ifdef TEST
616 int
main(int argc,char * argv[])617 main (int argc, char *argv[])
618 {
619 char buf[10240];
620 size_t len;
621 FILE *fh;
622 int rc;
623 struct ccache ccache;
624 struct ccache_credential cred;
625 size_t i = 0;
626
627 if (argc <= 1)
628 {
629 printf ("Usage: %s <krb5ccache-file>\n", argv[0]);
630 return 1;
631 }
632
633 fh = fopen (argv[1], "rb");
634 if (!fh)
635 {
636 puts ("Error: cannot open file");
637 return 1;
638 }
639
640 len = fread (buf, 1, sizeof (buf), fh);
641
642 if (len >= sizeof (buf))
643 {
644 puts ("Error: file too large");
645 return 1;
646 }
647
648 rc = ccache_parse (buf, len, &ccache);
649 if (rc < 0)
650 {
651 puts ("Error: syntax error");
652 return 1;
653 }
654
655 ccache_print (&ccache);
656
657 while (ccache.credentialslen)
658 {
659 size_t n;
660
661 rc = ccache_parse_credential (ccache.credentials,
662 ccache.credentialslen, &cred, &n);
663 if (rc < 0)
664 {
665 printf ("Error: cannot parse credential %d\n", i);
666 return rc;
667 }
668
669 printf ("\nCredential %d:\n", i++);
670
671 ccache_print_credential (&cred);
672
673 ccache.credentials += n;
674 ccache.credentialslen -= n;
675 }
676
677 if (fclose (fh))
678 {
679 puts ("Error: cannot close file");
680 return 1;
681 }
682
683 return 0;
684 }
685 #endif
686