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"
39 * Register a new keytab in `ops'
40 * Return 0 or an error.
43 krb5_error_code KRB5_LIB_FUNCTION
44 krb5_kt_register(krb5_context context
,
45 const krb5_kt_ops
*ops
)
47 struct krb5_keytab_data
*tmp
;
49 if (strlen(ops
->prefix
) > KRB5_KT_PREFIX_MAX_LEN
- 1) {
50 krb5_set_error_string(context
, "krb5_kt_register; prefix too long");
51 return KRB5_KT_BADNAME
;
54 tmp
= realloc(context
->kt_types
,
55 (context
->num_kt_types
+ 1) * sizeof(*context
->kt_types
));
57 krb5_set_error_string(context
, "malloc: out of memory");
60 memcpy(&tmp
[context
->num_kt_types
], ops
,
61 sizeof(tmp
[context
->num_kt_types
]));
62 context
->kt_types
= tmp
;
63 context
->num_kt_types
++;
68 * Resolve the keytab name (of the form `type:residual') in `name'
69 * into a keytab in `id'.
70 * Return 0 or an error
73 krb5_error_code KRB5_LIB_FUNCTION
74 krb5_kt_resolve(krb5_context context
,
80 const char *type
, *residual
;
84 residual
= strchr(name
, ':');
85 if(residual
== NULL
) {
87 type_len
= strlen(type
);
91 type_len
= residual
- name
;
95 for(i
= 0; i
< context
->num_kt_types
; i
++) {
96 if(strncasecmp(type
, context
->kt_types
[i
].prefix
, type_len
) == 0)
99 if(i
== context
->num_kt_types
) {
100 krb5_set_error_string(context
, "unknown keytab type %.*s",
101 (int)type_len
, type
);
102 return KRB5_KT_UNKNOWN_TYPE
;
105 k
= malloc (sizeof(*k
));
107 krb5_set_error_string(context
, "malloc: out of memory");
110 memcpy(k
, &context
->kt_types
[i
], sizeof(*k
));
112 ret
= (*k
->resolve
)(context
, residual
, k
);
122 * copy the name of the default keytab into `name'.
123 * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
126 krb5_error_code KRB5_LIB_FUNCTION
127 krb5_kt_default_name(krb5_context context
, char *name
, size_t namesize
)
129 if (strlcpy (name
, context
->default_keytab
, namesize
) >= namesize
) {
130 krb5_clear_error_string (context
);
131 return KRB5_CONFIG_NOTENUFSPACE
;
137 * copy the name of the default modify keytab into `name'.
138 * Return 0 or KRB5_CONFIG_NOTENUFSPACE if `namesize' is too short.
141 krb5_error_code KRB5_LIB_FUNCTION
142 krb5_kt_default_modify_name(krb5_context context
, char *name
, size_t namesize
)
144 const char *kt
= NULL
;
145 if(context
->default_keytab_modify
== NULL
) {
146 if(strncasecmp(context
->default_keytab
, "ANY:", 4) != 0)
147 kt
= context
->default_keytab
;
149 size_t len
= strcspn(context
->default_keytab
+ 4, ",");
150 if(len
>= namesize
) {
151 krb5_clear_error_string(context
);
152 return KRB5_CONFIG_NOTENUFSPACE
;
154 strlcpy(name
, context
->default_keytab
+ 4, namesize
);
159 kt
= context
->default_keytab_modify
;
160 if (strlcpy (name
, kt
, namesize
) >= namesize
) {
161 krb5_clear_error_string (context
);
162 return KRB5_CONFIG_NOTENUFSPACE
;
168 * Set `id' to the default keytab.
169 * Return 0 or an error.
172 krb5_error_code KRB5_LIB_FUNCTION
173 krb5_kt_default(krb5_context context
, krb5_keytab
*id
)
175 return krb5_kt_resolve (context
, context
->default_keytab
, id
);
179 * Read the key identified by `(principal, vno, enctype)' from the
180 * keytab in `keyprocarg' (the default if == NULL) into `*key'.
181 * Return 0 or an error.
184 krb5_error_code KRB5_LIB_FUNCTION
185 krb5_kt_read_service_key(krb5_context context
,
186 krb5_pointer keyprocarg
,
187 krb5_principal principal
,
189 krb5_enctype enctype
,
193 krb5_keytab_entry entry
;
197 ret
= krb5_kt_resolve (context
, keyprocarg
, &keytab
);
199 ret
= krb5_kt_default (context
, &keytab
);
204 ret
= krb5_kt_get_entry (context
, keytab
, principal
, vno
, enctype
, &entry
);
205 krb5_kt_close (context
, keytab
);
208 ret
= krb5_copy_keyblock (context
, &entry
.keyblock
, key
);
209 krb5_kt_free_entry(context
, &entry
);
214 * Return the type of the `keytab' in the string `prefix of length
218 krb5_error_code KRB5_LIB_FUNCTION
219 krb5_kt_get_type(krb5_context context
,
224 strlcpy(prefix
, keytab
->prefix
, prefixsize
);
229 * Retrieve the name of the keytab `keytab' into `name', `namesize'
230 * Return 0 or an error.
233 krb5_error_code KRB5_LIB_FUNCTION
234 krb5_kt_get_name(krb5_context context
,
239 return (*keytab
->get_name
)(context
, keytab
, name
, namesize
);
243 * Retrieve the full name of the keytab `keytab' and store the name in
244 * `str'. `str' needs to be freed by the caller using free(3).
245 * Returns 0 or an error. On error, *str is set to NULL.
248 krb5_error_code KRB5_LIB_FUNCTION
249 krb5_kt_get_full_name(krb5_context context
,
253 char type
[KRB5_KT_PREFIX_MAX_LEN
];
254 char name
[MAXPATHLEN
];
259 ret
= krb5_kt_get_type(context
, keytab
, type
, sizeof(type
));
263 ret
= krb5_kt_get_name(context
, keytab
, name
, sizeof(name
));
267 if (asprintf(str
, "%s:%s", type
, name
) == -1) {
268 krb5_set_error_string(context
, "malloc - out of memory");
277 * Finish using the keytab in `id'. All resources will be released,
278 * even on errors. Return 0 or an error.
281 krb5_error_code KRB5_LIB_FUNCTION
282 krb5_kt_close(krb5_context context
,
287 ret
= (*id
->close
)(context
, id
);
288 memset(id
, 0, sizeof(*id
));
294 * Compare `entry' against `principal, vno, enctype'.
295 * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
296 * Return TRUE if they compare the same, FALSE otherwise.
299 krb5_boolean KRB5_LIB_FUNCTION
300 krb5_kt_compare(krb5_context context
,
301 krb5_keytab_entry
*entry
,
302 krb5_const_principal principal
,
304 krb5_enctype enctype
)
306 if(principal
!= NULL
&&
307 !krb5_principal_compare(context
, entry
->principal
, principal
))
309 if(vno
&& vno
!= entry
->vno
)
311 if(enctype
&& enctype
!= entry
->keyblock
.keytype
)
317 * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
318 * from the keytab `id'.
319 * kvno == 0 is a wildcard and gives the keytab with the highest vno.
320 * Return 0 or an error.
323 krb5_error_code KRB5_LIB_FUNCTION
324 krb5_kt_get_entry(krb5_context context
,
326 krb5_const_principal principal
,
328 krb5_enctype enctype
,
329 krb5_keytab_entry
*entry
)
331 krb5_keytab_entry tmp
;
333 krb5_kt_cursor cursor
;
336 return (*id
->get
)(context
, id
, principal
, kvno
, enctype
, entry
);
338 ret
= krb5_kt_start_seq_get (context
, id
, &cursor
);
340 krb5_clear_error_string(context
);
341 return KRB5_KT_NOTFOUND
; /* XXX i.e. file not found */
345 while (krb5_kt_next_entry(context
, id
, &tmp
, &cursor
) == 0) {
346 if (krb5_kt_compare(context
, &tmp
, principal
, 0, enctype
)) {
347 /* the file keytab might only store the lower 8 bits of
348 the kvno, so only compare those bits */
350 || (tmp
.vno
< 256 && kvno
% 256 == tmp
.vno
)) {
351 krb5_kt_copy_entry_contents (context
, &tmp
, entry
);
352 krb5_kt_free_entry (context
, &tmp
);
353 krb5_kt_end_seq_get(context
, id
, &cursor
);
355 } else if (kvno
== 0 && tmp
.vno
> entry
->vno
) {
357 krb5_kt_free_entry (context
, entry
);
358 krb5_kt_copy_entry_contents (context
, &tmp
, entry
);
361 krb5_kt_free_entry(context
, &tmp
);
363 krb5_kt_end_seq_get (context
, id
, &cursor
);
367 char princ
[256], kvno_str
[25], *kt_name
;
368 char *enctype_str
= NULL
;
370 krb5_unparse_name_fixed (context
, principal
, princ
, sizeof(princ
));
371 krb5_kt_get_full_name (context
, id
, &kt_name
);
372 krb5_enctype_to_string(context
, enctype
, &enctype_str
);
375 snprintf(kvno_str
, sizeof(kvno_str
), "(kvno %d)", kvno
);
379 krb5_set_error_string (context
,
380 "Failed to find %s%s in keytab %s (%s)",
383 kt_name
? kt_name
: "unknown keytab",
384 enctype_str
? enctype_str
: "unknown enctype");
387 return KRB5_KT_NOTFOUND
;
392 * Copy the contents of `in' into `out'.
393 * Return 0 or an error. */
395 krb5_error_code KRB5_LIB_FUNCTION
396 krb5_kt_copy_entry_contents(krb5_context context
,
397 const krb5_keytab_entry
*in
,
398 krb5_keytab_entry
*out
)
402 memset(out
, 0, sizeof(*out
));
405 ret
= krb5_copy_principal (context
, in
->principal
, &out
->principal
);
408 ret
= krb5_copy_keyblock_contents (context
,
413 out
->timestamp
= in
->timestamp
;
416 krb5_kt_free_entry (context
, out
);
421 * Free the contents of `entry'.
424 krb5_error_code KRB5_LIB_FUNCTION
425 krb5_kt_free_entry(krb5_context context
,
426 krb5_keytab_entry
*entry
)
428 krb5_free_principal (context
, entry
->principal
);
429 krb5_free_keyblock_contents (context
, &entry
->keyblock
);
430 memset(entry
, 0, sizeof(*entry
));
435 * Set `cursor' to point at the beginning of `id'.
436 * Return 0 or an error.
439 krb5_error_code KRB5_LIB_FUNCTION
440 krb5_kt_start_seq_get(krb5_context context
,
442 krb5_kt_cursor
*cursor
)
444 if(id
->start_seq_get
== NULL
) {
445 krb5_set_error_string(context
,
446 "start_seq_get is not supported in the %s "
447 " keytab", id
->prefix
);
448 return HEIM_ERR_OPNOTSUPP
;
450 return (*id
->start_seq_get
)(context
, id
, cursor
);
454 * Get the next entry from `id' pointed to by `cursor' and advance the
456 * Return 0 or an error.
459 krb5_error_code KRB5_LIB_FUNCTION
460 krb5_kt_next_entry(krb5_context context
,
462 krb5_keytab_entry
*entry
,
463 krb5_kt_cursor
*cursor
)
465 if(id
->next_entry
== NULL
) {
466 krb5_set_error_string(context
,
467 "next_entry is not supported in the %s "
468 " keytab", id
->prefix
);
469 return HEIM_ERR_OPNOTSUPP
;
471 return (*id
->next_entry
)(context
, id
, entry
, cursor
);
475 * Release all resources associated with `cursor'.
478 krb5_error_code KRB5_LIB_FUNCTION
479 krb5_kt_end_seq_get(krb5_context context
,
481 krb5_kt_cursor
*cursor
)
483 if(id
->end_seq_get
== NULL
) {
484 krb5_set_error_string(context
,
485 "end_seq_get is not supported in the %s "
486 " keytab", id
->prefix
);
487 return HEIM_ERR_OPNOTSUPP
;
489 return (*id
->end_seq_get
)(context
, id
, cursor
);
493 * Add the entry in `entry' to the keytab `id'.
494 * Return 0 or an error.
497 krb5_error_code KRB5_LIB_FUNCTION
498 krb5_kt_add_entry(krb5_context context
,
500 krb5_keytab_entry
*entry
)
502 if(id
->add
== NULL
) {
503 krb5_set_error_string(context
, "Add is not supported in the %s keytab",
505 return KRB5_KT_NOWRITE
;
507 entry
->timestamp
= time(NULL
);
508 return (*id
->add
)(context
, id
,entry
);
512 * Remove the entry `entry' from the keytab `id'.
513 * Return 0 or an error.
516 krb5_error_code KRB5_LIB_FUNCTION
517 krb5_kt_remove_entry(krb5_context context
,
519 krb5_keytab_entry
*entry
)
521 if(id
->remove
== NULL
) {
522 krb5_set_error_string(context
,
523 "Remove is not supported in the %s keytab",
525 return KRB5_KT_NOWRITE
;
527 return (*id
->remove
)(context
, id
, entry
);