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