Add.
[shishi.git] / lib / ccache.c
blob099b3da27ad362552450a0b805e71fe793fda9ea
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 3 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, 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
21 #include "ccache.h"
22 #include <stdio.h>
24 /* See ccache.txt for a description of the file format. Currently
25 this implementation do not support addresses nor auth-data. */
27 static int
28 get_uint8 (const char **data, size_t * len, uint8_t * i)
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;
39 static int
40 get_uint16 (const char **data, size_t * len, uint16_t * i)
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;
51 static int
52 get_uint32 (const char **data, size_t * len, uint32_t * i)
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;
64 static int
65 get_uint32_swapped (const char **data, size_t * len, uint32_t * i)
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;
77 static int
78 put_uint8 (uint8_t i, char **data, size_t * len)
80 if (*len < 1)
81 return -1;
82 *(*data)++ = i;
83 *len -= 1;
84 return 0;
87 static int
88 put_uint16 (uint16_t i, char **data, size_t * len)
90 if (*len < 2)
91 return -1;
92 *(*data)++ = (i >> 8) & 0xFF;
93 *(*data)++ = i;
94 *len -= 2;
95 return 0;
98 static int
99 put_uint32 (uint32_t i, char **data, size_t * len)
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;
111 static int
112 put_uint32_swapped (uint32_t i, char **data, size_t * len)
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;
124 static int
125 parse_principal (const char **data, size_t * len,
126 struct ccache_principal *out)
128 size_t n;
129 int rc;
131 rc = get_uint32 (data, len, &out->name_type);
132 if (rc < 0)
133 return rc;
135 rc = get_uint32 (data, len, &out->num_components);
136 if (rc < 0)
137 return rc;
139 if (out->num_components >= CCACHE_MAX_COMPONENTS)
140 return -1;
142 rc = get_uint32 (data, len, &out->realm.length);
143 if (rc < 0)
144 return rc;
146 if (*len < out->realm.length)
147 return -1;
148 out->realm.data = *data;
149 *data += out->realm.length;
150 *len -= out->realm.length;
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;
157 for (n = 0; n < out->num_components; n++)
159 rc = get_uint32 (data, len, &out->components[n].length);
160 if (rc < 0)
161 return rc;
163 if (*len < out->components[n].length)
164 return -1;
165 out->components[n].data = *data;
166 *data += out->components[n].length;
167 *len -= out->components[n].length;
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;
176 return 0;
179 static int
180 skip_address (const char **data, size_t * len)
182 uint16_t addrtype;
183 uint32_t addrlen;
184 int rc;
186 rc = get_uint16 (data, len, &addrtype);
187 if (rc < 0)
188 return rc;
190 rc = get_uint32 (data, len, &addrlen);
191 if (rc < 0)
192 return rc;
194 if (*len < addrlen)
195 return -1;
196 *data += addrlen;
197 *len -= addrlen;
199 return 0;
202 static int
203 skip_authdata (const char **data, size_t * len)
205 uint16_t authdatatype;
206 uint32_t authdatalen;
207 int rc;
209 rc = get_uint16 (data, len, &authdatatype);
210 if (rc < 0)
211 return rc;
213 rc = get_uint32 (data, len, &authdatalen);
214 if (rc < 0)
215 return rc;
217 if (*len < authdatalen)
218 return -1;
219 *data += authdatalen;
220 *len -= authdatalen;
222 return 0;
225 static int
226 parse_credential (const char **data, size_t * len,
227 struct ccache_credential *out)
229 struct ccache_principal princ;
230 uint32_t num_address;
231 uint32_t num_authdata;
232 int rc;
234 rc = parse_principal (data, len, &out->client);
235 if (rc < 0)
236 return rc;
238 /* Make sure the last component is zero terminated. This limits the
239 next name-type to 2^24 bytes. */
240 if (*len > 0 && **(char**)data != '\0')
241 return -1;
243 rc = parse_principal (data, len, &out->server);
244 if (rc < 0)
245 return rc;
247 /* Make sure the last component is zero terminated. This limits the
248 next key-type to lower 1 byte. */
249 if (*len > 0 && **(char**)data != '\0')
250 return -1;
252 rc = get_uint16 (data, len, &out->key.keytype);
253 if (rc < 0)
254 return rc;
256 rc = get_uint16 (data, len, &out->key.etype);
257 if (rc < 0)
258 return rc;
260 rc = get_uint16 (data, len, &out->key.keylen);
261 if (rc < 0)
262 return rc;
264 if (*len < out->key.keylen)
265 return -1;
267 out->key.keyvalue = *data;
269 *data += out->key.keylen;
270 *len -= out->key.keylen;
272 rc = get_uint32 (data, len, &out->authtime);
273 if (rc < 0)
274 return rc;
276 rc = get_uint32 (data, len, &out->starttime);
277 if (rc < 0)
278 return rc;
280 rc = get_uint32 (data, len, &out->endtime);
281 if (rc < 0)
282 return rc;
284 rc = get_uint32 (data, len, &out->renew_till);
285 if (rc < 0)
286 return rc;
288 rc = get_uint8 (data, len, &out->is_skey);
289 if (rc < 0)
290 return rc;
292 rc = get_uint32_swapped (data, len, &out->tktflags);
293 if (rc < 0)
294 return rc;
296 rc = get_uint32 (data, len, &num_address);
297 if (rc < 0)
298 return rc;
300 for (; num_address; num_address--)
302 /* XXX Don't just skip data. */
303 rc = skip_address (data, len);
304 if (rc < 0)
305 return rc;
308 rc = get_uint32 (data, len, &num_authdata);
309 if (rc < 0)
310 return rc;
312 for (; num_authdata; num_authdata--)
314 /* XXX Don't just skip data. */
315 rc = skip_authdata (data, len);
316 if (rc < 0)
317 return rc;
320 rc = get_uint32 (data, len, &out->ticket.length);
321 if (rc < 0)
322 return rc;
324 if (*len < out->ticket.length)
325 return -1;
326 out->ticket.data = *data;
327 *data += out->ticket.length;
328 *len -= out->ticket.length;
330 rc = get_uint32 (data, len, &out->second_ticket.length);
331 if (rc < 0)
332 return rc;
334 if (*len < out->second_ticket.length)
335 return -1;
336 out->second_ticket.data = *data;
337 *data += out->second_ticket.length;
338 *len -= out->second_ticket.length;
340 return 0;
344 ccache_parse (const char *data, size_t len, struct ccache *out)
346 size_t pos = 0;
347 int rc;
349 rc = get_uint16 (&data, &len, &out->file_format_version);
350 if (rc < 0)
351 return rc;
353 rc = get_uint16 (&data, &len, &out->headerlen);
354 if (rc < 0)
355 return rc;
357 if (len < out->headerlen)
358 return -1;
359 out->header = data;
360 data += out->headerlen;
361 len -= out->headerlen;
363 rc = parse_principal (&data, &len, &out->default_principal);
364 if (rc < 0)
365 return rc;
367 out->credentials = data;
368 out->credentialslen = len;
370 return 0;
374 ccache_parse_credential (const char *data, size_t len,
375 struct ccache_credential *out, size_t * n)
377 size_t savelen = len;
378 int rc = parse_credential (&data, &len, out);
380 if (rc < 0)
381 return rc;
383 *n = savelen - len;
384 return 0;
387 static int
388 pack_principal (struct ccache_principal *princ,
389 char **out, size_t * len)
392 size_t n;
393 int rc;
395 rc = put_uint32 (princ->name_type, out, len);
396 if (rc < 0)
397 return rc;
399 rc = put_uint32 (princ->num_components, out, len);
400 if (rc < 0)
401 return rc;
403 if (princ->num_components >= CCACHE_MAX_COMPONENTS)
404 return -1;
406 rc = put_uint32 (princ->realm.length, out, len);
407 if (rc < 0)
408 return rc;
410 if (*len < princ->realm.length)
411 return -1;
412 memcpy (*out, princ->realm.data, princ->realm.length);
413 *out += princ->realm.length;
414 *len -= princ->realm.length;
416 for (n = 0; n < princ->num_components; n++)
418 rc = put_uint32 (princ->components[n].length, out, len);
419 if (rc < 0)
420 return rc;
422 if (*len < princ->components[n].length)
423 return -1;
424 memcpy (*out, princ->components[n].data, princ->components[n].length);
425 *out += princ->components[n].length;
426 *len -= princ->components[n].length;
429 return 0;
432 static int
433 pack_credential (struct ccache_credential *cred,
434 char **out, size_t *len)
436 struct ccache_principal princ;
437 uint32_t num_address;
438 uint32_t num_authdata;
439 int rc;
441 rc = pack_principal (&cred->client, out, len);
442 if (rc < 0)
443 return rc;
445 rc = pack_principal (&cred->server, out, len);
446 if (rc < 0)
447 return rc;
449 rc = put_uint16 (cred->key.keytype, out, len);
450 if (rc < 0)
451 return rc;
453 rc = put_uint16 (cred->key.etype, out, len);
454 if (rc < 0)
455 return rc;
457 rc = put_uint16 (cred->key.keylen, out, len);
458 if (rc < 0)
459 return rc;
461 if (*len < cred->key.keylen)
462 return -1;
464 memcpy (*out, cred->key.keyvalue, cred->key.keylen);
466 *out += cred->key.keylen;
467 *len -= cred->key.keylen;
469 rc = put_uint32 (cred->authtime, out, len);
470 if (rc < 0)
471 return rc;
473 rc = put_uint32 (cred->starttime, out, len);
474 if (rc < 0)
475 return rc;
477 rc = put_uint32 (cred->endtime, out, len);
478 if (rc < 0)
479 return rc;
481 rc = put_uint32 (cred->renew_till, out, len);
482 if (rc < 0)
483 return rc;
485 rc = put_uint8 (0, out, len);
486 if (rc < 0)
487 return rc;
489 rc = put_uint32_swapped (cred->tktflags, out, len);
490 if (rc < 0)
491 return rc;
493 /* XXX Write addresses. */
494 rc = put_uint32 (0, out, len);
495 if (rc < 0)
496 return rc;
498 /* XXX Write auth-data. */
499 rc = put_uint32 (0, out, len);
500 if (rc < 0)
501 return rc;
503 rc = put_uint32 (cred->ticket.length, out, len);
504 if (rc < 0)
505 return rc;
507 if (*len < cred->ticket.length)
508 return -1;
509 memcpy (*out, cred->ticket.data, cred->ticket.length);
510 *out += cred->ticket.length;
511 *len -= cred->ticket.length;
513 rc = put_uint32 (cred->second_ticket.length, out, len);
514 if (rc < 0)
515 return rc;
517 if (*len < cred->second_ticket.length)
518 return -1;
519 memcpy (*out, cred->second_ticket.data, cred->second_ticket.length);
520 *out += cred->second_ticket.length;
521 *len -= cred->second_ticket.length;
523 return 0;
527 ccache_pack_credential (struct ccache_credential *cred,
528 char *out, size_t *len)
530 size_t savelen = *len;
531 int rc = pack_credential (cred, &out, len);
533 if (rc < 0)
534 return rc;
536 *len = savelen - *len;
537 return 0;
541 ccache_pack (struct ccache *info, char *data, size_t *len)
543 size_t savelen = *len;
544 int rc;
546 rc = put_uint16 (info->file_format_version
547 ? info->file_format_version : 0x0504, &data, len);
548 if (rc < 0)
549 return rc;
551 rc = put_uint16 (info->headerlen, &data, len);
552 if (rc < 0)
553 return rc;
555 if (*len < info->headerlen)
556 return -1;
557 memcpy (data, info->header, info->headerlen);
558 data += info->headerlen;
559 *len -= info->headerlen;
561 rc = pack_principal (&info->default_principal, &data, len);
562 if (rc < 0)
563 return rc;
565 *len = savelen - *len;
566 return 0;
569 void
570 ccache_print (struct ccache *ccache)
572 size_t n;
574 printf ("file_format_version %04x\n", ccache->file_format_version);
575 printf ("headerlen %04x\n", ccache->headerlen);
576 printf ("default_principal\n");
577 ccache_print_principal (&ccache->default_principal);
580 void
581 ccache_print_principal (struct ccache_principal *princ)
583 size_t n;
585 printf ("\tname_type %04x\n", princ->name_type);
586 printf ("\tnum_components %04x\n", princ->num_components);
587 printf ("\trealmlen %04x\n", princ->realm.length);
588 printf ("\trealm %.*s\n", princ->realm.length, princ->realm.data);
590 for (n = 0; n < princ->num_components; n++)
592 printf ("\t\tcomponentlen %04x\n", princ->components[n].length);
593 printf ("\t\tcomponent %.*s\n", princ->components[n].length,
594 princ->components[n].data);
598 void
599 ccache_print_credential (struct ccache_credential *cred)
601 size_t i;
602 printf ("\tclient:\n");
603 ccache_print_principal (&cred->client);
604 printf ("\tserver:\n");
605 ccache_print_principal (&cred->server);
606 printf ("\tkey:\n");
607 printf ("\t\tkeytype %04x\n", cred->key.keytype);
608 printf ("\t\tetype %04x\n", cred->key.etype);
609 printf ("\t\tkeylen %04x\n", cred->key.keylen);
610 printf ("\t\tkey value: ");
611 for (i = 0; i < cred->key.keylen; i++)
612 printf ("%02x", ((char *) cred->key.keyvalue)[i] & 0xFF);
613 printf ("\n");
614 printf ("\ttimes:\n");
615 printf ("\t\tauthtime %04x\n", cred->authtime);
616 printf ("\t\tstarttime %04x\n", cred->starttime);
617 printf ("\t\tendtime %04x\n", cred->endtime);
618 printf ("\t\trenew_till %04x\n", cred->renew_till);
619 printf ("\tis_skey %04x\n", cred->is_skey);
620 printf ("\ttktflags %04x\n", cred->tktflags);
621 printf ("\tticketlen %04x\n", cred->ticket.length);
622 printf ("\tsecond_ticketlen %04x\n", cred->second_ticket.length);
625 #ifdef TEST
627 main (int argc, char *argv[])
629 char buf[10240];
630 size_t len;
631 FILE *fh;
632 int rc;
633 struct ccache ccache;
634 struct ccache_credential cred;
635 size_t i = 0;
637 if (argc <= 1)
639 printf ("Usage: %s <krb5ccache-file>\n", argv[0]);
640 return 1;
643 fh = fopen (argv[1], "rb");
644 if (!fh)
646 puts ("Error: cannot open file");
647 return 1;
650 len = fread (buf, 1, sizeof (buf), fh);
652 if (len >= sizeof (buf))
654 puts ("Error: file too large");
655 return 1;
658 rc = ccache_parse (buf, len, &ccache);
659 if (rc < 0)
661 puts ("Error: syntax error");
662 return 1;
665 ccache_print (&ccache);
667 while (ccache.credentialslen)
669 size_t n;
671 rc = ccache_parse_credential (ccache.credentials,
672 ccache.credentialslen, &cred, &n);
673 if (rc < 0)
675 printf ("Error: cannot parse credential %d\n", i);
676 return rc;
679 printf ("\nCredential %d:\n", i++);
681 ccache_print_credential (&cred);
683 ccache.credentials += n;
684 ccache.credentialslen -= n;
687 if (fclose (fh))
689 puts ("Error: cannot close file");
690 return 1;
693 return 0;
695 #endif