• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src/router/samba-3.5.8/source4/heimdal/lib/krb5/
1/*
2 * Copyright (c) 1997-2008 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 *
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * 3. Neither the name of the Institute nor the names of its contributors
18 *    may be used to endorse or promote products derived from this software
19 *    without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include "krb5_locl.h"
35#include "store-int.h"
36
37#define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
38#define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
39#define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
40#define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
41			       krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
42
43void KRB5_LIB_FUNCTION
44krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
45{
46    sp->flags |= flags;
47}
48
49void KRB5_LIB_FUNCTION
50krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
51{
52    sp->flags &= ~flags;
53}
54
55/**
56 * Return true or false depending on if the storage flags is set or
57 * not. NB testing for the flag 0 always return true.
58 *
59 * @param sp the storage buffer to check flags on
60 * @param flags The flags to test for
61 *
62 * @return true if all the flags are set, false if not.
63 *
64 * @ingroup krb5_storage
65 */
66
67krb5_boolean KRB5_LIB_FUNCTION
68krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
69{
70    return (sp->flags & flags) == flags;
71}
72
73/**
74 * Set the new byte order of the storage buffer.
75 *
76 * @param sp the storage buffer to set the byte order for.
77 * @param byteorder the new byte order.
78 *
79 * The byte order are: KRB5_STORAGE_BYTEORDER_BE,
80 * KRB5_STORAGE_BYTEORDER_LE and KRB5_STORAGE_BYTEORDER_HOST.
81 *
82 * @ingroup krb5_storage
83 */
84
85void KRB5_LIB_FUNCTION
86krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
87{
88    sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
89    sp->flags |= byteorder;
90}
91
92/**
93 * Return the current byteorder for the buffer. See krb5_storage_set_byteorder() for the list or byte order contants.
94 *
95 * @ingroup krb5_storage
96 */
97
98krb5_flags KRB5_LIB_FUNCTION
99krb5_storage_get_byteorder(krb5_storage *sp)
100{
101    return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
102}
103
104/**
105 * Seek to a new offset.
106 *
107 * @param sp the storage buffer to seek in.
108 * @param offset the offset to seek
109 * @param whence relateive searching, SEEK_CUR from the current
110 * position, SEEK_END from the end, SEEK_SET absolute from the start.
111 *
112 * @return The new current offset
113 *
114 * @ingroup krb5_storage
115 */
116
117off_t KRB5_LIB_FUNCTION
118krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
119{
120    return (*sp->seek)(sp, offset, whence);
121}
122
123/**
124 * Truncate the storage buffer in sp to offset.
125 *
126 * @param sp the storage buffer to truncate.
127 * @param offset the offset to truncate too.
128 *
129 * @return An Kerberos 5 error code.
130 *
131 * @ingroup krb5_storage
132 */
133
134int KRB5_LIB_FUNCTION
135krb5_storage_truncate(krb5_storage *sp, off_t offset)
136{
137    return (*sp->trunc)(sp, offset);
138}
139
140/**
141 * Read to the storage buffer.
142 *
143 * @param sp the storage buffer to read from
144 * @param buf the buffer to store the data in
145 * @param len the length to read
146 *
147 * @return The length of data read (can be shorter then len), or negative on error.
148 *
149 * @ingroup krb5_storage
150 */
151
152krb5_ssize_t KRB5_LIB_FUNCTION
153krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
154{
155    return sp->fetch(sp, buf, len);
156}
157
158/**
159 * Write to the storage buffer.
160 *
161 * @param sp the storage buffer to write to
162 * @param buf the buffer to write to the storage buffer
163 * @param len the length to write
164 *
165 * @return The length of data written (can be shorter then len), or negative on error.
166 *
167 * @ingroup krb5_storage
168 */
169
170krb5_ssize_t KRB5_LIB_FUNCTION
171krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
172{
173    return sp->store(sp, buf, len);
174}
175
176/**
177 * Set the return code that will be used when end of storage is reached.
178 *
179 * @param sp the storage
180 * @param code the error code to return on end of storage
181 *
182 * @ingroup krb5_storage
183 */
184
185void KRB5_LIB_FUNCTION
186krb5_storage_set_eof_code(krb5_storage *sp, int code)
187{
188    sp->eof_code = code;
189}
190
191/**
192 * Get the return code that will be used when end of storage is reached.
193 *
194 * @param sp the storage
195 *
196 * @return storage error code
197 *
198 * @ingroup krb5_storage
199 */
200
201int KRB5_LIB_FUNCTION
202krb5_storage_get_eof_code(krb5_storage *sp)
203{
204    return sp->eof_code;
205}
206
207krb5_ssize_t KRB5_LIB_FUNCTION
208_krb5_put_int(void *buffer, unsigned long value, size_t size)
209{
210    unsigned char *p = buffer;
211    int i;
212    for (i = size - 1; i >= 0; i--) {
213	p[i] = value & 0xff;
214	value >>= 8;
215    }
216    return size;
217}
218
219krb5_ssize_t KRB5_LIB_FUNCTION
220_krb5_get_int(void *buffer, unsigned long *value, size_t size)
221{
222    unsigned char *p = buffer;
223    unsigned long v = 0;
224    int i;
225    for (i = 0; i < size; i++)
226	v = (v << 8) + p[i];
227    *value = v;
228    return size;
229}
230
231/**
232 * Free a krb5 storage.
233 *
234 * @param sp the storage to free.
235 *
236 * @return An Kerberos 5 error code.
237 *
238 * @ingroup krb5_storage
239 */
240
241krb5_error_code KRB5_LIB_FUNCTION
242krb5_storage_free(krb5_storage *sp)
243{
244    if(sp->free)
245	(*sp->free)(sp);
246    free(sp->data);
247    free(sp);
248    return 0;
249}
250
251/**
252 * Copy the contnent of storage
253 *
254 * @param sp the storage to copy to a data
255 * @param data the copied data, free with krb5_data_free()
256 *
257 * @return 0 for success, or a Kerberos 5 error code on failure.
258 *
259 * @ingroup krb5_storage
260 */
261
262krb5_error_code KRB5_LIB_FUNCTION
263krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
264{
265    off_t pos, size;
266    krb5_error_code ret;
267
268    pos = sp->seek(sp, 0, SEEK_CUR);
269    if (pos < 0)
270	return HEIM_ERR_NOT_SEEKABLE;
271    size = (size_t)sp->seek(sp, 0, SEEK_END);
272    if (size > (size_t)-1)
273	return HEIM_ERR_TOO_BIG;
274    ret = krb5_data_alloc (data, size);
275    if (ret) {
276	sp->seek(sp, pos, SEEK_SET);
277	return ret;
278    }
279    if (size) {
280	sp->seek(sp, 0, SEEK_SET);
281	sp->fetch(sp, data->data, data->length);
282	sp->seek(sp, pos, SEEK_SET);
283    }
284    return 0;
285}
286
287static krb5_error_code
288krb5_store_int(krb5_storage *sp,
289	       int32_t value,
290	       size_t len)
291{
292    int ret;
293    unsigned char v[16];
294
295    if(len > sizeof(v))
296	return EINVAL;
297    _krb5_put_int(v, value, len);
298    ret = sp->store(sp, v, len);
299    if (ret != len)
300	return (ret<0)?errno:sp->eof_code;
301    return 0;
302}
303
304/**
305 * Store a int32 to storage, byte order is controlled by the settings
306 * on the storage, see krb5_storage_set_byteorder().
307 *
308 * @param sp the storage to write too
309 * @param value the value to store
310 *
311 * @return 0 for success, or a Kerberos 5 error code on failure.
312 *
313 * @ingroup krb5_storage
314 */
315
316krb5_error_code KRB5_LIB_FUNCTION
317krb5_store_int32(krb5_storage *sp,
318		 int32_t value)
319{
320    if(BYTEORDER_IS_HOST(sp))
321	value = htonl(value);
322    else if(BYTEORDER_IS_LE(sp))
323	value = bswap32(value);
324    return krb5_store_int(sp, value, 4);
325}
326
327/**
328 * Store a uint32 to storage, byte order is controlled by the settings
329 * on the storage, see krb5_storage_set_byteorder().
330 *
331 * @param sp the storage to write too
332 * @param value the value to store
333 *
334 * @return 0 for success, or a Kerberos 5 error code on failure.
335 *
336 * @ingroup krb5_storage
337 */
338
339krb5_error_code KRB5_LIB_FUNCTION
340krb5_store_uint32(krb5_storage *sp,
341		  uint32_t value)
342{
343    return krb5_store_int32(sp, (int32_t)value);
344}
345
346static krb5_error_code
347krb5_ret_int(krb5_storage *sp,
348	     int32_t *value,
349	     size_t len)
350{
351    int ret;
352    unsigned char v[4];
353    unsigned long w;
354    ret = sp->fetch(sp, v, len);
355    if(ret != len)
356	return (ret<0)?errno:sp->eof_code;
357    _krb5_get_int(v, &w, len);
358    *value = w;
359    return 0;
360}
361
362krb5_error_code KRB5_LIB_FUNCTION
363krb5_ret_int32(krb5_storage *sp,
364	       int32_t *value)
365{
366    krb5_error_code ret = krb5_ret_int(sp, value, 4);
367    if(ret)
368	return ret;
369    if(BYTEORDER_IS_HOST(sp))
370	*value = htonl(*value);
371    else if(BYTEORDER_IS_LE(sp))
372	*value = bswap32(*value);
373    return 0;
374}
375
376krb5_error_code KRB5_LIB_FUNCTION
377krb5_ret_uint32(krb5_storage *sp,
378		uint32_t *value)
379{
380    krb5_error_code ret;
381    int32_t v;
382
383    ret = krb5_ret_int32(sp, &v);
384    if (ret == 0)
385	*value = (uint32_t)v;
386
387    return ret;
388}
389
390/**
391 * Store a int16 to storage, byte order is controlled by the settings
392 * on the storage, see krb5_storage_set_byteorder().
393 *
394 * @param sp the storage to write too
395 * @param value the value to store
396 *
397 * @return 0 for success, or a Kerberos 5 error code on failure.
398 *
399 * @ingroup krb5_storage
400 */
401
402krb5_error_code KRB5_LIB_FUNCTION
403krb5_store_int16(krb5_storage *sp,
404		 int16_t value)
405{
406    if(BYTEORDER_IS_HOST(sp))
407	value = htons(value);
408    else if(BYTEORDER_IS_LE(sp))
409	value = bswap16(value);
410    return krb5_store_int(sp, value, 2);
411}
412
413/**
414 * Store a uint16 to storage, byte order is controlled by the settings
415 * on the storage, see krb5_storage_set_byteorder().
416 *
417 * @param sp the storage to write too
418 * @param value the value to store
419 *
420 * @return 0 for success, or a Kerberos 5 error code on failure.
421 *
422 * @ingroup krb5_storage
423 */
424
425krb5_error_code KRB5_LIB_FUNCTION
426krb5_store_uint16(krb5_storage *sp,
427		  uint16_t value)
428{
429    return krb5_store_int16(sp, (int16_t)value);
430}
431
432krb5_error_code KRB5_LIB_FUNCTION
433krb5_ret_int16(krb5_storage *sp,
434	       int16_t *value)
435{
436    int32_t v;
437    int ret;
438    ret = krb5_ret_int(sp, &v, 2);
439    if(ret)
440	return ret;
441    *value = v;
442    if(BYTEORDER_IS_HOST(sp))
443	*value = htons(*value);
444    else if(BYTEORDER_IS_LE(sp))
445	*value = bswap16(*value);
446    return 0;
447}
448
449krb5_error_code KRB5_LIB_FUNCTION
450krb5_ret_uint16(krb5_storage *sp,
451		uint16_t *value)
452{
453    krb5_error_code ret;
454    int16_t v;
455
456    ret = krb5_ret_int16(sp, &v);
457    if (ret == 0)
458	*value = (uint16_t)v;
459
460    return ret;
461}
462
463/**
464 * Store a int8 to storage.
465 *
466 * @param sp the storage to write too
467 * @param value the value to store
468 *
469 * @return 0 for success, or a Kerberos 5 error code on failure.
470 *
471 * @ingroup krb5_storage
472 */
473
474krb5_error_code KRB5_LIB_FUNCTION
475krb5_store_int8(krb5_storage *sp,
476		int8_t value)
477{
478    int ret;
479
480    ret = sp->store(sp, &value, sizeof(value));
481    if (ret != sizeof(value))
482	return (ret<0)?errno:sp->eof_code;
483    return 0;
484}
485
486/**
487 * Store a uint8 to storage.
488 *
489 * @param sp the storage to write too
490 * @param value the value to store
491 *
492 * @return 0 for success, or a Kerberos 5 error code on failure.
493 *
494 * @ingroup krb5_storage
495 */
496
497krb5_error_code KRB5_LIB_FUNCTION
498krb5_store_uint8(krb5_storage *sp,
499		 uint8_t value)
500{
501    return krb5_store_int8(sp, (int8_t)value);
502}
503
504krb5_error_code KRB5_LIB_FUNCTION
505krb5_ret_int8(krb5_storage *sp,
506	      int8_t *value)
507{
508    int ret;
509
510    ret = sp->fetch(sp, value, sizeof(*value));
511    if (ret != sizeof(*value))
512	return (ret<0)?errno:sp->eof_code;
513    return 0;
514}
515
516krb5_error_code KRB5_LIB_FUNCTION
517krb5_ret_uint8(krb5_storage *sp,
518	       uint8_t *value)
519{
520    krb5_error_code ret;
521    int8_t v;
522
523    ret = krb5_ret_int8(sp, &v);
524    if (ret == 0)
525	*value = (uint8_t)v;
526
527    return ret;
528}
529
530/**
531 * Store a data to the storage.
532 *
533 * @param sp the storage buffer to write to
534 * @param data the buffer to store.
535 *
536 * @return 0 on success, a Kerberos 5 error code on failure.
537 *
538 * @ingroup krb5_storage
539 */
540
541krb5_error_code KRB5_LIB_FUNCTION
542krb5_store_data(krb5_storage *sp,
543		krb5_data data)
544{
545    int ret;
546    ret = krb5_store_int32(sp, data.length);
547    if(ret < 0)
548	return ret;
549    ret = sp->store(sp, data.data, data.length);
550    if(ret != data.length){
551	if(ret < 0)
552	    return errno;
553	return sp->eof_code;
554    }
555    return 0;
556}
557
558/**
559 * Parse a data from the storage.
560 *
561 * @param sp the storage buffer to read from
562 * @param data the parsed data
563 *
564 * @return 0 on success, a Kerberos 5 error code on failure.
565 *
566 * @ingroup krb5_storage
567 */
568
569krb5_error_code KRB5_LIB_FUNCTION
570krb5_ret_data(krb5_storage *sp,
571	      krb5_data *data)
572{
573    int ret;
574    int32_t size;
575
576    ret = krb5_ret_int32(sp, &size);
577    if(ret)
578	return ret;
579    ret = krb5_data_alloc (data, size);
580    if (ret)
581	return ret;
582    if (size) {
583	ret = sp->fetch(sp, data->data, size);
584	if(ret != size)
585	    return (ret < 0)? errno : sp->eof_code;
586    }
587    return 0;
588}
589
590krb5_error_code KRB5_LIB_FUNCTION
591krb5_store_string(krb5_storage *sp, const char *s)
592{
593    krb5_data data;
594    data.length = strlen(s);
595    data.data = rk_UNCONST(s);
596    return krb5_store_data(sp, data);
597}
598
599krb5_error_code KRB5_LIB_FUNCTION
600krb5_ret_string(krb5_storage *sp,
601		char **string)
602{
603    int ret;
604    krb5_data data;
605    ret = krb5_ret_data(sp, &data);
606    if(ret)
607	return ret;
608    *string = realloc(data.data, data.length + 1);
609    if(*string == NULL){
610	free(data.data);
611	return ENOMEM;
612    }
613    (*string)[data.length] = 0;
614    return 0;
615}
616
617krb5_error_code KRB5_LIB_FUNCTION
618krb5_store_stringz(krb5_storage *sp, const char *s)
619{
620    size_t len = strlen(s) + 1;
621    ssize_t ret;
622
623    ret = sp->store(sp, s, len);
624    if(ret != len) {
625	if(ret < 0)
626	    return ret;
627	else
628	    return sp->eof_code;
629    }
630    return 0;
631}
632
633krb5_error_code KRB5_LIB_FUNCTION
634krb5_ret_stringz(krb5_storage *sp,
635		char **string)
636{
637    char c;
638    char *s = NULL;
639    size_t len = 0;
640    ssize_t ret;
641
642    while((ret = sp->fetch(sp, &c, 1)) == 1){
643	char *tmp;
644
645	len++;
646	tmp = realloc (s, len);
647	if (tmp == NULL) {
648	    free (s);
649	    return ENOMEM;
650	}
651	s = tmp;
652	s[len - 1] = c;
653	if(c == 0)
654	    break;
655    }
656    if(ret != 1){
657	free(s);
658	if(ret == 0)
659	    return sp->eof_code;
660	return ret;
661    }
662    *string = s;
663    return 0;
664}
665
666krb5_error_code KRB5_LIB_FUNCTION
667krb5_store_stringnl(krb5_storage *sp, const char *s)
668{
669    size_t len = strlen(s);
670    ssize_t ret;
671
672    ret = sp->store(sp, s, len);
673    if(ret != len) {
674	if(ret < 0)
675	    return ret;
676	else
677	    return sp->eof_code;
678    }
679    ret = sp->store(sp, "\n", 1);
680    if(ret != 1) {
681	if(ret < 0)
682	    return ret;
683	else
684	    return sp->eof_code;
685    }
686
687    return 0;
688
689}
690
691krb5_error_code KRB5_LIB_FUNCTION
692krb5_ret_stringnl(krb5_storage *sp,
693		  char **string)
694{
695    int expect_nl = 0;
696    char c;
697    char *s = NULL;
698    size_t len = 0;
699    ssize_t ret;
700
701    while((ret = sp->fetch(sp, &c, 1)) == 1){
702	char *tmp;
703
704	if (c == '\r') {
705	    expect_nl = 1;
706	    continue;
707	}
708	if (expect_nl && c != '\n') {
709	    free(s);
710	    return KRB5_BADMSGTYPE;
711	}
712
713	len++;
714	tmp = realloc (s, len);
715	if (tmp == NULL) {
716	    free (s);
717	    return ENOMEM;
718	}
719	s = tmp;
720	if(c == '\n') {
721	    s[len - 1] = '\0';
722	    break;
723	}
724	s[len - 1] = c;
725    }
726    if(ret != 1){
727	free(s);
728	if(ret == 0)
729	    return sp->eof_code;
730	return ret;
731    }
732    *string = s;
733    return 0;
734}
735
736
737krb5_error_code KRB5_LIB_FUNCTION
738krb5_store_principal(krb5_storage *sp,
739		     krb5_const_principal p)
740{
741    int i;
742    int ret;
743
744    if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
745	ret = krb5_store_int32(sp, p->name.name_type);
746	if(ret) return ret;
747    }
748    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
749	ret = krb5_store_int32(sp, p->name.name_string.len + 1);
750    else
751	ret = krb5_store_int32(sp, p->name.name_string.len);
752
753    if(ret) return ret;
754    ret = krb5_store_string(sp, p->realm);
755    if(ret) return ret;
756    for(i = 0; i < p->name.name_string.len; i++){
757	ret = krb5_store_string(sp, p->name.name_string.val[i]);
758	if(ret) return ret;
759    }
760    return 0;
761}
762
763krb5_error_code KRB5_LIB_FUNCTION
764krb5_ret_principal(krb5_storage *sp,
765		   krb5_principal *princ)
766{
767    int i;
768    int ret;
769    krb5_principal p;
770    int32_t type;
771    int32_t ncomp;
772
773    p = calloc(1, sizeof(*p));
774    if(p == NULL)
775	return ENOMEM;
776
777    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
778	type = KRB5_NT_UNKNOWN;
779    else if((ret = krb5_ret_int32(sp, &type))){
780	free(p);
781	return ret;
782    }
783    if((ret = krb5_ret_int32(sp, &ncomp))){
784	free(p);
785	return ret;
786    }
787    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
788	ncomp--;
789    if (ncomp < 0) {
790	free(p);
791	return EINVAL;
792    }
793    p->name.name_type = type;
794    p->name.name_string.len = ncomp;
795    ret = krb5_ret_string(sp, &p->realm);
796    if(ret) {
797	free(p);
798	return ret;
799    }
800    p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
801    if(p->name.name_string.val == NULL && ncomp != 0){
802	free(p->realm);
803	free(p);
804	return ENOMEM;
805    }
806    for(i = 0; i < ncomp; i++){
807	ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
808	if(ret) {
809	    while (i >= 0)
810		free(p->name.name_string.val[i--]);
811	    free(p->realm);
812	    free(p);
813	    return ret;
814	}
815    }
816    *princ = p;
817    return 0;
818}
819
820/**
821 * Store a keyblock to the storage.
822 *
823 * @param sp the storage buffer to write to
824 * @param p the keyblock to write
825 *
826 * @return 0 on success, a Kerberos 5 error code on failure.
827 *
828 * @ingroup krb5_storage
829 */
830
831krb5_error_code KRB5_LIB_FUNCTION
832krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
833{
834    int ret;
835    ret = krb5_store_int16(sp, p.keytype);
836    if(ret) return ret;
837
838    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
839	/* this should really be enctype, but it is the same as
840           keytype nowadays */
841    ret = krb5_store_int16(sp, p.keytype);
842    if(ret) return ret;
843    }
844
845    ret = krb5_store_data(sp, p.keyvalue);
846    return ret;
847}
848
849/**
850 * Read a keyblock from the storage.
851 *
852 * @param sp the storage buffer to write to
853 * @param p the keyblock read from storage, free using krb5_free_keyblock()
854 *
855 * @return 0 on success, a Kerberos 5 error code on failure.
856 *
857 * @ingroup krb5_storage
858 */
859
860krb5_error_code KRB5_LIB_FUNCTION
861krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
862{
863    int ret;
864    int16_t tmp;
865
866    ret = krb5_ret_int16(sp, &tmp);
867    if(ret) return ret;
868    p->keytype = tmp;
869
870    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
871    ret = krb5_ret_int16(sp, &tmp);
872    if(ret) return ret;
873    }
874
875    ret = krb5_ret_data(sp, &p->keyvalue);
876    return ret;
877}
878
879/**
880 * Write a times block to storage.
881 *
882 * @param sp the storage buffer to write to
883 * @param times the times block to write.
884 *
885 * @return 0 on success, a Kerberos 5 error code on failure.
886 *
887 * @ingroup krb5_storage
888 */
889
890krb5_error_code KRB5_LIB_FUNCTION
891krb5_store_times(krb5_storage *sp, krb5_times times)
892{
893    int ret;
894    ret = krb5_store_int32(sp, times.authtime);
895    if(ret) return ret;
896    ret = krb5_store_int32(sp, times.starttime);
897    if(ret) return ret;
898    ret = krb5_store_int32(sp, times.endtime);
899    if(ret) return ret;
900    ret = krb5_store_int32(sp, times.renew_till);
901    return ret;
902}
903
904/**
905 * Read a times block from the storage.
906 *
907 * @param sp the storage buffer to write to
908 * @param times the times block read from storage
909 *
910 * @return 0 on success, a Kerberos 5 error code on failure.
911 *
912 * @ingroup krb5_storage
913 */
914
915krb5_error_code KRB5_LIB_FUNCTION
916krb5_ret_times(krb5_storage *sp, krb5_times *times)
917{
918    int ret;
919    int32_t tmp;
920    ret = krb5_ret_int32(sp, &tmp);
921    times->authtime = tmp;
922    if(ret) return ret;
923    ret = krb5_ret_int32(sp, &tmp);
924    times->starttime = tmp;
925    if(ret) return ret;
926    ret = krb5_ret_int32(sp, &tmp);
927    times->endtime = tmp;
928    if(ret) return ret;
929    ret = krb5_ret_int32(sp, &tmp);
930    times->renew_till = tmp;
931    return ret;
932}
933
934krb5_error_code KRB5_LIB_FUNCTION
935krb5_store_address(krb5_storage *sp, krb5_address p)
936{
937    int ret;
938    ret = krb5_store_int16(sp, p.addr_type);
939    if(ret) return ret;
940    ret = krb5_store_data(sp, p.address);
941    return ret;
942}
943
944krb5_error_code KRB5_LIB_FUNCTION
945krb5_ret_address(krb5_storage *sp, krb5_address *adr)
946{
947    int16_t t;
948    int ret;
949    ret = krb5_ret_int16(sp, &t);
950    if(ret) return ret;
951    adr->addr_type = t;
952    ret = krb5_ret_data(sp, &adr->address);
953    return ret;
954}
955
956krb5_error_code KRB5_LIB_FUNCTION
957krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
958{
959    int i;
960    int ret;
961    ret = krb5_store_int32(sp, p.len);
962    if(ret) return ret;
963    for(i = 0; i<p.len; i++){
964	ret = krb5_store_address(sp, p.val[i]);
965	if(ret) break;
966    }
967    return ret;
968}
969
970krb5_error_code KRB5_LIB_FUNCTION
971krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
972{
973    int i;
974    int ret;
975    int32_t tmp;
976
977    ret = krb5_ret_int32(sp, &tmp);
978    if(ret) return ret;
979    adr->len = tmp;
980    ALLOC(adr->val, adr->len);
981    if (adr->val == NULL && adr->len != 0)
982	return ENOMEM;
983    for(i = 0; i < adr->len; i++){
984	ret = krb5_ret_address(sp, &adr->val[i]);
985	if(ret) break;
986    }
987    return ret;
988}
989
990krb5_error_code KRB5_LIB_FUNCTION
991krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
992{
993    krb5_error_code ret;
994    int i;
995    ret = krb5_store_int32(sp, auth.len);
996    if(ret) return ret;
997    for(i = 0; i < auth.len; i++){
998	ret = krb5_store_int16(sp, auth.val[i].ad_type);
999	if(ret) break;
1000	ret = krb5_store_data(sp, auth.val[i].ad_data);
1001	if(ret) break;
1002    }
1003    return 0;
1004}
1005
1006krb5_error_code KRB5_LIB_FUNCTION
1007krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
1008{
1009    krb5_error_code ret;
1010    int32_t tmp;
1011    int16_t tmp2;
1012    int i;
1013    ret = krb5_ret_int32(sp, &tmp);
1014    if(ret) return ret;
1015    ALLOC_SEQ(auth, tmp);
1016    if (auth->val == NULL && tmp != 0)
1017	return ENOMEM;
1018    for(i = 0; i < tmp; i++){
1019	ret = krb5_ret_int16(sp, &tmp2);
1020	if(ret) break;
1021	auth->val[i].ad_type = tmp2;
1022	ret = krb5_ret_data(sp, &auth->val[i].ad_data);
1023	if(ret) break;
1024    }
1025    return ret;
1026}
1027
1028static int32_t
1029bitswap32(int32_t b)
1030{
1031    int32_t r = 0;
1032    int i;
1033    for (i = 0; i < 32; i++) {
1034	r = r << 1 | (b & 1);
1035	b = b >> 1;
1036    }
1037    return r;
1038}
1039
1040
1041/*
1042 *
1043 */
1044
1045krb5_error_code KRB5_LIB_FUNCTION
1046krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
1047{
1048    int ret;
1049
1050    ret = krb5_store_principal(sp, creds->client);
1051    if(ret)
1052	return ret;
1053    ret = krb5_store_principal(sp, creds->server);
1054    if(ret)
1055	return ret;
1056    ret = krb5_store_keyblock(sp, creds->session);
1057    if(ret)
1058	return ret;
1059    ret = krb5_store_times(sp, creds->times);
1060    if(ret)
1061	return ret;
1062    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1063    if(ret)
1064	return ret;
1065
1066    if(krb5_storage_is_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER))
1067	ret = krb5_store_int32(sp, creds->flags.i);
1068    else
1069	ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1070    if(ret)
1071	return ret;
1072
1073    ret = krb5_store_addrs(sp, creds->addresses);
1074    if(ret)
1075	return ret;
1076    ret = krb5_store_authdata(sp, creds->authdata);
1077    if(ret)
1078	return ret;
1079    ret = krb5_store_data(sp, creds->ticket);
1080    if(ret)
1081	return ret;
1082    ret = krb5_store_data(sp, creds->second_ticket);
1083    return ret;
1084}
1085
1086krb5_error_code KRB5_LIB_FUNCTION
1087krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
1088{
1089    krb5_error_code ret;
1090    int8_t dummy8;
1091    int32_t dummy32;
1092
1093    memset(creds, 0, sizeof(*creds));
1094    ret = krb5_ret_principal (sp,  &creds->client);
1095    if(ret) goto cleanup;
1096    ret = krb5_ret_principal (sp,  &creds->server);
1097    if(ret) goto cleanup;
1098    ret = krb5_ret_keyblock (sp,  &creds->session);
1099    if(ret) goto cleanup;
1100    ret = krb5_ret_times (sp,  &creds->times);
1101    if(ret) goto cleanup;
1102    ret = krb5_ret_int8 (sp,  &dummy8);
1103    if(ret) goto cleanup;
1104    ret = krb5_ret_int32 (sp,  &dummy32);
1105    if(ret) goto cleanup;
1106    /*
1107     * Runtime detect the what is the higher bits of the bitfield. If
1108     * any of the higher bits are set in the input data, it's either a
1109     * new ticket flag (and this code need to be removed), or it's a
1110     * MIT cache (or new Heimdal cache), lets change it to our current
1111     * format.
1112     */
1113    {
1114	uint32_t mask = 0xffff0000;
1115	creds->flags.i = 0;
1116	creds->flags.b.anonymous = 1;
1117	if (creds->flags.i & mask)
1118	    mask = ~mask;
1119	if (dummy32 & mask)
1120	    dummy32 = bitswap32(dummy32);
1121    }
1122    creds->flags.i = dummy32;
1123    ret = krb5_ret_addrs (sp,  &creds->addresses);
1124    if(ret) goto cleanup;
1125    ret = krb5_ret_authdata (sp,  &creds->authdata);
1126    if(ret) goto cleanup;
1127    ret = krb5_ret_data (sp,  &creds->ticket);
1128    if(ret) goto cleanup;
1129    ret = krb5_ret_data (sp,  &creds->second_ticket);
1130cleanup:
1131    if(ret) {
1132#if 0
1133	krb5_free_cred_contents(context, creds); /* XXX */
1134#endif
1135    }
1136    return ret;
1137}
1138
1139#define SC_CLIENT_PRINCIPAL	    0x0001
1140#define SC_SERVER_PRINCIPAL	    0x0002
1141#define SC_SESSION_KEY		    0x0004
1142#define SC_TICKET		    0x0008
1143#define SC_SECOND_TICKET	    0x0010
1144#define SC_AUTHDATA		    0x0020
1145#define SC_ADDRESSES		    0x0040
1146
1147/*
1148 *
1149 */
1150
1151krb5_error_code KRB5_LIB_FUNCTION
1152krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
1153{
1154    int ret;
1155    int32_t header = 0;
1156
1157    if (creds->client)
1158	header |= SC_CLIENT_PRINCIPAL;
1159    if (creds->server)
1160	header |= SC_SERVER_PRINCIPAL;
1161    if (creds->session.keytype != ETYPE_NULL)
1162	header |= SC_SESSION_KEY;
1163    if (creds->ticket.data)
1164	header |= SC_TICKET;
1165    if (creds->second_ticket.length)
1166	header |= SC_SECOND_TICKET;
1167    if (creds->authdata.len)
1168	header |= SC_AUTHDATA;
1169    if (creds->addresses.len)
1170	header |= SC_ADDRESSES;
1171
1172    ret = krb5_store_int32(sp, header);
1173    if (ret)
1174	return ret;
1175
1176    if (creds->client) {
1177	ret = krb5_store_principal(sp, creds->client);
1178	if(ret)
1179	    return ret;
1180    }
1181
1182    if (creds->server) {
1183	ret = krb5_store_principal(sp, creds->server);
1184	if(ret)
1185	    return ret;
1186    }
1187
1188    if (creds->session.keytype != ETYPE_NULL) {
1189	ret = krb5_store_keyblock(sp, creds->session);
1190	if(ret)
1191	    return ret;
1192    }
1193
1194    ret = krb5_store_times(sp, creds->times);
1195    if(ret)
1196	return ret;
1197    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
1198    if(ret)
1199	return ret;
1200
1201    ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
1202    if(ret)
1203	return ret;
1204
1205    if (creds->addresses.len) {
1206	ret = krb5_store_addrs(sp, creds->addresses);
1207	if(ret)
1208	    return ret;
1209    }
1210
1211    if (creds->authdata.len) {
1212	ret = krb5_store_authdata(sp, creds->authdata);
1213	if(ret)
1214	    return ret;
1215    }
1216
1217    if (creds->ticket.data) {
1218	ret = krb5_store_data(sp, creds->ticket);
1219	if(ret)
1220	    return ret;
1221    }
1222
1223    if (creds->second_ticket.data) {
1224	ret = krb5_store_data(sp, creds->second_ticket);
1225	if (ret)
1226	    return ret;
1227    }
1228
1229    return ret;
1230}
1231
1232krb5_error_code KRB5_LIB_FUNCTION
1233krb5_ret_creds_tag(krb5_storage *sp,
1234		   krb5_creds *creds)
1235{
1236    krb5_error_code ret;
1237    int8_t dummy8;
1238    int32_t dummy32, header;
1239
1240    memset(creds, 0, sizeof(*creds));
1241
1242    ret = krb5_ret_int32 (sp, &header);
1243    if (ret) goto cleanup;
1244
1245    if (header & SC_CLIENT_PRINCIPAL) {
1246	ret = krb5_ret_principal (sp,  &creds->client);
1247	if(ret) goto cleanup;
1248    }
1249    if (header & SC_SERVER_PRINCIPAL) {
1250	ret = krb5_ret_principal (sp,  &creds->server);
1251	if(ret) goto cleanup;
1252    }
1253    if (header & SC_SESSION_KEY) {
1254	ret = krb5_ret_keyblock (sp,  &creds->session);
1255	if(ret) goto cleanup;
1256    }
1257    ret = krb5_ret_times (sp,  &creds->times);
1258    if(ret) goto cleanup;
1259    ret = krb5_ret_int8 (sp,  &dummy8);
1260    if(ret) goto cleanup;
1261    ret = krb5_ret_int32 (sp,  &dummy32);
1262    if(ret) goto cleanup;
1263    /*
1264     * Runtime detect the what is the higher bits of the bitfield. If
1265     * any of the higher bits are set in the input data, it's either a
1266     * new ticket flag (and this code need to be removed), or it's a
1267     * MIT cache (or new Heimdal cache), lets change it to our current
1268     * format.
1269     */
1270    {
1271	uint32_t mask = 0xffff0000;
1272	creds->flags.i = 0;
1273	creds->flags.b.anonymous = 1;
1274	if (creds->flags.i & mask)
1275	    mask = ~mask;
1276	if (dummy32 & mask)
1277	    dummy32 = bitswap32(dummy32);
1278    }
1279    creds->flags.i = dummy32;
1280    if (header & SC_ADDRESSES) {
1281	ret = krb5_ret_addrs (sp,  &creds->addresses);
1282	if(ret) goto cleanup;
1283    }
1284    if (header & SC_AUTHDATA) {
1285	ret = krb5_ret_authdata (sp,  &creds->authdata);
1286	if(ret) goto cleanup;
1287    }
1288    if (header & SC_TICKET) {
1289	ret = krb5_ret_data (sp,  &creds->ticket);
1290	if(ret) goto cleanup;
1291    }
1292    if (header & SC_SECOND_TICKET) {
1293	ret = krb5_ret_data (sp,  &creds->second_ticket);
1294	if(ret) goto cleanup;
1295    }
1296
1297cleanup:
1298    if(ret) {
1299#if 0
1300	krb5_free_cred_contents(context, creds); /* XXX */
1301#endif
1302    }
1303    return ret;
1304}
1305