s4:heimdal: import lorikeet-heimdal-202201172009 (commit 5a0b45cd723628b3690ea848548b...
[samba.git] / source4 / heimdal / lib / krb5 / store.c
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 #define BYTEORDER_IS_PACKED(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_PACKED)
43
44 /**
45  * Add the flags on a storage buffer by or-ing in the flags to the buffer.
46  *
47  * @param sp the storage buffer to set the flags on
48  * @param flags the flags to set
49  *
50  * @ingroup krb5_storage
51  */
52
53 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
54 krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
55 {
56     sp->flags |= flags;
57 }
58
59 /**
60  * Clear the flags on a storage buffer
61  *
62  * @param sp the storage buffer to clear the flags on
63  * @param flags the flags to clear
64  *
65  * @ingroup krb5_storage
66  */
67
68 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
69 krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
70 {
71     sp->flags &= ~flags;
72 }
73
74 /**
75  * Return true or false depending on if the storage flags is set or
76  * not. NB testing for the flag 0 always return true.
77  *
78  * @param sp the storage buffer to check flags on
79  * @param flags The flags to test for
80  *
81  * @return true if all the flags are set, false if not.
82  *
83  * @ingroup krb5_storage
84  */
85
86 KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
87 krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
88 {
89     return (sp->flags & flags) == flags;
90 }
91
92 /**
93  * Set the new byte order of the storage buffer.
94  *
95  * @param sp the storage buffer to set the byte order for.
96  * @param byteorder the new byte order.
97  *
98  * The byte order are: KRB5_STORAGE_BYTEORDER_BE,
99  * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST.
100  *
101  * @ingroup krb5_storage
102  */
103
104 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
105 krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
106 {
107     sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
108     sp->flags |= byteorder;
109 }
110
111 /**
112  * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants.
113  *
114  * @ingroup krb5_storage
115  */
116
117 KRB5_LIB_FUNCTION krb5_flags KRB5_LIB_CALL
118 krb5_storage_get_byteorder(krb5_storage *sp)
119 {
120     return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
121 }
122
123 /**
124  * Set the max alloc value
125  *
126  * @param sp the storage buffer set the max allow for
127  * @param size maximum size to allocate, use 0 to remove limit
128  *
129  * @ingroup krb5_storage
130  */
131
132 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
133 krb5_storage_set_max_alloc(krb5_storage *sp, size_t size)
134 {
135     sp->max_alloc = size;
136 }
137
138 /* don't allocate unresonable amount of memory */
139 static krb5_error_code
140 size_too_large(krb5_storage *sp, size_t size)
141 {
142     if (sp->max_alloc && sp->max_alloc < size)
143         return HEIM_ERR_TOO_BIG;
144     return 0;
145 }
146
147 static krb5_error_code
148 size_too_large_num(krb5_storage *sp, size_t count, size_t size)
149 {
150     if (sp->max_alloc == 0 || size == 0)
151         return 0;
152     size = sp->max_alloc / size;
153     if (size < count)
154         return HEIM_ERR_TOO_BIG;
155     return 0;
156 }
157
158 /**
159  * Seek to a new offset.
160  *
161  * @param sp the storage buffer to seek in.
162  * @param offset the offset to seek
163  * @param whence relateive searching, SEEK_CUR from the current
164  * position, SEEK_END from the end, SEEK_SET absolute from the start.
165  *
166  * @return The new current offset
167  *
168  * @ingroup krb5_storage
169  */
170
171 KRB5_LIB_FUNCTION off_t KRB5_LIB_CALL
172 krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
173 {
174     return (*sp->seek)(sp, offset, whence);
175 }
176
177 /**
178  * Truncate the storage buffer in sp to offset.
179  *
180  * @param sp the storage buffer to truncate.
181  * @param offset the offset to truncate too.
182  *
183  * @return An Kerberos 5 error code.
184  *
185  * @ingroup krb5_storage
186  */
187
188 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
189 krb5_storage_truncate(krb5_storage *sp, off_t offset)
190 {
191     return (*sp->trunc)(sp, offset);
192 }
193
194 /**
195  * Sync the storage buffer to its backing store.  If there is no
196  * backing store this function will return success.
197  *
198  * @param sp the storage buffer to sync
199  *
200  * @return A Kerberos 5 error code
201  *
202  * @ingroup krb5_storage
203  */
204
205 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
206 krb5_storage_fsync(krb5_storage *sp)
207 {
208     if (sp->fsync != NULL)
209         return sp->fsync(sp);
210     return 0;
211 }
212
213 /**
214  * Read to the storage buffer.
215  *
216  * @param sp the storage buffer to read from
217  * @param buf the buffer to store the data in
218  * @param len the length to read
219  *
220  * @return The length of data read (can be shorter then len), or negative on error.
221  *
222  * @ingroup krb5_storage
223  */
224
225 KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
226 krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
227 {
228     return sp->fetch(sp, buf, len);
229 }
230
231 /**
232  * Write to the storage buffer.
233  *
234  * @param sp the storage buffer to write to
235  * @param buf the buffer to write to the storage buffer
236  * @param len the length to write
237  *
238  * @return The length of data written (can be shorter then len), or negative on error.
239  *
240  * @ingroup krb5_storage
241  */
242
243 KRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
244 krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
245 {
246     return sp->store(sp, buf, len);
247 }
248
249 /**
250  * Set the return code that will be used when end of storage is reached.
251  *
252  * @param sp the storage
253  * @param code the error code to return on end of storage
254  *
255  * @ingroup krb5_storage
256  */
257
258 KRB5_LIB_FUNCTION void KRB5_LIB_CALL
259 krb5_storage_set_eof_code(krb5_storage *sp, int code)
260 {
261     sp->eof_code = code;
262 }
263
264 /**
265  * Get the return code that will be used when end of storage is reached.
266  *
267  * @param sp the storage
268  *
269  * @return storage error code
270  *
271  * @ingroup krb5_storage
272  */
273
274 KRB5_LIB_FUNCTION int KRB5_LIB_CALL
275 krb5_storage_get_eof_code(krb5_storage *sp)
276 {
277     return sp->eof_code;
278 }
279
280 /**
281  * Free a krb5 storage.
282  *
283  * @param sp the storage to free.
284  *
285  * @return An Kerberos 5 error code.
286  *
287  * @ingroup krb5_storage
288  */
289
290 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
291 krb5_storage_free(krb5_storage *sp)
292 {
293     if (sp == NULL)
294         return 0;
295     if(sp->free)
296         (*sp->free)(sp);
297     free(sp->data);
298     free(sp);
299     return 0;
300 }
301
302 /**
303  * Copy the contnent of storage
304  *
305  * @param sp the storage to copy to a data
306  * @param data the copied data, free with krb5_data_free()
307  *
308  * @return 0 for success, or a Kerberos 5 error code on failure.
309  *
310  * @ingroup krb5_storage
311  */
312
313 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
314 krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
315 {
316     off_t pos, size;
317     krb5_error_code ret;
318
319     pos = sp->seek(sp, 0, SEEK_CUR);
320     if (pos < 0)
321         return HEIM_ERR_NOT_SEEKABLE;
322     size = sp->seek(sp, 0, SEEK_END);
323     ret = size_too_large(sp, size);
324     if (ret)
325         return ret;
326     ret = krb5_data_alloc(data, size);
327     if (ret) {
328         sp->seek(sp, pos, SEEK_SET);
329         return ret;
330     }
331     if (size) {
332         sp->seek(sp, 0, SEEK_SET);
333         sp->fetch(sp, data->data, data->length);
334         sp->seek(sp, pos, SEEK_SET);
335     }
336     return 0;
337 }
338
339 static size_t
340 pack_int(uint8_t *p, uint64_t val)
341 {
342     size_t l = 0;
343
344     if (val < 128) {
345         *p = val;
346     } else {
347         while (val > 0) {
348             *p-- = val % 256;
349             val /= 256;
350             l++;
351         }
352         *p = 0x80 | l;
353     }
354     return l + 1;
355 }
356
357 static size_t
358 unpack_int_length(uint8_t *v)
359 {
360     size_t size;
361
362     if (*v < 128)
363         size = 0;
364     else
365         size = *v & 0x7f;
366
367     return size + 1;
368 }
369
370 static int
371 unpack_int(uint8_t *p, size_t len, uint64_t *val, size_t *size)
372 {
373     size_t v;
374
375     if (len == 0)
376         return EINVAL;
377     --len;
378     v = *p++;
379     if (v < 128) {
380         *val = v;
381         *size = 1;
382     } else {
383         int e;
384         size_t l;
385         uint64_t tmp;
386
387         if (v == 0x80) {
388             *size = 1;
389             return EINVAL;
390         }
391         v &= 0x7F;
392         if (len < v)
393             return ERANGE;
394         e = der_get_unsigned64(p, v, &tmp, &l);
395         if (e)
396             return ERANGE;
397         *val = tmp;
398         *size = l + 1;
399     }
400     return 0;
401 }
402
403 static krb5_error_code
404 krb5_store_int(krb5_storage *sp,
405                int64_t value,
406                size_t len)
407 {
408     int ret;
409     uint8_t v[9], *p = v;
410
411     if (len > sizeof(value))
412         return EINVAL;
413
414     if (BYTEORDER_IS_PACKED(sp)) {
415         uint64_t mask = ~0ULL >> (64 - len * 8);
416         value &= mask;
417         p += sizeof(v) - 1;
418         len = pack_int(p, value);
419         p = v + sizeof(v) - len;
420     } else
421         _krb5_put_int(v, value, len);
422     ret = sp->store(sp, p, len);
423     if (ret < 0)
424         return errno;
425     if ((size_t)ret != len)
426         return sp->eof_code;
427     return 0;
428 }
429
430 /**
431  * Store a int32 to storage, byte order is controlled by the settings
432  * on the storage, see krb5_storage_set_byteorder().
433  *
434  * @param sp the storage to write too
435  * @param value the value to store
436  *
437  * @return 0 for success, or a Kerberos 5 error code on failure.
438  *
439  * @ingroup krb5_storage
440  */
441
442 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
443 krb5_store_int32(krb5_storage *sp,
444                  int32_t value)
445 {
446     if(BYTEORDER_IS_HOST(sp))
447         value = htonl(value);
448     else if(BYTEORDER_IS_LE(sp))
449         value = bswap32(value);
450     return krb5_store_int(sp, value, 4);
451 }
452
453 /**
454  * Store a int64 to storage, byte order is controlled by the settings
455  * on the storage, see krb5_storage_set_byteorder().
456  *
457  * @param sp the storage to write too
458  * @param value the value to store
459  *
460  * @return 0 for success, or a Kerberos 5 error code on failure.
461  *
462  * @ingroup krb5_storage
463  */
464
465 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
466 krb5_store_int64(krb5_storage *sp,
467                  int64_t value)
468 {
469     if (BYTEORDER_IS_HOST(sp))
470 #ifdef WORDS_BIGENDIAN
471         ;
472 #else
473         value = bswap64(value); /* There's no ntohll() */
474 #endif
475     else if (BYTEORDER_IS_LE(sp))
476         value = bswap64(value);
477     return krb5_store_int(sp, value, 8);
478 }
479
480 /**
481  * Store a uint32 to storage, byte order is controlled by the settings
482  * on the storage, see krb5_storage_set_byteorder().
483  *
484  * @param sp the storage to write too
485  * @param value the value to store
486  *
487  * @return 0 for success, or a Kerberos 5 error code on failure.
488  *
489  * @ingroup krb5_storage
490  */
491
492 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
493 krb5_store_uint32(krb5_storage *sp,
494                   uint32_t value)
495 {
496     return krb5_store_int32(sp, (int32_t)value);
497 }
498
499 /**
500  * Store a uint64 to storage, byte order is controlled by the settings
501  * on the storage, see krb5_storage_set_byteorder().
502  *
503  * @param sp the storage to write too
504  * @param value the value to store
505  *
506  * @return 0 for success, or a Kerberos 5 error code on failure.
507  *
508  * @ingroup krb5_storage
509  */
510
511 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
512 krb5_store_uint64(krb5_storage *sp,
513                   uint64_t value)
514 {
515     return krb5_store_int64(sp, (int64_t)value);
516 }
517
518 static krb5_error_code
519 krb5_ret_int(krb5_storage *sp,
520              int64_t *value,
521              size_t len)
522 {
523     int ret;
524     unsigned char v[9];
525     uint64_t w = 0;
526     *value = 0; /* quiets warnings */
527     if (BYTEORDER_IS_PACKED(sp)) {
528         ret = sp->fetch(sp, v, 1);
529         if (ret < 0)
530             return errno;
531
532         len = unpack_int_length(v);
533         if (len < 1)
534             return ERANGE;
535         else if (len > 1) {
536             ret = sp->fetch(sp, v + 1, len - 1);
537             if (ret < 0)
538                 return errno;
539         }
540         ret = unpack_int(v, len, &w, &len);
541         if (ret)
542             return ret;
543         *value = w;
544         return 0;
545     }
546     ret = sp->fetch(sp, v, len);
547     if (ret < 0)
548         return errno;
549     if ((size_t)ret != len)
550         return sp->eof_code;
551     _krb5_get_int64(v, &w, len);
552     *value = w;
553     return 0;
554 }
555
556 /**
557  * Read a int64 from storage, byte order is controlled by the settings
558  * on the storage, see krb5_storage_set_byteorder().
559  *
560  * @param sp the storage to write too
561  * @param value the value read from the buffer
562  *
563  * @return 0 for success, or a Kerberos 5 error code on failure.
564  *
565  * @ingroup krb5_storage
566  */
567
568 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
569 krb5_ret_int64(krb5_storage *sp,
570                int64_t *value)
571 {
572     krb5_error_code ret = krb5_ret_int(sp, value, 8);
573     if(ret)
574         return ret;
575     if(BYTEORDER_IS_HOST(sp))
576 #ifdef WORDS_BIGENDIAN
577         ;
578 #else
579         *value = bswap64(*value); /* There's no ntohll() */
580 #endif
581     else if(BYTEORDER_IS_LE(sp))
582         *value = bswap64(*value);
583     return 0;
584 }
585
586 /**
587  * Read a uint64 from storage, byte order is controlled by the settings
588  * on the storage, see krb5_storage_set_byteorder().
589  *
590  * @param sp the storage to write too
591  * @param value the value read from the buffer
592  *
593  * @return 0 for success, or a Kerberos 5 error code on failure.
594  *
595  * @ingroup krb5_storage
596  */
597
598 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
599 krb5_ret_uint64(krb5_storage *sp,
600                 uint64_t *value)
601 {
602     krb5_error_code ret;
603     int64_t v;
604
605     ret = krb5_ret_int64(sp, &v);
606     if (ret == 0)
607         *value = (uint64_t)v;
608
609     return ret;
610 }
611
612 /**
613  * Read a int32 from storage, byte order is controlled by the settings
614  * on the storage, see krb5_storage_set_byteorder().
615  *
616  * @param sp the storage to write too
617  * @param value the value read from the buffer
618  *
619  * @return 0 for success, or a Kerberos 5 error code on failure.
620  *
621  * @ingroup krb5_storage
622  */
623
624 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
625 krb5_ret_int32(krb5_storage *sp,
626                int32_t *value)
627 {
628     int64_t v;
629
630     krb5_error_code ret = krb5_ret_int(sp, &v, 4);
631     if (ret)
632         return ret;
633     *value = v;
634     if (BYTEORDER_IS_HOST(sp))
635         *value = htonl(*value);
636     else if (BYTEORDER_IS_LE(sp))
637         *value = bswap32(*value);
638     return 0;
639 }
640
641 /**
642  * Read a uint32 from storage, byte order is controlled by the settings
643  * on the storage, see krb5_storage_set_byteorder().
644  *
645  * @param sp the storage to write too
646  * @param value the value read from the buffer
647  *
648  * @return 0 for success, or a Kerberos 5 error code on failure.
649  *
650  * @ingroup krb5_storage
651  */
652
653 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
654 krb5_ret_uint32(krb5_storage *sp, uint32_t *value)
655 {
656     krb5_error_code ret;
657     int32_t v;
658
659     ret = krb5_ret_int32(sp, &v);
660     if (ret == 0)
661         *value = (uint32_t)v;
662
663     return ret;
664 }
665
666 /**
667  * Store a int16 to storage, byte order is controlled by the settings
668  * on the storage, see krb5_storage_set_byteorder().
669  *
670  * @param sp the storage to write too
671  * @param value the value to store
672  *
673  * @return 0 for success, or a Kerberos 5 error code on failure.
674  *
675  * @ingroup krb5_storage
676  */
677
678 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
679 krb5_store_int16(krb5_storage *sp,
680                  int16_t value)
681 {
682     if(BYTEORDER_IS_HOST(sp))
683         value = htons(value);
684     else if(BYTEORDER_IS_LE(sp))
685         value = bswap16(value);
686     return krb5_store_int(sp, value, 2);
687 }
688
689 /**
690  * Store a uint16 to storage, byte order is controlled by the settings
691  * on the storage, see krb5_storage_set_byteorder().
692  *
693  * @param sp the storage to write too
694  * @param value the value to store
695  *
696  * @return 0 for success, or a Kerberos 5 error code on failure.
697  *
698  * @ingroup krb5_storage
699  */
700
701 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
702 krb5_store_uint16(krb5_storage *sp,
703                   uint16_t value)
704 {
705     return krb5_store_int16(sp, (int16_t)value);
706 }
707
708 /**
709  * Read a int16 from storage, byte order is controlled by the settings
710  * on the storage, see krb5_storage_set_byteorder().
711  *
712  * @param sp the storage to write too
713  * @param value the value read from the buffer
714  *
715  * @return 0 for success, or a Kerberos 5 error code on failure.
716  *
717  * @ingroup krb5_storage
718  */
719
720 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
721 krb5_ret_int16(krb5_storage *sp,
722                int16_t *value)
723 {
724     int64_t v;
725     int ret;
726     ret = krb5_ret_int(sp, &v, 2);
727     if(ret)
728         return ret;
729     *value = v;
730     if(BYTEORDER_IS_HOST(sp))
731         *value = htons(*value);
732     else if(BYTEORDER_IS_LE(sp))
733         *value = bswap16(*value);
734     return 0;
735 }
736
737 /**
738  * Read a int16 from storage, byte order is controlled by the settings
739  * on the storage, see krb5_storage_set_byteorder().
740  *
741  * @param sp the storage to write too
742  * @param value the value read from the buffer
743  *
744  * @return 0 for success, or a Kerberos 5 error code on failure.
745  *
746  * @ingroup krb5_storage
747  */
748
749 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
750 krb5_ret_uint16(krb5_storage *sp,
751                 uint16_t *value)
752 {
753     krb5_error_code ret;
754     int16_t v;
755
756     ret = krb5_ret_int16(sp, &v);
757     if (ret == 0)
758         *value = (uint16_t)v;
759
760     return ret;
761 }
762
763 /**
764  * Store a int8 to storage.
765  *
766  * @param sp the storage to write too
767  * @param value the value to store
768  *
769  * @return 0 for success, or a Kerberos 5 error code on failure.
770  *
771  * @ingroup krb5_storage
772  */
773
774 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
775 krb5_store_int8(krb5_storage *sp,
776                 int8_t value)
777 {
778     int ret;
779
780     ret = sp->store(sp, &value, sizeof(value));
781     if (ret != sizeof(value))
782         return (ret<0)?errno:sp->eof_code;
783     return 0;
784 }
785
786 /**
787  * Store a uint8 to storage.
788  *
789  * @param sp the storage to write too
790  * @param value the value to store
791  *
792  * @return 0 for success, or a Kerberos 5 error code on failure.
793  *
794  * @ingroup krb5_storage
795  */
796
797 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
798 krb5_store_uint8(krb5_storage *sp,
799                  uint8_t value)
800 {
801     return krb5_store_int8(sp, (int8_t)value);
802 }
803
804 /**
805  * Read a int8 from storage
806  *
807  * @param sp the storage to write too
808  * @param value the value read from the buffer
809  *
810  * @return 0 for success, or a Kerberos 5 error code on failure.
811  *
812  * @ingroup krb5_storage
813  */
814
815 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
816 krb5_ret_int8(krb5_storage *sp,
817               int8_t *value)
818 {
819     int ret;
820
821     ret = sp->fetch(sp, value, sizeof(*value));
822     if (ret != sizeof(*value))
823         return (ret<0)?errno:sp->eof_code;
824     return 0;
825 }
826
827 /**
828  * Read a uint8 from storage
829  *
830  * @param sp the storage to write too
831  * @param value the value read from the buffer
832  *
833  * @return 0 for success, or a Kerberos 5 error code on failure.
834  *
835  * @ingroup krb5_storage
836  */
837
838 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
839 krb5_ret_uint8(krb5_storage *sp,
840                uint8_t *value)
841 {
842     krb5_error_code ret;
843     int8_t v;
844
845     ret = krb5_ret_int8(sp, &v);
846     if (ret == 0)
847         *value = (uint8_t)v;
848
849     return ret;
850 }
851
852 /**
853  * Store a data to the storage. The data is stored with an int32 as
854  * lenght plus the data (not padded).
855  *
856  * @param sp the storage buffer to write to
857  * @param data the buffer to store.
858  *
859  * @return 0 on success, a Kerberos 5 error code on failure.
860  *
861  * @ingroup krb5_storage
862  */
863
864 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
865 krb5_store_data(krb5_storage *sp,
866                 krb5_data data)
867 {
868     int ret;
869     ret = krb5_store_int32(sp, data.length);
870     if(ret < 0)
871         return ret;
872     ret = sp->store(sp, data.data, data.length);
873     if(ret < 0)
874         return errno;
875     if((size_t)ret != data.length)
876         return sp->eof_code;
877     return 0;
878 }
879
880 /**
881  * Store a data blob to the storage. The data is stored with an int32 as
882  * length plus the data (not padded).  This function only differs from
883  * krb5_store_data() insofar as it takes a void * and a length as parameters.
884  *
885  * @param sp the storage buffer to write to
886  * @param s the string to store.
887  * @param len length of the string to be stored.
888  *
889  * @return 0 on success, a Kerberos 5 error code on failure.
890  *
891  * @ingroup krb5_storage
892  */
893 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
894 krb5_store_datalen(krb5_storage *sp, const void *d, size_t len)
895 {
896     krb5_data data;
897     data.length = len;
898     data.data = (void *)d;
899     return krb5_store_data(sp, data);
900 }
901
902 /**
903  * Store a data blob to the storage. The data is stored without a length.
904  *
905  * @param sp the storage buffer to write to
906  * @param s the string to store.
907  * @param len length of the string to be stored.
908  *
909  * @return 0 on success, a Kerberos 5 error code on failure.
910  *
911  * @ingroup krb5_storage
912  */
913 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
914 krb5_store_bytes(krb5_storage *sp, const void *d, size_t len)
915 {
916     ssize_t ssize;
917
918     ssize = krb5_storage_write(sp, d, len);
919     if (ssize != len)
920         return ENOMEM;
921
922     return 0;
923 }
924
925 /**
926  * Parse a data from the storage.
927  *
928  * @param sp the storage buffer to read from
929  * @param data the parsed data
930  *
931  * @return 0 on success, a Kerberos 5 error code on failure.
932  *
933  * @ingroup krb5_storage
934  */
935
936 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
937 krb5_ret_data(krb5_storage *sp,
938               krb5_data *data)
939 {
940     int ret;
941     int32_t size;
942
943     ret = krb5_ret_int32(sp, &size);
944     if(ret)
945         return ret;
946     ret = size_too_large(sp, size);
947     if (ret)
948         return ret;
949     ret = krb5_data_alloc (data, size);
950     if (ret)
951         return ret;
952     if (size) {
953         ret = sp->fetch(sp, data->data, size);
954         if(ret != size) {
955             krb5_data_free(data);
956             return (ret < 0)? errno : sp->eof_code;
957         }
958     }
959     return 0;
960 }
961
962 /**
963  * Store a string to the buffer. The data is formated as an len:uint32
964  * plus the string itself (not padded).
965  *
966  * @param sp the storage buffer to write to
967  * @param s the string to store.
968  *
969  * @return 0 on success, a Kerberos 5 error code on failure.
970  *
971  * @ingroup krb5_storage
972  */
973
974 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
975 krb5_store_string(krb5_storage *sp, const char *s)
976 {
977     krb5_data data;
978     data.length = strlen(s);
979     data.data = rk_UNCONST(s);
980     return krb5_store_data(sp, data);
981 }
982
983 /**
984  * Parse a string from the storage.
985  *
986  * @param sp the storage buffer to read from
987  * @param string the parsed string
988  *
989  * @return 0 on success, a Kerberos 5 error code on failure.
990  *
991  * @ingroup krb5_storage
992  */
993
994
995 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
996 krb5_ret_string(krb5_storage *sp,
997                 char **string)
998 {
999     int ret;
1000     krb5_data data;
1001     ret = krb5_ret_data(sp, &data);
1002     if(ret)
1003         return ret;
1004     *string = realloc(data.data, data.length + 1);
1005     if(*string == NULL){
1006         free(data.data);
1007         return ENOMEM;
1008     }
1009     (*string)[data.length] = 0;
1010     return 0;
1011 }
1012
1013 /**
1014  * Store a zero terminated string to the buffer. The data is stored
1015  * one character at a time until a NUL is stored.
1016  *
1017  * @param sp the storage buffer to write to
1018  * @param s the string to store.
1019  *
1020  * @return 0 on success, a Kerberos 5 error code on failure.
1021  *
1022  * @ingroup krb5_storage
1023  */
1024
1025 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1026 krb5_store_stringz(krb5_storage *sp, const char *s)
1027 {
1028     size_t len = strlen(s) + 1;
1029     ssize_t ret;
1030
1031     ret = sp->store(sp, s, len);
1032     if(ret < 0)
1033         return ret;
1034     if((size_t)ret != len)
1035         return sp->eof_code;
1036     return 0;
1037 }
1038
1039 /**
1040  * Parse zero terminated string from the storage.
1041  *
1042  * @param sp the storage buffer to read from
1043  * @param string the parsed string
1044  *
1045  * @return 0 on success, a Kerberos 5 error code on failure.
1046  *
1047  * @ingroup krb5_storage
1048  */
1049
1050 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1051 krb5_ret_stringz(krb5_storage *sp,
1052                 char **string)
1053 {
1054     char c;
1055     char *s = NULL;
1056     size_t len = 0;
1057     ssize_t ret;
1058
1059     while((ret = sp->fetch(sp, &c, 1)) == 1){
1060         krb5_error_code eret;
1061         char *tmp;
1062
1063         len++;
1064         eret = size_too_large(sp, len);
1065         if (eret) {
1066             free(s);
1067             return eret;
1068         }
1069         tmp = realloc (s, len);
1070         if (tmp == NULL) {
1071             free (s);
1072             return ENOMEM;
1073         }
1074         s = tmp;
1075         s[len - 1] = c;
1076         if(c == 0)
1077             break;
1078     }
1079     if(ret != 1){
1080         free(s);
1081         if(ret == 0)
1082             return sp->eof_code;
1083         return ret;
1084     }
1085     *string = s;
1086     return 0;
1087 }
1088
1089 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1090 krb5_store_stringnl(krb5_storage *sp, const char *s)
1091 {
1092     size_t len = strlen(s);
1093     ssize_t ret;
1094
1095     ret = sp->store(sp, s, len);
1096     if(ret < 0)
1097         return ret;
1098     if((size_t)ret != len)
1099         return sp->eof_code;
1100     ret = sp->store(sp, "\n", 1);
1101     if(ret != 1) {
1102         if(ret < 0)
1103             return ret;
1104         else
1105             return sp->eof_code;
1106     }
1107
1108     return 0;
1109
1110 }
1111
1112 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1113 krb5_ret_stringnl(krb5_storage *sp,
1114                   char **string)
1115 {
1116     int expect_nl = 0;
1117     char c;
1118     char *s = NULL;
1119     size_t len = 0;
1120     ssize_t ret;
1121
1122     while((ret = sp->fetch(sp, &c, 1)) == 1){
1123         krb5_error_code eret;
1124         char *tmp;
1125
1126         if (c == '\r') {
1127             expect_nl = 1;
1128             continue;
1129         }
1130         if (expect_nl && c != '\n') {
1131             free(s);
1132             return KRB5_BADMSGTYPE;
1133         }
1134
1135         len++;
1136         eret = size_too_large(sp, len);
1137         if (eret) {
1138             free(s);
1139             return eret;
1140         }
1141         tmp = realloc (s, len);
1142         if (tmp == NULL) {
1143             free (s);
1144             return ENOMEM;
1145         }
1146         s = tmp;
1147         if(c == '\n') {
1148             s[len - 1] = '\0';
1149             break;
1150         }
1151         s[len - 1] = c;
1152     }
1153     if(ret != 1){
1154         free(s);
1155         if(ret == 0)
1156             return sp->eof_code;
1157         return ret;
1158     }
1159     *string = s;
1160     return 0;
1161 }
1162
1163 /**
1164  * Write a principal block to storage.
1165  *
1166  * @param sp the storage buffer to write to
1167  * @param p the principal block to write.
1168  *
1169  * @return 0 on success, a Kerberos 5 error code on failure.
1170  *
1171  * @ingroup krb5_storage
1172  */
1173
1174 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1175 krb5_store_principal(krb5_storage *sp,
1176                      krb5_const_principal p)
1177 {
1178     size_t i;
1179     int ret;
1180
1181     if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
1182         ret = krb5_store_int32(sp, p->name.name_type);
1183         if(ret) return ret;
1184     }
1185     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
1186         ret = krb5_store_int32(sp, p->name.name_string.len + 1);
1187     else
1188         ret = krb5_store_int32(sp, p->name.name_string.len);
1189
1190     if(ret) return ret;
1191     ret = krb5_store_string(sp, p->realm);
1192     if(ret) return ret;
1193     for(i = 0; i < p->name.name_string.len; i++){
1194         ret = krb5_store_string(sp, p->name.name_string.val[i]);
1195         if(ret) return ret;
1196     }
1197     return 0;
1198 }
1199
1200 /**
1201  * Parse principal from the storage.
1202  *
1203  * @param sp the storage buffer to read from
1204  * @param princ the parsed principal
1205  *
1206  * @return 0 on success, a Kerberos 5 error code on failure.
1207  *
1208  * @ingroup krb5_storage
1209  */
1210
1211 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1212 krb5_ret_principal(krb5_storage *sp,
1213                    krb5_principal *princ)
1214 {
1215     int i;
1216     int ret;
1217     krb5_principal p;
1218     int32_t type;
1219     int32_t ncomp;
1220
1221     p = calloc(1, sizeof(*p));
1222     if(p == NULL)
1223         return ENOMEM;
1224
1225     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
1226         type = KRB5_NT_UNKNOWN;
1227     else if((ret = krb5_ret_int32(sp, &type))){
1228         free(p);
1229         return ret;
1230     }
1231     if((ret = krb5_ret_int32(sp, &ncomp))){
1232         free(p);
1233         return ret;
1234     }
1235     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
1236         ncomp--;
1237     if (ncomp < 0) {
1238         free(p);
1239         return EINVAL;
1240     }
1241     ret = size_too_large_num(sp, ncomp, sizeof(p->name.name_string.val[0]));
1242     if (ret) {
1243         free(p);
1244         return ret;
1245     }
1246     p->name.name_type = type;
1247     p->name.name_string.len = ncomp;
1248     ret = krb5_ret_string(sp, &p->realm);
1249     if(ret) {
1250         free(p);
1251         return ret;
1252     }
1253     p->name.name_string.val = calloc(ncomp, sizeof(p->name.name_string.val[0]));
1254     if(p->name.name_string.val == NULL && ncomp != 0){
1255         free(p->realm);
1256         free(p);
1257         return ENOMEM;
1258     }
1259     for(i = 0; i < ncomp; i++){
1260         ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
1261         if(ret) {
1262             while (i >= 0)
1263                 free(p->name.name_string.val[i--]);
1264             free(p->realm);
1265             free(p);
1266             return ret;
1267         }
1268     }
1269     *princ = p;
1270     return 0;
1271 }
1272
1273 /**
1274  * Store a keyblock to the storage.
1275  *
1276  * @param sp the storage buffer to write to
1277  * @param p the keyblock to write
1278  *
1279  * @return 0 on success, a Kerberos 5 error code on failure.
1280  *
1281  * @ingroup krb5_storage
1282  */
1283
1284 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1285 krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
1286 {
1287     int ret;
1288     ret = krb5_store_int16(sp, p.keytype);
1289     if(ret) return ret;
1290
1291     if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
1292         /* this should really be enctype, but it is the same as
1293            keytype nowadays */
1294     ret = krb5_store_int16(sp, p.keytype);
1295     if(ret) return ret;
1296     }
1297
1298     ret = krb5_store_data(sp, p.keyvalue);
1299     return ret;
1300 }
1301
1302 /**
1303  * Read a keyblock from the storage.
1304  *
1305  * @param sp the storage buffer to write to
1306  * @param p the keyblock read from storage, free using krb5_free_keyblock()
1307  *
1308  * @return 0 on success, a Kerberos 5 error code on failure.
1309  *
1310  * @ingroup krb5_storage
1311  */
1312
1313 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1314 krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
1315 {
1316     int ret;
1317     int16_t tmp;
1318
1319     ret = krb5_ret_int16(sp, &tmp);
1320     if(ret) return ret;
1321     p->keytype = tmp;
1322
1323     if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
1324     ret = krb5_ret_int16(sp, &tmp);
1325     if(ret) return ret;
1326     }
1327
1328     ret = krb5_ret_data(sp, &p->keyvalue);
1329     return ret;
1330 }
1331
1332 /**
1333  * Write a times block to storage.
1334  *
1335  * @param sp the storage buffer to write to
1336  * @param times the times block to write.
1337  *
1338  * @return 0 on success, a Kerberos 5 error code on failure.
1339  *
1340  * @ingroup krb5_storage
1341  */
1342
1343 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1344 krb5_store_times(krb5_storage *sp, krb5_times times)
1345 {
1346     int ret;
1347     ret = krb5_store_int32(sp, times.authtime);
1348     if(ret) return ret;
1349     ret = krb5_store_int32(sp, times.starttime);
1350     if(ret) return ret;
1351     ret = krb5_store_int32(sp, times.endtime);
1352     if(ret) return ret;
1353     ret = krb5_store_int32(sp, times.renew_till);
1354     return ret;
1355 }
1356
1357 /**
1358  * Read a times block from the storage.
1359  *
1360  * @param sp the storage buffer to write to
1361  * @param times the times block read from storage
1362  *
1363  * @return 0 on success, a Kerberos 5 error code on failure.
1364  *
1365  * @ingroup krb5_storage
1366  */
1367
1368 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1369 krb5_ret_times(krb5_storage *sp, krb5_times *times)
1370 {
1371     int ret;
1372     int32_t tmp;
1373     ret = krb5_ret_int32(sp, &tmp);
1374     times->authtime = tmp;
1375     if(ret) return ret;
1376     ret = krb5_ret_int32(sp, &tmp);
1377     times->starttime = tmp;
1378     if(ret) return ret;
1379     ret = krb5_ret_int32(sp, &tmp);
1380     times->endtime = tmp;
1381     if(ret) return ret;
1382     ret = krb5_ret_int32(sp, &tmp);
1383     times->renew_till = tmp;
1384     return ret;
1385 }
1386
1387 /**
1388  * Write a address block to storage.
1389  *
1390  * @param sp the storage buffer to write to
1391  * @param p the address block to write.
1392  *
1393  * @return 0 on success, a Kerberos 5 error code on failure.
1394  *
1395  * @ingroup krb5_storage
1396  */
1397
1398 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1399 krb5_store_address(krb5_storage *sp, krb5_address p)
1400 {
1401     int ret;
1402     ret = krb5_store_int16(sp, p.addr_type);
1403     if(ret) return ret;
1404     ret = krb5_store_data(sp, p.address);
1405     return ret;
1406 }
1407
1408 /**
1409  * Read a address block from the storage.
1410  *
1411  * @param sp the storage buffer to write to
1412  * @param adr the address block read from storage
1413  *
1414  * @return 0 on success, a Kerberos 5 error code on failure.
1415  *
1416  * @ingroup krb5_storage
1417  */
1418
1419 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1420 krb5_ret_address(krb5_storage *sp, krb5_address *adr)
1421 {
1422     int16_t t;
1423     int ret;
1424     ret = krb5_ret_int16(sp, &t);
1425     if(ret) return ret;
1426     adr->addr_type = t;
1427     ret = krb5_ret_data(sp, &adr->address);
1428     return ret;
1429 }
1430
1431 /**
1432  * Write a addresses block to storage.
1433  *
1434  * @param sp the storage buffer to write to
1435  * @param p the addresses block to write.
1436  *
1437  * @return 0 on success, a Kerberos 5 error code on failure.
1438  *
1439  * @ingroup krb5_storage
1440  */
1441
1442 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1443 krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
1444 {
1445     size_t i;
1446     int ret;
1447     ret = krb5_store_int32(sp, p.len);
1448     if(ret) return ret;
1449     for(i = 0; i<p.len; i++){
1450         ret = krb5_store_address(sp, p.val[i]);
1451         if(ret) break;
1452     }
1453     return ret;
1454 }
1455
1456 /**
1457  * Read a addresses block from the storage.
1458  *
1459  * @param sp the storage buffer to write to
1460  * @param adr the addresses block read from storage
1461  *
1462  * @return 0 on success, a Kerberos 5 error code on failure.
1463  *
1464  * @ingroup krb5_storage
1465  */
1466
1467 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1468 krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
1469 {
1470     size_t i;
1471     int ret;
1472     int32_t tmp;
1473
1474     ret = krb5_ret_int32(sp, &tmp);
1475     if(ret) return ret;
1476     ret = size_too_large_num(sp, tmp, sizeof(adr->val[0]));
1477     if (ret) return ret;
1478     adr->len = tmp;
1479     ALLOC(adr->val, adr->len);
1480     if (adr->val == NULL && adr->len != 0)
1481         return ENOMEM;
1482     for(i = 0; i < adr->len; i++){
1483         ret = krb5_ret_address(sp, &adr->val[i]);
1484         if(ret) break;
1485     }
1486     return ret;
1487 }
1488
1489 /**
1490  * Write a auth data block to storage.
1491  *
1492  * @param sp the storage buffer to write to
1493  * @param auth the auth data block to write.
1494  *
1495  * @return 0 on success, a Kerberos 5 error code on failure.
1496  *
1497  * @ingroup krb5_storage
1498  */
1499
1500 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1501 krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
1502 {
1503     krb5_error_code ret;
1504     size_t i;
1505     ret = krb5_store_int32(sp, auth.len);
1506     if(ret) return ret;
1507     for(i = 0; i < auth.len; i++){
1508         ret = krb5_store_int16(sp, auth.val[i].ad_type);
1509         if(ret) break;
1510         ret = krb5_store_data(sp, auth.val[i].ad_data);
1511         if(ret) break;
1512     }
1513     return 0;
1514 }
1515
1516 /**
1517  * Read a auth data from the storage.
1518  *
1519  * @param sp the storage buffer to write to
1520  * @param auth the auth data block read from storage
1521  *
1522  * @return 0 on success, a Kerberos 5 error code on failure.
1523  *
1524  * @ingroup krb5_storage
1525  */
1526
1527 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1528 krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
1529 {
1530     krb5_error_code ret;
1531     int32_t tmp;
1532     int16_t tmp2;
1533     int i;
1534     ret = krb5_ret_int32(sp, &tmp);
1535     if(ret) return ret;
1536     ret = size_too_large_num(sp, tmp, sizeof(auth->val[0]));
1537     if (ret) return ret;
1538     ALLOC_SEQ(auth, tmp);
1539     if (auth->val == NULL && tmp != 0)
1540         return ENOMEM;
1541     for(i = 0; i < tmp; i++){
1542         ret = krb5_ret_int16(sp, &tmp2);
1543         if(ret) break;
1544         auth->val[i].ad_type = tmp2;
1545         ret = krb5_ret_data(sp, &auth->val[i].ad_data);
1546         if(ret) break;
1547     }
1548     return ret;
1549 }
1550
1551 static int32_t
1552 bitswap32(int32_t b)
1553 {
1554     int32_t r = 0;
1555     int i;
1556     for (i = 0; i < 32; i++) {
1557         r = r << 1 | (b & 1);
1558         b = b >> 1;
1559     }
1560     return r;
1561 }
1562
1563 /**
1564  * Write a credentials block to storage.
1565  *
1566  * @param sp the storage buffer to write to
1567  * @param creds the creds block to write.
1568  *
1569  * @return 0 on success, a Kerberos 5 error code on failure.
1570  *
1571  * @ingroup krb5_storage
1572  */
1573
1574 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1575 krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
1576 {
1577     int ret;
1578
1579     ret = krb5_store_principal(sp, creds->client);
1580     if(ret)
1581         return ret;
1582     ret = krb5_store_principal(sp, creds->server);
1583     if(ret)
1584         return ret;
1585     ret = krb5_store_keyblock(sp, creds->session);
1586     if(ret)
1587         return ret;
1588     ret = krb5_store_times(sp, creds->times);
1589     if(ret)
1590         return ret;
1591     ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1592     if(ret)
1593         return ret;
1594     ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1595     if(ret)
1596         return ret;
1597     ret = krb5_store_addrs(sp, creds->addresses);
1598     if(ret)
1599         return ret;
1600     ret = krb5_store_authdata(sp, creds->authdata);
1601     if(ret)
1602         return ret;
1603     ret = krb5_store_data(sp, creds->ticket);
1604     if(ret)
1605         return ret;
1606     ret = krb5_store_data(sp, creds->second_ticket);
1607     return ret;
1608 }
1609
1610 /**
1611  * Read a credentials block from the storage.
1612  *
1613  * @param sp the storage buffer to write to
1614  * @param creds the credentials block read from storage
1615  *
1616  * @return 0 on success, a Kerberos 5 error code on failure.
1617  *
1618  * @ingroup krb5_storage
1619  */
1620
1621 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1622 krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
1623 {
1624     krb5_error_code ret;
1625     int8_t dummy8;
1626     int32_t dummy32;
1627
1628     memset(creds, 0, sizeof(*creds));
1629     ret = krb5_ret_principal (sp,  &creds->client);
1630     if(ret) goto cleanup;
1631     ret = krb5_ret_principal (sp,  &creds->server);
1632     if(ret) goto cleanup;
1633     ret = krb5_ret_keyblock (sp,  &creds->session);
1634     if(ret) goto cleanup;
1635     ret = krb5_ret_times (sp,  &creds->times);
1636     if(ret) goto cleanup;
1637     ret = krb5_ret_int8 (sp,  &dummy8);
1638     if(ret) goto cleanup;
1639     ret = krb5_ret_int32 (sp,  &dummy32);
1640     if(ret) goto cleanup;
1641     creds->flags.b = int2TicketFlags(bitswap32(dummy32));
1642     ret = krb5_ret_addrs (sp,  &creds->addresses);
1643     if(ret) goto cleanup;
1644     ret = krb5_ret_authdata (sp,  &creds->authdata);
1645     if(ret) goto cleanup;
1646     ret = krb5_ret_data (sp,  &creds->ticket);
1647     if(ret) goto cleanup;
1648     ret = krb5_ret_data (sp,  &creds->second_ticket);
1649 cleanup:
1650     if(ret) {
1651 #if 0
1652         krb5_free_cred_contents(context, creds); /* XXX */
1653 #endif
1654     }
1655     return ret;
1656 }
1657
1658 #define SC_CLIENT_PRINCIPAL         0x0001
1659 #define SC_SERVER_PRINCIPAL         0x0002
1660 #define SC_SESSION_KEY              0x0004
1661 #define SC_TICKET                   0x0008
1662 #define SC_SECOND_TICKET            0x0010
1663 #define SC_AUTHDATA                 0x0020
1664 #define SC_ADDRESSES                0x0040
1665
1666 /**
1667  * Write a tagged credentials block to storage.
1668  *
1669  * @param sp the storage buffer to write to
1670  * @param creds the creds block to write.
1671  *
1672  * @return 0 on success, a Kerberos 5 error code on failure.
1673  *
1674  * @ingroup krb5_storage
1675  */
1676
1677 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1678 krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
1679 {
1680     int ret;
1681     int32_t header = 0;
1682
1683     if (creds->client)
1684         header |= SC_CLIENT_PRINCIPAL;
1685     if (creds->server)
1686         header |= SC_SERVER_PRINCIPAL;
1687     if (creds->session.keytype != ETYPE_NULL)
1688         header |= SC_SESSION_KEY;
1689     if (creds->ticket.data)
1690         header |= SC_TICKET;
1691     if (creds->second_ticket.length)
1692         header |= SC_SECOND_TICKET;
1693     if (creds->authdata.len)
1694         header |= SC_AUTHDATA;
1695     if (creds->addresses.len)
1696         header |= SC_ADDRESSES;
1697
1698     ret = krb5_store_int32(sp, header);
1699     if (ret)
1700         return ret;
1701
1702     if (creds->client) {
1703         ret = krb5_store_principal(sp, creds->client);
1704         if(ret)
1705             return ret;
1706     }
1707
1708     if (creds->server) {
1709         ret = krb5_store_principal(sp, creds->server);
1710         if(ret)
1711             return ret;
1712     }
1713
1714     if (creds->session.keytype != ETYPE_NULL) {
1715         ret = krb5_store_keyblock(sp, creds->session);
1716         if(ret)
1717             return ret;
1718     }
1719
1720     ret = krb5_store_times(sp, creds->times);
1721     if(ret)
1722         return ret;
1723     ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1724     if(ret)
1725         return ret;
1726
1727     ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1728     if(ret)
1729         return ret;
1730
1731     if (creds->addresses.len) {
1732         ret = krb5_store_addrs(sp, creds->addresses);
1733         if(ret)
1734             return ret;
1735     }
1736
1737     if (creds->authdata.len) {
1738         ret = krb5_store_authdata(sp, creds->authdata);
1739         if(ret)
1740             return ret;
1741     }
1742
1743     if (creds->ticket.data) {
1744         ret = krb5_store_data(sp, creds->ticket);
1745         if(ret)
1746             return ret;
1747     }
1748
1749     if (creds->second_ticket.data) {
1750         ret = krb5_store_data(sp, creds->second_ticket);
1751         if (ret)
1752             return ret;
1753     }
1754
1755     return ret;
1756 }
1757
1758 /**
1759  * Read a tagged credentials block from the storage.
1760  *
1761  * @param sp the storage buffer to write to
1762  * @param creds the credentials block read from storage
1763  *
1764  * @return 0 on success, a Kerberos 5 error code on failure.
1765  *
1766  * @ingroup krb5_storage
1767  */
1768
1769 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1770 krb5_ret_creds_tag(krb5_storage *sp,
1771                    krb5_creds *creds)
1772 {
1773     krb5_error_code ret;
1774     int8_t dummy8;
1775     int32_t dummy32, header;
1776
1777     memset(creds, 0, sizeof(*creds));
1778
1779     ret = krb5_ret_int32 (sp, &header);
1780     if (ret) goto cleanup;
1781
1782     if (header & SC_CLIENT_PRINCIPAL) {
1783         ret = krb5_ret_principal (sp,  &creds->client);
1784         if(ret) goto cleanup;
1785     }
1786     if (header & SC_SERVER_PRINCIPAL) {
1787         ret = krb5_ret_principal (sp,  &creds->server);
1788         if(ret) goto cleanup;
1789     }
1790     if (header & SC_SESSION_KEY) {
1791         ret = krb5_ret_keyblock (sp,  &creds->session);
1792         if(ret) goto cleanup;
1793     }
1794     ret = krb5_ret_times (sp,  &creds->times);
1795     if(ret) goto cleanup;
1796     ret = krb5_ret_int8 (sp,  &dummy8);
1797     if(ret) goto cleanup;
1798     ret = krb5_ret_int32 (sp,  &dummy32);
1799     if(ret) goto cleanup;
1800     creds->flags.b = int2TicketFlags(bitswap32(dummy32));
1801     if (header & SC_ADDRESSES) {
1802         ret = krb5_ret_addrs (sp,  &creds->addresses);
1803         if(ret) goto cleanup;
1804     }
1805     if (header & SC_AUTHDATA) {
1806         ret = krb5_ret_authdata (sp,  &creds->authdata);
1807         if(ret) goto cleanup;
1808     }
1809     if (header & SC_TICKET) {
1810         ret = krb5_ret_data (sp,  &creds->ticket);
1811         if(ret) goto cleanup;
1812     }
1813     if (header & SC_SECOND_TICKET) {
1814         ret = krb5_ret_data (sp,  &creds->second_ticket);
1815         if(ret) goto cleanup;
1816     }
1817
1818 cleanup:
1819     if(ret) {
1820 #if 0
1821         krb5_free_cred_contents(context, creds); /* XXX */
1822 #endif
1823     }
1824     return ret;
1825 }
1826
1827 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1828 _krb5_ret_data_at_offset(krb5_storage *sp,
1829                          size_t offset,
1830                          size_t length,
1831                          krb5_data *data)
1832 {
1833     krb5_error_code ret;
1834     off_t cur, size;
1835
1836     krb5_data_zero(data);
1837
1838     cur = sp->seek(sp, 0, SEEK_CUR);
1839     if (cur < 0)
1840         return HEIM_ERR_NOT_SEEKABLE;
1841
1842     size = sp->seek(sp, 0, SEEK_END);
1843     if (offset + length > size) {
1844         ret = ERANGE;
1845         goto cleanup;
1846     }
1847
1848     ret = krb5_data_alloc(data, length);
1849     if (ret)
1850         goto cleanup;
1851
1852     if (length) {
1853         sp->seek(sp, offset, SEEK_SET);
1854
1855         size = sp->fetch(sp, data->data, length);
1856         heim_assert(size == length, "incomplete buffer fetched");
1857     }
1858
1859 cleanup:
1860     sp->seek(sp, cur, SEEK_SET);
1861
1862     return ret;
1863 }
1864
1865 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1866 _krb5_ret_utf8_from_ucs2le_at_offset(krb5_storage *sp,
1867                                      off_t offset,
1868                                      size_t length,
1869                                      char **utf8)
1870 {
1871     krb5_error_code ret;
1872     krb5_data data;
1873     size_t ucs2len = length / 2;
1874     uint16_t *ucs2 = NULL;
1875     size_t u8len;
1876     unsigned int flags = WIND_RW_LE;
1877
1878     *utf8 = NULL;
1879
1880     krb5_data_zero(&data);
1881
1882     ret = _krb5_ret_data_at_offset(sp, offset, length, &data);
1883     if (ret)
1884         goto out;
1885
1886     ucs2 = malloc(sizeof(ucs2[0]) * ucs2len);
1887     if (ucs2 == NULL) {
1888         ret = ENOMEM;
1889         goto out;
1890     }
1891
1892     ret = wind_ucs2read(data.data, data.length, &flags, ucs2, &ucs2len);
1893     if (ret)
1894         goto out;
1895
1896     ret = wind_ucs2utf8_length(ucs2, ucs2len, &u8len);
1897     if (ret)
1898         goto out;
1899
1900     u8len += 1; /* Add space for NUL */
1901
1902     *utf8 = malloc(u8len);
1903     if (*utf8 == NULL) {
1904         ret = ENOMEM;
1905         goto out;
1906     }
1907
1908     ret = wind_ucs2utf8(ucs2, ucs2len, *utf8, &u8len);
1909     if (ret)
1910         goto out;
1911
1912 out:
1913     if (ret && *utf8) {
1914         free(*utf8);
1915         *utf8 = NULL;
1916     }
1917     free(ucs2);
1918     krb5_data_free(&data);
1919
1920     return ret;
1921 }
1922
1923 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1924 _krb5_store_data_at_offset(krb5_storage *sp,
1925                            size_t offset,
1926                            const krb5_data *data)
1927 {
1928     krb5_error_code ret;
1929     krb5_ssize_t nbytes;
1930     off_t pos;
1931
1932     if (offset == (off_t)-1) {
1933         if (data == NULL || data->data == NULL) {
1934             offset = 0;
1935         } else {
1936             pos = sp->seek(sp, 0, SEEK_CUR);
1937             offset = sp->seek(sp, 0, SEEK_END);
1938             sp->seek(sp, pos, SEEK_SET);
1939
1940             if (offset == (off_t)-1)
1941                 return HEIM_ERR_NOT_SEEKABLE;
1942         }
1943     }
1944
1945     if (offset > 0xFFFF)
1946         return ERANGE;
1947     else if ((offset != 0) != (data && data->data))
1948         return EINVAL;
1949     else if (data && data->length > 0xFFFF)
1950         return ERANGE;
1951
1952     ret = krb5_store_uint16(sp, data ? (uint16_t)data->length : 0);
1953     if (ret == 0)
1954         ret = krb5_store_uint16(sp, (uint16_t)offset);
1955     if (ret == 0 && offset) {
1956         pos = sp->seek(sp, 0, SEEK_CUR);
1957         sp->seek(sp, offset, SEEK_SET);
1958         nbytes = krb5_storage_write(sp, data->data, data->length);
1959         if ((size_t)nbytes != data->length)
1960             ret = sp->eof_code;
1961         sp->seek(sp, pos, SEEK_SET);
1962     }
1963
1964     return ret;
1965 }
1966
1967 KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1968 _krb5_store_utf8_as_ucs2le_at_offset(krb5_storage *sp,
1969                                      off_t offset,
1970                                      const char *utf8)
1971 {
1972     krb5_error_code ret;
1973     size_t ucs2_len, ucs2le_size;
1974     uint16_t *ucs2, *ucs2le;
1975     unsigned int flags;
1976
1977     if (utf8) {
1978         ret = wind_utf8ucs2_length(utf8, &ucs2_len);
1979         if (ret)
1980             return ret;
1981
1982         ucs2 = malloc(sizeof(ucs2[0]) * ucs2_len);
1983         if (ucs2 == NULL)
1984             return ENOMEM;
1985
1986         ret = wind_utf8ucs2(utf8, ucs2, &ucs2_len);
1987         if (ret) {
1988             free(ucs2);
1989             return ret;
1990         }
1991
1992         ucs2le_size = (ucs2_len + 1) * 2;
1993         ucs2le = malloc(ucs2le_size);
1994             if (ucs2le == NULL) {
1995                 free(ucs2);
1996                 return ENOMEM;
1997         }
1998
1999         flags = WIND_RW_LE;
2000         ret = wind_ucs2write(ucs2, ucs2_len, &flags, ucs2le, &ucs2le_size);
2001         free(ucs2);
2002         if (ret) {
2003             free(ucs2le);
2004             return ret;
2005         }
2006
2007         ucs2le_size = ucs2_len * 2;
2008     } else {
2009         ucs2le = NULL;
2010         ucs2le_size = 0;
2011         offset = 0;
2012         ret = 0;
2013     }
2014
2015     {
2016         krb5_data data;
2017
2018         data.data = ucs2le;
2019         data.length = ucs2le_size;
2020
2021         ret = _krb5_store_data_at_offset(sp, offset, &data);
2022     }
2023
2024     free(ucs2le);
2025
2026     return ret;
2027 }