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"
42 static krb5_error_code
43 krb4_kt_resolve(krb5_context context
, const char *name
, krb5_keytab id
)
45 struct krb4_kt_data
*d
;
47 d
= malloc (sizeof(*d
));
49 krb5_set_error_string (context
, "malloc: out of memory");
52 d
->filename
= strdup (name
);
53 if (d
->filename
== NULL
) {
55 krb5_set_error_string (context
, "malloc: out of memory");
62 static krb5_error_code
63 krb4_kt_get_name (krb5_context context
,
68 struct krb4_kt_data
*d
= id
->data
;
70 strlcpy (name
, d
->filename
, name_sz
);
74 static krb5_error_code
75 krb4_kt_close (krb5_context context
,
78 struct krb4_kt_data
*d
= id
->data
;
85 struct krb4_cursor_extra_data
{
86 krb5_keytab_entry entry
;
91 open_flock(const char *filename
, int flags
, int mode
)
95 int fd
= open(filename
, flags
, mode
);
98 if((flags
& O_ACCMODE
) == O_RDONLY
)
99 lock_mode
= LOCK_SH
| LOCK_NB
;
101 lock_mode
= LOCK_EX
| LOCK_NB
;
102 while(flock(fd
, lock_mode
) < 0) {
115 static krb5_error_code
116 krb4_kt_start_seq_get_int (krb5_context context
,
121 struct krb4_kt_data
*d
= id
->data
;
122 struct krb4_cursor_extra_data
*ed
;
125 ed
= malloc (sizeof(*ed
));
127 krb5_set_error_string (context
, "malloc: out of memory");
130 ed
->entry
.principal
= NULL
;
133 c
->fd
= open_flock (d
->filename
, flags
, 0);
137 krb5_set_error_string(context
, "keytab krb5 open %s failed: %s",
138 d
->filename
, strerror(ret
));
141 c
->sp
= krb5_storage_from_fd(c
->fd
);
145 krb5_set_error_string(context
, "malloc: out of memory");
148 krb5_storage_set_eof_code(c
->sp
, KRB5_KT_END
);
152 static krb5_error_code
153 krb4_kt_start_seq_get (krb5_context context
,
157 return krb4_kt_start_seq_get_int (context
, id
, O_BINARY
| O_RDONLY
, c
);
160 static krb5_error_code
161 read_v4_entry (krb5_context context
,
162 struct krb4_kt_data
*d
,
164 struct krb4_cursor_extra_data
*ed
)
166 unsigned char des_key
[8];
168 char *service
, *instance
, *realm
;
171 ret
= krb5_ret_stringz(c
->sp
, &service
);
174 ret
= krb5_ret_stringz(c
->sp
, &instance
);
179 ret
= krb5_ret_stringz(c
->sp
, &realm
);
185 ret
= krb5_425_conv_principal (context
, service
, instance
, realm
,
186 &ed
->entry
.principal
);
192 ret
= krb5_ret_int8(c
->sp
, &kvno
);
194 krb5_free_principal (context
, ed
->entry
.principal
);
197 ret
= krb5_storage_read(c
->sp
, des_key
, sizeof(des_key
));
199 krb5_free_principal(context
, ed
->entry
.principal
);
203 krb5_free_principal(context
, ed
->entry
.principal
);
206 ed
->entry
.vno
= kvno
;
207 ret
= krb5_data_copy (&ed
->entry
.keyblock
.keyvalue
,
208 des_key
, sizeof(des_key
));
211 ed
->entry
.timestamp
= time(NULL
);
216 static krb5_error_code
217 krb4_kt_next_entry (krb5_context context
,
219 krb5_keytab_entry
*entry
,
223 struct krb4_kt_data
*d
= id
->data
;
224 struct krb4_cursor_extra_data
*ed
= c
->data
;
225 const krb5_enctype keytypes
[] = {ETYPE_DES_CBC_MD5
,
230 ret
= read_v4_entry (context
, d
, c
, ed
);
234 ret
= krb5_kt_copy_entry_contents (context
,
239 entry
->keyblock
.keytype
= keytypes
[ed
->num
];
240 if (++ed
->num
== 3) {
241 krb5_kt_free_entry (context
, &ed
->entry
);
247 static krb5_error_code
248 krb4_kt_end_seq_get (krb5_context context
,
252 struct krb4_cursor_extra_data
*ed
= c
->data
;
254 krb5_storage_free (c
->sp
);
256 krb5_kt_free_entry (context
, &ed
->entry
);
262 static krb5_error_code
263 krb4_store_keytab_entry(krb5_context context
,
264 krb5_keytab_entry
*entry
,
271 char service
[ANAME_SZ
];
272 char instance
[INST_SZ
];
273 char realm
[REALM_SZ
];
274 ret
= krb5_524_conv_principal (context
, entry
->principal
,
275 service
, instance
, realm
);
278 if (entry
->keyblock
.keyvalue
.length
== 8
279 && entry
->keyblock
.keytype
== ETYPE_DES_CBC_MD5
) {
280 ret
= krb5_store_stringz(sp
, service
);
281 ret
= krb5_store_stringz(sp
, instance
);
282 ret
= krb5_store_stringz(sp
, realm
);
283 ret
= krb5_store_int8(sp
, entry
->vno
);
284 ret
= krb5_storage_write(sp
, entry
->keyblock
.keyvalue
.data
, 8);
289 static krb5_error_code
290 krb4_kt_add_entry (krb5_context context
,
292 krb5_keytab_entry
*entry
)
294 struct krb4_kt_data
*d
= id
->data
;
299 fd
= open_flock (d
->filename
, O_WRONLY
| O_APPEND
| O_BINARY
, 0);
301 fd
= open_flock (d
->filename
,
302 O_WRONLY
| O_APPEND
| O_BINARY
| O_CREAT
, 0600);
305 krb5_set_error_string(context
, "open(%s): %s", d
->filename
,
310 sp
= krb5_storage_from_fd(fd
);
315 krb5_storage_set_eof_code(sp
, KRB5_KT_END
);
316 ret
= krb4_store_keytab_entry(context
, entry
, sp
);
317 krb5_storage_free(sp
);
323 static krb5_error_code
324 krb4_kt_remove_entry(krb5_context context
,
326 krb5_keytab_entry
*entry
)
328 struct krb4_kt_data
*d
= id
->data
;
331 krb5_kt_cursor cursor
;
335 sp
= krb5_storage_emem();
337 krb5_set_error_string(context
, "malloc: out of memory");
340 ret
= krb5_kt_start_seq_get(context
, id
, &cursor
);
342 krb5_storage_free(sp
);
345 while(krb5_kt_next_entry(context
, id
, &e
, &cursor
) == 0) {
346 if(!krb5_kt_compare(context
, &e
, entry
->principal
,
347 entry
->vno
, entry
->keyblock
.keytype
)) {
348 ret
= krb4_store_keytab_entry(context
, &e
, sp
);
350 krb5_kt_free_entry(context
, &e
);
351 krb5_storage_free(sp
);
356 krb5_kt_free_entry(context
, &e
);
358 krb5_kt_end_seq_get(context
, id
, &cursor
);
361 unsigned char buf
[1024];
366 krb5_storage_to_data(sp
, &data
);
367 krb5_storage_free(sp
);
369 fd
= open_flock (d
->filename
, O_RDWR
| O_BINARY
, 0);
371 memset(data
.data
, 0, data
.length
);
372 krb5_data_free(&data
);
373 if(errno
== EACCES
|| errno
== EROFS
) {
374 krb5_set_error_string(context
, "failed to open %s for writing",
376 return KRB5_KT_NOWRITE
;
381 if(write(fd
, data
.data
, data
.length
) != data
.length
) {
382 memset(data
.data
, 0, data
.length
);
383 krb5_data_free(&data
);
385 krb5_set_error_string(context
, "failed writing to file %s",
389 memset(data
.data
, 0, data
.length
);
390 if(fstat(fd
, &st
) < 0) {
391 krb5_data_free(&data
);
393 krb5_set_error_string(context
, "failed getting size of file %s",
397 st
.st_size
-= data
.length
;
398 memset(buf
, 0, sizeof(buf
));
399 while(st
.st_size
> 0) {
400 n
= min(st
.st_size
, sizeof(buf
));
401 n
= write(fd
, buf
, n
);
403 krb5_data_free(&data
);
405 krb5_set_error_string(context
, "failed writing to file %s",
412 if(ftruncate(fd
, data
.length
) < 0) {
413 krb5_data_free(&data
);
415 krb5_set_error_string(context
, "failed truncating file %s",
419 krb5_data_free(&data
);
421 krb5_set_error_string(context
, "error closing %s",
427 krb5_storage_free(sp
);
428 krb5_set_error_string(context
, "Keytab entry not found");
429 return KRB5_KT_NOTFOUND
;
434 const krb5_kt_ops krb4_fkt_ops
= {
440 krb4_kt_start_seq_get
,
443 krb4_kt_add_entry
, /* add_entry */
444 krb4_kt_remove_entry
/* remove_entry */
447 const krb5_kt_ops krb5_srvtab_fkt_ops
= {
453 krb4_kt_start_seq_get
,
456 krb4_kt_add_entry
, /* add_entry */
457 krb4_kt_remove_entry
/* remove_entry */