1/*
2 * Copyright (c) 1997-2006 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
37RCSID("$Id: store.c 22071 2007-11-14 20:04:50Z lha $");
38
39#define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
40#define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
41#define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
42#define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
43			       krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
44
45void KRB5_LIB_FUNCTION
46krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
47{
48    sp->flags |= flags;
49}
50
51void KRB5_LIB_FUNCTION
52krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
53{
54    sp->flags &= ~flags;
55}
56
57krb5_boolean KRB5_LIB_FUNCTION
58krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
59{
60    return (sp->flags & flags) == flags;
61}
62
63void KRB5_LIB_FUNCTION
64krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
65{
66    sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
67    sp->flags |= byteorder;
68}
69
70krb5_flags KRB5_LIB_FUNCTION
71krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder)
72{
73    return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
74}
75
76off_t KRB5_LIB_FUNCTION
77krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
78{
79    return (*sp->seek)(sp, offset, whence);
80}
81
82krb5_ssize_t KRB5_LIB_FUNCTION
83krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
84{
85    return sp->fetch(sp, buf, len);
86}
87
88krb5_ssize_t KRB5_LIB_FUNCTION
89krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
90{
91    return sp->store(sp, buf, len);
92}
93
94void KRB5_LIB_FUNCTION
95krb5_storage_set_eof_code(krb5_storage *sp, int code)
96{
97    sp->eof_code = code;
98}
99
100krb5_ssize_t KRB5_LIB_FUNCTION
101_krb5_put_int(void *buffer, unsigned long value, size_t size)
102{
103    unsigned char *p = buffer;
104    int i;
105    for (i = size - 1; i >= 0; i--) {
106	p[i] = value & 0xff;
107	value >>= 8;
108    }
109    return size;
110}
111
112krb5_ssize_t KRB5_LIB_FUNCTION
113_krb5_get_int(void *buffer, unsigned long *value, size_t size)
114{
115    unsigned char *p = buffer;
116    unsigned long v = 0;
117    int i;
118    for (i = 0; i < size; i++)
119	v = (v << 8) + p[i];
120    *value = v;
121    return size;
122}
123
124krb5_error_code KRB5_LIB_FUNCTION
125krb5_storage_free(krb5_storage *sp)
126{
127    if(sp->free)
128	(*sp->free)(sp);
129    free(sp->data);
130    free(sp);
131    return 0;
132}
133
134krb5_error_code KRB5_LIB_FUNCTION
135krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
136{
137    off_t pos;
138    size_t size;
139    krb5_error_code ret;
140
141    pos = sp->seek(sp, 0, SEEK_CUR);
142    size = (size_t)sp->seek(sp, 0, SEEK_END);
143    ret = krb5_data_alloc (data, size);
144    if (ret) {
145	sp->seek(sp, pos, SEEK_SET);
146	return ret;
147    }
148    if (size) {
149	sp->seek(sp, 0, SEEK_SET);
150	sp->fetch(sp, data->data, data->length);
151	sp->seek(sp, pos, SEEK_SET);
152    }
153    return 0;
154}
155
156static krb5_error_code
157krb5_store_int(krb5_storage *sp,
158	       int32_t value,
159	       size_t len)
160{
161    int ret;
162    unsigned char v[16];
163
164    if(len > sizeof(v))
165	return EINVAL;
166    _krb5_put_int(v, value, len);
167    ret = sp->store(sp, v, len);
168    if (ret != len)
169	return (ret<0)?errno:sp->eof_code;
170    return 0;
171}
172
173krb5_error_code KRB5_LIB_FUNCTION
174krb5_store_int32(krb5_storage *sp,
175		 int32_t value)
176{
177    if(BYTEORDER_IS_HOST(sp))
178	value = htonl(value);
179    else if(BYTEORDER_IS_LE(sp))
180	value = bswap32(value);
181    return krb5_store_int(sp, value, 4);
182}
183
184krb5_error_code KRB5_LIB_FUNCTION
185krb5_store_uint32(krb5_storage *sp,
186		  uint32_t value)
187{
188    return krb5_store_int32(sp, (int32_t)value);
189}
190
191static krb5_error_code
192krb5_ret_int(krb5_storage *sp,
193	     int32_t *value,
194	     size_t len)
195{
196    int ret;
197    unsigned char v[4];
198    unsigned long w;
199    ret = sp->fetch(sp, v, len);
200    if(ret != len)
201	return (ret<0)?errno:sp->eof_code;
202    _krb5_get_int(v, &w, len);
203    *value = w;
204    return 0;
205}
206
207krb5_error_code KRB5_LIB_FUNCTION
208krb5_ret_int32(krb5_storage *sp,
209	       int32_t *value)
210{
211    krb5_error_code ret = krb5_ret_int(sp, value, 4);
212    if(ret)
213	return ret;
214    if(BYTEORDER_IS_HOST(sp))
215	*value = htonl(*value);
216    else if(BYTEORDER_IS_LE(sp))
217	*value = bswap32(*value);
218    return 0;
219}
220
221krb5_error_code KRB5_LIB_FUNCTION
222krb5_ret_uint32(krb5_storage *sp,
223		uint32_t *value)
224{
225    krb5_error_code ret;
226    int32_t v;
227
228    ret = krb5_ret_int32(sp, &v);
229    if (ret == 0)
230	*value = (uint32_t)v;
231
232    return ret;
233}
234
235krb5_error_code KRB5_LIB_FUNCTION
236krb5_store_int16(krb5_storage *sp,
237		 int16_t value)
238{
239    if(BYTEORDER_IS_HOST(sp))
240	value = htons(value);
241    else if(BYTEORDER_IS_LE(sp))
242	value = bswap16(value);
243    return krb5_store_int(sp, value, 2);
244}
245
246krb5_error_code KRB5_LIB_FUNCTION
247krb5_store_uint16(krb5_storage *sp,
248		  uint16_t value)
249{
250    return krb5_store_int16(sp, (int16_t)value);
251}
252
253krb5_error_code KRB5_LIB_FUNCTION
254krb5_ret_int16(krb5_storage *sp,
255	       int16_t *value)
256{
257    int32_t v;
258    int ret;
259    ret = krb5_ret_int(sp, &v, 2);
260    if(ret)
261	return ret;
262    *value = v;
263    if(BYTEORDER_IS_HOST(sp))
264	*value = htons(*value);
265    else if(BYTEORDER_IS_LE(sp))
266	*value = bswap16(*value);
267    return 0;
268}
269
270krb5_error_code KRB5_LIB_FUNCTION
271krb5_ret_uint16(krb5_storage *sp,
272		uint16_t *value)
273{
274    krb5_error_code ret;
275    int16_t v;
276
277    ret = krb5_ret_int16(sp, &v);
278    if (ret == 0)
279	*value = (uint16_t)v;
280
281    return ret;
282}
283
284krb5_error_code KRB5_LIB_FUNCTION
285krb5_store_int8(krb5_storage *sp,
286		int8_t value)
287{
288    int ret;
289
290    ret = sp->store(sp, &value, sizeof(value));
291    if (ret != sizeof(value))
292	return (ret<0)?errno:sp->eof_code;
293    return 0;
294}
295
296krb5_error_code KRB5_LIB_FUNCTION
297krb5_store_uint8(krb5_storage *sp,
298		 uint8_t value)
299{
300    return krb5_store_int8(sp, (int8_t)value);
301}
302
303krb5_error_code KRB5_LIB_FUNCTION
304krb5_ret_int8(krb5_storage *sp,
305	      int8_t *value)
306{
307    int ret;
308
309    ret = sp->fetch(sp, value, sizeof(*value));
310    if (ret != sizeof(*value))
311	return (ret<0)?errno:sp->eof_code;
312    return 0;
313}
314
315krb5_error_code KRB5_LIB_FUNCTION
316krb5_ret_uint8(krb5_storage *sp,
317	       uint8_t *value)
318{
319    krb5_error_code ret;
320    int8_t v;
321
322    ret = krb5_ret_int8(sp, &v);
323    if (ret == 0)
324	*value = (uint8_t)v;
325
326    return ret;
327}
328
329krb5_error_code KRB5_LIB_FUNCTION
330krb5_store_data(krb5_storage *sp,
331		krb5_data data)
332{
333    int ret;
334    ret = krb5_store_int32(sp, data.length);
335    if(ret < 0)
336	return ret;
337    ret = sp->store(sp, data.data, data.length);
338    if(ret != data.length){
339	if(ret < 0)
340	    return errno;
341	return sp->eof_code;
342    }
343    return 0;
344}
345
346krb5_error_code KRB5_LIB_FUNCTION
347krb5_ret_data(krb5_storage *sp,
348	      krb5_data *data)
349{
350    int ret;
351    int32_t size;
352
353    ret = krb5_ret_int32(sp, &size);
354    if(ret)
355	return ret;
356    ret = krb5_data_alloc (data, size);
357    if (ret)
358	return ret;
359    if (size) {
360	ret = sp->fetch(sp, data->data, size);
361	if(ret != size)
362	    return (ret < 0)? errno : sp->eof_code;
363    }
364    return 0;
365}
366
367krb5_error_code KRB5_LIB_FUNCTION
368krb5_store_string(krb5_storage *sp, const char *s)
369{
370    krb5_data data;
371    data.length = strlen(s);
372    data.data = rk_UNCONST(s);
373    return krb5_store_data(sp, data);
374}
375
376krb5_error_code KRB5_LIB_FUNCTION
377krb5_ret_string(krb5_storage *sp,
378		char **string)
379{
380    int ret;
381    krb5_data data;
382    ret = krb5_ret_data(sp, &data);
383    if(ret)
384	return ret;
385    *string = realloc(data.data, data.length + 1);
386    if(*string == NULL){
387	free(data.data);
388	return ENOMEM;
389    }
390    (*string)[data.length] = 0;
391    return 0;
392}
393
394krb5_error_code KRB5_LIB_FUNCTION
395krb5_store_stringz(krb5_storage *sp, const char *s)
396{
397    size_t len = strlen(s) + 1;
398    ssize_t ret;
399
400    ret = sp->store(sp, s, len);
401    if(ret != len) {
402	if(ret < 0)
403	    return ret;
404	else
405	    return sp->eof_code;
406    }
407    return 0;
408}
409
410krb5_error_code KRB5_LIB_FUNCTION
411krb5_ret_stringz(krb5_storage *sp,
412		char **string)
413{
414    char c;
415    char *s = NULL;
416    size_t len = 0;
417    ssize_t ret;
418
419    while((ret = sp->fetch(sp, &c, 1)) == 1){
420	char *tmp;
421
422	len++;
423	tmp = realloc (s, len);
424	if (tmp == NULL) {
425	    free (s);
426	    return ENOMEM;
427	}
428	s = tmp;
429	s[len - 1] = c;
430	if(c == 0)
431	    break;
432    }
433    if(ret != 1){
434	free(s);
435	if(ret == 0)
436	    return sp->eof_code;
437	return ret;
438    }
439    *string = s;
440    return 0;
441}
442
443krb5_error_code KRB5_LIB_FUNCTION
444krb5_store_stringnl(krb5_storage *sp, const char *s)
445{
446    size_t len = strlen(s);
447    ssize_t ret;
448
449    ret = sp->store(sp, s, len);
450    if(ret != len) {
451	if(ret < 0)
452	    return ret;
453	else
454	    return sp->eof_code;
455    }
456    ret = sp->store(sp, "\n", 1);
457    if(ret != 1) {
458	if(ret < 0)
459	    return ret;
460	else
461	    return sp->eof_code;
462    }
463
464    return 0;
465
466}
467
468krb5_error_code KRB5_LIB_FUNCTION
469krb5_ret_stringnl(krb5_storage *sp,
470		  char **string)
471{
472    int expect_nl = 0;
473    char c;
474    char *s = NULL;
475    size_t len = 0;
476    ssize_t ret;
477
478    while((ret = sp->fetch(sp, &c, 1)) == 1){
479	char *tmp;
480
481	if (c == '\r') {
482	    expect_nl = 1;
483	    continue;
484	}
485	if (expect_nl && c != '\n') {
486	    free(s);
487	    return KRB5_BADMSGTYPE;
488	}
489
490	len++;
491	tmp = realloc (s, len);
492	if (tmp == NULL) {
493	    free (s);
494	    return ENOMEM;
495	}
496	s = tmp;
497	if(c == '\n') {
498	    s[len - 1] = '\0';
499	    break;
500	}
501	s[len - 1] = c;
502    }
503    if(ret != 1){
504	free(s);
505	if(ret == 0)
506	    return sp->eof_code;
507	return ret;
508    }
509    *string = s;
510    return 0;
511}
512
513
514krb5_error_code KRB5_LIB_FUNCTION
515krb5_store_principal(krb5_storage *sp,
516		     krb5_const_principal p)
517{
518    int i;
519    int ret;
520
521    if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
522	ret = krb5_store_int32(sp, p->name.name_type);
523	if(ret) return ret;
524    }
525    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
526	ret = krb5_store_int32(sp, p->name.name_string.len + 1);
527    else
528	ret = krb5_store_int32(sp, p->name.name_string.len);
529
530    if(ret) return ret;
531    ret = krb5_store_string(sp, p->realm);
532    if(ret) return ret;
533    for(i = 0; i < p->name.name_string.len; i++){
534	ret = krb5_store_string(sp, p->name.name_string.val[i]);
535	if(ret) return ret;
536    }
537    return 0;
538}
539
540krb5_error_code KRB5_LIB_FUNCTION
541krb5_ret_principal(krb5_storage *sp,
542		   krb5_principal *princ)
543{
544    int i;
545    int ret;
546    krb5_principal p;
547    int32_t type;
548    int32_t ncomp;
549
550    p = calloc(1, sizeof(*p));
551    if(p == NULL)
552	return ENOMEM;
553
554    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
555	type = KRB5_NT_UNKNOWN;
556    else if((ret = krb5_ret_int32(sp, &type))){
557	free(p);
558	return ret;
559    }
560    if((ret = krb5_ret_int32(sp, &ncomp))){
561	free(p);
562	return ret;
563    }
564    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
565	ncomp--;
566    if (ncomp < 0) {
567	free(p);
568	return EINVAL;
569    }
570    p->name.name_type = type;
571    p->name.name_string.len = ncomp;
572    ret = krb5_ret_string(sp, &p->realm);
573    if(ret) {
574	free(p);
575	return ret;
576    }
577    p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
578    if(p->name.name_string.val == NULL && ncomp != 0){
579	free(p->realm);
580	free(p);
581	return ENOMEM;
582    }
583    for(i = 0; i < ncomp; i++){
584	ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
585	if(ret) {
586	    while (i >= 0)
587		free(p->name.name_string.val[i--]);
588	    free(p->realm);
589	    free(p);
590	    return ret;
591	}
592    }
593    *princ = p;
594    return 0;
595}
596
597krb5_error_code KRB5_LIB_FUNCTION
598krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
599{
600    int ret;
601    ret = krb5_store_int16(sp, p.keytype);
602    if(ret) return ret;
603
604    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
605	/* this should really be enctype, but it is the same as
606           keytype nowadays */
607    ret = krb5_store_int16(sp, p.keytype);
608    if(ret) return ret;
609    }
610
611    ret = krb5_store_data(sp, p.keyvalue);
612    return ret;
613}
614
615krb5_error_code KRB5_LIB_FUNCTION
616krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
617{
618    int ret;
619    int16_t tmp;
620
621    ret = krb5_ret_int16(sp, &tmp);
622    if(ret) return ret;
623    p->keytype = tmp;
624
625    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
626    ret = krb5_ret_int16(sp, &tmp);
627    if(ret) return ret;
628    }
629
630    ret = krb5_ret_data(sp, &p->keyvalue);
631    return ret;
632}
633
634krb5_error_code KRB5_LIB_FUNCTION
635krb5_store_times(krb5_storage *sp, krb5_times times)
636{
637    int ret;
638    ret = krb5_store_int32(sp, times.authtime);
639    if(ret) return ret;
640    ret = krb5_store_int32(sp, times.starttime);
641    if(ret) return ret;
642    ret = krb5_store_int32(sp, times.endtime);
643    if(ret) return ret;
644    ret = krb5_store_int32(sp, times.renew_till);
645    return ret;
646}
647
648krb5_error_code KRB5_LIB_FUNCTION
649krb5_ret_times(krb5_storage *sp, krb5_times *times)
650{
651    int ret;
652    int32_t tmp;
653    ret = krb5_ret_int32(sp, &tmp);
654    times->authtime = tmp;
655    if(ret) return ret;
656    ret = krb5_ret_int32(sp, &tmp);
657    times->starttime = tmp;
658    if(ret) return ret;
659    ret = krb5_ret_int32(sp, &tmp);
660    times->endtime = tmp;
661    if(ret) return ret;
662    ret = krb5_ret_int32(sp, &tmp);
663    times->renew_till = tmp;
664    return ret;
665}
666
667krb5_error_code KRB5_LIB_FUNCTION
668krb5_store_address(krb5_storage *sp, krb5_address p)
669{
670    int ret;
671    ret = krb5_store_int16(sp, p.addr_type);
672    if(ret) return ret;
673    ret = krb5_store_data(sp, p.address);
674    return ret;
675}
676
677krb5_error_code KRB5_LIB_FUNCTION
678krb5_ret_address(krb5_storage *sp, krb5_address *adr)
679{
680    int16_t t;
681    int ret;
682    ret = krb5_ret_int16(sp, &t);
683    if(ret) return ret;
684    adr->addr_type = t;
685    ret = krb5_ret_data(sp, &adr->address);
686    return ret;
687}
688
689krb5_error_code KRB5_LIB_FUNCTION
690krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
691{
692    int i;
693    int ret;
694    ret = krb5_store_int32(sp, p.len);
695    if(ret) return ret;
696    for(i = 0; i<p.len; i++){
697	ret = krb5_store_address(sp, p.val[i]);
698	if(ret) break;
699    }
700    return ret;
701}
702
703krb5_error_code KRB5_LIB_FUNCTION
704krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
705{
706    int i;
707    int ret;
708    int32_t tmp;
709
710    ret = krb5_ret_int32(sp, &tmp);
711    if(ret) return ret;
712    adr->len = tmp;
713    ALLOC(adr->val, adr->len);
714    if (adr->val == NULL && adr->len != 0)
715	return ENOMEM;
716    for(i = 0; i < adr->len; i++){
717	ret = krb5_ret_address(sp, &adr->val[i]);
718	if(ret) break;
719    }
720    return ret;
721}
722
723krb5_error_code KRB5_LIB_FUNCTION
724krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
725{
726    krb5_error_code ret;
727    int i;
728    ret = krb5_store_int32(sp, auth.len);
729    if(ret) return ret;
730    for(i = 0; i < auth.len; i++){
731	ret = krb5_store_int16(sp, auth.val[i].ad_type);
732	if(ret) break;
733	ret = krb5_store_data(sp, auth.val[i].ad_data);
734	if(ret) break;
735    }
736    return 0;
737}
738
739krb5_error_code KRB5_LIB_FUNCTION
740krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
741{
742    krb5_error_code ret;
743    int32_t tmp;
744    int16_t tmp2;
745    int i;
746    ret = krb5_ret_int32(sp, &tmp);
747    if(ret) return ret;
748    ALLOC_SEQ(auth, tmp);
749    if (auth->val == NULL && tmp != 0)
750	return ENOMEM;
751    for(i = 0; i < tmp; i++){
752	ret = krb5_ret_int16(sp, &tmp2);
753	if(ret) break;
754	auth->val[i].ad_type = tmp2;
755	ret = krb5_ret_data(sp, &auth->val[i].ad_data);
756	if(ret) break;
757    }
758    return ret;
759}
760
761static int32_t
762bitswap32(int32_t b)
763{
764    int32_t r = 0;
765    int i;
766    for (i = 0; i < 32; i++) {
767	r = r << 1 | (b & 1);
768	b = b >> 1;
769    }
770    return r;
771}
772
773
774/*
775 *
776 */
777
778krb5_error_code KRB5_LIB_FUNCTION
779krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
780{
781    int ret;
782
783    ret = krb5_store_principal(sp, creds->client);
784    if(ret)
785	return ret;
786    ret = krb5_store_principal(sp, creds->server);
787    if(ret)
788	return ret;
789    ret = krb5_store_keyblock(sp, creds->session);
790    if(ret)
791	return ret;
792    ret = krb5_store_times(sp, creds->times);
793    if(ret)
794	return ret;
795    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
796    if(ret)
797	return ret;
798
799    if(krb5_storage_is_flags(sp, KRB5_STORAGE_CREDS_FLAGS_WRONG_BITORDER))
800	ret = krb5_store_int32(sp, creds->flags.i);
801    else
802	ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
803    if(ret)
804	return ret;
805
806    ret = krb5_store_addrs(sp, creds->addresses);
807    if(ret)
808	return ret;
809    ret = krb5_store_authdata(sp, creds->authdata);
810    if(ret)
811	return ret;
812    ret = krb5_store_data(sp, creds->ticket);
813    if(ret)
814	return ret;
815    ret = krb5_store_data(sp, creds->second_ticket);
816    return ret;
817}
818
819krb5_error_code KRB5_LIB_FUNCTION
820krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
821{
822    krb5_error_code ret;
823    int8_t dummy8;
824    int32_t dummy32;
825
826    memset(creds, 0, sizeof(*creds));
827    ret = krb5_ret_principal (sp,  &creds->client);
828    if(ret) goto cleanup;
829    ret = krb5_ret_principal (sp,  &creds->server);
830    if(ret) goto cleanup;
831    ret = krb5_ret_keyblock (sp,  &creds->session);
832    if(ret) goto cleanup;
833    ret = krb5_ret_times (sp,  &creds->times);
834    if(ret) goto cleanup;
835    ret = krb5_ret_int8 (sp,  &dummy8);
836    if(ret) goto cleanup;
837    ret = krb5_ret_int32 (sp,  &dummy32);
838    if(ret) goto cleanup;
839    /*
840     * Runtime detect the what is the higher bits of the bitfield. If
841     * any of the higher bits are set in the input data, it's either a
842     * new ticket flag (and this code need to be removed), or it's a
843     * MIT cache (or new Heimdal cache), lets change it to our current
844     * format.
845     */
846    {
847	uint32_t mask = 0xffff0000;
848	creds->flags.i = 0;
849	creds->flags.b.anonymous = 1;
850	if (creds->flags.i & mask)
851	    mask = ~mask;
852	if (dummy32 & mask)
853	    dummy32 = bitswap32(dummy32);
854    }
855    creds->flags.i = dummy32;
856    ret = krb5_ret_addrs (sp,  &creds->addresses);
857    if(ret) goto cleanup;
858    ret = krb5_ret_authdata (sp,  &creds->authdata);
859    if(ret) goto cleanup;
860    ret = krb5_ret_data (sp,  &creds->ticket);
861    if(ret) goto cleanup;
862    ret = krb5_ret_data (sp,  &creds->second_ticket);
863cleanup:
864    if(ret) {
865#if 0
866	krb5_free_cred_contents(context, creds); /* XXX */
867#endif
868    }
869    return ret;
870}
871
872#define SC_CLIENT_PRINCIPAL	    0x0001
873#define SC_SERVER_PRINCIPAL	    0x0002
874#define SC_SESSION_KEY		    0x0004
875#define SC_TICKET		    0x0008
876#define SC_SECOND_TICKET	    0x0010
877#define SC_AUTHDATA		    0x0020
878#define SC_ADDRESSES		    0x0040
879
880/*
881 *
882 */
883
884krb5_error_code KRB5_LIB_FUNCTION
885krb5_store_creds_tag(krb5_storage *sp, krb5_creds *creds)
886{
887    int ret;
888    int32_t header = 0;
889
890    if (creds->client)
891	header |= SC_CLIENT_PRINCIPAL;
892    if (creds->server)
893	header |= SC_SERVER_PRINCIPAL;
894    if (creds->session.keytype != ETYPE_NULL)
895	header |= SC_SESSION_KEY;
896    if (creds->ticket.data)
897	header |= SC_TICKET;
898    if (creds->second_ticket.length)
899	header |= SC_SECOND_TICKET;
900    if (creds->authdata.len)
901	header |= SC_AUTHDATA;
902    if (creds->addresses.len)
903	header |= SC_ADDRESSES;
904
905    ret = krb5_store_int32(sp, header);
906
907    if (creds->client) {
908	ret = krb5_store_principal(sp, creds->client);
909	if(ret)
910	    return ret;
911    }
912
913    if (creds->server) {
914	ret = krb5_store_principal(sp, creds->server);
915	if(ret)
916	    return ret;
917    }
918
919    if (creds->session.keytype != ETYPE_NULL) {
920	ret = krb5_store_keyblock(sp, creds->session);
921	if(ret)
922	    return ret;
923    }
924
925    ret = krb5_store_times(sp, creds->times);
926    if(ret)
927	return ret;
928    ret = krb5_store_int8(sp, creds->second_ticket.length != 0); /* is_skey */
929    if(ret)
930	return ret;
931
932    ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
933    if(ret)
934	return ret;
935
936    if (creds->addresses.len) {
937	ret = krb5_store_addrs(sp, creds->addresses);
938	if(ret)
939	    return ret;
940    }
941
942    if (creds->authdata.len) {
943	ret = krb5_store_authdata(sp, creds->authdata);
944	if(ret)
945	    return ret;
946    }
947
948    if (creds->ticket.data) {
949	ret = krb5_store_data(sp, creds->ticket);
950	if(ret)
951	    return ret;
952    }
953
954    if (creds->second_ticket.data) {
955	ret = krb5_store_data(sp, creds->second_ticket);
956	if (ret)
957	    return ret;
958    }
959
960    return ret;
961}
962
963krb5_error_code KRB5_LIB_FUNCTION
964krb5_ret_creds_tag(krb5_storage *sp,
965		   krb5_creds *creds)
966{
967    krb5_error_code ret;
968    int8_t dummy8;
969    int32_t dummy32, header;
970
971    memset(creds, 0, sizeof(*creds));
972
973    ret = krb5_ret_int32 (sp, &header);
974    if (ret) goto cleanup;
975
976    if (header & SC_CLIENT_PRINCIPAL) {
977	ret = krb5_ret_principal (sp,  &creds->client);
978	if(ret) goto cleanup;
979    }
980    if (header & SC_SERVER_PRINCIPAL) {
981	ret = krb5_ret_principal (sp,  &creds->server);
982	if(ret) goto cleanup;
983    }
984    if (header & SC_SESSION_KEY) {
985	ret = krb5_ret_keyblock (sp,  &creds->session);
986	if(ret) goto cleanup;
987    }
988    ret = krb5_ret_times (sp,  &creds->times);
989    if(ret) goto cleanup;
990    ret = krb5_ret_int8 (sp,  &dummy8);
991    if(ret) goto cleanup;
992    ret = krb5_ret_int32 (sp,  &dummy32);
993    if(ret) goto cleanup;
994    /*
995     * Runtime detect the what is the higher bits of the bitfield. If
996     * any of the higher bits are set in the input data, it's either a
997     * new ticket flag (and this code need to be removed), or it's a
998     * MIT cache (or new Heimdal cache), lets change it to our current
999     * format.
1000     */
1001    {
1002	uint32_t mask = 0xffff0000;
1003	creds->flags.i = 0;
1004	creds->flags.b.anonymous = 1;
1005	if (creds->flags.i & mask)
1006	    mask = ~mask;
1007	if (dummy32 & mask)
1008	    dummy32 = bitswap32(dummy32);
1009    }
1010    creds->flags.i = dummy32;
1011    if (header & SC_ADDRESSES) {
1012	ret = krb5_ret_addrs (sp,  &creds->addresses);
1013	if(ret) goto cleanup;
1014    }
1015    if (header & SC_AUTHDATA) {
1016	ret = krb5_ret_authdata (sp,  &creds->authdata);
1017	if(ret) goto cleanup;
1018    }
1019    if (header & SC_TICKET) {
1020	ret = krb5_ret_data (sp,  &creds->ticket);
1021	if(ret) goto cleanup;
1022    }
1023    if (header & SC_SECOND_TICKET) {
1024	ret = krb5_ret_data (sp,  &creds->second_ticket);
1025	if(ret) goto cleanup;
1026    }
1027
1028cleanup:
1029    if(ret) {
1030#if 0
1031	krb5_free_cred_contents(context, creds); /* XXX */
1032#endif
1033    }
1034    return ret;
1035}
1036