1 /* $NetBSD: keytab_file.c,v 1.2 2017/01/28 21:31:49 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
5 * (Royal Institute of Technology, Stockholm, Sweden).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 *
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * 3. Neither the name of the Institute nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include "krb5_locl.h"
37
38 #define KRB5_KT_VNO_1 1
39 #define KRB5_KT_VNO_2 2
40 #define KRB5_KT_VNO KRB5_KT_VNO_2
41
42 #define KRB5_KT_FL_JAVA 1
43
44
45 /* file operations -------------------------------------------- */
46
47 struct fkt_data {
48 char *filename;
49 int flags;
50 };
51
52 static krb5_error_code
krb5_kt_ret_data(krb5_context context,krb5_storage * sp,krb5_data * data)53 krb5_kt_ret_data(krb5_context context,
54 krb5_storage *sp,
55 krb5_data *data)
56 {
57 int ret;
58 int16_t size;
59 ret = krb5_ret_int16(sp, &size);
60 if(ret)
61 return ret;
62 data->length = size;
63 data->data = malloc(size);
64 if (data->data == NULL)
65 return krb5_enomem(context);
66 ret = krb5_storage_read(sp, data->data, size);
67 if(ret != size)
68 return (ret < 0)? errno : KRB5_KT_END;
69 return 0;
70 }
71
72 static krb5_error_code
krb5_kt_ret_string(krb5_context context,krb5_storage * sp,heim_general_string * data)73 krb5_kt_ret_string(krb5_context context,
74 krb5_storage *sp,
75 heim_general_string *data)
76 {
77 int ret;
78 int16_t size;
79 ret = krb5_ret_int16(sp, &size);
80 if(ret)
81 return ret;
82 *data = malloc(size + 1);
83 if (*data == NULL)
84 return krb5_enomem(context);
85 ret = krb5_storage_read(sp, *data, size);
86 (*data)[size] = '\0';
87 if(ret != size)
88 return (ret < 0)? errno : KRB5_KT_END;
89 return 0;
90 }
91
92 static krb5_error_code
krb5_kt_store_data(krb5_context context,krb5_storage * sp,krb5_data data)93 krb5_kt_store_data(krb5_context context,
94 krb5_storage *sp,
95 krb5_data data)
96 {
97 int ret;
98 ret = krb5_store_int16(sp, data.length);
99 if(ret < 0)
100 return ret;
101 ret = krb5_storage_write(sp, data.data, data.length);
102 if(ret != (int)data.length){
103 if(ret < 0)
104 return errno;
105 return KRB5_KT_END;
106 }
107 return 0;
108 }
109
110 static krb5_error_code
krb5_kt_store_string(krb5_storage * sp,heim_general_string data)111 krb5_kt_store_string(krb5_storage *sp,
112 heim_general_string data)
113 {
114 int ret;
115 size_t len = strlen(data);
116 ret = krb5_store_int16(sp, len);
117 if(ret < 0)
118 return ret;
119 ret = krb5_storage_write(sp, data, len);
120 if(ret != (int)len){
121 if(ret < 0)
122 return errno;
123 return KRB5_KT_END;
124 }
125 return 0;
126 }
127
128 static krb5_error_code
krb5_kt_ret_keyblock(krb5_context context,struct fkt_data * fkt,krb5_storage * sp,krb5_keyblock * p)129 krb5_kt_ret_keyblock(krb5_context context,
130 struct fkt_data *fkt,
131 krb5_storage *sp,
132 krb5_keyblock *p)
133 {
134 int ret;
135 int16_t tmp;
136
137 ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
138 if(ret) {
139 krb5_set_error_message(context, ret,
140 N_("Cant read keyblock from file %s", ""),
141 fkt->filename);
142 return ret;
143 }
144 p->keytype = tmp;
145 ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
146 if (ret)
147 krb5_set_error_message(context, ret,
148 N_("Cant read keyblock from file %s", ""),
149 fkt->filename);
150 return ret;
151 }
152
153 static krb5_error_code
krb5_kt_store_keyblock(krb5_context context,struct fkt_data * fkt,krb5_storage * sp,krb5_keyblock * p)154 krb5_kt_store_keyblock(krb5_context context,
155 struct fkt_data *fkt,
156 krb5_storage *sp,
157 krb5_keyblock *p)
158 {
159 int ret;
160
161 ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
162 if(ret) {
163 krb5_set_error_message(context, ret,
164 N_("Cant store keyblock to file %s", ""),
165 fkt->filename);
166 return ret;
167 }
168 ret = krb5_kt_store_data(context, sp, p->keyvalue);
169 if (ret)
170 krb5_set_error_message(context, ret,
171 N_("Cant store keyblock to file %s", ""),
172 fkt->filename);
173 return ret;
174 }
175
176
177 static krb5_error_code
krb5_kt_ret_principal(krb5_context context,struct fkt_data * fkt,krb5_storage * sp,krb5_principal * princ)178 krb5_kt_ret_principal(krb5_context context,
179 struct fkt_data *fkt,
180 krb5_storage *sp,
181 krb5_principal *princ)
182 {
183 size_t i;
184 int ret;
185 krb5_principal p;
186 int16_t len;
187
188 ALLOC(p, 1);
189 if(p == NULL)
190 return krb5_enomem(context);
191
192 ret = krb5_ret_int16(sp, &len);
193 if(ret) {
194 krb5_set_error_message(context, ret,
195 N_("Failed decoding length of "
196 "keytab principal in keytab file %s", ""),
197 fkt->filename);
198 goto out;
199 }
200 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
201 len--;
202 if (len < 0) {
203 ret = KRB5_KT_END;
204 krb5_set_error_message(context, ret,
205 N_("Keytab principal contains "
206 "invalid length in keytab %s", ""),
207 fkt->filename);
208 goto out;
209 }
210 ret = krb5_kt_ret_string(context, sp, &p->realm);
211 if(ret) {
212 krb5_set_error_message(context, ret,
213 N_("Can't read realm from keytab: %s", ""),
214 fkt->filename);
215 goto out;
216 }
217 p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val));
218 if(p->name.name_string.val == NULL) {
219 ret = krb5_enomem(context);
220 goto out;
221 }
222 p->name.name_string.len = len;
223 for(i = 0; i < p->name.name_string.len; i++){
224 ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
225 if(ret) {
226 krb5_set_error_message(context, ret,
227 N_("Can't read principal from "
228 "keytab: %s", ""),
229 fkt->filename);
230 goto out;
231 }
232 }
233 if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
234 p->name.name_type = KRB5_NT_UNKNOWN;
235 else {
236 int32_t tmp32;
237 ret = krb5_ret_int32(sp, &tmp32);
238 p->name.name_type = tmp32;
239 if (ret) {
240 krb5_set_error_message(context, ret,
241 N_("Can't read name-type from "
242 "keytab: %s", ""),
243 fkt->filename);
244 goto out;
245 }
246 }
247 *princ = p;
248 return 0;
249 out:
250 krb5_free_principal(context, p);
251 return ret;
252 }
253
254 static krb5_error_code
krb5_kt_store_principal(krb5_context context,krb5_storage * sp,krb5_principal p)255 krb5_kt_store_principal(krb5_context context,
256 krb5_storage *sp,
257 krb5_principal p)
258 {
259 size_t i;
260 int ret;
261
262 if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
263 ret = krb5_store_int16(sp, p->name.name_string.len + 1);
264 else
265 ret = krb5_store_int16(sp, p->name.name_string.len);
266 if(ret) return ret;
267 ret = krb5_kt_store_string(sp, p->realm);
268 if(ret) return ret;
269 for(i = 0; i < p->name.name_string.len; i++){
270 ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
271 if(ret)
272 return ret;
273 }
274 if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
275 ret = krb5_store_int32(sp, p->name.name_type);
276 if(ret)
277 return ret;
278 }
279
280 return 0;
281 }
282
283 static krb5_error_code KRB5_CALLCONV
fkt_resolve(krb5_context context,const char * name,krb5_keytab id)284 fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
285 {
286 struct fkt_data *d;
287
288 d = malloc(sizeof(*d));
289 if(d == NULL)
290 return krb5_enomem(context);
291 d->filename = strdup(name);
292 if(d->filename == NULL) {
293 free(d);
294 return krb5_enomem(context);
295 }
296 d->flags = 0;
297 id->data = d;
298 return 0;
299 }
300
301 static krb5_error_code KRB5_CALLCONV
fkt_resolve_java14(krb5_context context,const char * name,krb5_keytab id)302 fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id)
303 {
304 krb5_error_code ret;
305
306 ret = fkt_resolve(context, name, id);
307 if (ret == 0) {
308 struct fkt_data *d = id->data;
309 d->flags |= KRB5_KT_FL_JAVA;
310 }
311 return ret;
312 }
313
314 static krb5_error_code KRB5_CALLCONV
fkt_close(krb5_context context,krb5_keytab id)315 fkt_close(krb5_context context, krb5_keytab id)
316 {
317 struct fkt_data *d = id->data;
318 free(d->filename);
319 free(d);
320 return 0;
321 }
322
323 static krb5_error_code KRB5_CALLCONV
fkt_destroy(krb5_context context,krb5_keytab id)324 fkt_destroy(krb5_context context, krb5_keytab id)
325 {
326 struct fkt_data *d = id->data;
327 _krb5_erase_file(context, d->filename);
328 return 0;
329 }
330
331 static krb5_error_code KRB5_CALLCONV
fkt_get_name(krb5_context context,krb5_keytab id,char * name,size_t namesize)332 fkt_get_name(krb5_context context,
333 krb5_keytab id,
334 char *name,
335 size_t namesize)
336 {
337 /* This function is XXX */
338 struct fkt_data *d = id->data;
339 strlcpy(name, d->filename, namesize);
340 return 0;
341 }
342
343 static void
storage_set_flags(krb5_context context,krb5_storage * sp,int vno)344 storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
345 {
346 int flags = 0;
347 switch(vno) {
348 case KRB5_KT_VNO_1:
349 flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
350 flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
351 flags |= KRB5_STORAGE_HOST_BYTEORDER;
352 break;
353 case KRB5_KT_VNO_2:
354 break;
355 default:
356 krb5_warnx(context,
357 "storage_set_flags called with bad vno (%d)", vno);
358 }
359 krb5_storage_set_flags(sp, flags);
360 }
361
362 static krb5_error_code
fkt_start_seq_get_int(krb5_context context,krb5_keytab id,int flags,int exclusive,krb5_kt_cursor * c)363 fkt_start_seq_get_int(krb5_context context,
364 krb5_keytab id,
365 int flags,
366 int exclusive,
367 krb5_kt_cursor *c)
368 {
369 int8_t pvno, tag;
370 krb5_error_code ret;
371 struct fkt_data *d = id->data;
372
373 c->fd = open (d->filename, flags);
374 if (c->fd < 0) {
375 ret = errno;
376 krb5_set_error_message(context, ret,
377 N_("keytab %s open failed: %s", ""),
378 d->filename, strerror(ret));
379 return ret;
380 }
381 rk_cloexec(c->fd);
382 ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
383 if (ret) {
384 close(c->fd);
385 return ret;
386 }
387 c->sp = krb5_storage_from_fd(c->fd);
388 if (c->sp == NULL) {
389 _krb5_xunlock(context, c->fd);
390 close(c->fd);
391 return krb5_enomem(context);
392 }
393 krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
394 ret = krb5_ret_int8(c->sp, &pvno);
395 if(ret) {
396 krb5_storage_free(c->sp);
397 _krb5_xunlock(context, c->fd);
398 close(c->fd);
399 krb5_clear_error_message(context);
400 return ret;
401 }
402 if(pvno != 5) {
403 krb5_storage_free(c->sp);
404 _krb5_xunlock(context, c->fd);
405 close(c->fd);
406 krb5_clear_error_message (context);
407 return KRB5_KEYTAB_BADVNO;
408 }
409 ret = krb5_ret_int8(c->sp, &tag);
410 if (ret) {
411 krb5_storage_free(c->sp);
412 _krb5_xunlock(context, c->fd);
413 close(c->fd);
414 krb5_clear_error_message(context);
415 return ret;
416 }
417 id->version = tag;
418 storage_set_flags(context, c->sp, id->version);
419 return 0;
420 }
421
422 static krb5_error_code KRB5_CALLCONV
fkt_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * c)423 fkt_start_seq_get(krb5_context context,
424 krb5_keytab id,
425 krb5_kt_cursor *c)
426 {
427 return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c);
428 }
429
430 static krb5_error_code
fkt_next_entry_int(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor,off_t * start,off_t * end)431 fkt_next_entry_int(krb5_context context,
432 krb5_keytab id,
433 krb5_keytab_entry *entry,
434 krb5_kt_cursor *cursor,
435 off_t *start,
436 off_t *end)
437 {
438 struct fkt_data *d = id->data;
439 int32_t len;
440 int ret;
441 int8_t tmp8;
442 int32_t tmp32;
443 uint32_t utmp32;
444 off_t pos, curpos;
445
446 pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
447 loop:
448 ret = krb5_ret_int32(cursor->sp, &len);
449 if (ret)
450 return ret;
451 if(len < 0) {
452 pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
453 goto loop;
454 }
455 ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
456 if (ret)
457 goto out;
458 ret = krb5_ret_uint32(cursor->sp, &utmp32);
459 entry->timestamp = utmp32;
460 if (ret)
461 goto out;
462 ret = krb5_ret_int8(cursor->sp, &tmp8);
463 if (ret)
464 goto out;
465 entry->vno = tmp8;
466 ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
467 if (ret)
468 goto out;
469 /* there might be a 32 bit kvno here
470 * if it's zero, assume that the 8bit one was right,
471 * otherwise trust the new value */
472 curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
473 if(len + 4 + pos - curpos >= 4) {
474 ret = krb5_ret_int32(cursor->sp, &tmp32);
475 if (ret == 0 && tmp32 != 0)
476 entry->vno = tmp32;
477 }
478 /* there might be a flags field here */
479 if(len + 4 + pos - curpos >= 8) {
480 ret = krb5_ret_uint32(cursor->sp, &utmp32);
481 if (ret == 0)
482 entry->flags = utmp32;
483 } else
484 entry->flags = 0;
485
486 entry->aliases = NULL;
487
488 if(start) *start = pos;
489 if(end) *end = pos + 4 + len;
490 out:
491 if (ret)
492 krb5_kt_free_entry(context, entry);
493 krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
494 return ret;
495 }
496
497 static krb5_error_code KRB5_CALLCONV
fkt_next_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)498 fkt_next_entry(krb5_context context,
499 krb5_keytab id,
500 krb5_keytab_entry *entry,
501 krb5_kt_cursor *cursor)
502 {
503 return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
504 }
505
506 static krb5_error_code KRB5_CALLCONV
fkt_end_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)507 fkt_end_seq_get(krb5_context context,
508 krb5_keytab id,
509 krb5_kt_cursor *cursor)
510 {
511 krb5_storage_free(cursor->sp);
512 _krb5_xunlock(context, cursor->fd);
513 close(cursor->fd);
514 return 0;
515 }
516
517 static krb5_error_code KRB5_CALLCONV
fkt_setup_keytab(krb5_context context,krb5_keytab id,krb5_storage * sp)518 fkt_setup_keytab(krb5_context context,
519 krb5_keytab id,
520 krb5_storage *sp)
521 {
522 krb5_error_code ret;
523 ret = krb5_store_int8(sp, 5);
524 if(ret)
525 return ret;
526 if(id->version == 0)
527 id->version = KRB5_KT_VNO;
528 return krb5_store_int8 (sp, id->version);
529 }
530
531 static krb5_error_code KRB5_CALLCONV
fkt_add_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)532 fkt_add_entry(krb5_context context,
533 krb5_keytab id,
534 krb5_keytab_entry *entry)
535 {
536 int ret;
537 int fd;
538 krb5_storage *sp;
539 struct fkt_data *d = id->data;
540 krb5_data keytab;
541 int32_t len;
542
543 fd = open (d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
544 if (fd < 0) {
545 fd = open (d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
546 if (fd < 0) {
547 ret = errno;
548 krb5_set_error_message(context, ret,
549 N_("open(%s): %s", ""), d->filename,
550 strerror(ret));
551 return ret;
552 }
553 rk_cloexec(fd);
554
555 ret = _krb5_xlock(context, fd, 1, d->filename);
556 if (ret) {
557 close(fd);
558 return ret;
559 }
560 sp = krb5_storage_from_fd(fd);
561 krb5_storage_set_eof_code(sp, KRB5_KT_END);
562 ret = fkt_setup_keytab(context, id, sp);
563 if(ret) {
564 goto out;
565 }
566 storage_set_flags(context, sp, id->version);
567 } else {
568 int8_t pvno, tag;
569
570 rk_cloexec(fd);
571
572 ret = _krb5_xlock(context, fd, 1, d->filename);
573 if (ret) {
574 close(fd);
575 return ret;
576 }
577 sp = krb5_storage_from_fd(fd);
578 krb5_storage_set_eof_code(sp, KRB5_KT_END);
579 ret = krb5_ret_int8(sp, &pvno);
580 if(ret) {
581 /* we probably have a zero byte file, so try to set it up
582 properly */
583 ret = fkt_setup_keytab(context, id, sp);
584 if(ret) {
585 krb5_set_error_message(context, ret,
586 N_("%s: keytab is corrupted: %s", ""),
587 d->filename, strerror(ret));
588 goto out;
589 }
590 storage_set_flags(context, sp, id->version);
591 } else {
592 if(pvno != 5) {
593 ret = KRB5_KEYTAB_BADVNO;
594 krb5_set_error_message(context, ret,
595 N_("Bad version in keytab %s", ""),
596 d->filename);
597 goto out;
598 }
599 ret = krb5_ret_int8 (sp, &tag);
600 if (ret) {
601 krb5_set_error_message(context, ret,
602 N_("failed reading tag from "
603 "keytab %s", ""),
604 d->filename);
605 goto out;
606 }
607 id->version = tag;
608 storage_set_flags(context, sp, id->version);
609 }
610 }
611
612 {
613 krb5_storage *emem;
614 emem = krb5_storage_emem();
615 if(emem == NULL) {
616 ret = krb5_enomem(context);
617 goto out;
618 }
619 ret = krb5_kt_store_principal(context, emem, entry->principal);
620 if(ret) {
621 krb5_set_error_message(context, ret,
622 N_("Failed storing principal "
623 "in keytab %s", ""),
624 d->filename);
625 krb5_storage_free(emem);
626 goto out;
627 }
628 ret = krb5_store_int32 (emem, entry->timestamp);
629 if(ret) {
630 krb5_set_error_message(context, ret,
631 N_("Failed storing timpstamp "
632 "in keytab %s", ""),
633 d->filename);
634 krb5_storage_free(emem);
635 goto out;
636 }
637 ret = krb5_store_int8 (emem, entry->vno % 256);
638 if(ret) {
639 krb5_set_error_message(context, ret,
640 N_("Failed storing kvno "
641 "in keytab %s", ""),
642 d->filename);
643 krb5_storage_free(emem);
644 goto out;
645 }
646 ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock);
647 if(ret) {
648 krb5_storage_free(emem);
649 goto out;
650 }
651 if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
652 ret = krb5_store_int32 (emem, entry->vno);
653 if (ret) {
654 krb5_set_error_message(context, ret,
655 N_("Failed storing extended kvno "
656 "in keytab %s", ""),
657 d->filename);
658 krb5_storage_free(emem);
659 goto out;
660 }
661 ret = krb5_store_uint32 (emem, entry->flags);
662 if (ret) {
663 krb5_set_error_message(context, ret,
664 N_("Failed storing extended kvno "
665 "in keytab %s", ""),
666 d->filename);
667 krb5_storage_free(emem);
668 goto out;
669 }
670 }
671
672 ret = krb5_storage_to_data(emem, &keytab);
673 krb5_storage_free(emem);
674 if(ret) {
675 krb5_set_error_message(context, ret,
676 N_("Failed converting keytab entry "
677 "to memory block for keytab %s", ""),
678 d->filename);
679 goto out;
680 }
681 }
682
683 while(1) {
684 ret = krb5_ret_int32(sp, &len);
685 if(ret == KRB5_KT_END) {
686 len = keytab.length;
687 break;
688 }
689 if(len < 0) {
690 len = -len;
691 if(len >= (int)keytab.length) {
692 krb5_storage_seek(sp, -4, SEEK_CUR);
693 break;
694 }
695 }
696 krb5_storage_seek(sp, len, SEEK_CUR);
697 }
698 ret = krb5_store_int32(sp, len);
699 if(krb5_storage_write(sp, keytab.data, keytab.length) < 0) {
700 ret = errno;
701 krb5_set_error_message(context, ret,
702 N_("Failed writing keytab block "
703 "in keytab %s: %s", ""),
704 d->filename, strerror(ret));
705 }
706 memset(keytab.data, 0, keytab.length);
707 krb5_data_free(&keytab);
708 out:
709 krb5_storage_free(sp);
710 _krb5_xunlock(context, fd);
711 close(fd);
712 return ret;
713 }
714
715 static krb5_error_code KRB5_CALLCONV
fkt_remove_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry)716 fkt_remove_entry(krb5_context context,
717 krb5_keytab id,
718 krb5_keytab_entry *entry)
719 {
720 krb5_keytab_entry e;
721 krb5_kt_cursor cursor;
722 off_t pos_start, pos_end;
723 int found = 0;
724 krb5_error_code ret;
725
726 ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor);
727 if(ret != 0)
728 goto out; /* return other error here? */
729 while(fkt_next_entry_int(context, id, &e, &cursor,
730 &pos_start, &pos_end) == 0) {
731 if(krb5_kt_compare(context, &e, entry->principal,
732 entry->vno, entry->keyblock.keytype)) {
733 int32_t len;
734 unsigned char buf[128];
735 found = 1;
736 krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
737 len = pos_end - pos_start - 4;
738 krb5_store_int32(cursor.sp, -len);
739 memset(buf, 0, sizeof(buf));
740 while(len > 0) {
741 krb5_storage_write(cursor.sp, buf,
742 min((size_t)len, sizeof(buf)));
743 len -= min((size_t)len, sizeof(buf));
744 }
745 }
746 krb5_kt_free_entry(context, &e);
747 }
748 krb5_kt_end_seq_get(context, id, &cursor);
749 out:
750 if (!found) {
751 krb5_clear_error_message (context);
752 return KRB5_KT_NOTFOUND;
753 }
754 return 0;
755 }
756
757 const krb5_kt_ops krb5_fkt_ops = {
758 "FILE",
759 fkt_resolve,
760 fkt_get_name,
761 fkt_close,
762 fkt_destroy,
763 NULL, /* get */
764 fkt_start_seq_get,
765 fkt_next_entry,
766 fkt_end_seq_get,
767 fkt_add_entry,
768 fkt_remove_entry,
769 NULL,
770 0
771 };
772
773 const krb5_kt_ops krb5_wrfkt_ops = {
774 "WRFILE",
775 fkt_resolve,
776 fkt_get_name,
777 fkt_close,
778 fkt_destroy,
779 NULL, /* get */
780 fkt_start_seq_get,
781 fkt_next_entry,
782 fkt_end_seq_get,
783 fkt_add_entry,
784 fkt_remove_entry,
785 NULL,
786 0
787 };
788
789 const krb5_kt_ops krb5_javakt_ops = {
790 "JAVA14",
791 fkt_resolve_java14,
792 fkt_get_name,
793 fkt_close,
794 fkt_destroy,
795 NULL, /* get */
796 fkt_start_seq_get,
797 fkt_next_entry,
798 fkt_end_seq_get,
799 fkt_add_entry,
800 fkt_remove_entry,
801 NULL,
802 0
803 };
804