heimdal Extend the 'hdb as a keytab' code [HEIMDAL-600]
[heimdal.git] / lib / krb5 / store.c
blob2ba83ef0d511d95aeac63838831e1029af8c10b2
1 /*
2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
35 #include "store-int.h"
37 #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
38 #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
39 #define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
40 #define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
41 krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
43 void KRB5_LIB_FUNCTION
44 krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
46 sp->flags |= flags;
49 void KRB5_LIB_FUNCTION
50 krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
52 sp->flags &= ~flags;
55 /**
56 * Return true or false depending on if the storage flags is set or
57 * not. NB testing for the flag 0 always return true.
59 * @param sp the storage buffer to check flags on
60 * @param flags The flags to test for
62 * @return true if all the flags are set, false if not.
64 * @ingroup krb5_storage
67 krb5_boolean KRB5_LIB_FUNCTION
68 krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
70 return (sp->flags & flags) == flags;
73 /**
74 * Set the new byte order of the storage buffer.
76 * @param sp the storage buffer to set the byte order for.
77 * @param byteorder the new byte order.
79 * The byte order are: KRB5_STORAGE_BYTEORDER_BE,
80 * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST.
82 * @ingroup krb5_storage
85 void KRB5_LIB_FUNCTION
86 krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
88 sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
89 sp->flags |= byteorder;
92 /**
93 * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants.
95 * @ingroup krb5_storage
98 krb5_flags KRB5_LIB_FUNCTION
99 krb5_storage_get_byteorder(krb5_storage *sp)
101 return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
105 * Seek to a new offset.
107 * @param sp the storage buffer to seek in.
108 * @param offset the offset to seek
109 * @param whence relateive searching, SEEK_CUR from the current
110 * position, SEEK_END from the end, SEEK_SET absolute from the start.
112 * @return The new current offset
114 * @ingroup krb5_storage
117 off_t KRB5_LIB_FUNCTION
118 krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
120 return (*sp->seek)(sp, offset, whence);
124 * Truncate the storage buffer in sp to offset.
126 * @param sp the storage buffer to truncate.
127 * @param offset the offset to truncate too.
129 * @return An Kerberos 5 error code.
131 * @ingroup krb5_storage
134 int KRB5_LIB_FUNCTION
135 krb5_storage_truncate(krb5_storage *sp, off_t offset)
137 return (*sp->trunc)(sp, offset);
141 * Read to the storage buffer.
143 * @param sp the storage buffer to read from
144 * @param buf the buffer to store the data in
145 * @param len the length to read
147 * @return The length of data read (can be shorter then len), or negative on error.
149 * @ingroup krb5_storage
152 krb5_ssize_t KRB5_LIB_FUNCTION
153 krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
155 return sp->fetch(sp, buf, len);
159 * Write to the storage buffer.
161 * @param sp the storage buffer to write to
162 * @param buf the buffer to write to the storage buffer
163 * @param len the length to write
165 * @return The length of data written (can be shorter then len), or negative on error.
167 * @ingroup krb5_storage
170 krb5_ssize_t KRB5_LIB_FUNCTION
171 krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
173 return sp->store(sp, buf, len);
177 * Set the return code that will be used when end of storage is reached.
179 * @param sp the storage
180 * @param code the error code to return on end of storage
182 * @ingroup krb5_storage
185 void KRB5_LIB_FUNCTION
186 krb5_storage_set_eof_code(krb5_storage *sp, int code)
188 sp->eof_code = code;
192 * Get the return code that will be used when end of storage is reached.
194 * @param sp the storage
196 * @return storage error code
198 * @ingroup krb5_storage
201 int KRB5_LIB_FUNCTION
202 krb5_storage_get_eof_code(krb5_storage *sp)
204 return sp->eof_code;
207 krb5_ssize_t KRB5_LIB_FUNCTION
208 _krb5_put_int(void *buffer, unsigned long value, size_t size)
210 unsigned char *p = buffer;
211 int i;
212 for (i = size - 1; i >= 0; i--) {
213 p[i] = value & 0xff;
214 value >>= 8;
216 return size;
219 krb5_ssize_t KRB5_LIB_FUNCTION
220 _krb5_get_int(void *buffer, unsigned long *value, size_t size)
222 unsigned char *p = buffer;
223 unsigned long v = 0;
224 int i;
225 for (i = 0; i < size; i++)
226 v = (v << 8) + p[i];
227 *value = v;
228 return size;
232 * Free a krb5 storage.
234 * @param sp the storage to free.
236 * @return An Kerberos 5 error code.
238 * @ingroup krb5_storage
241 krb5_error_code KRB5_LIB_FUNCTION
242 krb5_storage_free(krb5_storage *sp)
244 if(sp->free)
245 (*sp->free)(sp);
246 free(sp->data);
247 free(sp);
248 return 0;
252 * Copy the contnent of storage
254 * @param sp the storage to copy to a data
255 * @param data the copied data, free with krb5_data_free()
257 * @return 0 for success, or a Kerberos 5 error code on failure.
259 * @ingroup krb5_storage
262 krb5_error_code KRB5_LIB_FUNCTION
263 krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
265 off_t pos, size;
266 krb5_error_code ret;
268 pos = sp->seek(sp, 0, SEEK_CUR);
269 if (pos < 0)
270 return HEIM_ERR_NOT_SEEKABLE;
271 size = (size_t)sp->seek(sp, 0, SEEK_END);
272 if (size > (size_t)-1)
273 return HEIM_ERR_TOO_BIG;
274 ret = krb5_data_alloc (data, size);
275 if (ret) {
276 sp->seek(sp, pos, SEEK_SET);
277 return ret;
279 if (size) {
280 sp->seek(sp, 0, SEEK_SET);
281 sp->fetch(sp, data->data, data->length);
282 sp->seek(sp, pos, SEEK_SET);
284 return 0;
287 static krb5_error_code
288 krb5_store_int(krb5_storage *sp,
289 int32_t value,
290 size_t len)
292 int ret;
293 unsigned char v[16];
295 if(len > sizeof(v))
296 return EINVAL;
297 _krb5_put_int(v, value, len);
298 ret = sp->store(sp, v, len);
299 if (ret != len)
300 return (ret<0)?errno:sp->eof_code;
301 return 0;
305 * Store a int32 to storage, byte order is controlled by the settings
306 * on the storage, see krb5_storage_set_byteorder().
308 * @param sp the storage to write too
309 * @param value the value to store
311 * @return 0 for success, or a Kerberos 5 error code on failure.
313 * @ingroup krb5_storage
316 krb5_error_code KRB5_LIB_FUNCTION
317 krb5_store_int32(krb5_storage *sp,
318 int32_t value)
320 if(BYTEORDER_IS_HOST(sp))
321 value = htonl(value);
322 else if(BYTEORDER_IS_LE(sp))
323 value = bswap32(value);
324 return krb5_store_int(sp, value, 4);
328 * Store a uint32 to storage, byte order is controlled by the settings
329 * on the storage, see krb5_storage_set_byteorder().
331 * @param sp the storage to write too
332 * @param value the value to store
334 * @return 0 for success, or a Kerberos 5 error code on failure.
336 * @ingroup krb5_storage
339 krb5_error_code KRB5_LIB_FUNCTION
340 krb5_store_uint32(krb5_storage *sp,
341 uint32_t value)
343 return krb5_store_int32(sp, (int32_t)value);
346 static krb5_error_code
347 krb5_ret_int(krb5_storage *sp,
348 int32_t *value,
349 size_t len)
351 int ret;
352 unsigned char v[4];
353 unsigned long w;
354 ret = sp->fetch(sp, v, len);
355 if(ret != len)
356 return (ret<0)?errno:sp->eof_code;
357 _krb5_get_int(v, &w, len);
358 *value = w;
359 return 0;
362 krb5_error_code KRB5_LIB_FUNCTION
363 krb5_ret_int32(krb5_storage *sp,
364 int32_t *value)
366 krb5_error_code ret = krb5_ret_int(sp, value, 4);
367 if(ret)
368 return ret;
369 if(BYTEORDER_IS_HOST(sp))
370 *value = htonl(*value);
371 else if(BYTEORDER_IS_LE(sp))
372 *value = bswap32(*value);
373 return 0;
376 krb5_error_code KRB5_LIB_FUNCTION
377 krb5_ret_uint32(krb5_storage *sp,
378 uint32_t *value)
380 krb5_error_code ret;
381 int32_t v;
383 ret = krb5_ret_int32(sp, &v);
384 if (ret == 0)
385 *value = (uint32_t)v;
387 return ret;
391 * Store a int16 to storage, byte order is controlled by the settings
392 * on the storage, see krb5_storage_set_byteorder().
394 * @param sp the storage to write too
395 * @param value the value to store
397 * @return 0 for success, or a Kerberos 5 error code on failure.
399 * @ingroup krb5_storage
402 krb5_error_code KRB5_LIB_FUNCTION
403 krb5_store_int16(krb5_storage *sp,
404 int16_t value)
406 if(BYTEORDER_IS_HOST(sp))
407 value = htons(value);
408 else if(BYTEORDER_IS_LE(sp))
409 value = bswap16(value);
410 return krb5_store_int(sp, value, 2);
414 * Store a uint16 to storage, byte order is controlled by the settings
415 * on the storage, see krb5_storage_set_byteorder().
417 * @param sp the storage to write too
418 * @param value the value to store
420 * @return 0 for success, or a Kerberos 5 error code on failure.
422 * @ingroup krb5_storage
425 krb5_error_code KRB5_LIB_FUNCTION
426 krb5_store_uint16(krb5_storage *sp,
427 uint16_t value)
429 return krb5_store_int16(sp, (int16_t)value);
432 krb5_error_code KRB5_LIB_FUNCTION
433 krb5_ret_int16(krb5_storage *sp,
434 int16_t *value)
436 int32_t v;
437 int ret;
438 ret = krb5_ret_int(sp, &v, 2);
439 if(ret)
440 return ret;
441 *value = v;
442 if(BYTEORDER_IS_HOST(sp))
443 *value = htons(*value);
444 else if(BYTEORDER_IS_LE(sp))
445 *value = bswap16(*value);
446 return 0;
449 krb5_error_code KRB5_LIB_FUNCTION
450 krb5_ret_uint16(krb5_storage *sp,
451 uint16_t *value)
453 krb5_error_code ret;
454 int16_t v;
456 ret = krb5_ret_int16(sp, &v);
457 if (ret == 0)
458 *value = (uint16_t)v;
460 return ret;
464 * Store a int8 to storage.
466 * @param sp the storage to write too
467 * @param value the value to store
469 * @return 0 for success, or a Kerberos 5 error code on failure.
471 * @ingroup krb5_storage
474 krb5_error_code KRB5_LIB_FUNCTION
475 krb5_store_int8(krb5_storage *sp,
476 int8_t value)
478 int ret;
480 ret = sp->store(sp, &value, sizeof(value));
481 if (ret != sizeof(value))
482 return (ret<0)?errno:sp->eof_code;
483 return 0;
487 * Store a uint8 to storage.
489 * @param sp the storage to write too
490 * @param value the value to store
492 * @return 0 for success, or a Kerberos 5 error code on failure.
494 * @ingroup krb5_storage
497 krb5_error_code KRB5_LIB_FUNCTION
498 krb5_store_uint8(krb5_storage *sp,
499 uint8_t value)
501 return krb5_store_int8(sp, (int8_t)value);
504 krb5_error_code KRB5_LIB_FUNCTION
505 krb5_ret_int8(krb5_storage *sp,
506 int8_t *value)
508 int ret;
510 ret = sp->fetch(sp, value, sizeof(*value));
511 if (ret != sizeof(*value))
512 return (ret<0)?errno:sp->eof_code;
513 return 0;
516 krb5_error_code KRB5_LIB_FUNCTION
517 krb5_ret_uint8(krb5_storage *sp,
518 uint8_t *value)
520 krb5_error_code ret;
521 int8_t v;
523 ret = krb5_ret_int8(sp, &v);
524 if (ret == 0)
525 *value = (uint8_t)v;
527 return ret;
531 * Store a data to the storage.
533 * @param sp the storage buffer to write to
534 * @param data the buffer to store.
536 * @return 0 on success, a Kerberos 5 error code on failure.
538 * @ingroup krb5_storage
541 krb5_error_code KRB5_LIB_FUNCTION
542 krb5_store_data(krb5_storage *sp,
543 krb5_data data)
545 int ret;
546 ret = krb5_store_int32(sp, data.length);
547 if(ret < 0)
548 return ret;
549 ret = sp->store(sp, data.data, data.length);
550 if(ret != data.length){
551 if(ret < 0)
552 return errno;
553 return sp->eof_code;
555 return 0;
559 * Parse a data from the storage.
561 * @param sp the storage buffer to read from
562 * @param data the parsed data
564 * @return 0 on success, a Kerberos 5 error code on failure.
566 * @ingroup krb5_storage
569 krb5_error_code KRB5_LIB_FUNCTION
570 krb5_ret_data(krb5_storage *sp,
571 krb5_data *data)
573 int ret;
574 int32_t size;
576 ret = krb5_ret_int32(sp, &size);
577 if(ret)
578 return ret;
579 ret = krb5_data_alloc (data, size);
580 if (ret)
581 return ret;
582 if (size) {
583 ret = sp->fetch(sp, data->data, size);
584 if(ret != size)
585 return (ret < 0)? errno : sp->eof_code;
587 return 0;
590 krb5_error_code KRB5_LIB_FUNCTION
591 krb5_store_string(krb5_storage *sp, const char *s)
593 krb5_data data;
594 data.length = strlen(s);
595 data.data = rk_UNCONST(s);
596 return krb5_store_data(sp, data);
599 krb5_error_code KRB5_LIB_FUNCTION
600 krb5_ret_string(krb5_storage *sp,
601 char **string)
603 int ret;
604 krb5_data data;
605 ret = krb5_ret_data(sp, &data);
606 if(ret)
607 return ret;
608 *string = realloc(data.data, data.length + 1);
609 if(*string == NULL){
610 free(data.data);
611 return ENOMEM;
613 (*string)[data.length] = 0;
614 return 0;
617 krb5_error_code KRB5_LIB_FUNCTION
618 krb5_store_stringz(krb5_storage *sp, const char *s)
620 size_t len = strlen(s) + 1;
621 ssize_t ret;
623 ret = sp->store(sp, s, len);
624 if(ret != len) {
625 if(ret < 0)
626 return ret;
627 else
628 return sp->eof_code;
630 return 0;
633 krb5_error_code KRB5_LIB_FUNCTION
634 krb5_ret_stringz(krb5_storage *sp,
635 char **string)
637 char c;
638 char *s = NULL;
639 size_t len = 0;
640 ssize_t ret;
642 while((ret = sp->fetch(sp, &c, 1)) == 1){
643 char *tmp;
645 len++;
646 tmp = realloc (s, len);
647 if (tmp == NULL) {
648 free (s);
649 return ENOMEM;
651 s = tmp;
652 s[len - 1] = c;
653 if(c == 0)
654 break;
656 if(ret != 1){
657 free(s);
658 if(ret == 0)
659 return sp->eof_code;
660 return ret;
662 *string = s;
663 return 0;
666 krb5_error_code KRB5_LIB_FUNCTION
667 krb5_store_stringnl(krb5_storage *sp, const char *s)
669 size_t len = strlen(s);
670 ssize_t ret;
672 ret = sp->store(sp, s, len);
673 if(ret != len) {
674 if(ret < 0)
675 return ret;
676 else
677 return sp->eof_code;
679 ret = sp->store(sp, "\n", 1);
680 if(ret != 1) {
681 if(ret < 0)
682 return ret;
683 else
684 return sp->eof_code;
687 return 0;
691 krb5_error_code KRB5_LIB_FUNCTION
692 krb5_ret_stringnl(krb5_storage *sp,
693 char **string)
695 int expect_nl = 0;
696 char c;
697 char *s = NULL;
698 size_t len = 0;
699 ssize_t ret;
701 while((ret = sp->fetch(sp, &c, 1)) == 1){
702 char *tmp;
704 if (c == '\r') {
705 expect_nl = 1;
706 continue;
708 if (expect_nl && c != '\n') {
709 free(s);
710 return KRB5_BADMSGTYPE;
713 len++;
714 tmp = realloc (s, len);
715 if (tmp == NULL) {
716 free (s);
717 return ENOMEM;
719 s = tmp;
720 if(c == '\n') {
721 s[len - 1] = '\0';
722 break;
724 s[len - 1] = c;
726 if(ret != 1){
727 free(s);
728 if(ret == 0)
729 return sp->eof_code;
730 return ret;
732 *string = s;
733 return 0;
737 krb5_error_code KRB5_LIB_FUNCTION
738 krb5_store_principal(krb5_storage *sp,
739 krb5_const_principal p)
741 int i;
742 int ret;
744 if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
745 ret = krb5_store_int32(sp, p->name.name_type);
746 if(ret) return ret;
748 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
749 ret = krb5_store_int32(sp, p->name.name_string.len + 1);
750 else
751 ret = krb5_store_int32(sp, p->name.name_string.len);
753 if(ret) return ret;
754 ret = krb5_store_string(sp, p->realm);
755 if(ret) return ret;
756 for(i = 0; i < p->name.name_string.len; i++){
757 ret = krb5_store_string(sp, p->name.name_string.val[i]);
758 if(ret) return ret;
760 return 0;
763 krb5_error_code KRB5_LIB_FUNCTION
764 krb5_ret_principal(krb5_storage *sp,
765 krb5_principal *princ)
767 int i;
768 int ret;
769 krb5_principal p;
770 int32_t type;
771 int32_t ncomp;
773 p = calloc(1, sizeof(*p));
774 if(p == NULL)
775 return ENOMEM;
777 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
778 type = KRB5_NT_UNKNOWN;
779 else if((ret = krb5_ret_int32(sp, &type))){
780 free(p);
781 return ret;
783 if((ret = krb5_ret_int32(sp, &ncomp))){
784 free(p);
785 return ret;
787 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
788 ncomp--;
789 if (ncomp < 0) {
790 free(p);
791 return EINVAL;
793 p->name.name_type = type;
794 p->name.name_string.len = ncomp;
795 ret = krb5_ret_string(sp, &p->realm);
796 if(ret) {
797 free(p);
798 return ret;
800 p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
801 if(p->name.name_string.val == NULL && ncomp != 0){
802 free(p->realm);
803 free(p);
804 return ENOMEM;
806 for(i = 0; i < ncomp; i++){
807 ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
808 if(ret) {
809 while (i >= 0)
810 free(p->name.name_string.val[i--]);
811 free(p->realm);
812 free(p);
813 return ret;
816 *princ = p;
817 return 0;
821 * Store a keyblock to the storage.
823 * @param sp the storage buffer to write to
824 * @param p the keyblock to write
826 * @return 0 on success, a Kerberos 5 error code on failure.
828 * @ingroup krb5_storage
831 krb5_error_code KRB5_LIB_FUNCTION
832 krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
834 int ret;
835 ret = krb5_store_int16(sp, p.keytype);
836 if(ret) return ret;
838 if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
839 /* this should really be enctype, but it is the same as
840 keytype nowadays */
841 ret = krb5_store_int16(sp, p.keytype);
842 if(ret) return ret;
845 ret = krb5_store_data(sp, p.keyvalue);
846 return ret;
850 * Read a keyblock from the storage.
852 * @param sp the storage buffer to write to
853 * @param p the keyblock read from storage, free using krb5_free_keyblock()
855 * @return 0 on success, a Kerberos 5 error code on failure.
857 * @ingroup krb5_storage
860 krb5_error_code KRB5_LIB_FUNCTION
861 krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
863 int ret;
864 int16_t tmp;
866 ret = krb5_ret_int16(sp, &tmp);
867 if(ret) return ret;
868 p->keytype = tmp;
870 if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
871 ret = krb5_ret_int16(sp, &tmp);
872 if(ret) return ret;
875 ret = krb5_ret_data(sp, &p->keyvalue);
876 return ret;
880 * Write a times block to storage.
882 * @param sp the storage buffer to write to
883 * @param times the times block to write.
885 * @return 0 on success, a Kerberos 5 error code on failure.
887 * @ingroup krb5_storage
890 krb5_error_code KRB5_LIB_FUNCTION
891 krb5_store_times(krb5_storage *sp, krb5_times times)
893 int ret;
894 ret = krb5_store_int32(sp, times.authtime);
895 if(ret) return ret;
896 ret = krb5_store_int32(sp, times.starttime);
897 if(ret) return ret;
898 ret = krb5_store_int32(sp, times.endtime);
899 if(ret) return ret;
900 ret = krb5_store_int32(sp, times.renew_till);
901 return ret;
905 * Read a times block from the storage.
907 * @param sp the storage buffer to write to
908 * @param times the times block read from storage
910 * @return 0 on success, a Kerberos 5 error code on failure.
912 * @ingroup krb5_storage
915 krb5_error_code KRB5_LIB_FUNCTION
916 krb5_ret_times(krb5_storage *sp, krb5_times *times)
918 int ret;
919 int32_t tmp;
920 ret = krb5_ret_int32(sp, &tmp);
921 times->authtime = tmp;
922 if(ret) return ret;
923 ret = krb5_ret_int32(sp, &tmp);
924 times->starttime = tmp;
925 if(ret) return ret;
926 ret = krb5_ret_int32(sp, &tmp);
927 times->endtime = tmp;
928 if(ret) return ret;
929 ret = krb5_ret_int32(sp, &tmp);
930 times->renew_till = tmp;
931 return ret;
934 krb5_error_code KRB5_LIB_FUNCTION
935 krb5_store_address(krb5_storage *sp, krb5_address p)
937 int ret;
938 ret = krb5_store_int16(sp, p.addr_type);
939 if(ret) return ret;
940 ret = krb5_store_data(sp, p.address);
941 return ret;
944 krb5_error_code KRB5_LIB_FUNCTION
945 krb5_ret_address(krb5_storage *sp, krb5_address *adr)
947 int16_t t;
948 int ret;
949 ret = krb5_ret_int16(sp, &t);
950 if(ret) return ret;
951 adr->addr_type = t;
952 ret = krb5_ret_data(sp, &adr->address);
953 return ret;
956 krb5_error_code KRB5_LIB_FUNCTION
957 krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
959 int i;
960 int ret;
961 ret = krb5_store_int32(sp, p.len);
962 if(ret) return ret;
963 for(i = 0; i<p.len; i++){
964 ret = krb5_store_address(sp, p.val[i]);
965 if(ret) break;
967 return ret;
970 krb5_error_code KRB5_LIB_FUNCTION
971 krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
973 int i;
974 int ret;
975 int32_t tmp;
977 ret = krb5_ret_int32(sp, &tmp);
978 if(ret) return ret;
979 adr->len = tmp;
980 ALLOC(adr->val, adr->len);
981 if (adr->val == NULL && adr->len != 0)
982 return ENOMEM;
983 for(i = 0; i < adr->len; i++){
984 ret = krb5_ret_address(sp, &adr->val[i]);
985 if(ret) break;
987 return ret;
990 krb5_error_code KRB5_LIB_FUNCTION
991 krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
993 krb5_error_code ret;
994 int i;
995 ret = krb5_store_int32(sp, auth.len);
996 if(ret) return ret;
997 for(i = 0; i < auth.len; i++){
998 ret = krb5_store_int16(sp, auth.val[i].ad_type);
999 if(ret) break;
1000 ret = krb5_store_data(sp, auth.val[i].ad_data);
1001 if(ret) break;
1003 return 0;
1006 krb5_error_code KRB5_LIB_FUNCTION
1007 krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
1009 krb5_error_code ret;
1010 int32_t tmp;
1011 int16_t tmp2;
1012 int i;
1013 ret = krb5_ret_int32(sp, &tmp);
1014 if(ret) return ret;
1015 ALLOC_SEQ(auth, tmp);
1016 if (auth->val == NULL && tmp != 0)
1017 return ENOMEM;
1018 for(i = 0; i < tmp; i++){
1019 ret = krb5_ret_int16(sp, &tmp2);
1020 if(ret) break;
1021 auth->val[i].ad_type = tmp2;
1022 ret = krb5_ret_data(sp, &auth->val[i].ad_data);
1023 if(ret) break;
1025 return ret;
1028 static int32_t
1029 bitswap32(int32_t b)
1031 int32_t r = 0;
1032 int i;
1033 for (i = 0; i < 32; i++) {
1034 r = r << 1 | (b & 1);
1035 b = b >> 1;
1037 return r;
1045 krb5_error_code KRB5_LIB_FUNCTION
1046 krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
1048 int ret;
1050 ret = krb5_store_principal(sp, creds->client);
1051 if(ret)
1052 return ret;
1053 ret = krb5_store_principal(sp, creds->server);
1054 if(ret)
1055 return ret;
1056 ret = krb5_store_keyblock(sp, creds->session);
1057 if(ret)
1058 return ret;
1059 ret = krb5_store_times(sp, creds->times);
1060 if(ret)
1061 return ret;
1062 ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1063 if(ret)
1064 return ret;
1066 if(krb5_storage_is_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER))
1067 ret = krb5_store_int32(sp, creds->flags.i);
1068 else
1069 ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1070 if(ret)
1071 return ret;
1073 ret = krb5_store_addrs(sp, creds->addresses);
1074 if(ret)
1075 return ret;
1076 ret = krb5_store_authdata(sp, creds->authdata);
1077 if(ret)
1078 return ret;
1079 ret = krb5_store_data(sp, creds->ticket);
1080 if(ret)
1081 return ret;
1082 ret = krb5_store_data(sp, creds->second_ticket);
1083 return ret;
1086 krb5_error_code KRB5_LIB_FUNCTION
1087 krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
1089 krb5_error_code ret;
1090 int8_t dummy8;
1091 int32_t dummy32;
1093 memset(creds, 0, sizeof(*creds));
1094 ret = krb5_ret_principal (sp, &creds->client);
1095 if(ret) goto cleanup;
1096 ret = krb5_ret_principal (sp, &creds->server);
1097 if(ret) goto cleanup;
1098 ret = krb5_ret_keyblock (sp, &creds->session);
1099 if(ret) goto cleanup;
1100 ret = krb5_ret_times (sp, &creds->times);
1101 if(ret) goto cleanup;
1102 ret = krb5_ret_int8 (sp, &dummy8);
1103 if(ret) goto cleanup;
1104 ret = krb5_ret_int32 (sp, &dummy32);
1105 if(ret) goto cleanup;
1107 * Runtime detect the what is the higher bits of the bitfield. If
1108 * any of the higher bits are set in the input data, it's either a
1109 * new ticket flag (and this code need to be removed), or it's a
1110 * MIT cache (or new Heimdal cache), lets change it to our current
1111 * format.
1114 uint32_t mask = 0xffff0000;
1115 creds->flags.i = 0;
1116 creds->flags.b.anonymous = 1;
1117 if (creds->flags.i & mask)
1118 mask = ~mask;
1119 if (dummy32 & mask)
1120 dummy32 = bitswap32(dummy32);
1122 creds->flags.i = dummy32;
1123 ret = krb5_ret_addrs (sp, &creds->addresses);
1124 if(ret) goto cleanup;
1125 ret = krb5_ret_authdata (sp, &creds->authdata);
1126 if(ret) goto cleanup;
1127 ret = krb5_ret_data (sp, &creds->ticket);
1128 if(ret) goto cleanup;
1129 ret = krb5_ret_data (sp, &creds->second_ticket);
1130 cleanup:
1131 if(ret) {
1132 #if 0
1133 krb5_free_cred_contents(context, creds); /* XXX */
1134 #endif
1136 return ret;
1139 #define SC_CLIENT_PRINCIPAL 0x0001
1140 #define SC_SERVER_PRINCIPAL 0x0002
1141 #define SC_SESSION_KEY 0x0004
1142 #define SC_TICKET 0x0008
1143 #define SC_SECOND_TICKET 0x0010
1144 #define SC_AUTHDATA 0x0020
1145 #define SC_ADDRESSES 0x0040
1151 krb5_error_code KRB5_LIB_FUNCTION
1152 krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
1154 int ret;
1155 int32_t header = 0;
1157 if (creds->client)
1158 header |= SC_CLIENT_PRINCIPAL;
1159 if (creds->server)
1160 header |= SC_SERVER_PRINCIPAL;
1161 if (creds->session.keytype != ETYPE_NULL)
1162 header |= SC_SESSION_KEY;
1163 if (creds->ticket.data)
1164 header |= SC_TICKET;
1165 if (creds->second_ticket.length)
1166 header |= SC_SECOND_TICKET;
1167 if (creds->authdata.len)
1168 header |= SC_AUTHDATA;
1169 if (creds->addresses.len)
1170 header |= SC_ADDRESSES;
1172 ret = krb5_store_int32(sp, header);
1173 if (ret)
1174 return ret;
1176 if (creds->client) {
1177 ret = krb5_store_principal(sp, creds->client);
1178 if(ret)
1179 return ret;
1182 if (creds->server) {
1183 ret = krb5_store_principal(sp, creds->server);
1184 if(ret)
1185 return ret;
1188 if (creds->session.keytype != ETYPE_NULL) {
1189 ret = krb5_store_keyblock(sp, creds->session);
1190 if(ret)
1191 return ret;
1194 ret = krb5_store_times(sp, creds->times);
1195 if(ret)
1196 return ret;
1197 ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1198 if(ret)
1199 return ret;
1201 ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1202 if(ret)
1203 return ret;
1205 if (creds->addresses.len) {
1206 ret = krb5_store_addrs(sp, creds->addresses);
1207 if(ret)
1208 return ret;
1211 if (creds->authdata.len) {
1212 ret = krb5_store_authdata(sp, creds->authdata);
1213 if(ret)
1214 return ret;
1217 if (creds->ticket.data) {
1218 ret = krb5_store_data(sp, creds->ticket);
1219 if(ret)
1220 return ret;
1223 if (creds->second_ticket.data) {
1224 ret = krb5_store_data(sp, creds->second_ticket);
1225 if (ret)
1226 return ret;
1229 return ret;
1232 krb5_error_code KRB5_LIB_FUNCTION
1233 krb5_ret_creds_tag(krb5_storage *sp,
1234 krb5_creds *creds)
1236 krb5_error_code ret;
1237 int8_t dummy8;
1238 int32_t dummy32, header;
1240 memset(creds, 0, sizeof(*creds));
1242 ret = krb5_ret_int32 (sp, &header);
1243 if (ret) goto cleanup;
1245 if (header & SC_CLIENT_PRINCIPAL) {
1246 ret = krb5_ret_principal (sp, &creds->client);
1247 if(ret) goto cleanup;
1249 if (header & SC_SERVER_PRINCIPAL) {
1250 ret = krb5_ret_principal (sp, &creds->server);
1251 if(ret) goto cleanup;
1253 if (header & SC_SESSION_KEY) {
1254 ret = krb5_ret_keyblock (sp, &creds->session);
1255 if(ret) goto cleanup;
1257 ret = krb5_ret_times (sp, &creds->times);
1258 if(ret) goto cleanup;
1259 ret = krb5_ret_int8 (sp, &dummy8);
1260 if(ret) goto cleanup;
1261 ret = krb5_ret_int32 (sp, &dummy32);
1262 if(ret) goto cleanup;
1264 * Runtime detect the what is the higher bits of the bitfield. If
1265 * any of the higher bits are set in the input data, it's either a
1266 * new ticket flag (and this code need to be removed), or it's a
1267 * MIT cache (or new Heimdal cache), lets change it to our current
1268 * format.
1271 uint32_t mask = 0xffff0000;
1272 creds->flags.i = 0;
1273 creds->flags.b.anonymous = 1;
1274 if (creds->flags.i & mask)
1275 mask = ~mask;
1276 if (dummy32 & mask)
1277 dummy32 = bitswap32(dummy32);
1279 creds->flags.i = dummy32;
1280 if (header & SC_ADDRESSES) {
1281 ret = krb5_ret_addrs (sp, &creds->addresses);
1282 if(ret) goto cleanup;
1284 if (header & SC_AUTHDATA) {
1285 ret = krb5_ret_authdata (sp, &creds->authdata);
1286 if(ret) goto cleanup;
1288 if (header & SC_TICKET) {
1289 ret = krb5_ret_data (sp, &creds->ticket);
1290 if(ret) goto cleanup;
1292 if (header & SC_SECOND_TICKET) {
1293 ret = krb5_ret_data (sp, &creds->second_ticket);
1294 if(ret) goto cleanup;
1297 cleanup:
1298 if(ret) {
1299 #if 0
1300 krb5_free_cred_contents(context, creds); /* XXX */
1301 #endif
1303 return ret;