store.c revision 127808
1/*
2 * Copyright (c) 1997-2002 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,v 1.38.4.1 2004/03/09 19:32:14 lha Exp $");
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
46krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
47{
48    sp->flags |= flags;
49}
50
51void
52krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
53{
54    sp->flags &= ~flags;
55}
56
57krb5_boolean
58krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
59{
60    return (sp->flags & flags) == flags;
61}
62
63void
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
71krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder)
72{
73    return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
74}
75
76off_t
77krb5_storage_seek(krb5_storage *sp, off_t offset, int whence)
78{
79    return (*sp->seek)(sp, offset, whence);
80}
81
82krb5_ssize_t
83krb5_storage_read(krb5_storage *sp, void *buf, size_t len)
84{
85    return sp->fetch(sp, buf, len);
86}
87
88krb5_ssize_t
89krb5_storage_write(krb5_storage *sp, const void *buf, size_t len)
90{
91    return sp->store(sp, buf, len);
92}
93
94void
95krb5_storage_set_eof_code(krb5_storage *sp, int code)
96{
97    sp->eof_code = code;
98}
99
100krb5_ssize_t
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
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
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
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
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
184static krb5_error_code
185krb5_ret_int(krb5_storage *sp,
186	     int32_t *value,
187	     size_t len)
188{
189    int ret;
190    unsigned char v[4];
191    unsigned long w;
192    ret = sp->fetch(sp, v, len);
193    if(ret != len)
194	return (ret<0)?errno:sp->eof_code;
195    _krb5_get_int(v, &w, len);
196    *value = w;
197    return 0;
198}
199
200krb5_error_code
201krb5_ret_int32(krb5_storage *sp,
202	       int32_t *value)
203{
204    krb5_error_code ret = krb5_ret_int(sp, value, 4);
205    if(ret)
206	return ret;
207    if(BYTEORDER_IS_HOST(sp))
208	*value = htonl(*value);
209    else if(BYTEORDER_IS_LE(sp))
210	*value = bswap32(*value);
211    return 0;
212}
213
214krb5_error_code
215krb5_store_int16(krb5_storage *sp,
216		 int16_t value)
217{
218    if(BYTEORDER_IS_HOST(sp))
219	value = htons(value);
220    else if(BYTEORDER_IS_LE(sp))
221	value = bswap16(value);
222    return krb5_store_int(sp, value, 2);
223}
224
225krb5_error_code
226krb5_ret_int16(krb5_storage *sp,
227	       int16_t *value)
228{
229    int32_t v;
230    int ret;
231    ret = krb5_ret_int(sp, &v, 2);
232    if(ret)
233	return ret;
234    *value = v;
235    if(BYTEORDER_IS_HOST(sp))
236	*value = htons(*value);
237    else if(BYTEORDER_IS_LE(sp))
238	*value = bswap16(*value);
239    return 0;
240}
241
242krb5_error_code
243krb5_store_int8(krb5_storage *sp,
244		int8_t value)
245{
246    int ret;
247
248    ret = sp->store(sp, &value, sizeof(value));
249    if (ret != sizeof(value))
250	return (ret<0)?errno:sp->eof_code;
251    return 0;
252}
253
254krb5_error_code
255krb5_ret_int8(krb5_storage *sp,
256	      int8_t *value)
257{
258    int ret;
259
260    ret = sp->fetch(sp, value, sizeof(*value));
261    if (ret != sizeof(*value))
262	return (ret<0)?errno:sp->eof_code;
263    return 0;
264}
265
266krb5_error_code
267krb5_store_data(krb5_storage *sp,
268		krb5_data data)
269{
270    int ret;
271    ret = krb5_store_int32(sp, data.length);
272    if(ret < 0)
273	return ret;
274    ret = sp->store(sp, data.data, data.length);
275    if(ret != data.length){
276	if(ret < 0)
277	    return errno;
278	return sp->eof_code;
279    }
280    return 0;
281}
282
283krb5_error_code
284krb5_ret_data(krb5_storage *sp,
285	      krb5_data *data)
286{
287    int ret;
288    int32_t size;
289
290    ret = krb5_ret_int32(sp, &size);
291    if(ret)
292	return ret;
293    ret = krb5_data_alloc (data, size);
294    if (ret)
295	return ret;
296    if (size) {
297	ret = sp->fetch(sp, data->data, size);
298	if(ret != size)
299	    return (ret < 0)? errno : sp->eof_code;
300    }
301    return 0;
302}
303
304krb5_error_code
305krb5_store_string(krb5_storage *sp, const char *s)
306{
307    krb5_data data;
308    data.length = strlen(s);
309    data.data = (void*)s;
310    return krb5_store_data(sp, data);
311}
312
313krb5_error_code
314krb5_ret_string(krb5_storage *sp,
315		char **string)
316{
317    int ret;
318    krb5_data data;
319    ret = krb5_ret_data(sp, &data);
320    if(ret)
321	return ret;
322    *string = realloc(data.data, data.length + 1);
323    if(*string == NULL){
324	free(data.data);
325	return ENOMEM;
326    }
327    (*string)[data.length] = 0;
328    return 0;
329}
330
331krb5_error_code
332krb5_store_stringz(krb5_storage *sp, const char *s)
333{
334    size_t len = strlen(s) + 1;
335    ssize_t ret;
336
337    ret = sp->store(sp, s, len);
338    if(ret != len) {
339	if(ret < 0)
340	    return ret;
341	else
342	    return sp->eof_code;
343    }
344    return 0;
345}
346
347krb5_error_code
348krb5_ret_stringz(krb5_storage *sp,
349		char **string)
350{
351    char c;
352    char *s = NULL;
353    size_t len = 0;
354    ssize_t ret;
355
356    while((ret = sp->fetch(sp, &c, 1)) == 1){
357	char *tmp;
358
359	len++;
360	tmp = realloc (s, len);
361	if (tmp == NULL) {
362	    free (s);
363	    return ENOMEM;
364	}
365	s = tmp;
366	s[len - 1] = c;
367	if(c == 0)
368	    break;
369    }
370    if(ret != 1){
371	free(s);
372	if(ret == 0)
373	    return sp->eof_code;
374	return ret;
375    }
376    *string = s;
377    return 0;
378}
379
380
381krb5_error_code
382krb5_store_principal(krb5_storage *sp,
383		     krb5_principal p)
384{
385    int i;
386    int ret;
387
388    if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
389    ret = krb5_store_int32(sp, p->name.name_type);
390    if(ret) return ret;
391    }
392    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
393	ret = krb5_store_int32(sp, p->name.name_string.len + 1);
394    else
395    ret = krb5_store_int32(sp, p->name.name_string.len);
396
397    if(ret) return ret;
398    ret = krb5_store_string(sp, p->realm);
399    if(ret) return ret;
400    for(i = 0; i < p->name.name_string.len; i++){
401	ret = krb5_store_string(sp, p->name.name_string.val[i]);
402	if(ret) return ret;
403    }
404    return 0;
405}
406
407krb5_error_code
408krb5_ret_principal(krb5_storage *sp,
409		   krb5_principal *princ)
410{
411    int i;
412    int ret;
413    krb5_principal p;
414    int32_t type;
415    int32_t ncomp;
416
417    p = calloc(1, sizeof(*p));
418    if(p == NULL)
419	return ENOMEM;
420
421    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
422	type = KRB5_NT_UNKNOWN;
423    else 	if((ret = krb5_ret_int32(sp, &type))){
424	free(p);
425	return ret;
426    }
427    if((ret = krb5_ret_int32(sp, &ncomp))){
428	free(p);
429	return ret;
430    }
431    if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
432	ncomp--;
433    p->name.name_type = type;
434    p->name.name_string.len = ncomp;
435    ret = krb5_ret_string(sp, &p->realm);
436    if(ret) return ret;
437    p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
438    if(p->name.name_string.val == NULL){
439	free(p->realm);
440	return ENOMEM;
441    }
442    for(i = 0; i < ncomp; i++){
443	ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
444	if(ret) return ret; /* XXX */
445    }
446    *princ = p;
447    return 0;
448}
449
450krb5_error_code
451krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
452{
453    int ret;
454    ret = krb5_store_int16(sp, p.keytype);
455    if(ret) return ret;
456
457    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
458	/* this should really be enctype, but it is the same as
459           keytype nowadays */
460    ret = krb5_store_int16(sp, p.keytype);
461    if(ret) return ret;
462    }
463
464    ret = krb5_store_data(sp, p.keyvalue);
465    return ret;
466}
467
468krb5_error_code
469krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
470{
471    int ret;
472    int16_t tmp;
473
474    ret = krb5_ret_int16(sp, &tmp);
475    if(ret) return ret;
476    p->keytype = tmp;
477
478    if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
479    ret = krb5_ret_int16(sp, &tmp);
480    if(ret) return ret;
481    }
482
483    ret = krb5_ret_data(sp, &p->keyvalue);
484    return ret;
485}
486
487krb5_error_code
488krb5_store_times(krb5_storage *sp, krb5_times times)
489{
490    int ret;
491    ret = krb5_store_int32(sp, times.authtime);
492    if(ret) return ret;
493    ret = krb5_store_int32(sp, times.starttime);
494    if(ret) return ret;
495    ret = krb5_store_int32(sp, times.endtime);
496    if(ret) return ret;
497    ret = krb5_store_int32(sp, times.renew_till);
498    return ret;
499}
500
501krb5_error_code
502krb5_ret_times(krb5_storage *sp, krb5_times *times)
503{
504    int ret;
505    int32_t tmp;
506    ret = krb5_ret_int32(sp, &tmp);
507    times->authtime = tmp;
508    if(ret) return ret;
509    ret = krb5_ret_int32(sp, &tmp);
510    times->starttime = tmp;
511    if(ret) return ret;
512    ret = krb5_ret_int32(sp, &tmp);
513    times->endtime = tmp;
514    if(ret) return ret;
515    ret = krb5_ret_int32(sp, &tmp);
516    times->renew_till = tmp;
517    return ret;
518}
519
520krb5_error_code
521krb5_store_address(krb5_storage *sp, krb5_address p)
522{
523    int ret;
524    ret = krb5_store_int16(sp, p.addr_type);
525    if(ret) return ret;
526    ret = krb5_store_data(sp, p.address);
527    return ret;
528}
529
530krb5_error_code
531krb5_ret_address(krb5_storage *sp, krb5_address *adr)
532{
533    int16_t t;
534    int ret;
535    ret = krb5_ret_int16(sp, &t);
536    if(ret) return ret;
537    adr->addr_type = t;
538    ret = krb5_ret_data(sp, &adr->address);
539    return ret;
540}
541
542krb5_error_code
543krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
544{
545    int i;
546    int ret;
547    ret = krb5_store_int32(sp, p.len);
548    if(ret) return ret;
549    for(i = 0; i<p.len; i++){
550	ret = krb5_store_address(sp, p.val[i]);
551	if(ret) break;
552    }
553    return ret;
554}
555
556krb5_error_code
557krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
558{
559    int i;
560    int ret;
561    int32_t tmp;
562
563    ret = krb5_ret_int32(sp, &tmp);
564    if(ret) return ret;
565    adr->len = tmp;
566    ALLOC(adr->val, adr->len);
567    for(i = 0; i < adr->len; i++){
568	ret = krb5_ret_address(sp, &adr->val[i]);
569	if(ret) break;
570    }
571    return ret;
572}
573
574krb5_error_code
575krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
576{
577    krb5_error_code ret;
578    int i;
579    ret = krb5_store_int32(sp, auth.len);
580    if(ret) return ret;
581    for(i = 0; i < auth.len; i++){
582	ret = krb5_store_int16(sp, auth.val[i].ad_type);
583	if(ret) break;
584	ret = krb5_store_data(sp, auth.val[i].ad_data);
585	if(ret) break;
586    }
587    return 0;
588}
589
590krb5_error_code
591krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
592{
593    krb5_error_code ret;
594    int32_t tmp;
595    int16_t tmp2;
596    int i;
597    ret = krb5_ret_int32(sp, &tmp);
598    if(ret) return ret;
599    ALLOC_SEQ(auth, tmp);
600    for(i = 0; i < tmp; i++){
601	ret = krb5_ret_int16(sp, &tmp2);
602	if(ret) break;
603	auth->val[i].ad_type = tmp2;
604	ret = krb5_ret_data(sp, &auth->val[i].ad_data);
605	if(ret) break;
606    }
607    return ret;
608}
609
610static int32_t
611bitswap32(int32_t b)
612{
613    int32_t r = 0;
614    int i;
615    for (i = 0; i < 32; i++) {
616	r = r << 1 | (b & 1);
617	b = b >> 1;
618    }
619    return r;
620}
621
622
623/*
624 *
625 */
626
627krb5_error_code
628_krb5_store_creds_internal(krb5_storage *sp, krb5_creds *creds, int v0_6)
629{
630    int ret;
631
632    ret = krb5_store_principal(sp, creds->client);
633    if(ret)
634	return ret;
635    ret = krb5_store_principal(sp, creds->server);
636    if(ret)
637	return ret;
638    ret = krb5_store_keyblock(sp, creds->session);
639    if(ret)
640	return ret;
641    ret = krb5_store_times(sp, creds->times);
642    if(ret)
643	return ret;
644    ret = krb5_store_int8(sp, 0);  /* this is probably the
645				enc-tkt-in-skey bit from KDCOptions */
646    if(ret)
647	return ret;
648    if (v0_6) {
649	ret = krb5_store_int32(sp, creds->flags.i);
650	if(ret)
651	    return ret;
652    } else {
653	ret = krb5_store_int32(sp, bitswap32(TicketFlags2int(creds->flags.b)));
654	if(ret)
655	    return ret;
656    }
657    ret = krb5_store_addrs(sp, creds->addresses);
658    if(ret)
659	return ret;
660    ret = krb5_store_authdata(sp, creds->authdata);
661    if(ret)
662	return ret;
663    ret = krb5_store_data(sp, creds->ticket);
664    if(ret)
665	return ret;
666    ret = krb5_store_data(sp, creds->second_ticket);
667    return ret;
668}
669
670/*
671 * store `creds' on `sp' returning error or zero
672 */
673
674krb5_error_code
675krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
676{
677    return _krb5_store_creds_internal(sp, creds, 1);
678}
679
680krb5_error_code
681_krb5_store_creds_heimdal_0_7(krb5_storage *sp, krb5_creds *creds)
682{
683    return _krb5_store_creds_internal(sp, creds, 0);
684}
685
686krb5_error_code
687_krb5_store_creds_heimdal_pre_0_7(krb5_storage *sp, krb5_creds *creds)
688{
689    return _krb5_store_creds_internal(sp, creds, 1);
690}
691
692krb5_error_code
693krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
694{
695    krb5_error_code ret;
696    int8_t dummy8;
697    int32_t dummy32;
698
699    memset(creds, 0, sizeof(*creds));
700    ret = krb5_ret_principal (sp,  &creds->client);
701    if(ret) goto cleanup;
702    ret = krb5_ret_principal (sp,  &creds->server);
703    if(ret) goto cleanup;
704    ret = krb5_ret_keyblock (sp,  &creds->session);
705    if(ret) goto cleanup;
706    ret = krb5_ret_times (sp,  &creds->times);
707    if(ret) goto cleanup;
708    ret = krb5_ret_int8 (sp,  &dummy8);
709    if(ret) goto cleanup;
710    ret = krb5_ret_int32 (sp,  &dummy32);
711    if(ret) goto cleanup;
712    /*
713     * Runtime detect the what is the higher bits of the bitfield. If
714     * any of the higher bits are set in the input data, its either a
715     * new ticket flag (and this code need to be removed), or its a
716     * MIT cache (or new Heimdal cache), lets change it to our current
717     * format.
718     */
719    {
720	u_int32_t mask = 0xffff0000;
721	creds->flags.i = 0;
722	creds->flags.b.anonymous = 1;
723	if (creds->flags.i & mask)
724	    mask = ~mask;
725	if (dummy32 & mask)
726	    dummy32 = bitswap32(dummy32);
727    }
728    creds->flags.i = dummy32;
729    ret = krb5_ret_addrs (sp,  &creds->addresses);
730    if(ret) goto cleanup;
731    ret = krb5_ret_authdata (sp,  &creds->authdata);
732    if(ret) goto cleanup;
733    ret = krb5_ret_data (sp,  &creds->ticket);
734    if(ret) goto cleanup;
735    ret = krb5_ret_data (sp,  &creds->second_ticket);
736cleanup:
737    if(ret) {
738#if 0
739	krb5_free_creds_contents(context, creds); /* XXX */
740#endif
741    }
742    return ret;
743}
744