1/*	$NetBSD: store.c,v 1.2 2017/01/28 21:31:49 christos Exp $	*/
2
3/*
4 * Copyright (c) 1997-2008 Kungliga Tekniska H��gskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 *    notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36#include "krb5_locl.h"
37#include "store-int.h"
38
39#define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
40#define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
41#define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
42#define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
43			       krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
44
45/**
46 * Add the flags on a storage buffer by or-ing in the flags to the buffer.
47 *
48 * @param sp the storage buffer to set the flags on
49 * @param flags the flags to set
50 *
51 * @ingroup krb5_storage
52 */
53
54KRB5_LIB_FUNCTION void KRB5_LIB_CALL
55krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
56{
57    sp->flags |= flags;
58}
59
60/**
61 * Clear the flags on a storage buffer
62 *
63 * @param sp the storage buffer to clear the flags on
64 * @param flags the flags to clear
65 *
66 * @ingroup krb5_storage
67 */
68
69KRB5_LIB_FUNCTION void KRB5_LIB_CALL
70krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
71{
72    sp->flags &= ~flags;
73}
74
75/**
76 * Return true or false depending on if the storage flags is set or
77 * not. NB testing for the flag 0 always return true.
78 *
79 * @param sp the storage buffer to check flags on
80 * @param flags The flags to test for
81 *
82 * @return true if all the flags are set, false if not.
83 *
84 * @ingroup krb5_storage
85 */
86
87KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
88krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
89{
90    return (sp->flags & flags) == flags;
91}
92
93/**
94 * Set the new byte order of the storage buffer.
95 *
96 * @param sp the storage buffer to set the byte order for.
97 * @param byteorder the new byte order.
98 *
99 * The byte order are: KRB5_STORAGE_BYTEORDER_BE,
100 * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST.
101 *
102 * @ingroup krb5_storage
103 */
104
105KRB5_LIB_FUNCTION void KRB5_LIB_CALL
106krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
107{
108    sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
109    sp->flags |= byteorder;
110}
111
112/**
113 * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants.
114 *
115 * @ingroup krb5_storage
116 */
117
118KRB5_LIB_FUNCTION krb5_flags KRB5_LIB_CALL
119krb5_storage_get_byteorder(krb5_storage *sp)
120{
121    return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
122}
123
124/**
125 * Set the max alloc value
126 *
127 * @param sp the storage buffer set the max allow for
128 * @param size maximum size to allocate, use 0 to remove limit
129 *
130 * @ingroup krb5_storage
131 */
132
133KRB5_LIB_FUNCTION void KRB5_LIB_CALL
134krb5_storage_set_max_alloc(krb5_storage *sp, size_t size)
135{
136    sp->max_alloc = size;
137}
138
139/* don't allocate unresonable amount of memory */
140static krb5_error_code
141size_too_large(krb5_storage *sp, size_t size)
142{
143    if (sp->max_alloc && sp->max_alloc < size)
144	return HEIM_ERR_TOO_BIG;
145    return 0;
146}
147
148static krb5_error_code
149size_too_large_num(krb5_storage *sp, size_t count, size_t size)
150{
151    if (sp->max_alloc == 0 || size == 0)
152	return 0;
153    size = sp->max_alloc / size;
154    if (size < count)
155	return HEIM_ERR_TOO_BIG;
156    return 0;
157}
158
159/**
160 * Seek to a new offset.
161 *
162 * @param sp the storage buffer to seek in.
163 * @param offset the offset to seek
164 * @param whence relateive searching, SEEK_CUR from the current
165 * position, SEEK_END from the end, SEEK_SET absolute from the start.
166 *
167 * @return The new current offset
168 *
169 * @ingroup krb5_storage
170 */
171
172KRB5_LIB_FUNCTION off_t KRB5_LIB_CALL
173krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
174{
175    return (*sp->seek)(sp, offset, whence);
176}
177
178/**
179 * Truncate the storage buffer in sp to offset.
180 *
181 * @param sp the storage buffer to truncate.
182 * @param offset the offset to truncate too.
183 *
184 * @return An Kerberos 5 error code.
185 *
186 * @ingroup krb5_storage
187 */
188
189KRB5_LIB_FUNCTION int KRB5_LIB_CALL
190krb5_storage_truncate(krb5_storage *sp, off_t offset)
191{
192    return (*sp->trunc)(sp, offset);
193}
194
195/**
196 * Sync the storage buffer to its backing store.  If there is no
197 * backing store this function will return success.
198 *
199 * @param sp the storage buffer to sync
200 *
201 * @return A Kerberos 5 error code
202 *
203 * @ingroup krb5_storage
204 */
205
206KRB5_LIB_FUNCTION int KRB5_LIB_CALL
207krb5_storage_fsync(krb5_storage *sp)
208{
209    if (sp->fsync != NULL)
210	return sp->fsync(sp);
211    return 0;
212}
213
214/**
215 * Read to the storage buffer.
216 *
217 * @param sp the storage buffer to read from
218 * @param buf the buffer to store the data in
219 * @param len the length to read
220 *
221 * @return The length of data read (can be shorter then len), or negative on error.
222 *
223 * @ingroup krb5_storage
224 */
225
226KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
227krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
228{
229    return sp->fetch(sp, buf, len);
230}
231
232/**
233 * Write to the storage buffer.
234 *
235 * @param sp the storage buffer to write to
236 * @param buf the buffer to write to the storage buffer
237 * @param len the length to write
238 *
239 * @return The length of data written (can be shorter then len), or negative on error.
240 *
241 * @ingroup krb5_storage
242 */
243
244KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
245krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
246{
247    return sp->store(sp, buf, len);
248}
249
250/**
251 * Set the return code that will be used when end of storage is reached.
252 *
253 * @param sp the storage
254 * @param code the error code to return on end of storage
255 *
256 * @ingroup krb5_storage
257 */
258
259KRB5_LIB_FUNCTION void KRB5_LIB_CALL
260krb5_storage_set_eof_code(krb5_storage *sp, int code)
261{
262    sp->eof_code = code;
263}
264
265/**
266 * Get the return code that will be used when end of storage is reached.
267 *
268 * @param sp the storage
269 *
270 * @return storage error code
271 *
272 * @ingroup krb5_storage
273 */
274
275KRB5_LIB_FUNCTION int KRB5_LIB_CALL
276krb5_storage_get_eof_code(krb5_storage *sp)
277{
278    return sp->eof_code;
279}
280
281/**
282 * Free a krb5 storage.
283 *
284 * @param sp the storage to free.
285 *
286 * @return An Kerberos 5 error code.
287 *
288 * @ingroup krb5_storage
289 */
290
291KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
292krb5_storage_free(krb5_storage *sp)
293{
294    if (sp == NULL)
295        return 0;
296    if(sp->free)
297	(*sp->free)(sp);
298    free(sp->data);
299    free(sp);
300    return 0;
301}
302
303/**
304 * Copy the contnent of storage
305 *
306 * @param sp the storage to copy to a data
307 * @param data the copied data, free with krb5_data_free()
308 *
309 * @return 0 for success, or a Kerberos 5 error code on failure.
310 *
311 * @ingroup krb5_storage
312 */
313
314KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
315krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
316{
317    off_t pos, size;
318    krb5_error_code ret;
319
320    pos = sp->seek(sp, 0, SEEK_CUR);
321    if (pos < 0)
322	return HEIM_ERR_NOT_SEEKABLE;
323    size = sp->seek(sp, 0, SEEK_END);
324    ret = size_too_large(sp, size);
325    if (ret)
326	return ret;
327    ret = krb5_data_alloc(data, size);
328    if (ret) {
329	sp->seek(sp, pos, SEEK_SET);
330	return ret;
331    }
332    if (size) {
333	sp->seek(sp, 0, SEEK_SET);
334	sp->fetch(sp, data->data, data->length);
335	sp->seek(sp, pos, SEEK_SET);
336    }
337    return 0;
338}
339
340static krb5_error_code
341krb5_store_int(krb5_storage *sp,
342	       int64_t value,
343	       size_t len)
344{
345    int ret;
346    unsigned char v[8];
347
348    if (len > sizeof(v))
349	return EINVAL;
350    _krb5_put_int(v, value, len);
351    ret = sp->store(sp, v, len);
352    if (ret < 0)
353	return errno;
354    if ((size_t)ret != len)
355	return sp->eof_code;
356    return 0;
357}
358
359/**
360 * Store a int32 to storage, byte order is controlled by the settings
361 * on the storage, see krb5_storage_set_byteorder().
362 *
363 * @param sp the storage to write too
364 * @param value the value to store
365 *
366 * @return 0 for success, or a Kerberos 5 error code on failure.
367 *
368 * @ingroup krb5_storage
369 */
370
371KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
372krb5_store_int32(krb5_storage *sp,
373		 int32_t value)
374{
375    if(BYTEORDER_IS_HOST(sp))
376	value = htonl(value);
377    else if(BYTEORDER_IS_LE(sp))
378	value = bswap32(value);
379    return krb5_store_int(sp, value, 4);
380}
381
382/**
383 * Store a int64 to storage, byte order is controlled by the settings
384 * on the storage, see krb5_storage_set_byteorder().
385 *
386 * @param sp the storage to write too
387 * @param value the value to store
388 *
389 * @return 0 for success, or a Kerberos 5 error code on failure.
390 *
391 * @ingroup krb5_storage
392 */
393
394KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
395krb5_store_int64(krb5_storage *sp,
396		 int64_t value)
397{
398    if (BYTEORDER_IS_HOST(sp))
399#ifdef WORDS_BIGENDIAN
400        ;
401#else
402	value = bswap64(value); /* There's no ntohll() */
403#endif
404    else if (BYTEORDER_IS_LE(sp))
405	value = bswap64(value);
406    return krb5_store_int(sp, value, 8);
407}
408
409/**
410 * Store a uint32 to storage, byte order is controlled by the settings
411 * on the storage, see krb5_storage_set_byteorder().
412 *
413 * @param sp the storage to write too
414 * @param value the value to store
415 *
416 * @return 0 for success, or a Kerberos 5 error code on failure.
417 *
418 * @ingroup krb5_storage
419 */
420
421KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
422krb5_store_uint32(krb5_storage *sp,
423		  uint32_t value)
424{
425    return krb5_store_int32(sp, (int32_t)value);
426}
427
428/**
429 * Store a uint64 to storage, byte order is controlled by the settings
430 * on the storage, see krb5_storage_set_byteorder().
431 *
432 * @param sp the storage to write too
433 * @param value the value to store
434 *
435 * @return 0 for success, or a Kerberos 5 error code on failure.
436 *
437 * @ingroup krb5_storage
438 */
439
440KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
441krb5_store_uint64(krb5_storage *sp,
442		  uint64_t value)
443{
444    return krb5_store_int64(sp, (int64_t)value);
445}
446
447static krb5_error_code
448krb5_ret_int(krb5_storage *sp,
449	     int64_t *value,
450	     size_t len)
451{
452    int ret;
453    unsigned char v[8];
454    uint64_t w;
455    *value = 0; /* quiets warnings */
456    ret = sp->fetch(sp, v, len);
457    if (ret < 0)
458	return errno;
459    if ((size_t)ret != len)
460	return sp->eof_code;
461    _krb5_get_int64(v, &w, len);
462    *value = w;
463    return 0;
464}
465
466/**
467 * Read a int64 from storage, byte order is controlled by the settings
468 * on the storage, see krb5_storage_set_byteorder().
469 *
470 * @param sp the storage to write too
471 * @param value the value read from the buffer
472 *
473 * @return 0 for success, or a Kerberos 5 error code on failure.
474 *
475 * @ingroup krb5_storage
476 */
477
478KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
479krb5_ret_int64(krb5_storage *sp,
480	       int64_t *value)
481{
482    krb5_error_code ret = krb5_ret_int(sp, value, 8);
483    if(ret)
484	return ret;
485    if(BYTEORDER_IS_HOST(sp))
486#ifdef WORDS_BIGENDIAN
487        ;
488#else
489	*value = bswap64(*value); /* There's no ntohll() */
490#endif
491    else if(BYTEORDER_IS_LE(sp))
492	*value = bswap64(*value);
493    return 0;
494}
495
496/**
497 * Read a uint64 from storage, byte order is controlled by the settings
498 * on the storage, see krb5_storage_set_byteorder().
499 *
500 * @param sp the storage to write too
501 * @param value the value read from the buffer
502 *
503 * @return 0 for success, or a Kerberos 5 error code on failure.
504 *
505 * @ingroup krb5_storage
506 */
507
508KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
509krb5_ret_uint64(krb5_storage *sp,
510		uint64_t *value)
511{
512    krb5_error_code ret;
513    int64_t v;
514
515    ret = krb5_ret_int64(sp, &v);
516    if (ret == 0)
517	*value = (uint64_t)v;
518
519    return ret;
520}
521
522/**
523 * Read a int32 from storage, byte order is controlled by the settings
524 * on the storage, see krb5_storage_set_byteorder().
525 *
526 * @param sp the storage to write too
527 * @param value the value read from the buffer
528 *
529 * @return 0 for success, or a Kerberos 5 error code on failure.
530 *
531 * @ingroup krb5_storage
532 */
533
534KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
535krb5_ret_int32(krb5_storage *sp,
536	       int32_t *value)
537{
538    int64_t v;
539
540    krb5_error_code ret = krb5_ret_int(sp, &v, 4);
541    if (ret)
542	return ret;
543    *value = v;
544    if (BYTEORDER_IS_HOST(sp))
545	*value = htonl(*value);
546    else if (BYTEORDER_IS_LE(sp))
547	*value = bswap32(*value);
548    return 0;
549}
550
551/**
552 * Read a uint32 from storage, byte order is controlled by the settings
553 * on the storage, see krb5_storage_set_byteorder().
554 *
555 * @param sp the storage to write too
556 * @param value the value read from the buffer
557 *
558 * @return 0 for success, or a Kerberos 5 error code on failure.
559 *
560 * @ingroup krb5_storage
561 */
562
563KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
564krb5_ret_uint32(krb5_storage *sp, uint32_t *value)
565{
566    krb5_error_code ret;
567    int32_t v;
568
569    ret = krb5_ret_int32(sp, &v);
570    if (ret == 0)
571	*value = (uint32_t)v;
572
573    return ret;
574}
575
576/**
577 * Store a int16 to storage, byte order is controlled by the settings
578 * on the storage, see krb5_storage_set_byteorder().
579 *
580 * @param sp the storage to write too
581 * @param value the value to store
582 *
583 * @return 0 for success, or a Kerberos 5 error code on failure.
584 *
585 * @ingroup krb5_storage
586 */
587
588KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
589krb5_store_int16(krb5_storage *sp,
590		 int16_t value)
591{
592    if(BYTEORDER_IS_HOST(sp))
593	value = htons(value);
594    else if(BYTEORDER_IS_LE(sp))
595	value = bswap16(value);
596    return krb5_store_int(sp, value, 2);
597}
598
599/**
600 * Store a uint16 to storage, byte order is controlled by the settings
601 * on the storage, see krb5_storage_set_byteorder().
602 *
603 * @param sp the storage to write too
604 * @param value the value to store
605 *
606 * @return 0 for success, or a Kerberos 5 error code on failure.
607 *
608 * @ingroup krb5_storage
609 */
610
611KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
612krb5_store_uint16(krb5_storage *sp,
613		  uint16_t value)
614{
615    return krb5_store_int16(sp, (int16_t)value);
616}
617
618/**
619 * Read a int16 from storage, byte order is controlled by the settings
620 * on the storage, see krb5_storage_set_byteorder().
621 *
622 * @param sp the storage to write too
623 * @param value the value read from the buffer
624 *
625 * @return 0 for success, or a Kerberos 5 error code on failure.
626 *
627 * @ingroup krb5_storage
628 */
629
630KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
631krb5_ret_int16(krb5_storage *sp,
632	       int16_t *value)
633{
634    int64_t v;
635    int ret;
636    ret = krb5_ret_int(sp, &v, 2);
637    if(ret)
638	return ret;
639    *value = v;
640    if(BYTEORDER_IS_HOST(sp))
641	*value = htons(*value);
642    else if(BYTEORDER_IS_LE(sp))
643	*value = bswap16(*value);
644    return 0;
645}
646
647/**
648 * Read a int16 from storage, byte order is controlled by the settings
649 * on the storage, see krb5_storage_set_byteorder().
650 *
651 * @param sp the storage to write too
652 * @param value the value read from the buffer
653 *
654 * @return 0 for success, or a Kerberos 5 error code on failure.
655 *
656 * @ingroup krb5_storage
657 */
658
659KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
660krb5_ret_uint16(krb5_storage *sp,
661		uint16_t *value)
662{
663    krb5_error_code ret;
664    int16_t v;
665
666    ret = krb5_ret_int16(sp, &v);
667    if (ret == 0)
668	*value = (uint16_t)v;
669
670    return ret;
671}
672
673/**
674 * Store a int8 to storage.
675 *
676 * @param sp the storage to write too
677 * @param value the value to store
678 *
679 * @return 0 for success, or a Kerberos 5 error code on failure.
680 *
681 * @ingroup krb5_storage
682 */
683
684KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
685krb5_store_int8(krb5_storage *sp,
686		int8_t value)
687{
688    int ret;
689
690    ret = sp->store(sp, &value, sizeof(value));
691    if (ret != sizeof(value))
692	return (ret<0)?errno:sp->eof_code;
693    return 0;
694}
695
696/**
697 * Store a uint8 to storage.
698 *
699 * @param sp the storage to write too
700 * @param value the value to store
701 *
702 * @return 0 for success, or a Kerberos 5 error code on failure.
703 *
704 * @ingroup krb5_storage
705 */
706
707KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
708krb5_store_uint8(krb5_storage *sp,
709		 uint8_t value)
710{
711    return krb5_store_int8(sp, (int8_t)value);
712}
713
714/**
715 * Read a int8 from storage
716 *
717 * @param sp the storage to write too
718 * @param value the value read from the buffer
719 *
720 * @return 0 for success, or a Kerberos 5 error code on failure.
721 *
722 * @ingroup krb5_storage
723 */
724
725KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
726krb5_ret_int8(krb5_storage *sp,
727	      int8_t *value)
728{
729    int ret;
730
731    ret = sp->fetch(sp, value, sizeof(*value));
732    if (ret != sizeof(*value))
733	return (ret<0)?errno:sp->eof_code;
734    return 0;
735}
736
737/**
738 * Read a uint8 from storage
739 *
740 * @param sp the storage to write too
741 * @param value the value read from the buffer
742 *
743 * @return 0 for success, or a Kerberos 5 error code on failure.
744 *
745 * @ingroup krb5_storage
746 */
747
748KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
749krb5_ret_uint8(krb5_storage *sp,
750	       uint8_t *value)
751{
752    krb5_error_code ret;
753    int8_t v;
754
755    ret = krb5_ret_int8(sp, &v);
756    if (ret == 0)
757	*value = (uint8_t)v;
758
759    return ret;
760}
761
762/**
763 * Store a data to the storage. The data is stored with an int32 as
764 * lenght plus the data (not padded).
765 *
766 * @param sp the storage buffer to write to
767 * @param data the buffer to store.
768 *
769 * @return 0 on success, a Kerberos 5 error code on failure.
770 *
771 * @ingroup krb5_storage
772 */
773
774KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
775krb5_store_data(krb5_storage *sp,
776		krb5_data data)
777{
778    int ret;
779    ret = krb5_store_int32(sp, data.length);
780    if(ret < 0)
781	return ret;
782    ret = sp->store(sp, data.data, data.length);
783    if(ret < 0)
784	return errno;
785    if((size_t)ret != data.length)
786	return sp->eof_code;
787    return 0;
788}
789
790/**
791 * Parse a data from the storage.
792 *
793 * @param sp the storage buffer to read from
794 * @param data the parsed data
795 *
796 * @return 0 on success, a Kerberos 5 error code on failure.
797 *
798 * @ingroup krb5_storage
799 */
800
801KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
802krb5_ret_data(krb5_storage *sp,
803	      krb5_data *data)
804{
805    int ret;
806    int32_t size;
807
808    ret = krb5_ret_int32(sp, &size);
809    if(ret)
810	return ret;
811    ret = size_too_large(sp, size);
812    if (ret)
813	return ret;
814    ret = krb5_data_alloc (data, size);
815    if (ret)
816	return ret;
817    if (size) {
818	ret = sp->fetch(sp, data->data, size);
819	if(ret != size) {
820            krb5_data_free(data);
821	    return (ret < 0)? errno : sp->eof_code;
822	}
823    }
824    return 0;
825}
826
827/**
828 * Store a string to the buffer. The data is formated as an len:uint32
829 * plus the string itself (not padded).
830 *
831 * @param sp the storage buffer to write to
832 * @param s the string to store.
833 *
834 * @return 0 on success, a Kerberos 5 error code on failure.
835 *
836 * @ingroup krb5_storage
837 */
838
839KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
840krb5_store_string(krb5_storage *sp, const char *s)
841{
842    krb5_data data;
843    data.length = strlen(s);
844    data.data = rk_UNCONST(s);
845    return krb5_store_data(sp, data);
846}
847
848/**
849 * Parse a string from the storage.
850 *
851 * @param sp the storage buffer to read from
852 * @param string the parsed string
853 *
854 * @return 0 on success, a Kerberos 5 error code on failure.
855 *
856 * @ingroup krb5_storage
857 */
858
859
860KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
861krb5_ret_string(krb5_storage *sp,
862		char **string)
863{
864    int ret;
865    krb5_data data;
866    ret = krb5_ret_data(sp, &data);
867    if(ret)
868	return ret;
869    *string = realloc(data.data, data.length + 1);
870    if(*string == NULL){
871	free(data.data);
872	return ENOMEM;
873    }
874    (*string)[data.length] = 0;
875    return 0;
876}
877
878/**
879 * Store a zero terminated string to the buffer. The data is stored
880 * one character at a time until a NUL is stored.
881 *
882 * @param sp the storage buffer to write to
883 * @param s the string to store.
884 *
885 * @return 0 on success, a Kerberos 5 error code on failure.
886 *
887 * @ingroup krb5_storage
888 */
889
890KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
891krb5_store_stringz(krb5_storage *sp, const char *s)
892{
893    size_t len = strlen(s) + 1;
894    ssize_t ret;
895
896    ret = sp->store(sp, s, len);
897    if(ret < 0)
898	return ret;
899    if((size_t)ret != len)
900	return sp->eof_code;
901    return 0;
902}
903
904/**
905 * Parse zero terminated string from the storage.
906 *
907 * @param sp the storage buffer to read from
908 * @param string the parsed string
909 *
910 * @return 0 on success, a Kerberos 5 error code on failure.
911 *
912 * @ingroup krb5_storage
913 */
914
915KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
916krb5_ret_stringz(krb5_storage *sp,
917		char **string)
918{
919    char c;
920    char *s = NULL;
921    size_t len = 0;
922    ssize_t ret;
923
924    while((ret = sp->fetch(sp, &c, 1)) == 1){
925	krb5_error_code eret;
926	char *tmp;
927
928	len++;
929	eret = size_too_large(sp, len);
930	if (eret) {
931	    free(s);
932	    return eret;
933	}
934	tmp = realloc (s, len);
935	if (tmp == NULL) {
936	    free (s);
937	    return ENOMEM;
938	}
939	s = tmp;
940	s[len - 1] = c;
941	if(c == 0)
942	    break;
943    }
944    if(ret != 1){
945	free(s);
946	if(ret == 0)
947	    return sp->eof_code;
948	return ret;
949    }
950    *string = s;
951    return 0;
952}
953
954KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
955krb5_store_stringnl(krb5_storage *sp, const char *s)
956{
957    size_t len = strlen(s);
958    ssize_t ret;
959
960    ret = sp->store(sp, s, len);
961    if(ret < 0)
962	return ret;
963    if((size_t)ret != len)
964	return sp->eof_code;
965    ret = sp->store(sp, "\n", 1);
966    if(ret != 1) {
967	if(ret < 0)
968	    return ret;
969	else
970	    return sp->eof_code;
971    }
972
973    return 0;
974
975}
976
977KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
978krb5_ret_stringnl(krb5_storage *sp,
979		  char **string)
980{
981    int expect_nl = 0;
982    char c;
983    char *s = NULL;
984    size_t len = 0;
985    ssize_t ret;
986
987    while((ret = sp->fetch(sp, &c, 1)) == 1){
988	krb5_error_code eret;
989	char *tmp;
990
991	if (c == '\r') {
992	    expect_nl = 1;
993	    continue;
994	}
995	if (expect_nl && c != '\n') {
996	    free(s);
997	    return KRB5_BADMSGTYPE;
998	}
999
1000	len++;
1001	eret = size_too_large(sp, len);
1002	if (eret) {
1003	    free(s);
1004	    return eret;
1005	}
1006	tmp = realloc (s, len);
1007	if (tmp == NULL) {
1008	    free (s);
1009	    return ENOMEM;
1010	}
1011	s = tmp;
1012	if(c == '\n') {
1013	    s[len - 1] = '\0';
1014	    break;
1015	}
1016	s[len - 1] = c;
1017    }
1018    if(ret != 1){
1019	free(s);
1020	if(ret == 0)
1021	    return sp->eof_code;
1022	return ret;
1023    }
1024    *string = s;
1025    return 0;
1026}
1027
1028/**
1029 * Write a principal block to storage.
1030 *
1031 * @param sp the storage buffer to write to
1032 * @param p the principal block to write.
1033 *
1034 * @return 0 on success, a Kerberos 5 error code on failure.
1035 *
1036 * @ingroup krb5_storage
1037 */
1038
1039KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1040krb5_store_principal(krb5_storage *sp,
1041		     krb5_const_principal p)
1042{
1043    size_t i;
1044    int ret;
1045
1046    if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
1047	ret = krb5_store_int32(sp, p->name.name_type);
1048	if(ret) return ret;
1049    }
1050    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
1051	ret = krb5_store_int32(sp, p->name.name_string.len + 1);
1052    else
1053	ret = krb5_store_int32(sp, p->name.name_string.len);
1054
1055    if(ret) return ret;
1056    ret = krb5_store_string(sp, p->realm);
1057    if(ret) return ret;
1058    for(i = 0; i < p->name.name_string.len; i++){
1059	ret = krb5_store_string(sp, p->name.name_string.val[i]);
1060	if(ret) return ret;
1061    }
1062    return 0;
1063}
1064
1065/**
1066 * Parse principal from the storage.
1067 *
1068 * @param sp the storage buffer to read from
1069 * @param princ the parsed principal
1070 *
1071 * @return 0 on success, a Kerberos 5 error code on failure.
1072 *
1073 * @ingroup krb5_storage
1074 */
1075
1076KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1077krb5_ret_principal(krb5_storage *sp,
1078		   krb5_principal *princ)
1079{
1080    int i;
1081    int ret;
1082    krb5_principal p;
1083    int32_t type;
1084    int32_t ncomp;
1085
1086    p = calloc(1, sizeof(*p));
1087    if(p == NULL)
1088	return ENOMEM;
1089
1090    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
1091	type = KRB5_NT_UNKNOWN;
1092    else if((ret = krb5_ret_int32(sp, &type))){
1093	free(p);
1094	return ret;
1095    }
1096    if((ret = krb5_ret_int32(sp, &ncomp))){
1097	free(p);
1098	return ret;
1099    }
1100    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
1101	ncomp--;
1102    if (ncomp < 0) {
1103	free(p);
1104	return EINVAL;
1105    }
1106    ret = size_too_large_num(sp, ncomp, sizeof(p->name.name_string.val[0]));
1107    if (ret) {
1108	free(p);
1109	return ret;
1110    }
1111    p->name.name_type = type;
1112    p->name.name_string.len = ncomp;
1113    ret = krb5_ret_string(sp, &p->realm);
1114    if(ret) {
1115	free(p);
1116	return ret;
1117    }
1118    p->name.name_string.val = calloc(ncomp, sizeof(p->name.name_string.val[0]));
1119    if(p->name.name_string.val == NULL && ncomp != 0){
1120	free(p->realm);
1121	free(p);
1122	return ENOMEM;
1123    }
1124    for(i = 0; i < ncomp; i++){
1125	ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
1126	if(ret) {
1127	    while (i >= 0)
1128		free(p->name.name_string.val[i--]);
1129	    free(p->realm);
1130	    free(p);
1131	    return ret;
1132	}
1133    }
1134    *princ = p;
1135    return 0;
1136}
1137
1138/**
1139 * Store a keyblock to the storage.
1140 *
1141 * @param sp the storage buffer to write to
1142 * @param p the keyblock to write
1143 *
1144 * @return 0 on success, a Kerberos 5 error code on failure.
1145 *
1146 * @ingroup krb5_storage
1147 */
1148
1149KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1150krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
1151{
1152    int ret;
1153    ret = krb5_store_int16(sp, p.keytype);
1154    if(ret) return ret;
1155
1156    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
1157	/* this should really be enctype, but it is the same as
1158           keytype nowadays */
1159    ret = krb5_store_int16(sp, p.keytype);
1160    if(ret) return ret;
1161    }
1162
1163    ret = krb5_store_data(sp, p.keyvalue);
1164    return ret;
1165}
1166
1167/**
1168 * Read a keyblock from the storage.
1169 *
1170 * @param sp the storage buffer to write to
1171 * @param p the keyblock read from storage, free using krb5_free_keyblock()
1172 *
1173 * @return 0 on success, a Kerberos 5 error code on failure.
1174 *
1175 * @ingroup krb5_storage
1176 */
1177
1178KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1179krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
1180{
1181    int ret;
1182    int16_t tmp;
1183
1184    ret = krb5_ret_int16(sp, &tmp);
1185    if(ret) return ret;
1186    p->keytype = tmp;
1187
1188    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
1189    ret = krb5_ret_int16(sp, &tmp);
1190    if(ret) return ret;
1191    }
1192
1193    ret = krb5_ret_data(sp, &p->keyvalue);
1194    return ret;
1195}
1196
1197/**
1198 * Write a times block to storage.
1199 *
1200 * @param sp the storage buffer to write to
1201 * @param times the times block to write.
1202 *
1203 * @return 0 on success, a Kerberos 5 error code on failure.
1204 *
1205 * @ingroup krb5_storage
1206 */
1207
1208KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1209krb5_store_times(krb5_storage *sp, krb5_times times)
1210{
1211    int ret;
1212    ret = krb5_store_int32(sp, times.authtime);
1213    if(ret) return ret;
1214    ret = krb5_store_int32(sp, times.starttime);
1215    if(ret) return ret;
1216    ret = krb5_store_int32(sp, times.endtime);
1217    if(ret) return ret;
1218    ret = krb5_store_int32(sp, times.renew_till);
1219    return ret;
1220}
1221
1222/**
1223 * Read a times block from the storage.
1224 *
1225 * @param sp the storage buffer to write to
1226 * @param times the times block read from storage
1227 *
1228 * @return 0 on success, a Kerberos 5 error code on failure.
1229 *
1230 * @ingroup krb5_storage
1231 */
1232
1233KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1234krb5_ret_times(krb5_storage *sp, krb5_times *times)
1235{
1236    int ret;
1237    int32_t tmp;
1238    ret = krb5_ret_int32(sp, &tmp);
1239    times->authtime = tmp;
1240    if(ret) return ret;
1241    ret = krb5_ret_int32(sp, &tmp);
1242    times->starttime = tmp;
1243    if(ret) return ret;
1244    ret = krb5_ret_int32(sp, &tmp);
1245    times->endtime = tmp;
1246    if(ret) return ret;
1247    ret = krb5_ret_int32(sp, &tmp);
1248    times->renew_till = tmp;
1249    return ret;
1250}
1251
1252/**
1253 * Write a address block to storage.
1254 *
1255 * @param sp the storage buffer to write to
1256 * @param p the address block to write.
1257 *
1258 * @return 0 on success, a Kerberos 5 error code on failure.
1259 *
1260 * @ingroup krb5_storage
1261 */
1262
1263KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1264krb5_store_address(krb5_storage *sp, krb5_address p)
1265{
1266    int ret;
1267    ret = krb5_store_int16(sp, p.addr_type);
1268    if(ret) return ret;
1269    ret = krb5_store_data(sp, p.address);
1270    return ret;
1271}
1272
1273/**
1274 * Read a address block from the storage.
1275 *
1276 * @param sp the storage buffer to write to
1277 * @param adr the address block read from storage
1278 *
1279 * @return 0 on success, a Kerberos 5 error code on failure.
1280 *
1281 * @ingroup krb5_storage
1282 */
1283
1284KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1285krb5_ret_address(krb5_storage *sp, krb5_address *adr)
1286{
1287    int16_t t;
1288    int ret;
1289    ret = krb5_ret_int16(sp, &t);
1290    if(ret) return ret;
1291    adr->addr_type = t;
1292    ret = krb5_ret_data(sp, &adr->address);
1293    return ret;
1294}
1295
1296/**
1297 * Write a addresses block to storage.
1298 *
1299 * @param sp the storage buffer to write to
1300 * @param p the addresses block to write.
1301 *
1302 * @return 0 on success, a Kerberos 5 error code on failure.
1303 *
1304 * @ingroup krb5_storage
1305 */
1306
1307KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1308krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
1309{
1310    size_t i;
1311    int ret;
1312    ret = krb5_store_int32(sp, p.len);
1313    if(ret) return ret;
1314    for(i = 0; i<p.len; i++){
1315	ret = krb5_store_address(sp, p.val[i]);
1316	if(ret) break;
1317    }
1318    return ret;
1319}
1320
1321/**
1322 * Read a addresses block from the storage.
1323 *
1324 * @param sp the storage buffer to write to
1325 * @param adr the addresses block read from storage
1326 *
1327 * @return 0 on success, a Kerberos 5 error code on failure.
1328 *
1329 * @ingroup krb5_storage
1330 */
1331
1332KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1333krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
1334{
1335    size_t i;
1336    int ret;
1337    int32_t tmp;
1338
1339    ret = krb5_ret_int32(sp, &tmp);
1340    if(ret) return ret;
1341    ret = size_too_large_num(sp, tmp, sizeof(adr->val[0]));
1342    if (ret) return ret;
1343    adr->len = tmp;
1344    ALLOC(adr->val, adr->len);
1345    if (adr->val == NULL && adr->len != 0)
1346	return ENOMEM;
1347    for(i = 0; i < adr->len; i++){
1348	ret = krb5_ret_address(sp, &adr->val[i]);
1349	if(ret) break;
1350    }
1351    return ret;
1352}
1353
1354/**
1355 * Write a auth data block to storage.
1356 *
1357 * @param sp the storage buffer to write to
1358 * @param auth the auth data block to write.
1359 *
1360 * @return 0 on success, a Kerberos 5 error code on failure.
1361 *
1362 * @ingroup krb5_storage
1363 */
1364
1365KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1366krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
1367{
1368    krb5_error_code ret;
1369    size_t i;
1370    ret = krb5_store_int32(sp, auth.len);
1371    if(ret) return ret;
1372    for(i = 0; i < auth.len; i++){
1373	ret = krb5_store_int16(sp, auth.val[i].ad_type);
1374	if(ret) break;
1375	ret = krb5_store_data(sp, auth.val[i].ad_data);
1376	if(ret) break;
1377    }
1378    return 0;
1379}
1380
1381/**
1382 * Read a auth data from the storage.
1383 *
1384 * @param sp the storage buffer to write to
1385 * @param auth the auth data block read from storage
1386 *
1387 * @return 0 on success, a Kerberos 5 error code on failure.
1388 *
1389 * @ingroup krb5_storage
1390 */
1391
1392KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1393krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
1394{
1395    krb5_error_code ret;
1396    int32_t tmp;
1397    int16_t tmp2;
1398    int i;
1399    ret = krb5_ret_int32(sp, &tmp);
1400    if(ret) return ret;
1401    ret = size_too_large_num(sp, tmp, sizeof(auth->val[0]));
1402    if (ret) return ret;
1403    ALLOC_SEQ(auth, tmp);
1404    if (auth->val == NULL && tmp != 0)
1405	return ENOMEM;
1406    for(i = 0; i < tmp; i++){
1407	ret = krb5_ret_int16(sp, &tmp2);
1408	if(ret) break;
1409	auth->val[i].ad_type = tmp2;
1410	ret = krb5_ret_data(sp, &auth->val[i].ad_data);
1411	if(ret) break;
1412    }
1413    return ret;
1414}
1415
1416static int32_t
1417bitswap32(int32_t b)
1418{
1419    int32_t r = 0;
1420    int i;
1421    for (i = 0; i < 32; i++) {
1422	r = r << 1 | (b & 1);
1423	b = b >> 1;
1424    }
1425    return r;
1426}
1427
1428/**
1429 * Write a credentials block to storage.
1430 *
1431 * @param sp the storage buffer to write to
1432 * @param creds the creds block to write.
1433 *
1434 * @return 0 on success, a Kerberos 5 error code on failure.
1435 *
1436 * @ingroup krb5_storage
1437 */
1438
1439KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1440krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
1441{
1442    int ret;
1443
1444    ret = krb5_store_principal(sp, creds->client);
1445    if(ret)
1446	return ret;
1447    ret = krb5_store_principal(sp, creds->server);
1448    if(ret)
1449	return ret;
1450    ret = krb5_store_keyblock(sp, creds->session);
1451    if(ret)
1452	return ret;
1453    ret = krb5_store_times(sp, creds->times);
1454    if(ret)
1455	return ret;
1456    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1457    if(ret)
1458	return ret;
1459    ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1460    if(ret)
1461	return ret;
1462    ret = krb5_store_addrs(sp, creds->addresses);
1463    if(ret)
1464	return ret;
1465    ret = krb5_store_authdata(sp, creds->authdata);
1466    if(ret)
1467	return ret;
1468    ret = krb5_store_data(sp, creds->ticket);
1469    if(ret)
1470	return ret;
1471    ret = krb5_store_data(sp, creds->second_ticket);
1472    return ret;
1473}
1474
1475/**
1476 * Read a credentials block from the storage.
1477 *
1478 * @param sp the storage buffer to write to
1479 * @param creds the credentials block read from storage
1480 *
1481 * @return 0 on success, a Kerberos 5 error code on failure.
1482 *
1483 * @ingroup krb5_storage
1484 */
1485
1486KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1487krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
1488{
1489    krb5_error_code ret;
1490    int8_t dummy8;
1491    int32_t dummy32;
1492
1493    memset(creds, 0, sizeof(*creds));
1494    ret = krb5_ret_principal (sp,  &creds->client);
1495    if(ret) goto cleanup;
1496    ret = krb5_ret_principal (sp,  &creds->server);
1497    if(ret) goto cleanup;
1498    ret = krb5_ret_keyblock (sp,  &creds->session);
1499    if(ret) goto cleanup;
1500    ret = krb5_ret_times (sp,  &creds->times);
1501    if(ret) goto cleanup;
1502    ret = krb5_ret_int8 (sp,  &dummy8);
1503    if(ret) goto cleanup;
1504    ret = krb5_ret_int32 (sp,  &dummy32);
1505    if(ret) goto cleanup;
1506    creds->flags.b = int2TicketFlags(bitswap32(dummy32));
1507    ret = krb5_ret_addrs (sp,  &creds->addresses);
1508    if(ret) goto cleanup;
1509    ret = krb5_ret_authdata (sp,  &creds->authdata);
1510    if(ret) goto cleanup;
1511    ret = krb5_ret_data (sp,  &creds->ticket);
1512    if(ret) goto cleanup;
1513    ret = krb5_ret_data (sp,  &creds->second_ticket);
1514cleanup:
1515    if(ret) {
1516#if 0
1517	krb5_free_cred_contents(context, creds); /* XXX */
1518#endif
1519    }
1520    return ret;
1521}
1522
1523#define SC_CLIENT_PRINCIPAL	    0x0001
1524#define SC_SERVER_PRINCIPAL	    0x0002
1525#define SC_SESSION_KEY		    0x0004
1526#define SC_TICKET		    0x0008
1527#define SC_SECOND_TICKET	    0x0010
1528#define SC_AUTHDATA		    0x0020
1529#define SC_ADDRESSES		    0x0040
1530
1531/**
1532 * Write a tagged credentials block to storage.
1533 *
1534 * @param sp the storage buffer to write to
1535 * @param creds the creds block to write.
1536 *
1537 * @return 0 on success, a Kerberos 5 error code on failure.
1538 *
1539 * @ingroup krb5_storage
1540 */
1541
1542KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1543krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
1544{
1545    int ret;
1546    int32_t header = 0;
1547
1548    if (creds->client)
1549	header |= SC_CLIENT_PRINCIPAL;
1550    if (creds->server)
1551	header |= SC_SERVER_PRINCIPAL;
1552    if (creds->session.keytype != ETYPE_NULL)
1553	header |= SC_SESSION_KEY;
1554    if (creds->ticket.data)
1555	header |= SC_TICKET;
1556    if (creds->second_ticket.length)
1557	header |= SC_SECOND_TICKET;
1558    if (creds->authdata.len)
1559	header |= SC_AUTHDATA;
1560    if (creds->addresses.len)
1561	header |= SC_ADDRESSES;
1562
1563    ret = krb5_store_int32(sp, header);
1564    if (ret)
1565	return ret;
1566
1567    if (creds->client) {
1568	ret = krb5_store_principal(sp, creds->client);
1569	if(ret)
1570	    return ret;
1571    }
1572
1573    if (creds->server) {
1574	ret = krb5_store_principal(sp, creds->server);
1575	if(ret)
1576	    return ret;
1577    }
1578
1579    if (creds->session.keytype != ETYPE_NULL) {
1580	ret = krb5_store_keyblock(sp, creds->session);
1581	if(ret)
1582	    return ret;
1583    }
1584
1585    ret = krb5_store_times(sp, creds->times);
1586    if(ret)
1587	return ret;
1588    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1589    if(ret)
1590	return ret;
1591
1592    ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1593    if(ret)
1594	return ret;
1595
1596    if (creds->addresses.len) {
1597	ret = krb5_store_addrs(sp, creds->addresses);
1598	if(ret)
1599	    return ret;
1600    }
1601
1602    if (creds->authdata.len) {
1603	ret = krb5_store_authdata(sp, creds->authdata);
1604	if(ret)
1605	    return ret;
1606    }
1607
1608    if (creds->ticket.data) {
1609	ret = krb5_store_data(sp, creds->ticket);
1610	if(ret)
1611	    return ret;
1612    }
1613
1614    if (creds->second_ticket.data) {
1615	ret = krb5_store_data(sp, creds->second_ticket);
1616	if (ret)
1617	    return ret;
1618    }
1619
1620    return ret;
1621}
1622
1623/**
1624 * Read a tagged credentials block from the storage.
1625 *
1626 * @param sp the storage buffer to write to
1627 * @param creds the credentials block read from storage
1628 *
1629 * @return 0 on success, a Kerberos 5 error code on failure.
1630 *
1631 * @ingroup krb5_storage
1632 */
1633
1634KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1635krb5_ret_creds_tag(krb5_storage *sp,
1636		   krb5_creds *creds)
1637{
1638    krb5_error_code ret;
1639    int8_t dummy8;
1640    int32_t dummy32, header;
1641
1642    memset(creds, 0, sizeof(*creds));
1643
1644    ret = krb5_ret_int32 (sp, &header);
1645    if (ret) goto cleanup;
1646
1647    if (header & SC_CLIENT_PRINCIPAL) {
1648	ret = krb5_ret_principal (sp,  &creds->client);
1649	if(ret) goto cleanup;
1650    }
1651    if (header & SC_SERVER_PRINCIPAL) {
1652	ret = krb5_ret_principal (sp,  &creds->server);
1653	if(ret) goto cleanup;
1654    }
1655    if (header & SC_SESSION_KEY) {
1656	ret = krb5_ret_keyblock (sp,  &creds->session);
1657	if(ret) goto cleanup;
1658    }
1659    ret = krb5_ret_times (sp,  &creds->times);
1660    if(ret) goto cleanup;
1661    ret = krb5_ret_int8 (sp,  &dummy8);
1662    if(ret) goto cleanup;
1663    ret = krb5_ret_int32 (sp,  &dummy32);
1664    if(ret) goto cleanup;
1665    creds->flags.b = int2TicketFlags(bitswap32(dummy32));
1666    if (header & SC_ADDRESSES) {
1667	ret = krb5_ret_addrs (sp,  &creds->addresses);
1668	if(ret) goto cleanup;
1669    }
1670    if (header & SC_AUTHDATA) {
1671	ret = krb5_ret_authdata (sp,  &creds->authdata);
1672	if(ret) goto cleanup;
1673    }
1674    if (header & SC_TICKET) {
1675	ret = krb5_ret_data (sp,  &creds->ticket);
1676	if(ret) goto cleanup;
1677    }
1678    if (header & SC_SECOND_TICKET) {
1679	ret = krb5_ret_data (sp,  &creds->second_ticket);
1680	if(ret) goto cleanup;
1681    }
1682
1683cleanup:
1684    if(ret) {
1685#if 0
1686	krb5_free_cred_contents(context, creds); /* XXX */
1687#endif
1688    }
1689    return ret;
1690}
1691