xref: /freebsd/crypto/heimdal/lib/krb5/store.c (revision 1b6c76a2fe091c74f08427e6c870851025a9cf67)
1 /*
2  * Copyright (c) 1997-2001 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 
36 RCSID("$Id: store.c,v 1.35 2001/05/11 13:01:43 joda Exp $");
37 
38 #define BYTEORDER_IS(SP, V) (((SP)->flags & KRB5_STORAGE_BYTEORDER_MASK) == (V))
39 #define BYTEORDER_IS_LE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_LE)
40 #define BYTEORDER_IS_BE(SP) BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_BE)
41 #define BYTEORDER_IS_HOST(SP) (BYTEORDER_IS((SP), KRB5_STORAGE_BYTEORDER_HOST) || \
42 			       krb5_storage_is_flags((SP), KRB5_STORAGE_HOST_BYTEORDER))
43 
44 void
45 krb5_storage_set_flags(krb5_storage *sp, krb5_flags flags)
46 {
47     sp->flags |= flags;
48 }
49 
50 void
51 krb5_storage_clear_flags(krb5_storage *sp, krb5_flags flags)
52 {
53     sp->flags &= ~flags;
54 }
55 
56 krb5_boolean
57 krb5_storage_is_flags(krb5_storage *sp, krb5_flags flags)
58 {
59     return (sp->flags & flags) == flags;
60 }
61 
62 void
63 krb5_storage_set_byteorder(krb5_storage *sp, krb5_flags byteorder)
64 {
65     sp->flags &= ~KRB5_STORAGE_BYTEORDER_MASK;
66     sp->flags |= byteorder;
67 }
68 
69 krb5_flags
70 krb5_storage_get_byteorder(krb5_storage *sp, krb5_flags byteorder)
71 {
72     return sp->flags & KRB5_STORAGE_BYTEORDER_MASK;
73 }
74 
75 
76 ssize_t
77 _krb5_put_int(void *buffer, unsigned long value, size_t size)
78 {
79     unsigned char *p = buffer;
80     int i;
81     for (i = size - 1; i >= 0; i--) {
82 	p[i] = value & 0xff;
83 	value >>= 8;
84     }
85     return size;
86 }
87 
88 ssize_t
89 _krb5_get_int(void *buffer, unsigned long *value, size_t size)
90 {
91     unsigned char *p = buffer;
92     unsigned long v = 0;
93     int i;
94     for (i = 0; i < size; i++)
95 	v = (v << 8) + p[i];
96     *value = v;
97     return size;
98 }
99 
100 krb5_error_code
101 krb5_storage_free(krb5_storage *sp)
102 {
103     if(sp->free)
104 	(*sp->free)(sp);
105     free(sp->data);
106     free(sp);
107     return 0;
108 }
109 
110 krb5_error_code
111 krb5_storage_to_data(krb5_storage *sp, krb5_data *data)
112 {
113     off_t pos;
114     size_t size;
115     krb5_error_code ret;
116 
117     pos = sp->seek(sp, 0, SEEK_CUR);
118     size = (size_t)sp->seek(sp, 0, SEEK_END);
119     ret = krb5_data_alloc (data, size);
120     if (ret) {
121 	sp->seek(sp, pos, SEEK_SET);
122 	return ret;
123     }
124     if (size) {
125 	sp->seek(sp, 0, SEEK_SET);
126 	sp->fetch(sp, data->data, data->length);
127 	sp->seek(sp, pos, SEEK_SET);
128     }
129     return 0;
130 }
131 
132 static krb5_error_code
133 krb5_store_int(krb5_storage *sp,
134 	       int32_t value,
135 	       size_t len)
136 {
137     int ret;
138     unsigned char v[16];
139 
140     if(len > sizeof(v))
141 	return EINVAL;
142     _krb5_put_int(v, value, len);
143     ret = sp->store(sp, v, len);
144     if (ret != len)
145 	return (ret<0)?errno:KRB5_CC_END;
146     return 0;
147 }
148 
149 krb5_error_code
150 krb5_store_int32(krb5_storage *sp,
151 		 int32_t value)
152 {
153     if(BYTEORDER_IS_HOST(sp))
154 	value = htonl(value);
155     else if(BYTEORDER_IS_LE(sp))
156 	value = bswap32(value);
157     return krb5_store_int(sp, value, 4);
158 }
159 
160 static krb5_error_code
161 krb5_ret_int(krb5_storage *sp,
162 	     int32_t *value,
163 	     size_t len)
164 {
165     int ret;
166     unsigned char v[4];
167     unsigned long w;
168     ret = sp->fetch(sp, v, len);
169     if(ret != len)
170 	return (ret<0)?errno:KRB5_CC_END;
171     _krb5_get_int(v, &w, len);
172     *value = w;
173     return 0;
174 }
175 
176 krb5_error_code
177 krb5_ret_int32(krb5_storage *sp,
178 	       int32_t *value)
179 {
180     krb5_error_code ret = krb5_ret_int(sp, value, 4);
181     if(ret)
182 	return ret;
183     if(BYTEORDER_IS_HOST(sp))
184 	*value = htonl(*value);
185     else if(BYTEORDER_IS_LE(sp))
186 	*value = bswap32(*value);
187     return 0;
188 }
189 
190 krb5_error_code
191 krb5_store_int16(krb5_storage *sp,
192 		 int16_t value)
193 {
194     if(BYTEORDER_IS_HOST(sp))
195 	value = htons(value);
196     else if(BYTEORDER_IS_LE(sp))
197 	value = bswap16(value);
198     return krb5_store_int(sp, value, 2);
199 }
200 
201 krb5_error_code
202 krb5_ret_int16(krb5_storage *sp,
203 	       int16_t *value)
204 {
205     int32_t v;
206     int ret;
207     ret = krb5_ret_int(sp, &v, 2);
208     if(ret)
209 	return ret;
210     *value = v;
211     if(BYTEORDER_IS_HOST(sp))
212 	*value = htons(*value);
213     else if(BYTEORDER_IS_LE(sp))
214 	*value = bswap16(*value);
215     return 0;
216 }
217 
218 krb5_error_code
219 krb5_store_int8(krb5_storage *sp,
220 		int8_t value)
221 {
222     int ret;
223 
224     ret = sp->store(sp, &value, sizeof(value));
225     if (ret != sizeof(value))
226 	return (ret<0)?errno:KRB5_CC_END;
227     return 0;
228 }
229 
230 krb5_error_code
231 krb5_ret_int8(krb5_storage *sp,
232 	      int8_t *value)
233 {
234     int ret;
235 
236     ret = sp->fetch(sp, value, sizeof(*value));
237     if (ret != sizeof(*value))
238 	return (ret<0)?errno:KRB5_CC_END;
239     return 0;
240 }
241 
242 krb5_error_code
243 krb5_store_data(krb5_storage *sp,
244 		krb5_data data)
245 {
246     int ret;
247     ret = krb5_store_int32(sp, data.length);
248     if(ret < 0)
249 	return ret;
250     ret = sp->store(sp, data.data, data.length);
251     if(ret != data.length){
252 	if(ret < 0)
253 	    return errno;
254 	return KRB5_CC_END;
255     }
256     return 0;
257 }
258 
259 krb5_error_code
260 krb5_ret_data(krb5_storage *sp,
261 	      krb5_data *data)
262 {
263     int ret;
264     int32_t size;
265 
266     ret = krb5_ret_int32(sp, &size);
267     if(ret)
268 	return ret;
269     ret = krb5_data_alloc (data, size);
270     if (ret)
271 	return ret;
272     if (size) {
273 	ret = sp->fetch(sp, data->data, size);
274 	if(ret != size)
275 	    return (ret < 0)? errno : KRB5_CC_END;
276     }
277     return 0;
278 }
279 
280 krb5_error_code
281 krb5_store_string(krb5_storage *sp, const char *s)
282 {
283     krb5_data data;
284     data.length = strlen(s);
285     data.data = (void*)s;
286     return krb5_store_data(sp, data);
287 }
288 
289 krb5_error_code
290 krb5_ret_string(krb5_storage *sp,
291 		char **string)
292 {
293     int ret;
294     krb5_data data;
295     ret = krb5_ret_data(sp, &data);
296     if(ret)
297 	return ret;
298     *string = realloc(data.data, data.length + 1);
299     if(*string == NULL){
300 	free(data.data);
301 	return ENOMEM;
302     }
303     (*string)[data.length] = 0;
304     return 0;
305 }
306 
307 krb5_error_code
308 krb5_store_stringz(krb5_storage *sp, const char *s)
309 {
310     size_t len = strlen(s) + 1;
311     ssize_t ret;
312 
313     ret = sp->store(sp, s, len);
314     if(ret != len) {
315 	if(ret < 0)
316 	    return ret;
317 	else
318 	    return KRB5_CC_END;
319     }
320     return 0;
321 }
322 
323 krb5_error_code
324 krb5_ret_stringz(krb5_storage *sp,
325 		char **string)
326 {
327     char c;
328     char *s = NULL;
329     size_t len = 0;
330     ssize_t ret;
331 
332     while((ret = sp->fetch(sp, &c, 1)) == 1){
333 	char *tmp;
334 
335 	len++;
336 	tmp = realloc (s, len);
337 	if (tmp == NULL) {
338 	    free (s);
339 	    return ENOMEM;
340 	}
341 	s = tmp;
342 	s[len - 1] = c;
343 	if(c == 0)
344 	    break;
345     }
346     if(ret != 1){
347 	free(s);
348 	if(ret == 0)
349 	    return KRB5_CC_END;
350 	return ret;
351     }
352     *string = s;
353     return 0;
354 }
355 
356 
357 krb5_error_code
358 krb5_store_principal(krb5_storage *sp,
359 		     krb5_principal p)
360 {
361     int i;
362     int ret;
363 
364     if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
365     ret = krb5_store_int32(sp, p->name.name_type);
366     if(ret) return ret;
367     }
368     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
369 	ret = krb5_store_int32(sp, p->name.name_string.len + 1);
370     else
371     ret = krb5_store_int32(sp, p->name.name_string.len);
372 
373     if(ret) return ret;
374     ret = krb5_store_string(sp, p->realm);
375     if(ret) return ret;
376     for(i = 0; i < p->name.name_string.len; i++){
377 	ret = krb5_store_string(sp, p->name.name_string.val[i]);
378 	if(ret) return ret;
379     }
380     return 0;
381 }
382 
383 krb5_error_code
384 krb5_ret_principal(krb5_storage *sp,
385 		   krb5_principal *princ)
386 {
387     int i;
388     int ret;
389     krb5_principal p;
390     int32_t type;
391     int32_t ncomp;
392 
393     p = calloc(1, sizeof(*p));
394     if(p == NULL)
395 	return ENOMEM;
396 
397     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
398 	type = KRB5_NT_UNKNOWN;
399     else 	if((ret = krb5_ret_int32(sp, &type))){
400 	free(p);
401 	return ret;
402     }
403     if((ret = krb5_ret_int32(sp, &ncomp))){
404 	free(p);
405 	return ret;
406     }
407     if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
408 	ncomp--;
409     p->name.name_type = type;
410     p->name.name_string.len = ncomp;
411     ret = krb5_ret_string(sp, &p->realm);
412     if(ret) return ret;
413     p->name.name_string.val = calloc(ncomp, sizeof(*p->name.name_string.val));
414     if(p->name.name_string.val == NULL){
415 	free(p->realm);
416 	return ENOMEM;
417     }
418     for(i = 0; i < ncomp; i++){
419 	ret = krb5_ret_string(sp, &p->name.name_string.val[i]);
420 	if(ret) return ret; /* XXX */
421     }
422     *princ = p;
423     return 0;
424 }
425 
426 krb5_error_code
427 krb5_store_keyblock(krb5_storage *sp, krb5_keyblock p)
428 {
429     int ret;
430     ret = krb5_store_int16(sp, p.keytype);
431     if(ret) return ret;
432 
433     if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
434 	/* this should really be enctype, but it is the same as
435            keytype nowadays */
436     ret = krb5_store_int16(sp, p.keytype);
437     if(ret) return ret;
438     }
439 
440     ret = krb5_store_data(sp, p.keyvalue);
441     return ret;
442 }
443 
444 krb5_error_code
445 krb5_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
446 {
447     int ret;
448     int16_t tmp;
449 
450     ret = krb5_ret_int16(sp, &tmp);
451     if(ret) return ret;
452     p->keytype = tmp;
453 
454     if(krb5_storage_is_flags(sp, KRB5_STORAGE_KEYBLOCK_KEYTYPE_TWICE)){
455     ret = krb5_ret_int16(sp, &tmp);
456     if(ret) return ret;
457     }
458 
459     ret = krb5_ret_data(sp, &p->keyvalue);
460     return ret;
461 }
462 
463 krb5_error_code
464 krb5_store_times(krb5_storage *sp, krb5_times times)
465 {
466     int ret;
467     ret = krb5_store_int32(sp, times.authtime);
468     if(ret) return ret;
469     ret = krb5_store_int32(sp, times.starttime);
470     if(ret) return ret;
471     ret = krb5_store_int32(sp, times.endtime);
472     if(ret) return ret;
473     ret = krb5_store_int32(sp, times.renew_till);
474     return ret;
475 }
476 
477 krb5_error_code
478 krb5_ret_times(krb5_storage *sp, krb5_times *times)
479 {
480     int ret;
481     int32_t tmp;
482     ret = krb5_ret_int32(sp, &tmp);
483     times->authtime = tmp;
484     if(ret) return ret;
485     ret = krb5_ret_int32(sp, &tmp);
486     times->starttime = tmp;
487     if(ret) return ret;
488     ret = krb5_ret_int32(sp, &tmp);
489     times->endtime = tmp;
490     if(ret) return ret;
491     ret = krb5_ret_int32(sp, &tmp);
492     times->renew_till = tmp;
493     return ret;
494 }
495 
496 krb5_error_code
497 krb5_store_address(krb5_storage *sp, krb5_address p)
498 {
499     int ret;
500     ret = krb5_store_int16(sp, p.addr_type);
501     if(ret) return ret;
502     ret = krb5_store_data(sp, p.address);
503     return ret;
504 }
505 
506 krb5_error_code
507 krb5_ret_address(krb5_storage *sp, krb5_address *adr)
508 {
509     int16_t t;
510     int ret;
511     ret = krb5_ret_int16(sp, &t);
512     if(ret) return ret;
513     adr->addr_type = t;
514     ret = krb5_ret_data(sp, &adr->address);
515     return ret;
516 }
517 
518 krb5_error_code
519 krb5_store_addrs(krb5_storage *sp, krb5_addresses p)
520 {
521     int i;
522     int ret;
523     ret = krb5_store_int32(sp, p.len);
524     if(ret) return ret;
525     for(i = 0; i<p.len; i++){
526 	ret = krb5_store_address(sp, p.val[i]);
527 	if(ret) break;
528     }
529     return ret;
530 }
531 
532 krb5_error_code
533 krb5_ret_addrs(krb5_storage *sp, krb5_addresses *adr)
534 {
535     int i;
536     int ret;
537     int32_t tmp;
538 
539     ret = krb5_ret_int32(sp, &tmp);
540     if(ret) return ret;
541     adr->len = tmp;
542     ALLOC(adr->val, adr->len);
543     for(i = 0; i < adr->len; i++){
544 	ret = krb5_ret_address(sp, &adr->val[i]);
545 	if(ret) break;
546     }
547     return ret;
548 }
549 
550 krb5_error_code
551 krb5_store_authdata(krb5_storage *sp, krb5_authdata auth)
552 {
553     krb5_error_code ret;
554     int i;
555     ret = krb5_store_int32(sp, auth.len);
556     if(ret) return ret;
557     for(i = 0; i < auth.len; i++){
558 	ret = krb5_store_int16(sp, auth.val[i].ad_type);
559 	if(ret) break;
560 	ret = krb5_store_data(sp, auth.val[i].ad_data);
561 	if(ret) break;
562     }
563     return 0;
564 }
565 
566 krb5_error_code
567 krb5_ret_authdata(krb5_storage *sp, krb5_authdata *auth)
568 {
569     krb5_error_code ret;
570     int32_t tmp;
571     int16_t tmp2;
572     int i;
573     ret = krb5_ret_int32(sp, &tmp);
574     if(ret) return ret;
575     ALLOC_SEQ(auth, tmp);
576     for(i = 0; i < tmp; i++){
577 	ret = krb5_ret_int16(sp, &tmp2);
578 	if(ret) break;
579 	auth->val[i].ad_type = tmp2;
580 	ret = krb5_ret_data(sp, &auth->val[i].ad_data);
581 	if(ret) break;
582     }
583     return ret;
584 }
585 
586 /*
587  * store `creds' on `sp' returning error or zero
588  */
589 
590 krb5_error_code
591 krb5_store_creds(krb5_storage *sp, krb5_creds *creds)
592 {
593     int ret;
594 
595     ret = krb5_store_principal(sp, creds->client);
596     if (ret)
597 	return ret;
598     ret = krb5_store_principal(sp, creds->server);
599     if (ret)
600 	return ret;
601     ret = krb5_store_keyblock(sp, creds->session);
602     if (ret)
603 	return ret;
604     ret = krb5_store_times(sp, creds->times);
605     if (ret)
606 	return ret;
607     ret = krb5_store_int8(sp, 0);  /* this is probably the
608 				enc-tkt-in-skey bit from KDCOptions */
609     if (ret)
610 	return ret;
611     ret = krb5_store_int32(sp, creds->flags.i);
612     if (ret)
613 	return ret;
614     ret = krb5_store_addrs(sp, creds->addresses);
615     if (ret)
616 	return ret;
617     ret = krb5_store_authdata(sp, creds->authdata);
618     if (ret)
619 	return ret;
620     ret = krb5_store_data(sp, creds->ticket);
621     if (ret)
622 	return ret;
623     ret = krb5_store_data(sp, creds->second_ticket);
624     if (ret)
625 	return ret;
626     return 0;
627 }
628 
629 krb5_error_code
630 krb5_ret_creds(krb5_storage *sp, krb5_creds *creds)
631 {
632     krb5_error_code ret;
633     int8_t dummy8;
634     int32_t dummy32;
635 
636     memset(creds, 0, sizeof(*creds));
637     ret = krb5_ret_principal (sp,  &creds->client);
638     if(ret) goto cleanup;
639     ret = krb5_ret_principal (sp,  &creds->server);
640     if(ret) goto cleanup;
641     ret = krb5_ret_keyblock (sp,  &creds->session);
642     if(ret) goto cleanup;
643     ret = krb5_ret_times (sp,  &creds->times);
644     if(ret) goto cleanup;
645     ret = krb5_ret_int8 (sp,  &dummy8);
646     if(ret) goto cleanup;
647     ret = krb5_ret_int32 (sp,  &dummy32);
648     if(ret) goto cleanup;
649     creds->flags.i = dummy32;
650     ret = krb5_ret_addrs (sp,  &creds->addresses);
651     if(ret) goto cleanup;
652     ret = krb5_ret_authdata (sp,  &creds->authdata);
653     if(ret) goto cleanup;
654     ret = krb5_ret_data (sp,  &creds->ticket);
655     if(ret) goto cleanup;
656     ret = krb5_ret_data (sp,  &creds->second_ticket);
657 cleanup:
658     if(ret)
659 #if 0
660 	krb5_free_creds_contents(context, creds) /* XXX */
661 #endif
662 	    ;
663     return ret;
664 }
665