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 212297 : krb5_kt_ret_data(krb5_context context,
52 : krb5_storage *sp,
53 : krb5_data *data)
54 : {
55 4404 : krb5_error_code ret;
56 4404 : krb5_ssize_t bytes;
57 4404 : int16_t size;
58 :
59 212297 : ret = krb5_ret_int16(sp, &size);
60 212297 : if(ret)
61 0 : return ret;
62 212297 : data->length = size;
63 212297 : data->data = malloc(size);
64 212297 : if (data->data == NULL)
65 0 : return krb5_enomem(context);
66 212297 : bytes = krb5_storage_read(sp, data->data, size);
67 212297 : if (bytes != size)
68 0 : return (bytes == -1) ? errno : KRB5_KT_END;
69 207893 : return 0;
70 : }
71 :
72 : static krb5_error_code
73 567542 : krb5_kt_ret_string(krb5_context context,
74 : krb5_storage *sp,
75 : heim_general_string *data)
76 : {
77 11809 : krb5_error_code ret;
78 11809 : krb5_ssize_t bytes;
79 11809 : int16_t size;
80 :
81 567542 : ret = krb5_ret_int16(sp, &size);
82 567542 : if(ret)
83 0 : return ret;
84 567542 : *data = malloc(size + 1);
85 567542 : if (*data == NULL)
86 0 : return krb5_enomem(context);
87 567542 : bytes = krb5_storage_read(sp, *data, size);
88 567542 : (*data)[size] = '\0';
89 567542 : if (bytes != size)
90 0 : return (bytes == -1) ? errno : KRB5_KT_END;
91 555733 : return 0;
92 : }
93 :
94 : static krb5_error_code
95 2282 : 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 2282 : ret = krb5_store_int16(sp, data.length);
103 2282 : if (ret != 0)
104 0 : return ret;
105 2282 : bytes = krb5_storage_write(sp, data.data, data.length);
106 2282 : if (bytes != (int)data.length)
107 0 : return bytes == -1 ? errno : KRB5_KT_END;
108 2051 : return 0;
109 : }
110 :
111 : static krb5_error_code
112 6043 : 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 6043 : size_t len = strlen(data);
118 :
119 6043 : ret = krb5_store_int16(sp, len);
120 6043 : if (ret != 0)
121 0 : return ret;
122 6043 : bytes = krb5_storage_write(sp, data, len);
123 6043 : if (bytes != (int)len)
124 0 : return bytes == -1 ? errno : KRB5_KT_END;
125 5428 : return 0;
126 : }
127 :
128 : static krb5_error_code
129 212297 : krb5_kt_ret_keyblock(krb5_context context,
130 : struct fkt_data *fkt,
131 : krb5_storage *sp,
132 : krb5_keyblock *p)
133 : {
134 4404 : int ret;
135 4404 : int16_t tmp;
136 :
137 212297 : ret = krb5_ret_int16(sp, &tmp); /* keytype + etype */
138 212297 : 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 212297 : p->keytype = tmp;
145 212297 : ret = krb5_kt_ret_data(context, sp, &p->keyvalue);
146 212297 : if (ret)
147 0 : krb5_set_error_message(context, ret,
148 0 : N_("Cant read keyblock from file %s", ""),
149 : fkt->filename);
150 207893 : return ret;
151 : }
152 :
153 : static krb5_error_code
154 2282 : 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 2282 : ret = krb5_store_int16(sp, p->keytype); /* keytype + etype */
162 2282 : 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 2282 : ret = krb5_kt_store_data(context, sp, p->keyvalue);
169 2282 : if (ret)
170 0 : krb5_set_error_message(context, ret,
171 0 : N_("Cant store keyblock to file %s", ""),
172 : fkt->filename);
173 2051 : return ret;
174 : }
175 :
176 :
177 : static krb5_error_code
178 212297 : krb5_kt_ret_principal(krb5_context context,
179 : struct fkt_data *fkt,
180 : krb5_storage *sp,
181 : krb5_principal *princ)
182 : {
183 4404 : size_t i;
184 4404 : int ret;
185 4404 : krb5_principal p;
186 4404 : int16_t len;
187 :
188 212297 : ALLOC(p, 1);
189 212297 : if(p == NULL)
190 0 : return krb5_enomem(context);
191 :
192 212297 : ret = krb5_ret_int16(sp, &len);
193 212297 : 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 212297 : if(krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS))
201 0 : len--;
202 212297 : 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 212297 : ret = krb5_kt_ret_string(context, sp, &p->realm);
211 212297 : 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 212297 : p->name.name_string.val = calloc(len, sizeof(*p->name.name_string.val));
218 212297 : if(p->name.name_string.val == NULL) {
219 0 : ret = krb5_enomem(context);
220 0 : goto out;
221 : }
222 212297 : p->name.name_string.len = len;
223 567542 : for(i = 0; i < p->name.name_string.len; i++){
224 355245 : ret = krb5_kt_ret_string(context, sp, p->name.name_string.val + i);
225 355245 : 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 212297 : if (krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE))
234 0 : p->name.name_type = KRB5_NT_UNKNOWN;
235 : else {
236 4404 : int32_t tmp32;
237 212297 : ret = krb5_ret_int32(sp, &tmp32);
238 212297 : p->name.name_type = tmp32;
239 212297 : 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 212297 : *princ = p;
248 212297 : return 0;
249 0 : out:
250 0 : krb5_free_principal(context, p);
251 0 : return ret;
252 : }
253 :
254 : static krb5_error_code
255 2282 : 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 2282 : 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 2282 : ret = krb5_store_int16(sp, p->name.name_string.len);
266 2282 : if(ret) return ret;
267 2282 : ret = krb5_kt_store_string(sp, p->realm);
268 2282 : if(ret) return ret;
269 6043 : for(i = 0; i < p->name.name_string.len; i++){
270 3761 : ret = krb5_kt_store_string(sp, p->name.name_string.val[i]);
271 3761 : if(ret)
272 0 : return ret;
273 : }
274 2282 : if(!krb5_storage_is_flags(sp, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE)) {
275 2282 : ret = krb5_store_int32(sp, p->name.name_type);
276 2282 : if(ret)
277 0 : return ret;
278 : }
279 :
280 2051 : return 0;
281 : }
282 :
283 : static krb5_error_code KRB5_CALLCONV
284 221245 : fkt_resolve(krb5_context context, const char *name, krb5_keytab id)
285 : {
286 6998 : struct fkt_data *d;
287 :
288 221245 : d = malloc(sizeof(*d));
289 221245 : if(d == NULL)
290 0 : return krb5_enomem(context);
291 221245 : d->filename = strdup(name);
292 221245 : if(d->filename == NULL) {
293 0 : free(d);
294 0 : return krb5_enomem(context);
295 : }
296 221245 : d->flags = 0;
297 221245 : id->data = d;
298 221245 : 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 221201 : fkt_close(krb5_context context, krb5_keytab id)
316 : {
317 221201 : struct fkt_data *d = id->data;
318 221201 : free(d->filename);
319 221201 : free(d);
320 221201 : 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 123169 : fkt_get_name(krb5_context context,
333 : krb5_keytab id,
334 : char *name,
335 : size_t namesize)
336 : {
337 : /* This function is XXX */
338 123169 : struct fkt_data *d = id->data;
339 123169 : strlcpy(name, d->filename, namesize);
340 123169 : return 0;
341 : }
342 :
343 : static void
344 58104 : storage_set_flags(krb5_context context, krb5_storage *sp, int vno)
345 : {
346 58104 : int flags = 0;
347 58104 : 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 56725 : case KRB5_KT_VNO_2:
354 56725 : break;
355 0 : default:
356 0 : krb5_warnx(context,
357 : "storage_set_flags called with bad vno (%d)", vno);
358 : }
359 58104 : krb5_storage_set_flags(sp, flags);
360 58104 : }
361 :
362 : static krb5_error_code
363 56181 : 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 1192 : int8_t pvno, tag;
370 1192 : krb5_error_code ret;
371 56181 : struct fkt_data *d = id->data;
372 56181 : const char *stdio_mode = "rb";
373 :
374 56181 : memset(c, 0, sizeof(*c));
375 56181 : c->fd = open (d->filename, flags);
376 56181 : if (c->fd < 0) {
377 359 : ret = errno;
378 359 : krb5_set_error_message(context, ret,
379 359 : N_("keytab %s open failed: %s", ""),
380 : d->filename, strerror(ret));
381 359 : return ret;
382 : }
383 55822 : rk_cloexec(c->fd);
384 55822 : ret = _krb5_xlock(context, c->fd, exclusive, d->filename);
385 55822 : if (ret) {
386 0 : close(c->fd);
387 0 : return ret;
388 : }
389 55822 : if ((flags & O_ACCMODE) == O_RDWR && (flags & O_APPEND))
390 0 : stdio_mode = "ab+";
391 55822 : else if ((flags & O_ACCMODE) == O_RDWR)
392 482 : stdio_mode = "rb+";
393 55313 : else if ((flags & O_ACCMODE) == O_WRONLY)
394 0 : stdio_mode = "wb";
395 55822 : c->sp = krb5_storage_stdio_from_fd(c->fd, stdio_mode);
396 55822 : if (c->sp == NULL) {
397 0 : close(c->fd);
398 0 : return krb5_enomem(context);
399 : }
400 55822 : krb5_storage_set_eof_code(c->sp, KRB5_KT_END);
401 55822 : ret = krb5_ret_int8(c->sp, &pvno);
402 55822 : 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 55822 : 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 55822 : ret = krb5_ret_int8(c->sp, &tag);
415 55822 : 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 55822 : id->version = tag;
422 55822 : storage_set_flags(context, c->sp, id->version);
423 55822 : return 0;
424 : }
425 :
426 : static krb5_error_code KRB5_CALLCONV
427 55672 : fkt_start_seq_get(krb5_context context,
428 : krb5_keytab id,
429 : krb5_kt_cursor *c)
430 : {
431 55672 : return fkt_start_seq_get_int(context, id, O_RDONLY | O_BINARY | O_CLOEXEC, 0, c);
432 : }
433 :
434 : static krb5_error_code
435 215053 : 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 215053 : struct fkt_data *d = id->data;
443 4644 : int32_t len;
444 4644 : int ret;
445 4644 : int8_t tmp8;
446 4644 : int32_t tmp32;
447 4644 : uint32_t utmp32;
448 4644 : off_t pos, curpos;
449 :
450 215053 : pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
451 220522 : loop:
452 220522 : ret = krb5_ret_int32(cursor->sp, &len);
453 220522 : if (ret)
454 2756 : return ret;
455 217766 : if(len < 0) {
456 5469 : pos = krb5_storage_seek(cursor->sp, -len, SEEK_CUR);
457 5469 : goto loop;
458 : }
459 212297 : ret = krb5_kt_ret_principal (context, d, cursor->sp, &entry->principal);
460 212297 : if (ret)
461 0 : goto out;
462 212297 : ret = krb5_ret_uint32(cursor->sp, &utmp32);
463 212297 : entry->timestamp = utmp32;
464 212297 : if (ret)
465 0 : goto out;
466 212297 : ret = krb5_ret_int8(cursor->sp, &tmp8);
467 212297 : if (ret)
468 0 : goto out;
469 212297 : entry->vno = tmp8;
470 212297 : ret = krb5_kt_ret_keyblock (context, d, cursor->sp, &entry->keyblock);
471 212297 : 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 212297 : curpos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
477 212297 : if(len + 4 + pos - curpos >= 4) {
478 212297 : ret = krb5_ret_int32(cursor->sp, &tmp32);
479 212297 : if (ret == 0 && tmp32 != 0)
480 212297 : entry->vno = tmp32;
481 : }
482 : /* there might be a flags field here */
483 212297 : if(len + 4 + pos - curpos >= 8) {
484 212297 : ret = krb5_ret_uint32(cursor->sp, &utmp32);
485 212297 : if (ret == 0)
486 212297 : entry->flags = utmp32;
487 : } else
488 0 : entry->flags = 0;
489 :
490 212297 : entry->aliases = NULL;
491 :
492 212297 : if(start) *start = pos;
493 212297 : if(end) *end = pos + 4 + len;
494 203859 : out:
495 212297 : if (ret)
496 0 : krb5_kt_free_entry(context, entry);
497 212297 : krb5_storage_seek(cursor->sp, pos + 4 + len, SEEK_SET);
498 212297 : return ret;
499 : }
500 :
501 : static krb5_error_code KRB5_CALLCONV
502 206106 : fkt_next_entry(krb5_context context,
503 : krb5_keytab id,
504 : krb5_keytab_entry *entry,
505 : krb5_kt_cursor *cursor)
506 : {
507 206106 : return fkt_next_entry_int(context, id, entry, cursor, NULL, NULL);
508 : }
509 :
510 : static krb5_error_code KRB5_CALLCONV
511 55822 : fkt_end_seq_get(krb5_context context,
512 : krb5_keytab id,
513 : krb5_kt_cursor *cursor)
514 : {
515 55822 : krb5_storage_free(cursor->sp);
516 55822 : close(cursor->fd);
517 55822 : return 0;
518 : }
519 :
520 : static krb5_error_code KRB5_CALLCONV
521 182 : fkt_setup_keytab(krb5_context context,
522 : krb5_keytab id,
523 : krb5_storage *sp)
524 : {
525 22 : krb5_error_code ret;
526 182 : ret = krb5_store_int8(sp, 5);
527 182 : if(ret)
528 0 : return ret;
529 182 : if(id->version == 0)
530 182 : id->version = KRB5_KT_VNO;
531 182 : return krb5_store_int8 (sp, id->version);
532 : }
533 :
534 : static krb5_error_code KRB5_CALLCONV
535 2282 : 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 2282 : struct fkt_data *d = id->data;
544 231 : krb5_data keytab;
545 231 : int32_t len;
546 :
547 2282 : fd = open(d->filename, O_RDWR | O_BINARY | O_CLOEXEC);
548 2282 : if (fd < 0) {
549 182 : fd = open(d->filename, O_RDWR | O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC, 0600);
550 182 : 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 182 : rk_cloexec(fd);
558 :
559 182 : ret = _krb5_xlock(context, fd, 1, d->filename);
560 182 : if (ret) {
561 0 : close(fd);
562 0 : return ret;
563 : }
564 182 : sp = krb5_storage_stdio_from_fd(fd, "wb+");
565 182 : if (sp == NULL) {
566 0 : close(fd);
567 0 : return krb5_enomem(context);
568 : }
569 182 : krb5_storage_set_eof_code(sp, KRB5_KT_END);
570 182 : ret = fkt_setup_keytab(context, id, sp);
571 182 : if (ret) {
572 0 : goto out;
573 : }
574 182 : storage_set_flags(context, sp, id->version);
575 : } else {
576 209 : int8_t pvno, tag;
577 :
578 2100 : rk_cloexec(fd);
579 :
580 2100 : ret = _krb5_xlock(context, fd, 1, d->filename);
581 2100 : if (ret) {
582 0 : close(fd);
583 0 : return ret;
584 : }
585 2100 : sp = krb5_storage_stdio_from_fd(fd, "wb+");
586 2100 : if (sp == NULL) {
587 0 : (void) close(fd);
588 0 : return ret;
589 : }
590 2100 : krb5_storage_set_eof_code(sp, KRB5_KT_END);
591 2100 : ret = krb5_ret_int8(sp, &pvno);
592 2100 : 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 2100 : 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 2100 : ret = krb5_ret_int8 (sp, &tag);
612 2100 : 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 2100 : id->version = tag;
620 2100 : storage_set_flags(context, sp, id->version);
621 : }
622 : }
623 :
624 : {
625 231 : krb5_storage *emem;
626 2282 : emem = krb5_storage_emem();
627 2282 : if(emem == NULL) {
628 0 : ret = krb5_enomem(context);
629 0 : goto out;
630 : }
631 2282 : ret = krb5_kt_store_principal(context, emem, entry->principal);
632 2282 : 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 2282 : ret = krb5_store_int32 (emem, entry->timestamp);
641 2282 : 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 2282 : ret = krb5_store_int8 (emem, entry->vno % 256);
650 2282 : 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 2282 : ret = krb5_kt_store_keyblock (context, d, emem, &entry->keyblock);
659 2282 : if(ret) {
660 0 : krb5_storage_free(emem);
661 0 : goto out;
662 : }
663 2282 : if ((d->flags & KRB5_KT_FL_JAVA) == 0) {
664 2282 : ret = krb5_store_int32 (emem, entry->vno);
665 2282 : 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 2282 : ret = krb5_store_uint32 (emem, entry->flags);
674 2282 : 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 2282 : ret = krb5_storage_to_data(emem, &keytab);
685 2282 : krb5_storage_free(emem);
686 2282 : 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 15128 : while(1) {
696 1308 : off_t here;
697 :
698 17410 : here = krb5_storage_seek(sp, 0, SEEK_CUR);
699 17410 : 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 17410 : ret = krb5_ret_int32(sp, &len);
708 17410 : if (ret) {
709 : /* There could have been a partial length. Recover! */
710 1816 : (void) krb5_storage_truncate(sp, here);
711 1816 : len = keytab.length;
712 1816 : break;
713 : }
714 15594 : if(len < 0) {
715 782 : len = -len;
716 782 : if(len >= (int)keytab.length) {
717 466 : krb5_storage_seek(sp, -4, SEEK_CUR);
718 466 : break;
719 : }
720 : }
721 15128 : krb5_storage_seek(sp, len, SEEK_CUR);
722 : }
723 2282 : ret = krb5_store_int32(sp, len);
724 2282 : if (ret != 0)
725 0 : goto out;
726 2282 : bytes = krb5_storage_write(sp, keytab.data, keytab.length);
727 2282 : 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 2282 : memset(keytab.data, 0, keytab.length);
735 2282 : krb5_data_free(&keytab);
736 2282 : out:
737 2282 : if (ret == 0)
738 2282 : ret = krb5_storage_fsync(sp);
739 2282 : krb5_storage_free(sp);
740 2282 : close(fd);
741 2282 : return ret;
742 : }
743 :
744 : static krb5_error_code KRB5_CALLCONV
745 509 : fkt_remove_entry(krb5_context context,
746 : krb5_keytab id,
747 : krb5_keytab_entry *entry)
748 : {
749 509 : 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 509 : int found = 0;
755 27 : krb5_error_code ret;
756 :
757 509 : ret = fkt_start_seq_get_int(context, id, O_RDWR | O_BINARY | O_CLOEXEC, 1, &cursor);
758 509 : 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 17489 : while (ret == 0 &&
769 8947 : (ret = fkt_next_entry_int(context, id, &e, &cursor,
770 : &pos_start, &pos_end)) == 0) {
771 8438 : if (krb5_kt_compare(context, &e, entry->principal,
772 8438 : entry->vno, entry->keyblock.keytype)) {
773 27 : int32_t len;
774 27 : unsigned char buf[128];
775 509 : found = 1;
776 509 : krb5_storage_seek(cursor.sp, pos_start, SEEK_SET);
777 509 : len = pos_end - pos_start - 4;
778 509 : ret = krb5_store_int32(cursor.sp, -len);
779 509 : memset(buf, 0, sizeof(buf));
780 1044 : while (ret == 0 && len > 0) {
781 535 : bytes = krb5_storage_write(cursor.sp, buf,
782 535 : min((size_t)len, sizeof(buf)));
783 535 : if (bytes != min((size_t)len, sizeof(buf))) {
784 0 : ret = bytes == -1 ? errno : KRB5_KT_END;
785 0 : break;
786 : }
787 562 : len -= min((size_t)len, sizeof(buf));
788 : }
789 : }
790 8438 : krb5_kt_free_entry(context, &e);
791 : }
792 509 : (void) krb5_kt_end_seq_get(context, id, &cursor);
793 509 : if (ret == KRB5_KT_END)
794 482 : ret = 0;
795 482 : 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 509 : } else if (!found) {
804 0 : krb5_clear_error_message(context);
805 0 : return KRB5_KT_NOTFOUND;
806 : }
807 482 : 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 : };
|