2 * Copyright (c) 1997 - 2002 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"
38 #define KRB5_KT_VNO_1 1
39 #define KRB5_KT_VNO_2 2
40 #define KRB5_KT_VNO KRB5_KT_VNO_2
42 /* file operations -------------------------------------------- */
48 static krb5_error_code
49 krb5_kt_ret_data(krb5_context context
,
55 ret
= krb5_ret_int16(sp
, &size
);
59 data
->data
= malloc(size
);
60 if (data
->data
== NULL
) {
61 krb5_set_error_string (context
, "malloc: out of memory");
64 ret
= krb5_storage_read(sp
, data
->data
, size
);
66 return (ret
< 0)? errno
: KRB5_KT_END
;
70 static krb5_error_code
71 krb5_kt_ret_string(krb5_context context
,
77 ret
= krb5_ret_int16(sp
, &size
);
80 *data
= malloc(size
+ 1);
82 krb5_set_error_string (context
, "malloc: out of memory");
85 ret
= krb5_storage_read(sp
, *data
, size
);
88 return (ret
< 0)? errno
: KRB5_KT_END
;
92 static krb5_error_code
93 krb5_kt_store_data(krb5_context context
,
98 ret
= krb5_store_int16(sp
, data
.length
);
101 ret
= krb5_storage_write(sp
, data
.data
, data
.length
);
102 if(ret
!= data
.length
){
110 static krb5_error_code
111 krb5_kt_store_string(krb5_storage
*sp
,
115 size_t len
= strlen(data
);
116 ret
= krb5_store_int16(sp
, len
);
119 ret
= krb5_storage_write(sp
, data
, len
);
128 static krb5_error_code
129 krb5_kt_ret_keyblock(krb5_context context
, krb5_storage
*sp
, krb5_keyblock
*p
)
134 ret
= krb5_ret_int16(sp
, &tmp
); /* keytype + etype */
137 ret
= krb5_kt_ret_data(context
, sp
, &p
->keyvalue
);
141 static krb5_error_code
142 krb5_kt_store_keyblock(krb5_context context
,
148 ret
= krb5_store_int16(sp
, p
->keytype
); /* keytype + etype */
150 ret
= krb5_kt_store_data(context
, sp
, p
->keyvalue
);
155 static krb5_error_code
156 krb5_kt_ret_principal(krb5_context context
,
158 krb5_principal
*princ
)
167 krb5_set_error_string (context
, "malloc: out of memory");
171 ret
= krb5_ret_int16(sp
, &tmp
);
174 if(krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS
))
176 p
->name
.name_string
.len
= tmp
;
177 ret
= krb5_kt_ret_string(context
, sp
, &p
->realm
);
180 p
->name
.name_string
.val
= calloc(p
->name
.name_string
.len
,
181 sizeof(*p
->name
.name_string
.val
));
182 if(p
->name
.name_string
.val
== NULL
) {
183 krb5_set_error_string (context
, "malloc: out of memory");
186 for(i
= 0; i
< p
->name
.name_string
.len
; i
++){
187 ret
= krb5_kt_ret_string(context
, sp
, p
->name
.name_string
.val
+ i
);
191 if (krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE
))
192 p
->name
.name_type
= KRB5_NT_UNKNOWN
;
195 ret
= krb5_ret_int32(sp
, &tmp32
);
196 p
->name
.name_type
= tmp32
;
204 static krb5_error_code
205 krb5_kt_store_principal(krb5_context context
,
212 if(krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS
))
213 ret
= krb5_store_int16(sp
, p
->name
.name_string
.len
+ 1);
215 ret
= krb5_store_int16(sp
, p
->name
.name_string
.len
);
217 ret
= krb5_kt_store_string(sp
, p
->realm
);
219 for(i
= 0; i
< p
->name
.name_string
.len
; i
++){
220 ret
= krb5_kt_store_string(sp
, p
->name
.name_string
.val
[i
]);
224 if(!krb5_storage_is_flags(sp
, KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE
)) {
225 ret
= krb5_store_int32(sp
, p
->name
.name_type
);
233 static krb5_error_code
234 fkt_resolve(krb5_context context
, const char *name
, krb5_keytab id
)
238 d
= malloc(sizeof(*d
));
240 krb5_set_error_string (context
, "malloc: out of memory");
243 d
->filename
= strdup(name
);
244 if(d
->filename
== NULL
) {
246 krb5_set_error_string (context
, "malloc: out of memory");
253 static krb5_error_code
254 fkt_close(krb5_context context
, krb5_keytab id
)
256 struct fkt_data
*d
= id
->data
;
262 static krb5_error_code
263 fkt_get_name(krb5_context context
,
268 /* This function is XXX */
269 struct fkt_data
*d
= id
->data
;
270 strlcpy(name
, d
->filename
, namesize
);
275 storage_set_flags(krb5_context context
, krb5_storage
*sp
, int vno
)
280 flags
|= KRB5_STORAGE_PRINCIPAL_WRONG_NUM_COMPONENTS
;
281 flags
|= KRB5_STORAGE_PRINCIPAL_NO_NAME_TYPE
;
282 flags
|= KRB5_STORAGE_HOST_BYTEORDER
;
288 "storage_set_flags called with bad vno (%d)", vno
);
290 krb5_storage_set_flags(sp
, flags
);
293 static krb5_error_code
294 fkt_start_seq_get_int(krb5_context context
,
301 struct fkt_data
*d
= id
->data
;
303 c
->fd
= open (d
->filename
, flags
);
306 krb5_set_error_string(context
, "%s: %s", d
->filename
,
310 c
->sp
= krb5_storage_from_fd(c
->fd
);
311 krb5_storage_set_eof_code(c
->sp
, KRB5_KT_END
);
312 ret
= krb5_ret_int8(c
->sp
, &pvno
);
314 krb5_storage_free(c
->sp
);
319 krb5_storage_free(c
->sp
);
321 krb5_clear_error_string (context
);
322 return KRB5_KEYTAB_BADVNO
;
324 ret
= krb5_ret_int8(c
->sp
, &tag
);
326 krb5_storage_free(c
->sp
);
331 storage_set_flags(context
, c
->sp
, id
->version
);
335 static krb5_error_code
336 fkt_start_seq_get(krb5_context context
,
340 return fkt_start_seq_get_int(context
, id
, O_RDONLY
| O_BINARY
, c
);
343 static krb5_error_code
344 fkt_next_entry_int(krb5_context context
,
346 krb5_keytab_entry
*entry
,
347 krb5_kt_cursor
*cursor
,
357 pos
= krb5_storage_seek(cursor
->sp
, 0, SEEK_CUR
);
359 ret
= krb5_ret_int32(cursor
->sp
, &len
);
363 pos
= krb5_storage_seek(cursor
->sp
, -len
, SEEK_CUR
);
366 ret
= krb5_kt_ret_principal (context
, cursor
->sp
, &entry
->principal
);
369 ret
= krb5_ret_int32(cursor
->sp
, &tmp32
);
370 entry
->timestamp
= tmp32
;
373 ret
= krb5_ret_int8(cursor
->sp
, &tmp8
);
377 ret
= krb5_kt_ret_keyblock (context
, cursor
->sp
, &entry
->keyblock
);
380 /* there might be a 32 bit kvno here
381 * if it's zero, assume that the 8bit one was right,
382 * otherwise trust the new value */
383 curpos
= krb5_storage_seek(cursor
->sp
, 0, SEEK_CUR
);
384 if(len
+ 4 + pos
- curpos
== 4) {
385 ret
= krb5_ret_int32(cursor
->sp
, &tmp32
);
386 if (ret
== 0 && tmp32
!= 0) {
390 if(start
) *start
= pos
;
391 if(end
) *end
= *start
+ 4 + len
;
393 krb5_storage_seek(cursor
->sp
, pos
+ 4 + len
, SEEK_SET
);
397 static krb5_error_code
398 fkt_next_entry(krb5_context context
,
400 krb5_keytab_entry
*entry
,
401 krb5_kt_cursor
*cursor
)
403 return fkt_next_entry_int(context
, id
, entry
, cursor
, NULL
, NULL
);
406 static krb5_error_code
407 fkt_end_seq_get(krb5_context context
,
409 krb5_kt_cursor
*cursor
)
411 krb5_storage_free(cursor
->sp
);
416 static krb5_error_code
417 fkt_setup_keytab(krb5_context context
,
422 ret
= krb5_store_int8(sp
, 5);
426 id
->version
= KRB5_KT_VNO
;
427 return krb5_store_int8 (sp
, id
->version
);
430 static krb5_error_code
431 fkt_add_entry(krb5_context context
,
433 krb5_keytab_entry
*entry
)
438 struct fkt_data
*d
= id
->data
;
442 fd
= open (d
->filename
, O_RDWR
| O_BINARY
);
444 fd
= open (d
->filename
, O_RDWR
| O_CREAT
| O_EXCL
| O_BINARY
, 0600);
447 krb5_set_error_string(context
, "open(%s): %s", d
->filename
,
451 sp
= krb5_storage_from_fd(fd
);
452 krb5_storage_set_eof_code(sp
, KRB5_KT_END
);
453 ret
= fkt_setup_keytab(context
, id
, sp
);
455 krb5_storage_free(sp
);
459 storage_set_flags(context
, sp
, id
->version
);
462 sp
= krb5_storage_from_fd(fd
);
463 krb5_storage_set_eof_code(sp
, KRB5_KT_END
);
464 ret
= krb5_ret_int8(sp
, &pvno
);
466 /* we probably have a zero byte file, so try to set it up
468 ret
= fkt_setup_keytab(context
, id
, sp
);
470 krb5_set_error_string(context
, "%s: keytab is corrupted: %s",
471 d
->filename
, strerror(ret
));
472 krb5_storage_free(sp
);
476 storage_set_flags(context
, sp
, id
->version
);
479 krb5_storage_free(sp
);
481 krb5_clear_error_string (context
);
482 ret
= KRB5_KEYTAB_BADVNO
;
483 krb5_set_error_string(context
, "%s: %s",
484 d
->filename
, strerror(ret
));
487 ret
= krb5_ret_int8 (sp
, &tag
);
489 krb5_set_error_string(context
, "%s: reading tag: %s",
490 d
->filename
, strerror(ret
));
491 krb5_storage_free(sp
);
496 storage_set_flags(context
, sp
, id
->version
);
502 emem
= krb5_storage_emem();
505 krb5_set_error_string (context
, "malloc: out of memory");
508 ret
= krb5_kt_store_principal(context
, emem
, entry
->principal
);
510 krb5_storage_free(emem
);
513 ret
= krb5_store_int32 (emem
, entry
->timestamp
);
515 krb5_storage_free(emem
);
518 ret
= krb5_store_int8 (emem
, entry
->vno
% 256);
520 krb5_storage_free(emem
);
523 ret
= krb5_kt_store_keyblock (context
, emem
, &entry
->keyblock
);
525 krb5_storage_free(emem
);
528 ret
= krb5_store_int32 (emem
, entry
->vno
);
530 krb5_storage_free(emem
);
534 ret
= krb5_storage_to_data(emem
, &keytab
);
535 krb5_storage_free(emem
);
541 ret
= krb5_ret_int32(sp
, &len
);
542 if(ret
== KRB5_KT_END
) {
548 if(len
>= keytab
.length
) {
549 krb5_storage_seek(sp
, -4, SEEK_CUR
);
553 krb5_storage_seek(sp
, len
, SEEK_CUR
);
555 ret
= krb5_store_int32(sp
, len
);
556 if(krb5_storage_write(sp
, keytab
.data
, keytab
.length
) < 0)
558 memset(keytab
.data
, 0, keytab
.length
);
559 krb5_data_free(&keytab
);
561 krb5_storage_free(sp
);
566 static krb5_error_code
567 fkt_remove_entry(krb5_context context
,
569 krb5_keytab_entry
*entry
)
572 krb5_kt_cursor cursor
;
573 off_t pos_start
, pos_end
;
577 ret
= fkt_start_seq_get_int(context
, id
, O_RDWR
| O_BINARY
, &cursor
);
579 goto out
; /* return other error here? */
580 while(fkt_next_entry_int(context
, id
, &e
, &cursor
,
581 &pos_start
, &pos_end
) == 0) {
582 if(krb5_kt_compare(context
, &e
, entry
->principal
,
583 entry
->vno
, entry
->keyblock
.keytype
)) {
585 unsigned char buf
[128];
587 krb5_storage_seek(cursor
.sp
, pos_start
, SEEK_SET
);
588 len
= pos_end
- pos_start
- 4;
589 krb5_store_int32(cursor
.sp
, -len
);
590 memset(buf
, 0, sizeof(buf
));
592 krb5_storage_write(cursor
.sp
, buf
, min(len
, sizeof(buf
)));
593 len
-= min(len
, sizeof(buf
));
597 krb5_kt_end_seq_get(context
, id
, &cursor
);
600 krb5_clear_error_string (context
);
601 return KRB5_KT_NOTFOUND
;
606 const krb5_kt_ops krb5_fkt_ops
= {