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