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