155682Smarkm/*
2233294Sstas * Copyright (c) 1997-2008 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "krb5_locl.h"
35102644Snectar#include "store-int.h"
3655682Smarkm
3778527Sassar#define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
3878527Sassar#define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
3978527Sassar#define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
4078527Sassar#define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
4178527Sassar			       krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
4278527Sassar
43233294Sstas/**
44233294Sstas * Add the flags on a storage buffer by or-ing in the flags to the buffer.
45233294Sstas *
46233294Sstas * @param sp the storage buffer to set the flags on
47233294Sstas * @param flags the flags to set
48233294Sstas *
49233294Sstas * @ingroup krb5_storage
50233294Sstas */
51233294Sstas
52233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
5355682Smarkmkrb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
5455682Smarkm{
5555682Smarkm    sp->flags |= flags;
5655682Smarkm}
5755682Smarkm
58233294Sstas/**
59233294Sstas * Clear the flags on a storage buffer
60233294Sstas *
61233294Sstas * @param sp the storage buffer to clear the flags on
62233294Sstas * @param flags the flags to clear
63233294Sstas *
64233294Sstas * @ingroup krb5_storage
65233294Sstas */
66233294Sstas
67233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
6855682Smarkmkrb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
6955682Smarkm{
7055682Smarkm    sp->flags &= ~flags;
7155682Smarkm}
7255682Smarkm
73233294Sstas/**
74233294Sstas * Return true or false depending on if the storage flags is set or
75233294Sstas * not. NB testing for the flag 0 always return true.
76233294Sstas *
77233294Sstas * @param sp the storage buffer to check flags on
78233294Sstas * @param flags The flags to test for
79233294Sstas *
80233294Sstas * @return true if all the flags are set, false if not.
81233294Sstas *
82233294Sstas * @ingroup krb5_storage
83233294Sstas */
84233294Sstas
85233294SstasKRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
8655682Smarkmkrb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
8755682Smarkm{
8855682Smarkm    return (sp->flags & flags) == flags;
8955682Smarkm}
9055682Smarkm
91233294Sstas/**
92233294Sstas * Set the new byte order of the storage buffer.
93233294Sstas *
94233294Sstas * @param sp the storage buffer to set the byte order for.
95233294Sstas * @param byteorder the new byte order.
96233294Sstas *
97233294Sstas * The byte order are: KRB5_STORAGE_BYTEORDER_BE,
98233294Sstas * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST.
99233294Sstas *
100233294Sstas * @ingroup krb5_storage
101233294Sstas */
102233294Sstas
103233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
10478527Sassarkrb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
10578527Sassar{
10678527Sassar    sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
10778527Sassar    sp->flags |= byteorder;
10878527Sassar}
10978527Sassar
110233294Sstas/**
111233294Sstas * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants.
112233294Sstas *
113233294Sstas * @ingroup krb5_storage
114233294Sstas */
115233294Sstas
116233294SstasKRB5_LIB_FUNCTION krb5_flags KRB5_LIB_CALL
117233294Sstaskrb5_storage_get_byteorder(krb5_storage *sp)
11878527Sassar{
11978527Sassar    return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
12078527Sassar}
12178527Sassar
122233294Sstas/**
123233294Sstas * Set the max alloc value
124233294Sstas *
125233294Sstas * @param sp the storage buffer set the max allow for
126233294Sstas * @param size maximum size to allocate, use 0 to remove limit
127233294Sstas *
128233294Sstas * @ingroup krb5_storage
129233294Sstas */
130233294Sstas
131233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
132233294Sstaskrb5_storage_set_max_alloc(krb5_storage *sp, size_t size)
133233294Sstas{
134233294Sstas    sp->max_alloc = size;
135233294Sstas}
136233294Sstas
137233294Sstas/* don't allocate unresonable amount of memory */
138233294Sstasstatic krb5_error_code
139233294Sstassize_too_large(krb5_storage *sp, size_t size)
140233294Sstas{
141233294Sstas    if (sp->max_alloc && sp->max_alloc < size)
142233294Sstas	return HEIM_ERR_TOO_BIG;
143233294Sstas    return 0;
144233294Sstas}
145233294Sstas
146233294Sstasstatic krb5_error_code
147233294Sstassize_too_large_num(krb5_storage *sp, size_t count, size_t size)
148233294Sstas{
149233294Sstas    if (sp->max_alloc == 0 || size == 0)
150233294Sstas	return 0;
151233294Sstas    size = sp->max_alloc / size;
152233294Sstas    if (size < count)
153233294Sstas	return HEIM_ERR_TOO_BIG;
154233294Sstas    return 0;
155233294Sstas}
156233294Sstas
157233294Sstas/**
158233294Sstas * Seek to a new offset.
159233294Sstas *
160233294Sstas * @param sp the storage buffer to seek in.
161233294Sstas * @param offset the offset to seek
162233294Sstas * @param whence relateive searching, SEEK_CUR from the current
163233294Sstas * position, SEEK_END from the end, SEEK_SET absolute from the start.
164233294Sstas *
165233294Sstas * @return The new current offset
166233294Sstas *
167233294Sstas * @ingroup krb5_storage
168233294Sstas */
169233294Sstas
170233294SstasKRB5_LIB_FUNCTION off_t KRB5_LIB_CALL
171102644Snectarkrb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
172102644Snectar{
173102644Snectar    return (*sp->seek)(sp, offset, whence);
174102644Snectar}
17578527Sassar
176233294Sstas/**
177233294Sstas * Truncate the storage buffer in sp to offset.
178233294Sstas *
179233294Sstas * @param sp the storage buffer to truncate.
180233294Sstas * @param offset the offset to truncate too.
181233294Sstas *
182233294Sstas * @return An Kerberos 5 error code.
183233294Sstas *
184233294Sstas * @ingroup krb5_storage
185233294Sstas */
186233294Sstas
187233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
188233294Sstaskrb5_storage_truncate(krb5_storage *sp, off_t offset)
189233294Sstas{
190233294Sstas    return (*sp->trunc)(sp, offset);
191233294Sstas}
192233294Sstas
193233294Sstas/**
194233294Sstas * Read to the storage buffer.
195233294Sstas *
196233294Sstas * @param sp the storage buffer to read from
197233294Sstas * @param buf the buffer to store the data in
198233294Sstas * @param len the length to read
199233294Sstas *
200233294Sstas * @return The length of data read (can be shorter then len), or negative on error.
201233294Sstas *
202233294Sstas * @ingroup krb5_storage
203233294Sstas */
204233294Sstas
205233294SstasKRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
206102644Snectarkrb5_storage_read(krb5_storage *sp, void *buf, size_t len)
207102644Snectar{
208102644Snectar    return sp->fetch(sp, buf, len);
209102644Snectar}
210102644Snectar
211233294Sstas/**
212233294Sstas * Write to the storage buffer.
213233294Sstas *
214233294Sstas * @param sp the storage buffer to write to
215233294Sstas * @param buf the buffer to write to the storage buffer
216233294Sstas * @param len the length to write
217233294Sstas *
218233294Sstas * @return The length of data written (can be shorter then len), or negative on error.
219233294Sstas *
220233294Sstas * @ingroup krb5_storage
221233294Sstas */
222233294Sstas
223233294SstasKRB5_LIB_FUNCTION krb5_ssize_t KRB5_LIB_CALL
224102644Snectarkrb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
225102644Snectar{
226102644Snectar    return sp->store(sp, buf, len);
227102644Snectar}
228102644Snectar
229233294Sstas/**
230233294Sstas * Set the return code that will be used when end of storage is reached.
231233294Sstas *
232233294Sstas * @param sp the storage
233233294Sstas * @param code the error code to return on end of storage
234233294Sstas *
235233294Sstas * @ingroup krb5_storage
236233294Sstas */
237233294Sstas
238233294SstasKRB5_LIB_FUNCTION void KRB5_LIB_CALL
239102644Snectarkrb5_storage_set_eof_code(krb5_storage *sp, int code)
240102644Snectar{
241102644Snectar    sp->eof_code = code;
242102644Snectar}
243102644Snectar
244233294Sstas/**
245233294Sstas * Get the return code that will be used when end of storage is reached.
246233294Sstas *
247233294Sstas * @param sp the storage
248233294Sstas *
249233294Sstas * @return storage error code
250233294Sstas *
251233294Sstas * @ingroup krb5_storage
252233294Sstas */
25355682Smarkm
254233294SstasKRB5_LIB_FUNCTION int KRB5_LIB_CALL
255233294Sstaskrb5_storage_get_eof_code(krb5_storage *sp)
25655682Smarkm{
257233294Sstas    return sp->eof_code;
25855682Smarkm}
25955682Smarkm
260233294Sstas/**
261233294Sstas * Free a krb5 storage.
262233294Sstas *
263233294Sstas * @param sp the storage to free.
264233294Sstas *
265233294Sstas * @return An Kerberos 5 error code.
266233294Sstas *
267233294Sstas * @ingroup krb5_storage
268233294Sstas */
269233294Sstas
270233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
27155682Smarkmkrb5_storage_free(krb5_storage *sp)
27255682Smarkm{
27355682Smarkm    if(sp->free)
27455682Smarkm	(*sp->free)(sp);
27555682Smarkm    free(sp->data);
27655682Smarkm    free(sp);
27755682Smarkm    return 0;
27855682Smarkm}
27955682Smarkm
280233294Sstas/**
281233294Sstas * Copy the contnent of storage
282233294Sstas *
283233294Sstas * @param sp the storage to copy to a data
284233294Sstas * @param data the copied data, free with krb5_data_free()
285233294Sstas *
286233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
287233294Sstas *
288233294Sstas * @ingroup krb5_storage
289233294Sstas */
290233294Sstas
291233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
29255682Smarkmkrb5_storage_to_data(krb5_storage *sp, krb5_data *data)
29355682Smarkm{
294233294Sstas    off_t pos, size;
29555682Smarkm    krb5_error_code ret;
29655682Smarkm
29755682Smarkm    pos = sp->seek(sp, 0, SEEK_CUR);
298233294Sstas    if (pos < 0)
299233294Sstas	return HEIM_ERR_NOT_SEEKABLE;
300233294Sstas    size = sp->seek(sp, 0, SEEK_END);
301233294Sstas    ret = size_too_large(sp, size);
302233294Sstas    if (ret)
303233294Sstas	return ret;
304233294Sstas    ret = krb5_data_alloc(data, size);
30555682Smarkm    if (ret) {
30655682Smarkm	sp->seek(sp, pos, SEEK_SET);
30755682Smarkm	return ret;
30855682Smarkm    }
30955682Smarkm    if (size) {
31055682Smarkm	sp->seek(sp, 0, SEEK_SET);
31155682Smarkm	sp->fetch(sp, data->data, data->length);
31255682Smarkm	sp->seek(sp, pos, SEEK_SET);
31355682Smarkm    }
31455682Smarkm    return 0;
31555682Smarkm}
31655682Smarkm
31755682Smarkmstatic krb5_error_code
31855682Smarkmkrb5_store_int(krb5_storage *sp,
31955682Smarkm	       int32_t value,
32055682Smarkm	       size_t len)
32155682Smarkm{
32255682Smarkm    int ret;
32378527Sassar    unsigned char v[16];
32455682Smarkm
32578527Sassar    if(len > sizeof(v))
32678527Sassar	return EINVAL;
32755682Smarkm    _krb5_put_int(v, value, len);
32855682Smarkm    ret = sp->store(sp, v, len);
329233294Sstas    if (ret < 0)
330233294Sstas	return errno;
331233294Sstas    if ((size_t)ret != len)
332233294Sstas	return sp->eof_code;
33355682Smarkm    return 0;
33455682Smarkm}
33555682Smarkm
336233294Sstas/**
337233294Sstas * Store a int32 to storage, byte order is controlled by the settings
338233294Sstas * on the storage, see krb5_storage_set_byteorder().
339233294Sstas *
340233294Sstas * @param sp the storage to write too
341233294Sstas * @param value the value to store
342233294Sstas *
343233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
344233294Sstas *
345233294Sstas * @ingroup krb5_storage
346233294Sstas */
347233294Sstas
348233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
34955682Smarkmkrb5_store_int32(krb5_storage *sp,
35055682Smarkm		 int32_t value)
35155682Smarkm{
35278527Sassar    if(BYTEORDER_IS_HOST(sp))
35355682Smarkm	value = htonl(value);
35478527Sassar    else if(BYTEORDER_IS_LE(sp))
35578527Sassar	value = bswap32(value);
35655682Smarkm    return krb5_store_int(sp, value, 4);
35755682Smarkm}
35855682Smarkm
359233294Sstas/**
360233294Sstas * Store a uint32 to storage, byte order is controlled by the settings
361233294Sstas * on the storage, see krb5_storage_set_byteorder().
362233294Sstas *
363233294Sstas * @param sp the storage to write too
364233294Sstas * @param value the value to store
365233294Sstas *
366233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
367233294Sstas *
368233294Sstas * @ingroup krb5_storage
369233294Sstas */
370233294Sstas
371233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
372178825Sdfrkrb5_store_uint32(krb5_storage *sp,
373178825Sdfr		  uint32_t value)
374178825Sdfr{
375178825Sdfr    return krb5_store_int32(sp, (int32_t)value);
376178825Sdfr}
377178825Sdfr
37855682Smarkmstatic krb5_error_code
37955682Smarkmkrb5_ret_int(krb5_storage *sp,
38055682Smarkm	     int32_t *value,
38155682Smarkm	     size_t len)
38255682Smarkm{
38355682Smarkm    int ret;
38455682Smarkm    unsigned char v[4];
38555682Smarkm    unsigned long w;
38655682Smarkm    ret = sp->fetch(sp, v, len);
387233294Sstas    if (ret < 0)
388233294Sstas	return errno;
389233294Sstas    if ((size_t)ret != len)
390233294Sstas	return sp->eof_code;
39155682Smarkm    _krb5_get_int(v, &w, len);
39255682Smarkm    *value = w;
39355682Smarkm    return 0;
39455682Smarkm}
39555682Smarkm
396233294Sstas/**
397233294Sstas * Read a int32 from storage, byte order is controlled by the settings
398233294Sstas * on the storage, see krb5_storage_set_byteorder().
399233294Sstas *
400233294Sstas * @param sp the storage to write too
401233294Sstas * @param value the value read from the buffer
402233294Sstas *
403233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
404233294Sstas *
405233294Sstas * @ingroup krb5_storage
406233294Sstas */
407233294Sstas
408233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
40955682Smarkmkrb5_ret_int32(krb5_storage *sp,
41055682Smarkm	       int32_t *value)
41155682Smarkm{
41255682Smarkm    krb5_error_code ret = krb5_ret_int(sp, value, 4);
41355682Smarkm    if(ret)
41455682Smarkm	return ret;
41578527Sassar    if(BYTEORDER_IS_HOST(sp))
41678527Sassar	*value = htonl(*value);
41778527Sassar    else if(BYTEORDER_IS_LE(sp))
41878527Sassar	*value = bswap32(*value);
41955682Smarkm    return 0;
42055682Smarkm}
42155682Smarkm
422233294Sstas/**
423233294Sstas * Read a uint32 from storage, byte order is controlled by the settings
424233294Sstas * on the storage, see krb5_storage_set_byteorder().
425233294Sstas *
426233294Sstas * @param sp the storage to write too
427233294Sstas * @param value the value read from the buffer
428233294Sstas *
429233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
430233294Sstas *
431233294Sstas * @ingroup krb5_storage
432233294Sstas */
433233294Sstas
434233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
435178825Sdfrkrb5_ret_uint32(krb5_storage *sp,
436178825Sdfr		uint32_t *value)
437178825Sdfr{
438178825Sdfr    krb5_error_code ret;
439178825Sdfr    int32_t v;
440178825Sdfr
441178825Sdfr    ret = krb5_ret_int32(sp, &v);
442178825Sdfr    if (ret == 0)
443178825Sdfr	*value = (uint32_t)v;
444178825Sdfr
445178825Sdfr    return ret;
446178825Sdfr}
447178825Sdfr
448233294Sstas/**
449233294Sstas * Store a int16 to storage, byte order is controlled by the settings
450233294Sstas * on the storage, see krb5_storage_set_byteorder().
451233294Sstas *
452233294Sstas * @param sp the storage to write too
453233294Sstas * @param value the value to store
454233294Sstas *
455233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
456233294Sstas *
457233294Sstas * @ingroup krb5_storage
458233294Sstas */
459233294Sstas
460233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
46155682Smarkmkrb5_store_int16(krb5_storage *sp,
46255682Smarkm		 int16_t value)
46355682Smarkm{
46478527Sassar    if(BYTEORDER_IS_HOST(sp))
46555682Smarkm	value = htons(value);
46678527Sassar    else if(BYTEORDER_IS_LE(sp))
46778527Sassar	value = bswap16(value);
46855682Smarkm    return krb5_store_int(sp, value, 2);
46955682Smarkm}
47055682Smarkm
471233294Sstas/**
472233294Sstas * Store a uint16 to storage, byte order is controlled by the settings
473233294Sstas * on the storage, see krb5_storage_set_byteorder().
474233294Sstas *
475233294Sstas * @param sp the storage to write too
476233294Sstas * @param value the value to store
477233294Sstas *
478233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
479233294Sstas *
480233294Sstas * @ingroup krb5_storage
481233294Sstas */
482233294Sstas
483233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
484178825Sdfrkrb5_store_uint16(krb5_storage *sp,
485178825Sdfr		  uint16_t value)
486178825Sdfr{
487178825Sdfr    return krb5_store_int16(sp, (int16_t)value);
488178825Sdfr}
489178825Sdfr
490233294Sstas/**
491233294Sstas * Read a int16 from storage, byte order is controlled by the settings
492233294Sstas * on the storage, see krb5_storage_set_byteorder().
493233294Sstas *
494233294Sstas * @param sp the storage to write too
495233294Sstas * @param value the value read from the buffer
496233294Sstas *
497233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
498233294Sstas *
499233294Sstas * @ingroup krb5_storage
500233294Sstas */
501233294Sstas
502233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
50355682Smarkmkrb5_ret_int16(krb5_storage *sp,
50455682Smarkm	       int16_t *value)
50555682Smarkm{
50655682Smarkm    int32_t v;
50755682Smarkm    int ret;
50855682Smarkm    ret = krb5_ret_int(sp, &v, 2);
50955682Smarkm    if(ret)
51055682Smarkm	return ret;
51155682Smarkm    *value = v;
51278527Sassar    if(BYTEORDER_IS_HOST(sp))
51378527Sassar	*value = htons(*value);
51478527Sassar    else if(BYTEORDER_IS_LE(sp))
51578527Sassar	*value = bswap16(*value);
51655682Smarkm    return 0;
51755682Smarkm}
51855682Smarkm
519233294Sstas/**
520233294Sstas * Read a int16 from storage, byte order is controlled by the settings
521233294Sstas * on the storage, see krb5_storage_set_byteorder().
522233294Sstas *
523233294Sstas * @param sp the storage to write too
524233294Sstas * @param value the value read from the buffer
525233294Sstas *
526233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
527233294Sstas *
528233294Sstas * @ingroup krb5_storage
529233294Sstas */
530233294Sstas
531233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
532178825Sdfrkrb5_ret_uint16(krb5_storage *sp,
533178825Sdfr		uint16_t *value)
534178825Sdfr{
535178825Sdfr    krb5_error_code ret;
536178825Sdfr    int16_t v;
537178825Sdfr
538178825Sdfr    ret = krb5_ret_int16(sp, &v);
539178825Sdfr    if (ret == 0)
540178825Sdfr	*value = (uint16_t)v;
541178825Sdfr
542178825Sdfr    return ret;
543178825Sdfr}
544178825Sdfr
545233294Sstas/**
546233294Sstas * Store a int8 to storage.
547233294Sstas *
548233294Sstas * @param sp the storage to write too
549233294Sstas * @param value the value to store
550233294Sstas *
551233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
552233294Sstas *
553233294Sstas * @ingroup krb5_storage
554233294Sstas */
555233294Sstas
556233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
55755682Smarkmkrb5_store_int8(krb5_storage *sp,
55855682Smarkm		int8_t value)
55955682Smarkm{
56055682Smarkm    int ret;
56155682Smarkm
56255682Smarkm    ret = sp->store(sp, &value, sizeof(value));
56355682Smarkm    if (ret != sizeof(value))
564102644Snectar	return (ret<0)?errno:sp->eof_code;
56555682Smarkm    return 0;
56655682Smarkm}
56755682Smarkm
568233294Sstas/**
569233294Sstas * Store a uint8 to storage.
570233294Sstas *
571233294Sstas * @param sp the storage to write too
572233294Sstas * @param value the value to store
573233294Sstas *
574233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
575233294Sstas *
576233294Sstas * @ingroup krb5_storage
577233294Sstas */
578233294Sstas
579233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
580178825Sdfrkrb5_store_uint8(krb5_storage *sp,
581178825Sdfr		 uint8_t value)
582178825Sdfr{
583178825Sdfr    return krb5_store_int8(sp, (int8_t)value);
584178825Sdfr}
585178825Sdfr
586233294Sstas/**
587233294Sstas * Read a int8 from storage
588233294Sstas *
589233294Sstas * @param sp the storage to write too
590233294Sstas * @param value the value read from the buffer
591233294Sstas *
592233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
593233294Sstas *
594233294Sstas * @ingroup krb5_storage
595233294Sstas */
596233294Sstas
597233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
59855682Smarkmkrb5_ret_int8(krb5_storage *sp,
59955682Smarkm	      int8_t *value)
60055682Smarkm{
60155682Smarkm    int ret;
60255682Smarkm
60355682Smarkm    ret = sp->fetch(sp, value, sizeof(*value));
60455682Smarkm    if (ret != sizeof(*value))
605102644Snectar	return (ret<0)?errno:sp->eof_code;
60655682Smarkm    return 0;
60755682Smarkm}
60855682Smarkm
609233294Sstas/**
610233294Sstas * Read a uint8 from storage
611233294Sstas *
612233294Sstas * @param sp the storage to write too
613233294Sstas * @param value the value read from the buffer
614233294Sstas *
615233294Sstas * @return 0 for success, or a Kerberos 5 error code on failure.
616233294Sstas *
617233294Sstas * @ingroup krb5_storage
618233294Sstas */
619233294Sstas
620233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
621178825Sdfrkrb5_ret_uint8(krb5_storage *sp,
622178825Sdfr	       uint8_t *value)
623178825Sdfr{
624178825Sdfr    krb5_error_code ret;
625178825Sdfr    int8_t v;
626178825Sdfr
627178825Sdfr    ret = krb5_ret_int8(sp, &v);
628178825Sdfr    if (ret == 0)
629178825Sdfr	*value = (uint8_t)v;
630178825Sdfr
631178825Sdfr    return ret;
632178825Sdfr}
633178825Sdfr
634233294Sstas/**
635233294Sstas * Store a data to the storage. The data is stored with an int32 as
636233294Sstas * lenght plus the data (not padded).
637233294Sstas *
638233294Sstas * @param sp the storage buffer to write to
639233294Sstas * @param data the buffer to store.
640233294Sstas *
641233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
642233294Sstas *
643233294Sstas * @ingroup krb5_storage
644233294Sstas */
645233294Sstas
646233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
64755682Smarkmkrb5_store_data(krb5_storage *sp,
64855682Smarkm		krb5_data data)
64955682Smarkm{
65055682Smarkm    int ret;
65155682Smarkm    ret = krb5_store_int32(sp, data.length);
65255682Smarkm    if(ret < 0)
65355682Smarkm	return ret;
65455682Smarkm    ret = sp->store(sp, data.data, data.length);
655233294Sstas    if(ret < 0)
656233294Sstas	return errno;
657233294Sstas    if((size_t)ret != data.length)
658102644Snectar	return sp->eof_code;
65955682Smarkm    return 0;
66055682Smarkm}
66155682Smarkm
662233294Sstas/**
663233294Sstas * Parse a data from the storage.
664233294Sstas *
665233294Sstas * @param sp the storage buffer to read from
666233294Sstas * @param data the parsed data
667233294Sstas *
668233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
669233294Sstas *
670233294Sstas * @ingroup krb5_storage
671233294Sstas */
672233294Sstas
673233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
67455682Smarkmkrb5_ret_data(krb5_storage *sp,
67555682Smarkm	      krb5_data *data)
67655682Smarkm{
67755682Smarkm    int ret;
67855682Smarkm    int32_t size;
67955682Smarkm
68055682Smarkm    ret = krb5_ret_int32(sp, &size);
68155682Smarkm    if(ret)
68255682Smarkm	return ret;
683233294Sstas    ret = size_too_large(sp, size);
684233294Sstas    if (ret)
685233294Sstas	return ret;
68655682Smarkm    ret = krb5_data_alloc (data, size);
68755682Smarkm    if (ret)
68855682Smarkm	return ret;
68955682Smarkm    if (size) {
69055682Smarkm	ret = sp->fetch(sp, data->data, size);
69155682Smarkm	if(ret != size)
692102644Snectar	    return (ret < 0)? errno : sp->eof_code;
69355682Smarkm    }
69455682Smarkm    return 0;
69555682Smarkm}
69655682Smarkm
697233294Sstas/**
698233294Sstas * Store a string to the buffer. The data is formated as an len:uint32
699233294Sstas * plus the string itself (not padded).
700233294Sstas *
701233294Sstas * @param sp the storage buffer to write to
702233294Sstas * @param s the string to store.
703233294Sstas *
704233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
705233294Sstas *
706233294Sstas * @ingroup krb5_storage
707233294Sstas */
708233294Sstas
709233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
71055682Smarkmkrb5_store_string(krb5_storage *sp, const char *s)
71155682Smarkm{
71255682Smarkm    krb5_data data;
71355682Smarkm    data.length = strlen(s);
714178825Sdfr    data.data = rk_UNCONST(s);
71555682Smarkm    return krb5_store_data(sp, data);
71655682Smarkm}
71755682Smarkm
718233294Sstas/**
719233294Sstas * Parse a string from the storage.
720233294Sstas *
721233294Sstas * @param sp the storage buffer to read from
722233294Sstas * @param string the parsed string
723233294Sstas *
724233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
725233294Sstas *
726233294Sstas * @ingroup krb5_storage
727233294Sstas */
728233294Sstas
729233294Sstas
730233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
73155682Smarkmkrb5_ret_string(krb5_storage *sp,
73255682Smarkm		char **string)
73355682Smarkm{
73455682Smarkm    int ret;
73555682Smarkm    krb5_data data;
73655682Smarkm    ret = krb5_ret_data(sp, &data);
73755682Smarkm    if(ret)
73855682Smarkm	return ret;
73955682Smarkm    *string = realloc(data.data, data.length + 1);
74055682Smarkm    if(*string == NULL){
74155682Smarkm	free(data.data);
74255682Smarkm	return ENOMEM;
74355682Smarkm    }
74455682Smarkm    (*string)[data.length] = 0;
74555682Smarkm    return 0;
74655682Smarkm}
74755682Smarkm
748233294Sstas/**
749233294Sstas * Store a zero terminated string to the buffer. The data is stored
750233294Sstas * one character at a time until a NUL is stored.
751233294Sstas *
752233294Sstas * @param sp the storage buffer to write to
753233294Sstas * @param s the string to store.
754233294Sstas *
755233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
756233294Sstas *
757233294Sstas * @ingroup krb5_storage
758233294Sstas */
759233294Sstas
760233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
76172445Sassarkrb5_store_stringz(krb5_storage *sp, const char *s)
76255682Smarkm{
76355682Smarkm    size_t len = strlen(s) + 1;
76455682Smarkm    ssize_t ret;
76555682Smarkm
76655682Smarkm    ret = sp->store(sp, s, len);
767233294Sstas    if(ret < 0)
768233294Sstas	return ret;
769233294Sstas    if((size_t)ret != len)
770233294Sstas	return sp->eof_code;
77155682Smarkm    return 0;
77255682Smarkm}
77355682Smarkm
774233294Sstas/**
775233294Sstas * Parse zero terminated string from the storage.
776233294Sstas *
777233294Sstas * @param sp the storage buffer to read from
778233294Sstas * @param string the parsed string
779233294Sstas *
780233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
781233294Sstas *
782233294Sstas * @ingroup krb5_storage
783233294Sstas */
784233294Sstas
785233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
78655682Smarkmkrb5_ret_stringz(krb5_storage *sp,
78755682Smarkm		char **string)
78855682Smarkm{
78955682Smarkm    char c;
79055682Smarkm    char *s = NULL;
79155682Smarkm    size_t len = 0;
79255682Smarkm    ssize_t ret;
79355682Smarkm
79455682Smarkm    while((ret = sp->fetch(sp, &c, 1)) == 1){
79555682Smarkm	char *tmp;
79655682Smarkm
79755682Smarkm	len++;
798233294Sstas	ret = size_too_large(sp, len);
799233294Sstas	if (ret)
800233294Sstas	    break;
80155682Smarkm	tmp = realloc (s, len);
80255682Smarkm	if (tmp == NULL) {
80355682Smarkm	    free (s);
80455682Smarkm	    return ENOMEM;
80555682Smarkm	}
80655682Smarkm	s = tmp;
80755682Smarkm	s[len - 1] = c;
80855682Smarkm	if(c == 0)
80955682Smarkm	    break;
81055682Smarkm    }
81155682Smarkm    if(ret != 1){
81255682Smarkm	free(s);
81355682Smarkm	if(ret == 0)
814102644Snectar	    return sp->eof_code;
81555682Smarkm	return ret;
81655682Smarkm    }
81755682Smarkm    *string = s;
81855682Smarkm    return 0;
81955682Smarkm}
82055682Smarkm
821233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
822178825Sdfrkrb5_store_stringnl(krb5_storage *sp, const char *s)
823178825Sdfr{
824178825Sdfr    size_t len = strlen(s);
825178825Sdfr    ssize_t ret;
82655682Smarkm
827178825Sdfr    ret = sp->store(sp, s, len);
828233294Sstas    if(ret < 0)
829233294Sstas	return ret;
830233294Sstas    if((size_t)ret != len)
831233294Sstas	return sp->eof_code;
832178825Sdfr    ret = sp->store(sp, "\n", 1);
833178825Sdfr    if(ret != 1) {
834178825Sdfr	if(ret < 0)
835178825Sdfr	    return ret;
836178825Sdfr	else
837178825Sdfr	    return sp->eof_code;
838178825Sdfr    }
839178825Sdfr
840178825Sdfr    return 0;
841178825Sdfr
842178825Sdfr}
843178825Sdfr
844233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
845178825Sdfrkrb5_ret_stringnl(krb5_storage *sp,
846178825Sdfr		  char **string)
847178825Sdfr{
848178825Sdfr    int expect_nl = 0;
849178825Sdfr    char c;
850178825Sdfr    char *s = NULL;
851178825Sdfr    size_t len = 0;
852178825Sdfr    ssize_t ret;
853178825Sdfr
854178825Sdfr    while((ret = sp->fetch(sp, &c, 1)) == 1){
855178825Sdfr	char *tmp;
856178825Sdfr
857178825Sdfr	if (c == '\r') {
858178825Sdfr	    expect_nl = 1;
859178825Sdfr	    continue;
860178825Sdfr	}
861178825Sdfr	if (expect_nl && c != '\n') {
862178825Sdfr	    free(s);
863178825Sdfr	    return KRB5_BADMSGTYPE;
864178825Sdfr	}
865178825Sdfr
866178825Sdfr	len++;
867233294Sstas	ret = size_too_large(sp, len);
868233294Sstas	if (ret)
869233294Sstas	    break;
870178825Sdfr	tmp = realloc (s, len);
871178825Sdfr	if (tmp == NULL) {
872178825Sdfr	    free (s);
873178825Sdfr	    return ENOMEM;
874178825Sdfr	}
875178825Sdfr	s = tmp;
876178825Sdfr	if(c == '\n') {
877178825Sdfr	    s[len - 1] = '\0';
878178825Sdfr	    break;
879178825Sdfr	}
880178825Sdfr	s[len - 1] = c;
881178825Sdfr    }
882178825Sdfr    if(ret != 1){
883178825Sdfr	free(s);
884178825Sdfr	if(ret == 0)
885178825Sdfr	    return sp->eof_code;
886178825Sdfr	return ret;
887178825Sdfr    }
888178825Sdfr    *string = s;
889178825Sdfr    return 0;
890178825Sdfr}
891178825Sdfr
892233294Sstas/**
893233294Sstas * Write a principal block to storage.
894233294Sstas *
895233294Sstas * @param sp the storage buffer to write to
896233294Sstas * @param p the principal block to write.
897233294Sstas *
898233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
899233294Sstas *
900233294Sstas * @ingroup krb5_storage
901233294Sstas */
902178825Sdfr
903233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
90455682Smarkmkrb5_store_principal(krb5_storage *sp,
905178825Sdfr		     krb5_const_principal p)
90655682Smarkm{
907233294Sstas    size_t i;
90855682Smarkm    int ret;
90955682Smarkm
91055682Smarkm    if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
911178825Sdfr	ret = krb5_store_int32(sp, p->name.name_type);
912178825Sdfr	if(ret) return ret;
91355682Smarkm    }
91455682Smarkm    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
91555682Smarkm	ret = krb5_store_int32(sp, p->name.name_string.len + 1);
91655682Smarkm    else
917178825Sdfr	ret = krb5_store_int32(sp, p->name.name_string.len);
918233294Sstas
91955682Smarkm    if(ret) return ret;
92055682Smarkm    ret = krb5_store_string(sp, p->realm);
92155682Smarkm    if(ret) return ret;
92255682Smarkm    for(i = 0; i < p->name.name_string.len; i++){
92355682Smarkm	ret = krb5_store_string(sp, p->name.name_string.val[i]);
92455682Smarkm	if(ret) return ret;
92555682Smarkm    }
92655682Smarkm    return 0;
92755682Smarkm}
92855682Smarkm
929233294Sstas/**
930233294Sstas * Parse principal from the storage.
931233294Sstas *
932233294Sstas * @param sp the storage buffer to read from
933233294Sstas * @param princ the parsed principal
934233294Sstas *
935233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
936233294Sstas *
937233294Sstas * @ingroup krb5_storage
938233294Sstas */
939233294Sstas
940233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
94155682Smarkmkrb5_ret_principal(krb5_storage *sp,
94255682Smarkm		   krb5_principal *princ)
94355682Smarkm{
94455682Smarkm    int i;
94555682Smarkm    int ret;
94655682Smarkm    krb5_principal p;
94755682Smarkm    int32_t type;
94855682Smarkm    int32_t ncomp;
949233294Sstas
95055682Smarkm    p = calloc(1, sizeof(*p));
95155682Smarkm    if(p == NULL)
95255682Smarkm	return ENOMEM;
95355682Smarkm
95455682Smarkm    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
95555682Smarkm	type = KRB5_NT_UNKNOWN;
956178825Sdfr    else if((ret = krb5_ret_int32(sp, &type))){
95755682Smarkm	free(p);
95855682Smarkm	return ret;
95955682Smarkm    }
96055682Smarkm    if((ret = krb5_ret_int32(sp, &ncomp))){
96155682Smarkm	free(p);
96255682Smarkm	return ret;
96355682Smarkm    }
96455682Smarkm    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
96555682Smarkm	ncomp--;
966178825Sdfr    if (ncomp < 0) {
967178825Sdfr	free(p);
968178825Sdfr	return EINVAL;
969178825Sdfr    }
970233294Sstas    ret = size_too_large_num(sp, ncomp, sizeof(p->name.name_string.val[0]));
971233294Sstas    if (ret) {
972233294Sstas	free(p);
973233294Sstas	return ret;
974233294Sstas    }
97555682Smarkm    p->name.name_type = type;
97655682Smarkm    p->name.name_string.len = ncomp;
97755682Smarkm    ret = krb5_ret_string(sp, &p->realm);
978178825Sdfr    if(ret) {
979178825Sdfr	free(p);
980178825Sdfr	return ret;
981178825Sdfr    }
982233294Sstas    p->name.name_string.val = calloc(ncomp, sizeof(p->name.name_string.val[0]));
983178825Sdfr    if(p->name.name_string.val == NULL && ncomp != 0){
98455682Smarkm	free(p->realm);
985178825Sdfr	free(p);
98655682Smarkm	return ENOMEM;
98755682Smarkm    }
98855682Smarkm    for(i = 0; i < ncomp; i++){
98955682Smarkm	ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
990178825Sdfr	if(ret) {
991178825Sdfr	    while (i >= 0)
992178825Sdfr		free(p->name.name_string.val[i--]);
993178825Sdfr	    free(p->realm);
994178825Sdfr	    free(p);
995178825Sdfr	    return ret;
996178825Sdfr	}
99755682Smarkm    }
99855682Smarkm    *princ = p;
99955682Smarkm    return 0;
100055682Smarkm}
100155682Smarkm
1002233294Sstas/**
1003233294Sstas * Store a keyblock to the storage.
1004233294Sstas *
1005233294Sstas * @param sp the storage buffer to write to
1006233294Sstas * @param p the keyblock to write
1007233294Sstas *
1008233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1009233294Sstas *
1010233294Sstas * @ingroup krb5_storage
1011233294Sstas */
1012233294Sstas
1013233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
101455682Smarkmkrb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
101555682Smarkm{
101655682Smarkm    int ret;
101755682Smarkm    ret = krb5_store_int16(sp, p.keytype);
101855682Smarkm    if(ret) return ret;
101955682Smarkm
102055682Smarkm    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
102155682Smarkm	/* this should really be enctype, but it is the same as
102255682Smarkm           keytype nowadays */
102355682Smarkm    ret = krb5_store_int16(sp, p.keytype);
102455682Smarkm    if(ret) return ret;
102555682Smarkm    }
102655682Smarkm
102755682Smarkm    ret = krb5_store_data(sp, p.keyvalue);
102855682Smarkm    return ret;
102955682Smarkm}
103055682Smarkm
1031233294Sstas/**
1032233294Sstas * Read a keyblock from the storage.
1033233294Sstas *
1034233294Sstas * @param sp the storage buffer to write to
1035233294Sstas * @param p the keyblock read from storage, free using krb5_free_keyblock()
1036233294Sstas *
1037233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1038233294Sstas *
1039233294Sstas * @ingroup krb5_storage
1040233294Sstas */
1041233294Sstas
1042233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
104355682Smarkmkrb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
104455682Smarkm{
104555682Smarkm    int ret;
104655682Smarkm    int16_t tmp;
104755682Smarkm
104855682Smarkm    ret = krb5_ret_int16(sp, &tmp);
104955682Smarkm    if(ret) return ret;
105055682Smarkm    p->keytype = tmp;
105155682Smarkm
105255682Smarkm    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
105355682Smarkm    ret = krb5_ret_int16(sp, &tmp);
105455682Smarkm    if(ret) return ret;
105555682Smarkm    }
105655682Smarkm
105755682Smarkm    ret = krb5_ret_data(sp, &p->keyvalue);
105855682Smarkm    return ret;
105955682Smarkm}
106055682Smarkm
1061233294Sstas/**
1062233294Sstas * Write a times block to storage.
1063233294Sstas *
1064233294Sstas * @param sp the storage buffer to write to
1065233294Sstas * @param times the times block to write.
1066233294Sstas *
1067233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1068233294Sstas *
1069233294Sstas * @ingroup krb5_storage
1070233294Sstas */
1071233294Sstas
1072233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
107355682Smarkmkrb5_store_times(krb5_storage *sp, krb5_times times)
107455682Smarkm{
107555682Smarkm    int ret;
107655682Smarkm    ret = krb5_store_int32(sp, times.authtime);
107755682Smarkm    if(ret) return ret;
107855682Smarkm    ret = krb5_store_int32(sp, times.starttime);
107955682Smarkm    if(ret) return ret;
108055682Smarkm    ret = krb5_store_int32(sp, times.endtime);
108155682Smarkm    if(ret) return ret;
108255682Smarkm    ret = krb5_store_int32(sp, times.renew_till);
108355682Smarkm    return ret;
108455682Smarkm}
108555682Smarkm
1086233294Sstas/**
1087233294Sstas * Read a times block from the storage.
1088233294Sstas *
1089233294Sstas * @param sp the storage buffer to write to
1090233294Sstas * @param times the times block read from storage
1091233294Sstas *
1092233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1093233294Sstas *
1094233294Sstas * @ingroup krb5_storage
1095233294Sstas */
1096233294Sstas
1097233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
109855682Smarkmkrb5_ret_times(krb5_storage *sp, krb5_times *times)
109955682Smarkm{
110055682Smarkm    int ret;
110155682Smarkm    int32_t tmp;
110255682Smarkm    ret = krb5_ret_int32(sp, &tmp);
110355682Smarkm    times->authtime = tmp;
110455682Smarkm    if(ret) return ret;
110555682Smarkm    ret = krb5_ret_int32(sp, &tmp);
110655682Smarkm    times->starttime = tmp;
110755682Smarkm    if(ret) return ret;
110855682Smarkm    ret = krb5_ret_int32(sp, &tmp);
110955682Smarkm    times->endtime = tmp;
111055682Smarkm    if(ret) return ret;
111155682Smarkm    ret = krb5_ret_int32(sp, &tmp);
111255682Smarkm    times->renew_till = tmp;
111355682Smarkm    return ret;
111455682Smarkm}
111555682Smarkm
1116233294Sstas/**
1117233294Sstas * Write a address block to storage.
1118233294Sstas *
1119233294Sstas * @param sp the storage buffer to write to
1120233294Sstas * @param p the address block to write.
1121233294Sstas *
1122233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1123233294Sstas *
1124233294Sstas * @ingroup krb5_storage
1125233294Sstas */
1126233294Sstas
1127233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
112855682Smarkmkrb5_store_address(krb5_storage *sp, krb5_address p)
112955682Smarkm{
113055682Smarkm    int ret;
113155682Smarkm    ret = krb5_store_int16(sp, p.addr_type);
113255682Smarkm    if(ret) return ret;
113355682Smarkm    ret = krb5_store_data(sp, p.address);
113455682Smarkm    return ret;
113555682Smarkm}
113655682Smarkm
1137233294Sstas/**
1138233294Sstas * Read a address block from the storage.
1139233294Sstas *
1140233294Sstas * @param sp the storage buffer to write to
1141233294Sstas * @param adr the address block read from storage
1142233294Sstas *
1143233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1144233294Sstas *
1145233294Sstas * @ingroup krb5_storage
1146233294Sstas */
1147233294Sstas
1148233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
114955682Smarkmkrb5_ret_address(krb5_storage *sp, krb5_address *adr)
115055682Smarkm{
115155682Smarkm    int16_t t;
115255682Smarkm    int ret;
115355682Smarkm    ret = krb5_ret_int16(sp, &t);
115455682Smarkm    if(ret) return ret;
115555682Smarkm    adr->addr_type = t;
115655682Smarkm    ret = krb5_ret_data(sp, &adr->address);
115755682Smarkm    return ret;
115855682Smarkm}
115955682Smarkm
1160233294Sstas/**
1161233294Sstas * Write a addresses block to storage.
1162233294Sstas *
1163233294Sstas * @param sp the storage buffer to write to
1164233294Sstas * @param p the addresses block to write.
1165233294Sstas *
1166233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1167233294Sstas *
1168233294Sstas * @ingroup krb5_storage
1169233294Sstas */
1170233294Sstas
1171233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
117255682Smarkmkrb5_store_addrs(krb5_storage *sp, krb5_addresses p)
117355682Smarkm{
1174233294Sstas    size_t i;
117555682Smarkm    int ret;
117655682Smarkm    ret = krb5_store_int32(sp, p.len);
117755682Smarkm    if(ret) return ret;
117855682Smarkm    for(i = 0; i<p.len; i++){
117955682Smarkm	ret = krb5_store_address(sp, p.val[i]);
118055682Smarkm	if(ret) break;
118155682Smarkm    }
118255682Smarkm    return ret;
118355682Smarkm}
118455682Smarkm
1185233294Sstas/**
1186233294Sstas * Read a addresses block from the storage.
1187233294Sstas *
1188233294Sstas * @param sp the storage buffer to write to
1189233294Sstas * @param adr the addresses block read from storage
1190233294Sstas *
1191233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1192233294Sstas *
1193233294Sstas * @ingroup krb5_storage
1194233294Sstas */
1195233294Sstas
1196233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
119755682Smarkmkrb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
119855682Smarkm{
1199233294Sstas    size_t i;
120055682Smarkm    int ret;
120155682Smarkm    int32_t tmp;
120255682Smarkm
120355682Smarkm    ret = krb5_ret_int32(sp, &tmp);
120455682Smarkm    if(ret) return ret;
1205233294Sstas    ret = size_too_large_num(sp, tmp, sizeof(adr->val[0]));
1206233294Sstas    if (ret) return ret;
120755682Smarkm    adr->len = tmp;
120855682Smarkm    ALLOC(adr->val, adr->len);
1209178825Sdfr    if (adr->val == NULL && adr->len != 0)
1210178825Sdfr	return ENOMEM;
121155682Smarkm    for(i = 0; i < adr->len; i++){
121255682Smarkm	ret = krb5_ret_address(sp, &adr->val[i]);
121355682Smarkm	if(ret) break;
121455682Smarkm    }
121555682Smarkm    return ret;
121655682Smarkm}
121755682Smarkm
1218233294Sstas/**
1219233294Sstas * Write a auth data block to storage.
1220233294Sstas *
1221233294Sstas * @param sp the storage buffer to write to
1222233294Sstas * @param auth the auth data block to write.
1223233294Sstas *
1224233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1225233294Sstas *
1226233294Sstas * @ingroup krb5_storage
1227233294Sstas */
1228233294Sstas
1229233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
123055682Smarkmkrb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
123155682Smarkm{
123255682Smarkm    krb5_error_code ret;
1233233294Sstas    size_t i;
123455682Smarkm    ret = krb5_store_int32(sp, auth.len);
123555682Smarkm    if(ret) return ret;
123655682Smarkm    for(i = 0; i < auth.len; i++){
123755682Smarkm	ret = krb5_store_int16(sp, auth.val[i].ad_type);
123855682Smarkm	if(ret) break;
123955682Smarkm	ret = krb5_store_data(sp, auth.val[i].ad_data);
124055682Smarkm	if(ret) break;
124155682Smarkm    }
124255682Smarkm    return 0;
124355682Smarkm}
124455682Smarkm
1245233294Sstas/**
1246233294Sstas * Read a auth data from the storage.
1247233294Sstas *
1248233294Sstas * @param sp the storage buffer to write to
1249233294Sstas * @param auth the auth data block read from storage
1250233294Sstas *
1251233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1252233294Sstas *
1253233294Sstas * @ingroup krb5_storage
1254233294Sstas */
1255233294Sstas
1256233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
125755682Smarkmkrb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
125855682Smarkm{
125955682Smarkm    krb5_error_code ret;
126055682Smarkm    int32_t tmp;
126155682Smarkm    int16_t tmp2;
126255682Smarkm    int i;
126355682Smarkm    ret = krb5_ret_int32(sp, &tmp);
126455682Smarkm    if(ret) return ret;
1265233294Sstas    ret = size_too_large_num(sp, tmp, sizeof(auth->val[0]));
1266233294Sstas    if (ret) return ret;
126755682Smarkm    ALLOC_SEQ(auth, tmp);
1268178825Sdfr    if (auth->val == NULL && tmp != 0)
1269178825Sdfr	return ENOMEM;
127055682Smarkm    for(i = 0; i < tmp; i++){
127155682Smarkm	ret = krb5_ret_int16(sp, &tmp2);
127255682Smarkm	if(ret) break;
127355682Smarkm	auth->val[i].ad_type = tmp2;
127455682Smarkm	ret = krb5_ret_data(sp, &auth->val[i].ad_data);
127555682Smarkm	if(ret) break;
127655682Smarkm    }
127755682Smarkm    return ret;
127855682Smarkm}
127955682Smarkm
1280127808Snectarstatic int32_t
1281127808Snectarbitswap32(int32_t b)
1282127808Snectar{
1283127808Snectar    int32_t r = 0;
1284127808Snectar    int i;
1285127808Snectar    for (i = 0; i < 32; i++) {
1286127808Snectar	r = r << 1 | (b & 1);
1287127808Snectar	b = b >> 1;
1288127808Snectar    }
1289127808Snectar    return r;
1290127808Snectar}
1291127808Snectar
1292233294Sstas/**
1293233294Sstas * Write a credentials block to storage.
1294127808Snectar *
1295233294Sstas * @param sp the storage buffer to write to
1296233294Sstas * @param creds the creds block to write.
1297233294Sstas *
1298233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1299233294Sstas *
1300233294Sstas * @ingroup krb5_storage
130172445Sassar */
130272445Sassar
1303233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1304178825Sdfrkrb5_store_creds(krb5_storage *sp, krb5_creds *creds)
130555682Smarkm{
130672445Sassar    int ret;
130772445Sassar
130872445Sassar    ret = krb5_store_principal(sp, creds->client);
1309102644Snectar    if(ret)
131072445Sassar	return ret;
131172445Sassar    ret = krb5_store_principal(sp, creds->server);
1312102644Snectar    if(ret)
131372445Sassar	return ret;
131472445Sassar    ret = krb5_store_keyblock(sp, creds->session);
1315102644Snectar    if(ret)
131672445Sassar	return ret;
131772445Sassar    ret = krb5_store_times(sp, creds->times);
1318102644Snectar    if(ret)
131972445Sassar	return ret;
1320178825Sdfr    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1321102644Snectar    if(ret)
132272445Sassar	return ret;
1323178825Sdfr
1324178825Sdfr    if(krb5_storage_is_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER))
1325127808Snectar	ret = krb5_store_int32(sp, creds->flags.i);
1326178825Sdfr    else
1327127808Snectar	ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1328178825Sdfr    if(ret)
1329178825Sdfr	return ret;
1330178825Sdfr
133172445Sassar    ret = krb5_store_addrs(sp, creds->addresses);
1332102644Snectar    if(ret)
133372445Sassar	return ret;
133472445Sassar    ret = krb5_store_authdata(sp, creds->authdata);
1335102644Snectar    if(ret)
133672445Sassar	return ret;
133772445Sassar    ret = krb5_store_data(sp, creds->ticket);
1338102644Snectar    if(ret)
133972445Sassar	return ret;
134072445Sassar    ret = krb5_store_data(sp, creds->second_ticket);
1341102644Snectar    return ret;
134255682Smarkm}
134355682Smarkm
1344233294Sstas/**
1345233294Sstas * Read a credentials block from the storage.
1346233294Sstas *
1347233294Sstas * @param sp the storage buffer to write to
1348233294Sstas * @param creds the credentials block read from storage
1349233294Sstas *
1350233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1351233294Sstas *
1352233294Sstas * @ingroup krb5_storage
1353233294Sstas */
1354233294Sstas
1355233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
135655682Smarkmkrb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
135755682Smarkm{
135855682Smarkm    krb5_error_code ret;
135955682Smarkm    int8_t dummy8;
136055682Smarkm    int32_t dummy32;
136155682Smarkm
136255682Smarkm    memset(creds, 0, sizeof(*creds));
136355682Smarkm    ret = krb5_ret_principal (sp,  &creds->client);
136455682Smarkm    if(ret) goto cleanup;
136555682Smarkm    ret = krb5_ret_principal (sp,  &creds->server);
136655682Smarkm    if(ret) goto cleanup;
136755682Smarkm    ret = krb5_ret_keyblock (sp,  &creds->session);
136855682Smarkm    if(ret) goto cleanup;
136955682Smarkm    ret = krb5_ret_times (sp,  &creds->times);
137055682Smarkm    if(ret) goto cleanup;
137155682Smarkm    ret = krb5_ret_int8 (sp,  &dummy8);
137255682Smarkm    if(ret) goto cleanup;
137355682Smarkm    ret = krb5_ret_int32 (sp,  &dummy32);
137455682Smarkm    if(ret) goto cleanup;
1375127808Snectar    /*
1376127808Snectar     * Runtime detect the what is the higher bits of the bitfield. If
1377178825Sdfr     * any of the higher bits are set in the input data, it's either a
1378178825Sdfr     * new ticket flag (and this code need to be removed), or it's a
1379127808Snectar     * MIT cache (or new Heimdal cache), lets change it to our current
1380127808Snectar     * format.
1381127808Snectar     */
1382127808Snectar    {
1383178825Sdfr	uint32_t mask = 0xffff0000;
1384127808Snectar	creds->flags.i = 0;
1385127808Snectar	creds->flags.b.anonymous = 1;
1386127808Snectar	if (creds->flags.i & mask)
1387127808Snectar	    mask = ~mask;
1388127808Snectar	if (dummy32 & mask)
1389127808Snectar	    dummy32 = bitswap32(dummy32);
1390127808Snectar    }
139155682Smarkm    creds->flags.i = dummy32;
139255682Smarkm    ret = krb5_ret_addrs (sp,  &creds->addresses);
139355682Smarkm    if(ret) goto cleanup;
139455682Smarkm    ret = krb5_ret_authdata (sp,  &creds->authdata);
139555682Smarkm    if(ret) goto cleanup;
139655682Smarkm    ret = krb5_ret_data (sp,  &creds->ticket);
139755682Smarkm    if(ret) goto cleanup;
139855682Smarkm    ret = krb5_ret_data (sp,  &creds->second_ticket);
139955682Smarkmcleanup:
1400102644Snectar    if(ret) {
1401233294Sstas#if 0
1402178825Sdfr	krb5_free_cred_contents(context, creds); /* XXX */
140355682Smarkm#endif
1404102644Snectar    }
140555682Smarkm    return ret;
140655682Smarkm}
1407178825Sdfr
1408178825Sdfr#define SC_CLIENT_PRINCIPAL	    0x0001
1409178825Sdfr#define SC_SERVER_PRINCIPAL	    0x0002
1410178825Sdfr#define SC_SESSION_KEY		    0x0004
1411178825Sdfr#define SC_TICKET		    0x0008
1412178825Sdfr#define SC_SECOND_TICKET	    0x0010
1413178825Sdfr#define SC_AUTHDATA		    0x0020
1414178825Sdfr#define SC_ADDRESSES		    0x0040
1415178825Sdfr
1416233294Sstas/**
1417233294Sstas * Write a tagged credentials block to storage.
1418178825Sdfr *
1419233294Sstas * @param sp the storage buffer to write to
1420233294Sstas * @param creds the creds block to write.
1421233294Sstas *
1422233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1423233294Sstas *
1424233294Sstas * @ingroup krb5_storage
1425178825Sdfr */
1426178825Sdfr
1427233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1428178825Sdfrkrb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
1429178825Sdfr{
1430178825Sdfr    int ret;
1431178825Sdfr    int32_t header = 0;
1432178825Sdfr
1433178825Sdfr    if (creds->client)
1434178825Sdfr	header |= SC_CLIENT_PRINCIPAL;
1435178825Sdfr    if (creds->server)
1436178825Sdfr	header |= SC_SERVER_PRINCIPAL;
1437178825Sdfr    if (creds->session.keytype != ETYPE_NULL)
1438178825Sdfr	header |= SC_SESSION_KEY;
1439178825Sdfr    if (creds->ticket.data)
1440178825Sdfr	header |= SC_TICKET;
1441178825Sdfr    if (creds->second_ticket.length)
1442178825Sdfr	header |= SC_SECOND_TICKET;
1443178825Sdfr    if (creds->authdata.len)
1444178825Sdfr	header |= SC_AUTHDATA;
1445178825Sdfr    if (creds->addresses.len)
1446178825Sdfr	header |= SC_ADDRESSES;
1447178825Sdfr
1448178825Sdfr    ret = krb5_store_int32(sp, header);
1449233294Sstas    if (ret)
1450233294Sstas	return ret;
1451178825Sdfr
1452178825Sdfr    if (creds->client) {
1453178825Sdfr	ret = krb5_store_principal(sp, creds->client);
1454178825Sdfr	if(ret)
1455178825Sdfr	    return ret;
1456178825Sdfr    }
1457178825Sdfr
1458178825Sdfr    if (creds->server) {
1459178825Sdfr	ret = krb5_store_principal(sp, creds->server);
1460178825Sdfr	if(ret)
1461178825Sdfr	    return ret;
1462178825Sdfr    }
1463178825Sdfr
1464178825Sdfr    if (creds->session.keytype != ETYPE_NULL) {
1465178825Sdfr	ret = krb5_store_keyblock(sp, creds->session);
1466178825Sdfr	if(ret)
1467178825Sdfr	    return ret;
1468178825Sdfr    }
1469178825Sdfr
1470178825Sdfr    ret = krb5_store_times(sp, creds->times);
1471178825Sdfr    if(ret)
1472178825Sdfr	return ret;
1473178825Sdfr    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1474178825Sdfr    if(ret)
1475178825Sdfr	return ret;
1476178825Sdfr
1477178825Sdfr    ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1478178825Sdfr    if(ret)
1479178825Sdfr	return ret;
1480178825Sdfr
1481178825Sdfr    if (creds->addresses.len) {
1482178825Sdfr	ret = krb5_store_addrs(sp, creds->addresses);
1483178825Sdfr	if(ret)
1484178825Sdfr	    return ret;
1485178825Sdfr    }
1486178825Sdfr
1487178825Sdfr    if (creds->authdata.len) {
1488178825Sdfr	ret = krb5_store_authdata(sp, creds->authdata);
1489178825Sdfr	if(ret)
1490178825Sdfr	    return ret;
1491178825Sdfr    }
1492178825Sdfr
1493178825Sdfr    if (creds->ticket.data) {
1494178825Sdfr	ret = krb5_store_data(sp, creds->ticket);
1495178825Sdfr	if(ret)
1496178825Sdfr	    return ret;
1497178825Sdfr    }
1498178825Sdfr
1499178825Sdfr    if (creds->second_ticket.data) {
1500178825Sdfr	ret = krb5_store_data(sp, creds->second_ticket);
1501178825Sdfr	if (ret)
1502178825Sdfr	    return ret;
1503178825Sdfr    }
1504178825Sdfr
1505178825Sdfr    return ret;
1506178825Sdfr}
1507178825Sdfr
1508233294Sstas/**
1509233294Sstas * Read a tagged credentials block from the storage.
1510233294Sstas *
1511233294Sstas * @param sp the storage buffer to write to
1512233294Sstas * @param creds the credentials block read from storage
1513233294Sstas *
1514233294Sstas * @return 0 on success, a Kerberos 5 error code on failure.
1515233294Sstas *
1516233294Sstas * @ingroup krb5_storage
1517233294Sstas */
1518233294Sstas
1519233294SstasKRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
1520178825Sdfrkrb5_ret_creds_tag(krb5_storage *sp,
1521178825Sdfr		   krb5_creds *creds)
1522178825Sdfr{
1523178825Sdfr    krb5_error_code ret;
1524178825Sdfr    int8_t dummy8;
1525178825Sdfr    int32_t dummy32, header;
1526178825Sdfr
1527178825Sdfr    memset(creds, 0, sizeof(*creds));
1528178825Sdfr
1529178825Sdfr    ret = krb5_ret_int32 (sp, &header);
1530178825Sdfr    if (ret) goto cleanup;
1531178825Sdfr
1532178825Sdfr    if (header & SC_CLIENT_PRINCIPAL) {
1533178825Sdfr	ret = krb5_ret_principal (sp,  &creds->client);
1534178825Sdfr	if(ret) goto cleanup;
1535178825Sdfr    }
1536178825Sdfr    if (header & SC_SERVER_PRINCIPAL) {
1537178825Sdfr	ret = krb5_ret_principal (sp,  &creds->server);
1538178825Sdfr	if(ret) goto cleanup;
1539178825Sdfr    }
1540178825Sdfr    if (header & SC_SESSION_KEY) {
1541178825Sdfr	ret = krb5_ret_keyblock (sp,  &creds->session);
1542178825Sdfr	if(ret) goto cleanup;
1543178825Sdfr    }
1544178825Sdfr    ret = krb5_ret_times (sp,  &creds->times);
1545178825Sdfr    if(ret) goto cleanup;
1546178825Sdfr    ret = krb5_ret_int8 (sp,  &dummy8);
1547178825Sdfr    if(ret) goto cleanup;
1548178825Sdfr    ret = krb5_ret_int32 (sp,  &dummy32);
1549178825Sdfr    if(ret) goto cleanup;
1550178825Sdfr    /*
1551178825Sdfr     * Runtime detect the what is the higher bits of the bitfield. If
1552178825Sdfr     * any of the higher bits are set in the input data, it's either a
1553178825Sdfr     * new ticket flag (and this code need to be removed), or it's a
1554178825Sdfr     * MIT cache (or new Heimdal cache), lets change it to our current
1555178825Sdfr     * format.
1556178825Sdfr     */
1557178825Sdfr    {
1558178825Sdfr	uint32_t mask = 0xffff0000;
1559178825Sdfr	creds->flags.i = 0;
1560178825Sdfr	creds->flags.b.anonymous = 1;
1561178825Sdfr	if (creds->flags.i & mask)
1562178825Sdfr	    mask = ~mask;
1563178825Sdfr	if (dummy32 & mask)
1564178825Sdfr	    dummy32 = bitswap32(dummy32);
1565178825Sdfr    }
1566178825Sdfr    creds->flags.i = dummy32;
1567178825Sdfr    if (header & SC_ADDRESSES) {
1568178825Sdfr	ret = krb5_ret_addrs (sp,  &creds->addresses);
1569178825Sdfr	if(ret) goto cleanup;
1570178825Sdfr    }
1571178825Sdfr    if (header & SC_AUTHDATA) {
1572178825Sdfr	ret = krb5_ret_authdata (sp,  &creds->authdata);
1573178825Sdfr	if(ret) goto cleanup;
1574178825Sdfr    }
1575178825Sdfr    if (header & SC_TICKET) {
1576178825Sdfr	ret = krb5_ret_data (sp,  &creds->ticket);
1577178825Sdfr	if(ret) goto cleanup;
1578178825Sdfr    }
1579178825Sdfr    if (header & SC_SECOND_TICKET) {
1580178825Sdfr	ret = krb5_ret_data (sp,  &creds->second_ticket);
1581178825Sdfr	if(ret) goto cleanup;
1582178825Sdfr    }
1583178825Sdfr
1584178825Sdfrcleanup:
1585178825Sdfr    if(ret) {
1586233294Sstas#if 0
1587178825Sdfr	krb5_free_cred_contents(context, creds); /* XXX */
1588178825Sdfr#endif
1589178825Sdfr    }
1590178825Sdfr    return ret;
1591178825Sdfr}
1592