free some more memory. check some more return values.
[heimdal.git] / lib / krb5 / keytab.c
blob774d6560fa86252103ddb0dd2607bebdb09c8d46
1 /*
2 * Copyright (c) 1997 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
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.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed by Kungliga Tekniska
20 * Högskolan and its contributors.
22 * 4. Neither the name of the Institute nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
39 #include "krb5_locl.h"
41 RCSID("$Id$");
43 krb5_error_code
44 krb5_kt_resolve(krb5_context context,
45 const char *name,
46 krb5_keytab *id)
48 krb5_keytab k;
50 if (strncmp (name, "FILE:", 5) != 0)
51 return KRB5_KT_UNKNOWN_TYPE;
53 ALLOC(k, 1);
54 if (k == NULL)
55 return ENOMEM;
56 k->filename = strdup(name + 5);
57 if (k->filename == NULL) {
58 free(k);
59 return ENOMEM;
61 *id = k;
62 return 0;
65 #define KEYTAB_DEFAULT "FILE:/etc/v5srvtab"
67 krb5_error_code
68 krb5_kt_default_name(krb5_context context,
69 char *name,
70 int namesize)
72 strncpy (name, KEYTAB_DEFAULT, namesize);
73 return 0;
76 krb5_error_code
77 krb5_kt_default(krb5_context context,
78 krb5_keytab *id)
80 return krb5_kt_resolve (context, KEYTAB_DEFAULT, id);
83 krb5_error_code
84 krb5_kt_read_service_key(krb5_context context,
85 krb5_pointer keyprocarg,
86 krb5_principal principal,
87 krb5_kvno vno,
88 krb5_keytype keytype,
89 krb5_keyblock **key)
91 krb5_keytab keytab;
92 krb5_keytab_entry entry;
93 krb5_error_code r;
95 if (keyprocarg)
96 r = krb5_kt_resolve (context, keyprocarg, &keytab);
97 else
98 r = krb5_kt_default (context, &keytab);
100 if (r)
101 return r;
103 r = krb5_kt_get_entry (context, keytab, principal, vno, keytype, &entry);
104 if (r)
105 return r;
106 *key = malloc(sizeof(**key));
107 (*key)->keytype = entry.keyblock.keytype;
108 (*key)->keyvalue.length = 0;
109 (*key)->keyvalue.data = NULL;
110 krb5_data_copy(&(*key)->keyvalue, entry.keyblock.keyvalue.data,
111 entry.keyblock.keyvalue.length);
113 krb5_kt_close (context, keytab);
114 return r;
117 #if 0 /* not implemented */
118 krb5_error_code
119 krb5_kt_remove_entry(krb5_context context,
120 krb5_keytab id,
121 krb5_keytab_entry *entry)
123 abort();
125 #endif
127 krb5_error_code
128 krb5_kt_get_name(krb5_context context,
129 krb5_keytab keytab,
130 char *name,
131 int namesize)
133 strncpy (name, keytab->filename, namesize);
134 return 0;
137 krb5_error_code
138 krb5_kt_close(krb5_context context,
139 krb5_keytab id)
141 free (id->filename);
142 free (id);
143 return 0;
146 krb5_error_code
147 krb5_kt_get_entry(krb5_context context,
148 krb5_keytab id,
149 krb5_const_principal principal,
150 krb5_kvno kvno,
151 krb5_keytype keytype,
152 krb5_keytab_entry *entry)
154 krb5_keytab_entry tmp;
155 krb5_error_code r;
156 krb5_kt_cursor cursor;
158 r = krb5_kt_start_seq_get (context, id, &cursor);
159 if (r)
160 return KRB5_KT_NOTFOUND; /* XXX i.e. file not found */
162 entry->vno = 0;
163 while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
164 if ((principal == NULL
165 || krb5_principal_compare(context,
166 principal,
167 tmp.principal))
168 && (keytype == 0 || keytype == tmp.keyblock.keytype)) {
169 if (kvno == tmp.vno) {
170 krb5_kt_copy_entry_contents (context, &tmp, entry);
171 krb5_kt_free_entry (context, &tmp);
172 krb5_kt_end_seq_get(context, id, &cursor);
173 return 0;
174 } else if (kvno == 0 && tmp.vno > entry->vno) {
175 if (entry->vno)
176 krb5_kt_free_entry (context, entry);
177 krb5_kt_copy_entry_contents (context, &tmp, entry);
180 krb5_kt_free_entry(context, &tmp);
182 krb5_kt_end_seq_get (context, id, &cursor);
183 if (entry->vno)
184 return 0;
185 else
186 return KRB5_KT_NOTFOUND;
189 krb5_error_code
190 krb5_kt_copy_entry_contents(krb5_context context,
191 const krb5_keytab_entry *in,
192 krb5_keytab_entry *out)
194 krb5_error_code ret;
196 memset(out, 0, sizeof(*out));
197 out->vno = in->vno;
199 ret = krb5_copy_principal (context, in->principal, &out->principal);
200 if (ret)
201 goto fail;
202 ret = krb5_copy_keyblock_contents (context,
203 &in->keyblock,
204 &out->keyblock);
205 if (ret)
206 goto fail;
207 return 0;
208 fail:
209 krb5_kt_free_entry (context, out);
210 return ret;
213 krb5_error_code
214 krb5_kt_free_entry(krb5_context context,
215 krb5_keytab_entry *entry)
217 krb5_free_principal (context, entry->principal);
218 krb5_free_keyblock_contents (context, &entry->keyblock);
219 return 0;
222 krb5_error_code
223 krb5_kt_start_seq_get(krb5_context context,
224 krb5_keytab id,
225 krb5_kt_cursor *cursor)
227 int16_t tag;
228 int ret;
230 cursor->fd = open (id->filename, O_RDONLY);
231 if (cursor->fd < 0)
232 return errno;
233 cursor->sp = krb5_storage_from_fd(cursor->fd);
234 ret = krb5_ret_int16(cursor->sp, &tag);
235 if (ret)
236 return ret;
237 if (tag != 0x0502)
238 return KRB5_KT_UNKNOWN_TYPE;
239 return 0;
242 static krb5_error_code
243 krb5_kt_ret_data(krb5_storage *sp,
244 krb5_data *data)
246 int ret;
247 int16_t size;
248 ret = krb5_ret_int16(sp, &size);
249 if(ret)
250 return ret;
251 data->length = size;
252 data->data = malloc(size);
253 if (data->data == NULL)
254 return ENOMEM;
255 ret = sp->fetch(sp, data->data, size);
256 if(ret != size)
257 return (ret < 0)? errno : KRB5_KT_END;
258 return 0;
261 static krb5_error_code
262 krb5_kt_ret_string(krb5_storage *sp,
263 general_string *data)
265 int ret;
266 int16_t size;
267 ret = krb5_ret_int16(sp, &size);
268 if(ret)
269 return ret;
270 *data = malloc(size + 1);
271 if (*data == NULL)
272 return ENOMEM;
273 ret = sp->fetch(sp, *data, size);
274 (*data)[size] = '\0';
275 if(ret != size)
276 return (ret < 0)? errno : KRB5_KT_END;
277 return 0;
280 static krb5_error_code
281 krb5_kt_ret_principal(krb5_storage *sp,
282 krb5_principal *princ)
284 int i;
285 int ret;
286 krb5_principal p;
287 int16_t tmp;
289 ALLOC(p, 1);
290 if(p == NULL)
291 return ENOMEM;
293 ret = krb5_ret_int16(sp, &tmp);
294 if(ret)
295 return ret;
296 p->name.name_type = KRB5_NT_SRV_HST;
297 p->name.name_string.len = tmp;
298 ret = krb5_kt_ret_string(sp, &p->realm);
299 if(ret) return ret;
300 p->name.name_string.val = calloc(p->name.name_string.len,
301 sizeof(*p->name.name_string.val));
302 if(p->name.name_string.val == NULL)
303 return ENOMEM;
304 for(i = 0; i < p->name.name_string.len; i++){
305 ret = krb5_kt_ret_string(sp, p->name.name_string.val + i);
306 if(ret) return ret;
308 *princ = p;
309 return 0;
312 static krb5_error_code
313 krb5_kt_ret_keyblock(krb5_storage *sp, krb5_keyblock *p)
315 int ret;
316 int16_t tmp;
318 ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
319 if(ret) return ret;
320 p->keytype = tmp;
321 ret = krb5_kt_ret_data(sp, &p->keyvalue);
322 return ret;
325 static krb5_error_code
326 krb5_kt_store_data(krb5_storage *sp,
327 krb5_data data)
329 int ret;
330 ret = krb5_store_int16(sp, data.length);
331 if(ret < 0)
332 return ret;
333 ret = sp->store(sp, data.data, data.length);
334 if(ret != data.length){
335 if(ret < 0)
336 return errno;
337 return KRB5_KT_END;
339 return 0;
342 static krb5_error_code
343 krb5_kt_store_string(krb5_storage *sp,
344 general_string data)
346 int ret;
347 size_t len = strlen(data);
348 ret = krb5_store_int16(sp, len);
349 if(ret < 0)
350 return ret;
351 ret = sp->store(sp, data, len);
352 if(ret != len){
353 if(ret < 0)
354 return errno;
355 return KRB5_KT_END;
357 return 0;
360 static krb5_error_code
361 krb5_kt_store_keyblock(krb5_storage *sp,
362 krb5_keyblock *p)
364 int ret;
366 ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
367 if(ret) return ret;
368 ret = krb5_kt_store_data(sp, p->keyvalue);
369 return ret;
373 static krb5_error_code
374 krb5_kt_store_principal(krb5_storage *sp,
375 krb5_principal p)
377 int i;
378 int ret;
380 ret = krb5_store_int16(sp, p->name.name_string.len);
381 if(ret) return ret;
382 ret = krb5_kt_store_string(sp, p->realm);
383 if(ret) return ret;
384 for(i = 0; i < p->name.name_string.len; i++){
385 ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
386 if(ret) return ret;
388 return 0;
392 krb5_error_code
393 krb5_kt_add_entry(krb5_context context,
394 krb5_keytab id,
395 krb5_keytab_entry *entry)
397 int ret;
398 int fd;
399 krb5_storage *sp;
401 fd = open (id->filename, O_WRONLY | O_APPEND);
402 if (fd < 0) {
403 fd = open (id->filename, O_WRONLY | O_CREAT, 0600);
404 if (fd < 0)
405 return errno;
406 sp = krb5_storage_from_fd(fd);
407 ret = krb5_store_int16 (sp, 0x0502);
408 if (ret) return ret;
409 } else {
410 sp = krb5_storage_from_fd(fd);
413 ret = krb5_store_int32 (sp, 4711); /* XXX */
414 if (ret) return ret;
415 ret = krb5_kt_store_principal (sp, entry->principal);
416 if (ret) return ret;
417 ret = krb5_store_int32 (sp, entry->principal->name.name_type);
418 if (ret) return ret;
419 ret = krb5_store_int32 (sp, time(NULL));
420 if (ret) return ret;
421 ret = krb5_store_int8 (sp, entry->vno);
422 if (ret) return ret;
423 ret = krb5_kt_store_keyblock (sp, &entry->keyblock);
424 if (ret) return ret;
425 krb5_storage_free (sp);
426 close (fd);
427 return 0;
430 krb5_error_code
431 krb5_kt_next_entry(krb5_context context,
432 krb5_keytab id,
433 krb5_keytab_entry *entry,
434 krb5_kt_cursor *cursor)
436 u_int32_t len;
437 u_int32_t timestamp;
438 int ret;
439 int8_t tmp8;
440 int32_t tmp32;
442 ret = krb5_ret_int32(cursor->sp, &tmp32);
443 if (ret)
444 return ret;
445 len = tmp32;
446 ret = krb5_kt_ret_principal (cursor->sp, &entry->principal);
447 if (ret)
448 return ret;
449 ret = krb5_ret_int32(cursor->sp, &tmp32);
450 entry->principal->name.name_type = tmp32;
451 if (ret)
452 return ret;
453 ret = krb5_ret_int32(cursor->sp, &tmp32);
454 timestamp = tmp32;
455 if (ret)
456 return ret;
457 ret = krb5_ret_int8(cursor->sp, &tmp8);
458 if (ret)
459 return ret;
460 entry->vno = tmp8;
461 ret = krb5_kt_ret_keyblock (cursor->sp, &entry->keyblock);
462 if (ret)
463 return ret;
464 return 0;
467 krb5_error_code
468 krb5_kt_end_seq_get(krb5_context context,
469 krb5_keytab id,
470 krb5_kt_cursor *cursor)
472 krb5_storage_free(cursor->sp);
473 close (cursor->fd);
474 return 0;