2 * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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. 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.
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
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: keytab_file.c 17457 2006-05-05 12:36:57Z lha $"
39 #define KRB5_KT_VNO_1 1
40 #define KRB5_KT_VNO_2 2
41 #define KRB5_KT_VNO KRB5_KT_VNO_2
43 #define KRB5_KT_FL_JAVA 1
46 /* file operations -------------------------------------------- */
53 static krb5_error_code
54 krb5_kt_ret_data(krb5_context context
,
60 ret
= krb5_ret_int16(sp
, &size
);
64 data
->data
= malloc(size
);
65 if (data
->data
== NULL
) {
66 krb5_set_error_string (context
, "malloc: out of memory");
69 ret
= krb5_storage_read(sp
, data
->data
, size
);
71 return (ret
< 0)? errno
: KRB5_KT_END
;
75 static krb5_error_code
76 krb5_kt_ret_string(krb5_context context
,
78 heim_general_string
*data
)
82 ret
= krb5_ret_int16(sp
, &size
);
85 *data
= malloc(size
+ 1);
87 krb5_set_error_string (context
, "malloc: out of memory");
90 ret
= krb5_storage_read(sp
, *data
, size
);
93 return (ret
< 0)? errno
: KRB5_KT_END
;
97 static krb5_error_code
98 krb5_kt_store_data(krb5_context context
,
103 ret
= krb5_store_int16(sp
, data
.length
);
106 ret
= krb5_storage_write(sp
, data
.data
, data
.length
);
107 if(ret
!= data
.length
){
115 static krb5_error_code
116 krb5_kt_store_string(krb5_storage
*sp
,
117 heim_general_string data
)
120 size_t len
= strlen(data
);
121 ret
= krb5_store_int16(sp
, len
);
124 ret
= krb5_storage_write(sp
, data
, len
);
133 static krb5_error_code
134 krb5_kt_ret_keyblock(krb5_context context
, krb5_storage
*sp
, krb5_keyblock
*p
)
139 ret
= krb5_ret_int16(sp
, &tmp
); /* keytype + etype */
142 ret
= krb5_kt_ret_data(context
, sp
, &p
->keyvalue
);
146 static krb5_error_code
147 krb5_kt_store_keyblock(krb5_context context
,
153 ret
= krb5_store_int16(sp
, p
->keytype
); /* keytype + etype */
155 ret
= krb5_kt_store_data(context
, sp
, p
->keyvalue
);
160 static krb5_error_code
161 krb5_kt_ret_principal(krb5_context context
,
163 krb5_principal
*princ
)
172 krb5_set_error_string (context
, "malloc: out of memory");
176 ret
= krb5_ret_int16(sp
, &len
);
178 krb5_set_error_string(context
,
179 "Failed decoding length of keytab principal");
182 if(krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS
))
185 krb5_set_error_string(context
,
186 "Keytab principal contains invalid length");
190 ret
= krb5_kt_ret_string(context
, sp
, &p
->realm
);
193 p
->name
.name_string
.val
= calloc(len
, sizeof(*p
->name
.name_string
.val
));
194 if(p
->name
.name_string
.val
== NULL
) {
195 krb5_set_error_string (context
, "malloc: out of memory");
199 p
->name
.name_string
.len
= len
;
200 for(i
= 0; i
< p
->name
.name_string
.len
; i
++){
201 ret
= krb5_kt_ret_string(context
, sp
, p
->name
.name_string
.val
+ i
);
205 if (krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE
))
206 p
->name
.name_type
= KRB5_NT_UNKNOWN
;
209 ret
= krb5_ret_int32(sp
, &tmp32
);
210 p
->name
.name_type
= tmp32
;
217 krb5_free_principal(context
, p
);
221 static krb5_error_code
222 krb5_kt_store_principal(krb5_context context
,
229 if(krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS
))
230 ret
= krb5_store_int16(sp
, p
->name
.name_string
.len
+ 1);
232 ret
= krb5_store_int16(sp
, p
->name
.name_string
.len
);
234 ret
= krb5_kt_store_string(sp
, p
->realm
);
236 for(i
= 0; i
< p
->name
.name_string
.len
; i
++){
237 ret
= krb5_kt_store_string(sp
, p
->name
.name_string
.val
[i
]);
241 if(!krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE
)) {
242 ret
= krb5_store_int32(sp
, p
->name
.name_type
);
250 static krb5_error_code
251 fkt_resolve(krb5_context context
, const char *name
, krb5_keytab id
)
255 d
= malloc(sizeof(*d
));
257 krb5_set_error_string (context
, "malloc: out of memory");
260 d
->filename
= strdup(name
);
261 if(d
->filename
== NULL
) {
263 krb5_set_error_string (context
, "malloc: out of memory");
271 static krb5_error_code
272 fkt_resolve_java14(krb5_context context
, const char *name
, krb5_keytab id
)
276 ret
= fkt_resolve(context
, name
, id
);
278 struct fkt_data
*d
= id
->data
;
279 d
->flags
|= KRB5_KT_FL_JAVA
;
284 static krb5_error_code
285 fkt_close(krb5_context context
, krb5_keytab id
)
287 struct fkt_data
*d
= id
->data
;
293 static krb5_error_code
294 fkt_get_name(krb5_context context
,
299 /* This function is XXX */
300 struct fkt_data
*d
= id
->data
;
301 strlcpy(name
, d
->filename
, namesize
);
306 storage_set_flags(krb5_context context
, krb5_storage
*sp
, int vno
)
311 flags
|= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS
;
312 flags
|= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE
;
313 flags
|= KRB5_STORAGE_HOST_BYTEORDER
;
319 "storage_set_flags called with bad vno (%d)", vno
);
321 krb5_storage_set_flags(sp
, flags
);
324 static krb5_error_code
325 fkt_start_seq_get_int(krb5_context context
,
333 struct fkt_data
*d
= id
->data
;
335 c
->fd
= open (d
->filename
, flags
);
338 krb5_set_error_string(context
, "%s: %s", d
->filename
,
342 ret
= _krb5_xlock(context
, c
->fd
, exclusive
, d
->filename
);
347 c
->sp
= krb5_storage_from_fd(c
->fd
);
349 _krb5_xunlock(context
, c
->fd
);
351 krb5_set_error_string (context
, "malloc: out of memory");
354 krb5_storage_set_eof_code(c
->sp
, KRB5_KT_END
);
355 ret
= krb5_ret_int8(c
->sp
, &pvno
);
357 krb5_storage_free(c
->sp
);
358 _krb5_xunlock(context
, c
->fd
);
360 krb5_clear_error_string(context
);
364 krb5_storage_free(c
->sp
);
365 _krb5_xunlock(context
, c
->fd
);
367 krb5_clear_error_string (context
);
368 return KRB5_KEYTAB_BADVNO
;
370 ret
= krb5_ret_int8(c
->sp
, &tag
);
372 krb5_storage_free(c
->sp
);
373 _krb5_xunlock(context
, c
->fd
);
375 krb5_clear_error_string(context
);
379 storage_set_flags(context
, c
->sp
, id
->version
);
383 static krb5_error_code
384 fkt_start_seq_get(krb5_context context
,
388 return fkt_start_seq_get_int(context
, id
, O_RDONLY
| O_BINARY
, 0, c
);
391 static krb5_error_code
392 fkt_next_entry_int(krb5_context context
,
394 krb5_keytab_entry
*entry
,
395 krb5_kt_cursor
*cursor
,
405 pos
= krb5_storage_seek(cursor
->sp
, 0, SEEK_CUR
);
407 ret
= krb5_ret_int32(cursor
->sp
, &len
);
411 pos
= krb5_storage_seek(cursor
->sp
, -len
, SEEK_CUR
);
414 ret
= krb5_kt_ret_principal (context
, cursor
->sp
, &entry
->principal
);
417 ret
= krb5_ret_int32(cursor
->sp
, &tmp32
);
418 entry
->timestamp
= tmp32
;
421 ret
= krb5_ret_int8(cursor
->sp
, &tmp8
);
425 ret
= krb5_kt_ret_keyblock (context
, cursor
->sp
, &entry
->keyblock
);
428 /* there might be a 32 bit kvno here
429 * if it's zero, assume that the 8bit one was right,
430 * otherwise trust the new value */
431 curpos
= krb5_storage_seek(cursor
->sp
, 0, SEEK_CUR
);
432 if(len
+ 4 + pos
- curpos
>= 4) {
433 ret
= krb5_ret_int32(cursor
->sp
, &tmp32
);
434 if (ret
== 0 && tmp32
!= 0) {
438 if(start
) *start
= pos
;
439 if(end
) *end
= pos
+ 4 + len
;
441 krb5_storage_seek(cursor
->sp
, pos
+ 4 + len
, SEEK_SET
);
445 static krb5_error_code
446 fkt_next_entry(krb5_context context
,
448 krb5_keytab_entry
*entry
,
449 krb5_kt_cursor
*cursor
)
451 return fkt_next_entry_int(context
, id
, entry
, cursor
, NULL
, NULL
);
454 static krb5_error_code
455 fkt_end_seq_get(krb5_context context
,
457 krb5_kt_cursor
*cursor
)
459 krb5_storage_free(cursor
->sp
);
460 _krb5_xunlock(context
, cursor
->fd
);
465 static krb5_error_code
466 fkt_setup_keytab(krb5_context context
,
471 ret
= krb5_store_int8(sp
, 5);
475 id
->version
= KRB5_KT_VNO
;
476 return krb5_store_int8 (sp
, id
->version
);
479 static krb5_error_code
480 fkt_add_entry(krb5_context context
,
482 krb5_keytab_entry
*entry
)
487 struct fkt_data
*d
= id
->data
;
491 fd
= open (d
->filename
, O_RDWR
| O_BINARY
);
493 fd
= open (d
->filename
, O_RDWR
| O_CREAT
| O_EXCL
| O_BINARY
, 0600);
496 krb5_set_error_string(context
, "open(%s): %s", d
->filename
,
500 ret
= _krb5_xlock(context
, fd
, 1, d
->filename
);
505 sp
= krb5_storage_from_fd(fd
);
506 krb5_storage_set_eof_code(sp
, KRB5_KT_END
);
507 ret
= fkt_setup_keytab(context
, id
, sp
);
511 storage_set_flags(context
, sp
, id
->version
);
514 ret
= _krb5_xlock(context
, fd
, 1, d
->filename
);
519 sp
= krb5_storage_from_fd(fd
);
520 krb5_storage_set_eof_code(sp
, KRB5_KT_END
);
521 ret
= krb5_ret_int8(sp
, &pvno
);
523 /* we probably have a zero byte file, so try to set it up
525 ret
= fkt_setup_keytab(context
, id
, sp
);
527 krb5_set_error_string(context
, "%s: keytab is corrupted: %s",
528 d
->filename
, strerror(ret
));
531 storage_set_flags(context
, sp
, id
->version
);
534 ret
= KRB5_KEYTAB_BADVNO
;
535 krb5_set_error_string(context
, "%s: %s",
536 d
->filename
, strerror(ret
));
539 ret
= krb5_ret_int8 (sp
, &tag
);
541 krb5_set_error_string(context
, "%s: reading tag: %s",
542 d
->filename
, strerror(ret
));
546 storage_set_flags(context
, sp
, id
->version
);
552 emem
= krb5_storage_emem();
555 krb5_set_error_string (context
, "malloc: out of memory");
558 ret
= krb5_kt_store_principal(context
, emem
, entry
->principal
);
560 krb5_storage_free(emem
);
563 ret
= krb5_store_int32 (emem
, entry
->timestamp
);
565 krb5_storage_free(emem
);
568 ret
= krb5_store_int8 (emem
, entry
->vno
% 256);
570 krb5_storage_free(emem
);
573 ret
= krb5_kt_store_keyblock (context
, emem
, &entry
->keyblock
);
575 krb5_storage_free(emem
);
578 if ((d
->flags
& KRB5_KT_FL_JAVA
) == 0) {
579 ret
= krb5_store_int32 (emem
, entry
->vno
);
581 krb5_storage_free(emem
);
586 ret
= krb5_storage_to_data(emem
, &keytab
);
587 krb5_storage_free(emem
);
593 ret
= krb5_ret_int32(sp
, &len
);
594 if(ret
== KRB5_KT_END
) {
600 if(len
>= keytab
.length
) {
601 krb5_storage_seek(sp
, -4, SEEK_CUR
);
605 krb5_storage_seek(sp
, len
, SEEK_CUR
);
607 ret
= krb5_store_int32(sp
, len
);
608 if(krb5_storage_write(sp
, keytab
.data
, keytab
.length
) < 0)
610 memset(keytab
.data
, 0, keytab
.length
);
611 krb5_data_free(&keytab
);
613 krb5_storage_free(sp
);
614 _krb5_xunlock(context
, fd
);
619 static krb5_error_code
620 fkt_remove_entry(krb5_context context
,
622 krb5_keytab_entry
*entry
)
625 krb5_kt_cursor cursor
;
626 off_t pos_start
, pos_end
;
630 ret
= fkt_start_seq_get_int(context
, id
, O_RDWR
| O_BINARY
, 1, &cursor
);
632 goto out
; /* return other error here? */
633 while(fkt_next_entry_int(context
, id
, &e
, &cursor
,
634 &pos_start
, &pos_end
) == 0) {
635 if(krb5_kt_compare(context
, &e
, entry
->principal
,
636 entry
->vno
, entry
->keyblock
.keytype
)) {
638 unsigned char buf
[128];
640 krb5_storage_seek(cursor
.sp
, pos_start
, SEEK_SET
);
641 len
= pos_end
- pos_start
- 4;
642 krb5_store_int32(cursor
.sp
, -len
);
643 memset(buf
, 0, sizeof(buf
));
645 krb5_storage_write(cursor
.sp
, buf
, min(len
, sizeof(buf
)));
646 len
-= min(len
, sizeof(buf
));
649 krb5_kt_free_entry(context
, &e
);
651 krb5_kt_end_seq_get(context
, id
, &cursor
);
654 krb5_clear_error_string (context
);
655 return KRB5_KT_NOTFOUND
;
660 const krb5_kt_ops krb5_fkt_ops
= {
673 const krb5_kt_ops krb5_wrfkt_ops
= {
686 const krb5_kt_ops krb5_javakt_ops
= {