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