Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2017 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 : #define KRB5_KT_VNO_1 1
37 : #define KRB5_KT_VNO_2 2
38 : #define KRB5_KT_VNO KRB5_KT_VNO_2
39 :
40 : #define KRB5_KT_FL_JAVA 1
41 :
42 :
43 : /* file operations -------------------------------------------- */
44 :
45 : struct fkt_data {
46 : char *filename;
47 : int flags;
48 : };
49 :
50 : static krb5_error_code
51 199200 : krb5_kt_ret_data(krb5_context context,
52 : krb5_storage *sp,
53 : krb5_data *data)
54 : {
55 3165 : krb5_error_code ret;
56 3165 : krb5_ssize_t bytes;
57 3165 : int16_t size;
58 :
59 199200 : ret = krb5_ret_int16(sp, &size);
60 199200 : if(ret)
61 0 : return ret;
62 199200 : data->length = size;
63 199200 : data->data = malloc(size);
64 199200 : if (data->data == NULL)
65 0 : return krb5_enomem(context);
66 199200 : bytes = krb5_storage_read(sp, data->data, size);
67 199200 : if (bytes != size)
68 0 : return (bytes == -1) ? errno : KRB5_KT_END;
69 196035 : return 0;
70 : }
71 :
72 : static krb5_error_code
73 533323 : krb5_kt_ret_string(krb5_context context,
74 : krb5_storage *sp,
75 : heim_general_string *data)
76 : {
77 8431 : krb5_error_code ret;
78 8431 : krb5_ssize_t bytes;
79 8431 : int16_t size;
80 :
81 533323 : ret = krb5_ret_int16(sp, &size);
82 533323 : if(ret)
83 0 : return ret;
84 533323 : *data = malloc(size + 1);
85 533323 : if (*data == NULL)
86 0 : return krb5_enomem(context);
87 533323 : bytes = krb5_storage_read(sp, *data, size);
88 533323 : (*data)[size] = '\0';
89 533323 : if (bytes != size)
90 0 : return (bytes == -1) ? errno : KRB5_KT_END;
91 524892 : return 0;
92 : }
93 :
94 : static krb5_error_code
95 2214 : krb5_kt_store_data(krb5_context context,
96 : krb5_storage *sp,
97 : krb5_data data)
98 : {
99 231 : krb5_error_code ret;
100 231 : krb5_ssize_t bytes;
101 :
102 2214 : ret = krb5_store_int16(sp, data.length);
103 2214 : if (ret != 0)
104 0 : return ret;
105 2214 : bytes = krb5_storage_write(sp, data.data, data.length);
106 2214 : if (bytes != (int)data.length)
107 0 : return bytes == -1 ? errno : KRB5_KT_END;
108 1983 : return 0;
109 : }
110 :
111 : static krb5_error_code
112 5907 : krb5_kt_store_string(krb5_storage *sp,
113 : heim_general_string data)
114 : {
115 615 : krb5_error_code ret;
116 615 : krb5_ssize_t bytes;
117 5907 : size_t len = strlen(data);
118 :
119 5907 : ret = krb5_store_int16(sp, len);
120 5907 : if (ret != 0)
121 0 : return ret;
122 5907 : bytes = krb5_storage_write(sp, data, len);
123 5907 : if (bytes != (int)len)
124 0 : return bytes == -1 ? errno : KRB5_KT_END;
125 5292 : return 0;
126 : }
127 :
128 : static krb5_error_code
129 199200 : krb5_kt_ret_keyblock(krb5_context context,
130 : struct fkt_data *fkt,
131 : krb5_storage *sp,
132 : krb5_keyblock *p)
133 : {
134 3165 : int ret;
135 3165 : int16_t tmp;
136 :
137 199200 : ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
138 199200 : if(ret) {
139 0 : krb5_set_error_message(context, ret,
140 0 : N_("Cant read keyblock from file %s", ""),
141 : fkt->filename);
142 0 : return ret;
143 : }
144 199200 : p->keytype = tmp;
145 199200 : ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
146 199200 : if (ret)
147 0 : krb5_set_error_message(context, ret,
148 0 : N_("Cant read keyblock from file %s", ""),
149 : fkt->filename);
150 196035 : return ret;
151 : }
152 :
153 : static krb5_error_code
154 2214 : krb5_kt_store_keyblock(krb5_context context,
155 : struct fkt_data *fkt,
156 : krb5_storage *sp,
157 : krb5_keyblock *p)
158 : {
159 231 : int ret;
160 :
161 2214 : ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
162 2214 : if(ret) {
163 0 : krb5_set_error_message(context, ret,
164 0 : N_("Cant store keyblock to file %s", ""),
165 : fkt->filename);
166 0 : return ret;
167 : }
168 2214 : ret = krb5_kt_store_data(context, sp, p->keyvalue);
169 2214 : if (ret)
170 0 : krb5_set_error_message(context, ret,
171 0 : N_("Cant store keyblock to file %s", ""),
172 : fkt->filename);
173 1983 : return ret;
174 : }
175 :
176 :
177 : static krb5_error_code
178 199200 : krb5_kt_ret_principal(krb5_context context,
179 : struct fkt_data *fkt,
180 : krb5_storage *sp,
181 : krb5_principal *princ)
182 : {
183 3165 : size_t i;
184 3165 : int ret;
185 3165 : krb5_principal p;
186 3165 : int16_t len;
187 :
188 199200 : ALLOC(p, 1);
189 199200 : if(p == NULL)
190 0 : return krb5_enomem(context);
191 :
192 199200 : ret = krb5_ret_int16(sp, &len);
193 199200 : if(ret) {
194 0 : krb5_set_error_message(context, ret,
195 0 : N_("Failed decoding length of "
196 : "keytab principal in keytab file %s", ""),
197 : fkt->filename);
198 0 : goto out;
199 : }
200 199200 : if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
201 0 : len--;
202 199200 : if (len < 0) {
203 0 : ret = KRB5_KT_END;
204 0 : krb5_set_error_message(context, ret,
205 0 : N_("Keytab principal contains "
206 : "invalid length in keytab %s", ""),
207 : fkt->filename);
208 0 : goto out;
209 : }
210 199200 : ret = krb5_kt_ret_string(context, sp, &p->realm);
211 199200 : if(ret) {
212 0 : krb5_set_error_message(context, ret,
213 0 : N_("Can't read realm from keytab: %s", ""),
214 : fkt->filename);
215 0 : goto out;
216 : }
217 199200 : p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val));
218 199200 : if(p->name.name_string.val == NULL) {
219 0 : ret = krb5_enomem(context);
220 0 : goto out;
221 : }
222 199200 : p->name.name_string.len = len;
223 533323 : for(i = 0; i < p->name.name_string.len; i++){
224 334123 : ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
225 334123 : if(ret) {
226 0 : krb5_set_error_message(context, ret,
227 0 : N_("Can't read principal from "
228 : "keytab: %s", ""),
229 : fkt->filename);
230 0 : goto out;
231 : }
232 : }
233 199200 : if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
234 0 : p->name.name_type = KRB5_NT_UNKNOWN;
235 : else {
236 3165 : int32_t tmp32;
237 199200 : ret = krb5_ret_int32(sp, &tmp32);
238 199200 : p->name.name_type = tmp32;
239 199200 : if (ret) {
240 0 : krb5_set_error_message(context, ret,
241 0 : N_("Can't read name-type from "
242 : "keytab: %s", ""),
243 : fkt->filename);
244 0 : goto out;
245 : }
246 : }
247 199200 : *princ = p;
248 199200 : return 0;
249 0 : out:
250 0 : krb5_free_principal(context, p);
251 0 : return ret;
252 : }
253 :
254 : static krb5_error_code
255 2214 : krb5_kt_store_principal(krb5_context context,
256 : krb5_storage *sp,
257 : krb5_principal p)
258 : {
259 231 : size_t i;
260 231 : int ret;
261 :
262 2214 : if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
263 0 : ret = krb5_store_int16(sp, p->name.name_string.len + 1);
264 : else
265 2214 : ret = krb5_store_int16(sp, p->name.name_string.len);
266 2214 : if(ret) return ret;
267 2214 : ret = krb5_kt_store_string(sp, p->realm);
268 2214 : if(ret) return ret;
269 5907 : for(i = 0; i < p->name.name_string.len; i++){
270 3693 : ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
271 3693 : if(ret)
272 0 : return ret;
273 : }
274 2214 : if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
275 2214 : ret = krb5_store_int32(sp, p->name.name_type);
276 2214 : if(ret)
277 0 : return ret;
278 : }
279 :
280 1983 : return 0;
281 : }
282 :
283 : static krb5_error_code KRB5_CALLCONV
284 218102 : fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
285 : {
286 6998 : struct fkt_data *d;
287 :
288 218102 : d = malloc(sizeof(*d));
289 218102 : if(d == NULL)
290 0 : return krb5_enomem(context);
291 218102 : d->filename = strdup(name);
292 218102 : if(d->filename == NULL) {
293 0 : free(d);
294 0 : return krb5_enomem(context);
295 : }
296 218102 : d->flags = 0;
297 218102 : id->data = d;
298 218102 : return 0;
299 : }
300 :
301 : static krb5_error_code KRB5_CALLCONV
302 0 : fkt_resolve_java14(krb5_context context, const char *name, krb5_keytab id)
303 : {
304 0 : krb5_error_code ret;
305 :
306 0 : ret = fkt_resolve(context, name, id);
307 0 : if (ret == 0) {
308 0 : struct fkt_data *d = id->data;
309 0 : d->flags |= KRB5_KT_FL_JAVA;
310 : }
311 0 : return ret;
312 : }
313 :
314 : static krb5_error_code KRB5_CALLCONV
315 218074 : fkt_close(krb5_context context, krb5_keytab id)
316 : {
317 218074 : struct fkt_data *d = id->data;
318 218074 : free(d->filename);
319 218074 : free(d);
320 218074 : return 0;
321 : }
322 :
323 : static krb5_error_code KRB5_CALLCONV
324 0 : fkt_destroy(krb5_context context, krb5_keytab id)
325 : {
326 0 : struct fkt_data *d = id->data;
327 0 : _krb5_erase_file(context, d->filename);
328 0 : return 0;
329 : }
330 :
331 : static krb5_error_code KRB5_CALLCONV
332 121589 : fkt_get_name(krb5_context context,
333 : krb5_keytab id,
334 : char *name,
335 : size_t namesize)
336 : {
337 : /* This function is XXX */
338 121589 : struct fkt_data *d = id->data;
339 121589 : strlcpy(name, d->filename, namesize);
340 121589 : return 0;
341 : }
342 :
343 : static void
344 55776 : storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
345 : {
346 55776 : int flags = 0;
347 55776 : switch(vno) {
348 0 : case KRB5_KT_VNO_1:
349 0 : flags |= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS;
350 0 : flags |= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE;
351 0 : flags |= KRB5_STORAGE_HOST_BYTEORDER;
352 0 : break;
353 54606 : case KRB5_KT_VNO_2:
354 54606 : break;
355 0 : default:
356 0 : krb5_warnx(context,
357 : "storage_set_flags called with bad vno (%d)", vno);
358 : }
359 55776 : krb5_storage_set_flags(sp, flags);
360 55776 : }
361 :
362 : static krb5_error_code
363 53738 : 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 961 : int8_t pvno, tag;
370 961 : krb5_error_code ret;
371 53738 : struct fkt_data *d = id->data;
372 53738 : const char *stdio_mode = "rb";
373 :
374 53738 : memset(c, 0, sizeof(*c));
375 53738 : c->fd = open (d->filename, flags);
376 53738 : if (c->fd < 0) {
377 176 : ret = errno;
378 176 : krb5_set_error_message(context, ret,
379 176 : N_("keytab %s open failed: %s", ""),
380 : d->filename, strerror(ret));
381 176 : return ret;
382 : }
383 53562 : rk_cloexec(c->fd);
384 53562 : ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
385 53562 : if (ret) {
386 0 : close(c->fd);
387 0 : return ret;
388 : }
389 53562 : if ((flags & O_ACCMODE) == O_RDWR && (flags & O_APPEND))
390 0 : stdio_mode = "ab+";
391 53562 : else if ((flags & O_ACCMODE) == O_RDWR)
392 476 : stdio_mode = "rb+";
393 53059 : else if ((flags & O_ACCMODE) == O_WRONLY)
394 0 : stdio_mode = "wb";
395 53562 : c->sp = krb5_storage_stdio_from_fd(c->fd, stdio_mode);
396 53562 : if (c->sp == NULL) {
397 0 : close(c->fd);
398 0 : return krb5_enomem(context);
399 : }
400 53562 : krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
401 53562 : ret = krb5_ret_int8(c->sp, &pvno);
402 53562 : if(ret) {
403 0 : krb5_storage_free(c->sp);
404 0 : close(c->fd);
405 0 : krb5_clear_error_message(context);
406 0 : return ret;
407 : }
408 53562 : if(pvno != 5) {
409 0 : krb5_storage_free(c->sp);
410 0 : close(c->fd);
411 0 : krb5_clear_error_message (context);
412 0 : return KRB5_KEYTAB_BADVNO;
413 : }
414 53562 : ret = krb5_ret_int8(c->sp, &tag);
415 53562 : if (ret) {
416 0 : krb5_storage_free(c->sp);
417 0 : close(c->fd);
418 0 : krb5_clear_error_message(context);
419 0 : return ret;
420 : }
421 53562 : id->version = tag;
422 53562 : storage_set_flags(context, c->sp, id->version);
423 53562 : return 0;
424 : }
425 :
426 : static krb5_error_code KRB5_CALLCONV
427 53235 : fkt_start_seq_get(krb5_context context,
428 : krb5_keytab id,
429 : krb5_kt_cursor *c)
430 : {
431 53235 : return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c);
432 : }
433 :
434 : static krb5_error_code
435 200199 : fkt_next_entry_int(krb5_context context,
436 : krb5_keytab id,
437 : krb5_keytab_entry *entry,
438 : krb5_kt_cursor *cursor,
439 : off_t *start,
440 : off_t *end)
441 : {
442 200199 : struct fkt_data *d = id->data;
443 3196 : int32_t len;
444 3196 : int ret;
445 3196 : int8_t tmp8;
446 3196 : int32_t tmp32;
447 3196 : uint32_t utmp32;
448 3196 : off_t pos, curpos;
449 :
450 200199 : pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
451 203966 : loop:
452 203966 : ret = krb5_ret_int32(cursor->sp, &len);
453 203966 : if (ret)
454 999 : return ret;
455 202967 : if(len < 0) {
456 3767 : pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
457 3767 : goto loop;
458 : }
459 199200 : ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
460 199200 : if (ret)
461 0 : goto out;
462 199200 : ret = krb5_ret_uint32(cursor->sp, &utmp32);
463 199200 : entry->timestamp = utmp32;
464 199200 : if (ret)
465 0 : goto out;
466 199200 : ret = krb5_ret_int8(cursor->sp, &tmp8);
467 199200 : if (ret)
468 0 : goto out;
469 199200 : entry->vno = tmp8;
470 199200 : ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
471 199200 : if (ret)
472 0 : goto out;
473 : /* there might be a 32 bit kvno here
474 : * if it's zero, assume that the 8bit one was right,
475 : * otherwise trust the new value */
476 199200 : curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
477 199200 : if(len + 4 + pos - curpos >= 4) {
478 199200 : ret = krb5_ret_int32(cursor->sp, &tmp32);
479 199200 : if (ret == 0 && tmp32 != 0)
480 199200 : entry->vno = tmp32;
481 : }
482 : /* there might be a flags field here */
483 199200 : if(len + 4 + pos - curpos >= 8) {
484 199200 : ret = krb5_ret_uint32(cursor->sp, &utmp32);
485 199200 : if (ret == 0)
486 199200 : entry->flags = utmp32;
487 : } else
488 0 : entry->flags = 0;
489 :
490 199200 : entry->aliases = NULL;
491 :
492 199200 : if(start) *start = pos;
493 199200 : if(end) *end = pos + 4 + len;
494 190771 : out:
495 199200 : if (ret)
496 0 : krb5_kt_free_entry(context, entry);
497 199200 : krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
498 199200 : return ret;
499 : }
500 :
501 : static krb5_error_code KRB5_CALLCONV
502 191267 : fkt_next_entry(krb5_context context,
503 : krb5_keytab id,
504 : krb5_keytab_entry *entry,
505 : krb5_kt_cursor *cursor)
506 : {
507 191267 : return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
508 : }
509 :
510 : static krb5_error_code KRB5_CALLCONV
511 53562 : fkt_end_seq_get(krb5_context context,
512 : krb5_keytab id,
513 : krb5_kt_cursor *cursor)
514 : {
515 53562 : krb5_storage_free(cursor->sp);
516 53562 : close(cursor->fd);
517 53562 : return 0;
518 : }
519 :
520 : static krb5_error_code KRB5_CALLCONV
521 174 : fkt_setup_keytab(krb5_context context,
522 : krb5_keytab id,
523 : krb5_storage *sp)
524 : {
525 22 : krb5_error_code ret;
526 174 : ret = krb5_store_int8(sp, 5);
527 174 : if(ret)
528 0 : return ret;
529 174 : if(id->version == 0)
530 174 : id->version = KRB5_KT_VNO;
531 174 : return krb5_store_int8 (sp, id->version);
532 : }
533 :
534 : static krb5_error_code KRB5_CALLCONV
535 2214 : fkt_add_entry(krb5_context context,
536 : krb5_keytab id,
537 : krb5_keytab_entry *entry)
538 : {
539 231 : int ret;
540 231 : int fd;
541 231 : krb5_storage *sp;
542 231 : krb5_ssize_t bytes;
543 2214 : struct fkt_data *d = id->data;
544 231 : krb5_data keytab;
545 231 : int32_t len;
546 :
547 2214 : fd = open(d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
548 2214 : if (fd < 0) {
549 174 : fd = open(d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
550 174 : if (fd < 0) {
551 0 : ret = errno;
552 0 : krb5_set_error_message(context, ret,
553 0 : N_("open(%s): %s", ""), d->filename,
554 : strerror(ret));
555 0 : return ret;
556 : }
557 174 : rk_cloexec(fd);
558 :
559 174 : ret = _krb5_xlock(context, fd, 1, d->filename);
560 174 : if (ret) {
561 0 : close(fd);
562 0 : return ret;
563 : }
564 174 : sp = krb5_storage_stdio_from_fd(fd, "wb+");
565 174 : if (sp == NULL) {
566 0 : close(fd);
567 0 : return krb5_enomem(context);
568 : }
569 174 : krb5_storage_set_eof_code(sp, KRB5_KT_END);
570 174 : ret = fkt_setup_keytab(context, id, sp);
571 174 : if (ret) {
572 0 : goto out;
573 : }
574 174 : storage_set_flags(context, sp, id->version);
575 : } else {
576 209 : int8_t pvno, tag;
577 :
578 2040 : rk_cloexec(fd);
579 :
580 2040 : ret = _krb5_xlock(context, fd, 1, d->filename);
581 2040 : if (ret) {
582 0 : close(fd);
583 0 : return ret;
584 : }
585 2040 : sp = krb5_storage_stdio_from_fd(fd, "wb+");
586 2040 : if (sp == NULL) {
587 0 : (void) close(fd);
588 0 : return ret;
589 : }
590 2040 : krb5_storage_set_eof_code(sp, KRB5_KT_END);
591 2040 : ret = krb5_ret_int8(sp, &pvno);
592 2040 : if(ret) {
593 : /* we probably have a zero byte file, so try to set it up
594 : properly */
595 0 : ret = fkt_setup_keytab(context, id, sp);
596 0 : if(ret) {
597 0 : krb5_set_error_message(context, ret,
598 0 : N_("%s: keytab is corrupted: %s", ""),
599 : d->filename, strerror(ret));
600 0 : goto out;
601 : }
602 0 : storage_set_flags(context, sp, id->version);
603 : } else {
604 2040 : if(pvno != 5) {
605 0 : ret = KRB5_KEYTAB_BADVNO;
606 0 : krb5_set_error_message(context, ret,
607 0 : N_("Bad version in keytab %s", ""),
608 : d->filename);
609 0 : goto out;
610 : }
611 2040 : ret = krb5_ret_int8 (sp, &tag);
612 2040 : if (ret) {
613 0 : krb5_set_error_message(context, ret,
614 0 : N_("failed reading tag from "
615 : "keytab %s", ""),
616 : d->filename);
617 0 : goto out;
618 : }
619 2040 : id->version = tag;
620 2040 : storage_set_flags(context, sp, id->version);
621 : }
622 : }
623 :
624 : {
625 231 : krb5_storage *emem;
626 2214 : emem = krb5_storage_emem();
627 2214 : if(emem == NULL) {
628 0 : ret = krb5_enomem(context);
629 0 : goto out;
630 : }
631 2214 : ret = krb5_kt_store_principal(context, emem, entry->principal);
632 2214 : if(ret) {
633 0 : krb5_set_error_message(context, ret,
634 0 : N_("Failed storing principal "
635 : "in keytab %s", ""),
636 : d->filename);
637 0 : krb5_storage_free(emem);
638 0 : goto out;
639 : }
640 2214 : ret = krb5_store_int32 (emem, entry->timestamp);
641 2214 : if(ret) {
642 0 : krb5_set_error_message(context, ret,
643 0 : N_("Failed storing timpstamp "
644 : "in keytab %s", ""),
645 : d->filename);
646 0 : krb5_storage_free(emem);
647 0 : goto out;
648 : }
649 2214 : ret = krb5_store_int8 (emem, entry->vno % 256);
650 2214 : if(ret) {
651 0 : krb5_set_error_message(context, ret,
652 0 : N_("Failed storing kvno "
653 : "in keytab %s", ""),
654 : d->filename);
655 0 : krb5_storage_free(emem);
656 0 : goto out;
657 : }
658 2214 : ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock);
659 2214 : if(ret) {
660 0 : krb5_storage_free(emem);
661 0 : goto out;
662 : }
663 2214 : if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
664 2214 : ret = krb5_store_int32 (emem, entry->vno);
665 2214 : if (ret) {
666 0 : krb5_set_error_message(context, ret,
667 0 : N_("Failed storing extended kvno "
668 : "in keytab %s", ""),
669 : d->filename);
670 0 : krb5_storage_free(emem);
671 0 : goto out;
672 : }
673 2214 : ret = krb5_store_uint32 (emem, entry->flags);
674 2214 : if (ret) {
675 0 : krb5_set_error_message(context, ret,
676 0 : N_("Failed storing extended kvno "
677 : "in keytab %s", ""),
678 : d->filename);
679 0 : krb5_storage_free(emem);
680 0 : goto out;
681 : }
682 : }
683 :
684 2214 : ret = krb5_storage_to_data(emem, &keytab);
685 2214 : krb5_storage_free(emem);
686 2214 : if(ret) {
687 0 : krb5_set_error_message(context, ret,
688 0 : N_("Failed converting keytab entry "
689 : "to memory block for keytab %s", ""),
690 : d->filename);
691 0 : goto out;
692 : }
693 : }
694 :
695 14582 : while(1) {
696 1308 : off_t here;
697 :
698 16796 : here = krb5_storage_seek(sp, 0, SEEK_CUR);
699 16796 : if (here == -1) {
700 0 : ret = errno;
701 0 : krb5_set_error_message(context, ret,
702 0 : N_("Failed writing keytab block "
703 : "in keytab %s: %s", ""),
704 : d->filename, strerror(ret));
705 0 : goto out;
706 : }
707 16796 : ret = krb5_ret_int32(sp, &len);
708 16796 : if (ret) {
709 : /* There could have been a partial length. Recover! */
710 1754 : (void) krb5_storage_truncate(sp, here);
711 1754 : len = keytab.length;
712 1754 : break;
713 : }
714 15042 : if(len < 0) {
715 776 : len = -len;
716 776 : if(len >= (int)keytab.length) {
717 460 : krb5_storage_seek(sp, -4, SEEK_CUR);
718 460 : break;
719 : }
720 : }
721 14582 : krb5_storage_seek(sp, len, SEEK_CUR);
722 : }
723 2214 : ret = krb5_store_int32(sp, len);
724 2214 : if (ret != 0)
725 0 : goto out;
726 2214 : bytes = krb5_storage_write(sp, keytab.data, keytab.length);
727 2214 : if (bytes != keytab.length) {
728 0 : ret = bytes == -1 ? errno : KRB5_KT_END;
729 0 : krb5_set_error_message(context, ret,
730 0 : N_("Failed writing keytab block "
731 : "in keytab %s: %s", ""),
732 : d->filename, strerror(ret));
733 : }
734 2214 : memset(keytab.data, 0, keytab.length);
735 2214 : krb5_data_free(&keytab);
736 2214 : out:
737 2214 : if (ret == 0)
738 2214 : ret = krb5_storage_fsync(sp);
739 2214 : krb5_storage_free(sp);
740 2214 : close(fd);
741 2214 : return ret;
742 : }
743 :
744 : static krb5_error_code KRB5_CALLCONV
745 503 : fkt_remove_entry(krb5_context context,
746 : krb5_keytab id,
747 : krb5_keytab_entry *entry)
748 : {
749 503 : struct fkt_data *fkt = id->data;
750 27 : krb5_ssize_t bytes;
751 27 : krb5_keytab_entry e;
752 27 : krb5_kt_cursor cursor;
753 27 : off_t pos_start, pos_end;
754 503 : int found = 0;
755 27 : krb5_error_code ret;
756 :
757 503 : ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor);
758 503 : if (ret != 0) {
759 0 : const char *emsg = krb5_get_error_message(context, ret);
760 :
761 0 : krb5_set_error_message(context, ret,
762 0 : N_("Could not open keytab file for write: %s: %s", ""),
763 : fkt->filename,
764 : emsg);
765 0 : krb5_free_error_message(context, emsg);
766 0 : return ret;
767 : }
768 17459 : while (ret == 0 &&
769 8932 : (ret = fkt_next_entry_int(context, id, &e, &cursor,
770 : &pos_start, &pos_end)) == 0) {
771 8429 : if (krb5_kt_compare(context, &e, entry->principal,
772 8429 : entry->vno, entry->keyblock.keytype)) {
773 27 : int32_t len;
774 27 : unsigned char buf[128];
775 503 : found = 1;
776 503 : krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
777 503 : len = pos_end - pos_start - 4;
778 503 : ret = krb5_store_int32(cursor.sp, -len);
779 503 : memset(buf, 0, sizeof(buf));
780 1032 : while (ret == 0 && len > 0) {
781 529 : bytes = krb5_storage_write(cursor.sp, buf,
782 529 : min((size_t)len, sizeof(buf)));
783 529 : if (bytes != min((size_t)len, sizeof(buf))) {
784 0 : ret = bytes == -1 ? errno : KRB5_KT_END;
785 0 : break;
786 : }
787 556 : len -= min((size_t)len, sizeof(buf));
788 : }
789 : }
790 8429 : krb5_kt_free_entry(context, &e);
791 : }
792 503 : (void) krb5_kt_end_seq_get(context, id, &cursor);
793 503 : if (ret == KRB5_KT_END)
794 476 : ret = 0;
795 476 : if (ret) {
796 0 : const char *emsg = krb5_get_error_message(context, ret);
797 :
798 0 : krb5_set_error_message(context, ret,
799 0 : N_("Could not remove keytab entry from %s: %s", ""),
800 : fkt->filename,
801 : emsg);
802 0 : krb5_free_error_message(context, emsg);
803 503 : } else if (!found) {
804 0 : krb5_clear_error_message(context);
805 0 : return KRB5_KT_NOTFOUND;
806 : }
807 476 : return ret;
808 : }
809 :
810 : const krb5_kt_ops krb5_fkt_ops = {
811 : "FILE",
812 : fkt_resolve,
813 : fkt_get_name,
814 : fkt_close,
815 : fkt_destroy,
816 : NULL, /* get */
817 : fkt_start_seq_get,
818 : fkt_next_entry,
819 : fkt_end_seq_get,
820 : fkt_add_entry,
821 : fkt_remove_entry,
822 : NULL,
823 : 0
824 : };
825 :
826 : const krb5_kt_ops krb5_wrfkt_ops = {
827 : "WRFILE",
828 : fkt_resolve,
829 : fkt_get_name,
830 : fkt_close,
831 : fkt_destroy,
832 : NULL, /* get */
833 : fkt_start_seq_get,
834 : fkt_next_entry,
835 : fkt_end_seq_get,
836 : fkt_add_entry,
837 : fkt_remove_entry,
838 : NULL,
839 : 0
840 : };
841 :
842 : const krb5_kt_ops krb5_javakt_ops = {
843 : "JAVA14",
844 : fkt_resolve_java14,
845 : fkt_get_name,
846 : fkt_close,
847 : fkt_destroy,
848 : NULL, /* get */
849 : fkt_start_seq_get,
850 : fkt_next_entry,
851 : fkt_end_seq_get,
852 : fkt_add_entry,
853 : fkt_remove_entry,
854 : NULL,
855 : 0
856 : };
|