Line data Source code
1 : /*
2 : * Copyright (c) 1997 - 2005 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 : /**
37 : * @page krb5_keytab_intro The keytab handing functions
38 : * @section section_krb5_keytab Kerberos Keytabs
39 : *
40 : * See the library functions here: @ref krb5_keytab
41 : *
42 : * Keytabs are long term key storage for servers, their equvalment of
43 : * password files.
44 : *
45 : * Normally the only function that useful for server are to specify
46 : * what keytab to use to other core functions like krb5_rd_req()
47 : * krb5_kt_resolve(), and krb5_kt_close().
48 : *
49 : * @subsection krb5_keytab_names Keytab names
50 : *
51 : * A keytab name is on the form type:residual. The residual part is
52 : * specific to each keytab-type.
53 : *
54 : * When a keytab-name is resolved, the type is matched with an internal
55 : * list of keytab types. If there is no matching keytab type,
56 : * the default keytab is used. The current default type is FILE.
57 : *
58 : * The default value can be changed in the configuration file
59 : * /etc/krb5.conf by setting the variable
60 : * [defaults]default_keytab_name.
61 : *
62 : * The keytab types that are implemented in Heimdal are:
63 : * - file
64 : * store the keytab in a file, the type's name is FILE . The
65 : * residual part is a filename. For compatibility with other
66 : * Kerberos implemtation WRFILE and JAVA14 is also accepted. WRFILE
67 : * has the same format as FILE. JAVA14 have a format that is
68 : * compatible with older versions of MIT kerberos and SUN's Java
69 : * based installation. They store a truncted kvno, so when the knvo
70 : * excess 255, they are truncted in this format.
71 : *
72 : * - keytab
73 : * store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ),
74 : * the type's name is AFSKEYFILE. The residual part is a filename.
75 : *
76 : * - memory
77 : * The keytab is stored in a memory segment. This allows sensitive
78 : * and/or temporary data not to be stored on disk. The type's name
79 : * is MEMORY. Each MEMORY keytab is referenced counted by and
80 : * opened by the residual name, so two handles can point to the
81 : * same memory area. When the last user closes using krb5_kt_close()
82 : * the keytab, the keys in they keytab is memset() to zero and freed
83 : * and can no longer be looked up by name.
84 : *
85 : *
86 : * @subsection krb5_keytab_example Keytab example
87 : *
88 : * This is a minimalistic version of ktutil.
89 : *
90 : * @code
91 : int
92 : main (int argc, char **argv)
93 : {
94 : krb5_context context;
95 : krb5_keytab keytab;
96 : krb5_kt_cursor cursor;
97 : krb5_keytab_entry entry;
98 : krb5_error_code ret;
99 : char *principal;
100 :
101 : if (krb5_init_context (&context) != 0)
102 : errx(1, "krb5_context");
103 :
104 : ret = krb5_kt_default (context, &keytab);
105 : if (ret)
106 : krb5_err(context, 1, ret, "krb5_kt_default");
107 :
108 : ret = krb5_kt_start_seq_get(context, keytab, &cursor);
109 : if (ret)
110 : krb5_err(context, 1, ret, "krb5_kt_start_seq_get");
111 : while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
112 : krb5_unparse_name(context, entry.principal, &principal);
113 : printf("principal: %s\n", principal);
114 : free(principal);
115 : krb5_kt_free_entry(context, &entry);
116 : }
117 : ret = krb5_kt_end_seq_get(context, keytab, &cursor);
118 : if (ret)
119 : krb5_err(context, 1, ret, "krb5_kt_end_seq_get");
120 : ret = krb5_kt_close(context, keytab);
121 : if (ret)
122 : krb5_err(context, 1, ret, "krb5_kt_close");
123 : krb5_free_context(context);
124 : return 0;
125 : }
126 : * @endcode
127 : *
128 : */
129 :
130 :
131 : /**
132 : * Register a new keytab backend.
133 : *
134 : * @param context a Keberos context.
135 : * @param ops a backend to register.
136 : *
137 : * @return Return an error code or 0, see krb5_get_error_message().
138 : *
139 : * @ingroup krb5_keytab
140 : */
141 :
142 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
143 4752117 : krb5_kt_register(krb5_context context,
144 : const krb5_kt_ops *ops)
145 : {
146 117068 : struct krb5_keytab_data *tmp;
147 :
148 4752117 : if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) {
149 0 : krb5_set_error_message(context, KRB5_KT_BADNAME,
150 0 : N_("can't register cache type, prefix too long", ""));
151 0 : return KRB5_KT_BADNAME;
152 : }
153 :
154 4752117 : tmp = realloc(context->kt_types,
155 4752117 : (context->num_kt_types + 1) * sizeof(*context->kt_types));
156 4752117 : if(tmp == NULL)
157 0 : return krb5_enomem(context);
158 4752117 : memcpy(&tmp[context->num_kt_types], ops,
159 : sizeof(tmp[context->num_kt_types]));
160 4752117 : context->kt_types = tmp;
161 4752117 : context->num_kt_types++;
162 4752117 : return 0;
163 : }
164 :
165 : static const char *
166 227124 : keytab_name(const char *name, const char **type, size_t *type_len)
167 : {
168 7000 : const char *residual;
169 :
170 227124 : residual = strchr(name, ':');
171 :
172 227124 : if (residual == NULL ||
173 227117 : ISPATHSEP(name[0])
174 : #ifdef _WIN32
175 : /* Avoid treating <drive>:<path> as a keytab type
176 : * specification */
177 : || name + 1 == residual
178 : #endif
179 : ) {
180 :
181 7 : *type = "FILE";
182 7 : *type_len = strlen(*type);
183 7 : residual = name;
184 : } else {
185 227117 : *type = name;
186 227117 : *type_len = residual - name;
187 227117 : residual++;
188 : }
189 :
190 227124 : return residual;
191 : }
192 :
193 : /**
194 : * Resolve the keytab name (of the form `type:residual') in `name'
195 : * into a keytab in `id'.
196 : *
197 : * @param context a Keberos context.
198 : * @param name name to resolve
199 : * @param id resulting keytab, free with krb5_kt_close().
200 : *
201 : * @return Return an error code or 0, see krb5_get_error_message().
202 : *
203 : * @ingroup krb5_keytab
204 : */
205 :
206 :
207 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
208 227124 : krb5_kt_resolve(krb5_context context,
209 : const char *name,
210 : krb5_keytab *id)
211 : {
212 7000 : krb5_keytab k;
213 7000 : int i;
214 7000 : const char *type, *residual;
215 7000 : size_t type_len;
216 7000 : krb5_error_code ret;
217 :
218 227124 : residual = keytab_name(name, &type, &type_len);
219 :
220 251965 : for(i = 0; i < context->num_kt_types; i++) {
221 244965 : if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
222 220124 : break;
223 : }
224 227124 : if(i == context->num_kt_types) {
225 0 : krb5_set_error_message(context, KRB5_KT_UNKNOWN_TYPE,
226 0 : N_("unknown keytab type %.*s", "type"),
227 : (int)type_len, type);
228 0 : return KRB5_KT_UNKNOWN_TYPE;
229 : }
230 :
231 227124 : k = malloc (sizeof(*k));
232 227124 : if (k == NULL)
233 0 : return krb5_enomem(context);
234 227124 : memcpy(k, &context->kt_types[i], sizeof(*k));
235 227124 : k->data = NULL;
236 227124 : ret = (*k->resolve)(context, residual, k);
237 227124 : if(ret) {
238 0 : free(k);
239 0 : k = NULL;
240 : }
241 227124 : *id = k;
242 227124 : return ret;
243 : }
244 :
245 : /*
246 : * Default ktname from context with possible environment
247 : * override
248 : */
249 1 : static const char *default_ktname(krb5_context context)
250 : {
251 1 : const char *tmp = NULL;
252 :
253 2 : tmp = secure_getenv("KRB5_KTNAME");
254 1 : if(tmp != NULL)
255 0 : return tmp;
256 1 : return context->default_keytab;
257 : }
258 :
259 : /**
260 : * copy the name of the default keytab into `name'.
261 : *
262 : * @param context a Keberos context.
263 : * @param name buffer where the name will be written
264 : * @param namesize length of name
265 : *
266 : * @return Return an error code or 0, see krb5_get_error_message().
267 : *
268 : * @ingroup krb5_keytab
269 : */
270 :
271 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
272 1 : krb5_kt_default_name(krb5_context context, char *name, size_t namesize)
273 : {
274 2 : if (strlcpy (name, default_ktname(context), namesize) >= namesize) {
275 0 : krb5_clear_error_message (context);
276 0 : return KRB5_CONFIG_NOTENUFSPACE;
277 : }
278 0 : return 0;
279 : }
280 :
281 : /**
282 : * Copy the name of the default modify keytab into `name'.
283 : *
284 : * @param context a Keberos context.
285 : * @param name buffer where the name will be written
286 : * @param namesize length of name
287 : *
288 : * @return Return an error code or 0, see krb5_get_error_message().
289 : *
290 : * @ingroup krb5_keytab
291 : */
292 :
293 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
294 0 : krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
295 : {
296 0 : const char *kt;
297 :
298 0 : if(context->default_keytab_modify == NULL) {
299 0 : kt = default_ktname(context);
300 :
301 0 : if (strncasecmp(kt, "ANY:", 4) == 0) {
302 0 : size_t len = strcspn(kt + 4, ",");
303 0 : if (len >= namesize) {
304 0 : krb5_clear_error_message(context);
305 0 : return KRB5_CONFIG_NOTENUFSPACE;
306 : }
307 0 : strlcpy(name, kt + 4, namesize);
308 0 : name[len] = '\0';
309 0 : return 0;
310 : }
311 : } else
312 0 : kt = context->default_keytab_modify;
313 0 : if (strlcpy (name, kt, namesize) >= namesize) {
314 0 : krb5_clear_error_message (context);
315 0 : return KRB5_CONFIG_NOTENUFSPACE;
316 : }
317 0 : return 0;
318 : }
319 :
320 : /**
321 : * Set `id' to the default keytab.
322 : *
323 : * @param context a Keberos context.
324 : * @param id the new default keytab.
325 : *
326 : * @return Return an error code or 0, see krb5_get_error_message().
327 : *
328 : * @ingroup krb5_keytab
329 : */
330 :
331 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
332 0 : krb5_kt_default(krb5_context context, krb5_keytab *id)
333 : {
334 0 : return krb5_kt_resolve (context, default_ktname(context), id);
335 : }
336 :
337 : /**
338 : * Read the key identified by `(principal, vno, enctype)' from the
339 : * keytab in `keyprocarg' (the default if == NULL) into `*key'.
340 : *
341 : * @param context a Keberos context.
342 : * @param keyprocarg
343 : * @param principal
344 : * @param vno
345 : * @param enctype
346 : * @param key
347 : *
348 : * @return Return an error code or 0, see krb5_get_error_message().
349 : *
350 : * @ingroup krb5_keytab
351 : */
352 :
353 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
354 0 : krb5_kt_read_service_key(krb5_context context,
355 : krb5_pointer keyprocarg,
356 : krb5_principal principal,
357 : krb5_kvno vno,
358 : krb5_enctype enctype,
359 : krb5_keyblock **key)
360 : {
361 0 : krb5_keytab keytab = NULL; /* Quiet lint */
362 0 : krb5_keytab_entry entry;
363 0 : krb5_error_code ret;
364 :
365 0 : memset(&entry, 0, sizeof(entry));
366 0 : if (keyprocarg)
367 0 : ret = krb5_kt_resolve (context, keyprocarg, &keytab);
368 : else
369 0 : ret = krb5_kt_default (context, &keytab);
370 :
371 0 : if (ret)
372 0 : return ret;
373 :
374 0 : ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
375 0 : if (ret == 0) {
376 0 : ret = krb5_copy_keyblock (context, &entry.keyblock, key);
377 0 : krb5_kt_free_entry(context, &entry);
378 : }
379 0 : krb5_kt_close (context, keytab);
380 0 : return ret;
381 : }
382 :
383 : /**
384 : * Return the type of the `keytab' in the string `prefix of length
385 : * `prefixsize'.
386 : *
387 : * @param context a Keberos context.
388 : * @param keytab the keytab to get the prefix for
389 : * @param prefix prefix buffer
390 : * @param prefixsize length of prefix buffer
391 : *
392 : * @return Return an error code or 0, see krb5_get_error_message().
393 : *
394 : * @ingroup krb5_keytab
395 : */
396 :
397 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
398 127639 : krb5_kt_get_type(krb5_context context,
399 : krb5_keytab keytab,
400 : char *prefix,
401 : size_t prefixsize)
402 : {
403 127639 : strlcpy(prefix, keytab->prefix, prefixsize);
404 127639 : return 0;
405 : }
406 :
407 : /**
408 : * Retrieve the name of the keytab `keytab' into `name', `namesize'
409 : *
410 : * @param context a Keberos context.
411 : * @param keytab the keytab to get the name for.
412 : * @param name name buffer.
413 : * @param namesize size of name buffer.
414 : *
415 : * @return Return an error code or 0, see krb5_get_error_message().
416 : *
417 : * @ingroup krb5_keytab
418 : */
419 :
420 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
421 127639 : krb5_kt_get_name(krb5_context context,
422 : krb5_keytab keytab,
423 : char *name,
424 : size_t namesize)
425 : {
426 127639 : return (*keytab->get_name)(context, keytab, name, namesize);
427 : }
428 :
429 : /**
430 : * Retrieve the full name of the keytab `keytab' and store the name in
431 : * `str'.
432 : *
433 : * @param context a Keberos context.
434 : * @param keytab keytab to get name for.
435 : * @param str the name of the keytab name, usee krb5_xfree() to free
436 : * the string. On error, *str is set to NULL.
437 : *
438 : * @return Return an error code or 0, see krb5_get_error_message().
439 : *
440 : * @ingroup krb5_keytab
441 : */
442 :
443 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
444 127639 : krb5_kt_get_full_name(krb5_context context,
445 : krb5_keytab keytab,
446 : char **str)
447 : {
448 4314 : char type[KRB5_KT_PREFIX_MAX_LEN];
449 4314 : char name[MAXPATHLEN];
450 4314 : krb5_error_code ret;
451 :
452 127639 : *str = NULL;
453 :
454 127639 : ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
455 127639 : if (ret)
456 0 : return ret;
457 :
458 127639 : ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
459 127639 : if (ret)
460 0 : return ret;
461 :
462 127639 : if (asprintf(str, "%s:%s", type, name) == -1) {
463 0 : *str = NULL;
464 0 : return krb5_enomem(context);
465 : }
466 :
467 123325 : return 0;
468 : }
469 :
470 : /**
471 : * Finish using the keytab in `id'. All resources will be released,
472 : * even on errors.
473 : *
474 : * @param context a Keberos context.
475 : * @param id keytab to close.
476 : *
477 : * @return Return an error code or 0, see krb5_get_error_message().
478 : *
479 : * @ingroup krb5_keytab
480 : */
481 :
482 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
483 227060 : krb5_kt_close(krb5_context context,
484 : krb5_keytab id)
485 : {
486 227060 : krb5_error_code ret = 0;
487 :
488 227060 : if (id) {
489 227046 : ret = (id->close)(context, id);
490 227046 : memset(id, 0, sizeof(*id));
491 227046 : free(id);
492 : }
493 227060 : return ret;
494 : }
495 :
496 : /**
497 : * Destroy (remove) the keytab in `id'. All resources will be released,
498 : * even on errors, does the equvalment of krb5_kt_close() on the resources.
499 : *
500 : * @param context a Keberos context.
501 : * @param id keytab to destroy.
502 : *
503 : * @return Return an error code or 0, see krb5_get_error_message().
504 : *
505 : * @ingroup krb5_keytab
506 : */
507 :
508 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
509 0 : krb5_kt_destroy(krb5_context context,
510 : krb5_keytab id)
511 : {
512 0 : krb5_error_code ret;
513 :
514 0 : ret = (*id->destroy)(context, id);
515 0 : krb5_kt_close(context, id);
516 0 : return ret;
517 : }
518 :
519 : /*
520 : * Match any aliases in keytab `entry' with `principal'.
521 : */
522 :
523 : static krb5_boolean
524 151329 : compare_aliases(krb5_context context,
525 : krb5_keytab_entry *entry,
526 : krb5_const_principal principal)
527 : {
528 3371 : unsigned int i;
529 151329 : if (entry->aliases == NULL)
530 147958 : return FALSE;
531 0 : for (i = 0; i < entry->aliases->len; i++)
532 0 : if (krb5_principal_compare(context, &entry->aliases->val[i], principal))
533 0 : return TRUE;
534 0 : return FALSE;
535 : }
536 :
537 : /**
538 : * Compare `entry' against `principal, vno, enctype'.
539 : * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
540 : * Return TRUE if they compare the same, FALSE otherwise.
541 : *
542 : * @param context a Keberos context.
543 : * @param entry an entry to match with.
544 : * @param principal principal to match, NULL matches all principals.
545 : * @param vno key version to match, 0 matches all key version numbers.
546 : * @param enctype encryption type to match, 0 matches all encryption types.
547 : *
548 : * @return Return TRUE or match, FALSE if not matched.
549 : *
550 : * @ingroup krb5_keytab
551 : */
552 :
553 : KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
554 218360 : krb5_kt_compare(krb5_context context,
555 : krb5_keytab_entry *entry,
556 : krb5_const_principal principal,
557 : krb5_kvno vno,
558 : krb5_enctype enctype)
559 : {
560 : /* krb5_principal_compare() does not special-case the referral realm */
561 218360 : if (principal != NULL && strcmp(principal->realm, "") == 0 &&
562 0 : !(krb5_principal_compare_any_realm(context, entry->principal, principal) ||
563 0 : compare_aliases(context, entry, principal))) {
564 0 : return FALSE;
565 436720 : } else if (principal != NULL && strcmp(principal->realm, "") != 0 &&
566 369689 : !(krb5_principal_compare(context, entry->principal, principal) ||
567 151329 : compare_aliases(context, entry, principal))) {
568 147958 : return FALSE;
569 : }
570 67031 : if (vno && vno != entry->vno)
571 1044 : return FALSE;
572 65830 : if (enctype && enctype != entry->keyblock.keytype)
573 10253 : return FALSE;
574 54496 : return TRUE;
575 : }
576 :
577 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
578 903 : _krb5_kt_principal_not_found(krb5_context context,
579 : krb5_error_code ret,
580 : krb5_keytab id,
581 : krb5_const_principal principal,
582 : krb5_enctype enctype,
583 : int kvno)
584 : {
585 0 : char kvno_str[25];
586 903 : char *enctype_str = NULL;
587 903 : char *kt_name = NULL;
588 903 : char *princ = NULL;
589 :
590 903 : (void) krb5_unparse_name(context, principal, &princ);
591 903 : (void) krb5_kt_get_full_name(context, id, &kt_name);
592 903 : if (enctype)
593 903 : (void) krb5_enctype_to_string(context, enctype, &enctype_str);
594 :
595 903 : if (kvno)
596 903 : snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
597 : else
598 0 : kvno_str[0] = '\0';
599 :
600 2709 : krb5_set_error_message(context, ret,
601 903 : N_("Failed to find %s%s in keytab %s (%s)",
602 : "principal, kvno, keytab file, enctype"),
603 903 : princ ? princ : "<unknown>",
604 : kvno_str,
605 903 : kt_name ? kt_name : "unknown keytab",
606 903 : enctype_str ? enctype_str : "unknown enctype");
607 903 : free(princ);
608 903 : free(kt_name);
609 903 : free(enctype_str);
610 903 : return ret;
611 : }
612 :
613 : static krb5_error_code
614 53483 : krb5_kt_get_entry_wrapped(krb5_context context,
615 : krb5_keytab id,
616 : krb5_const_principal principal,
617 : krb5_kvno kvno,
618 : krb5_enctype enctype,
619 : krb5_keytab_entry *entry)
620 : {
621 881 : krb5_keytab_entry tmp;
622 881 : krb5_error_code ret;
623 881 : krb5_kt_cursor cursor;
624 :
625 53483 : if(id->get)
626 68 : return (*id->get)(context, id, principal, kvno, enctype, entry);
627 :
628 53415 : memset(&tmp, 0, sizeof(tmp));
629 53415 : ret = krb5_kt_start_seq_get (context, id, &cursor);
630 53415 : if (ret) {
631 : /* This is needed for krb5_verify_init_creds, but keep error
632 : * string from previous error for the human. */
633 0 : context->error_code = KRB5_KT_NOTFOUND;
634 0 : return KRB5_KT_NOTFOUND;
635 : }
636 :
637 53415 : entry->vno = 0;
638 185118 : while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
639 184201 : if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
640 : /* the file keytab might only store the lower 8 bits of
641 : the kvno, so only compare those bits */
642 52616 : if (kvno == tmp.vno
643 118 : || (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
644 52498 : krb5_kt_copy_entry_contents (context, &tmp, entry);
645 52498 : krb5_kt_free_entry (context, &tmp);
646 52498 : krb5_kt_end_seq_get(context, id, &cursor);
647 52498 : return 0;
648 118 : } else if (kvno == 0 && tmp.vno > entry->vno) {
649 14 : if (entry->vno)
650 0 : krb5_kt_free_entry (context, entry);
651 14 : krb5_kt_copy_entry_contents (context, &tmp, entry);
652 : }
653 : }
654 131703 : krb5_kt_free_entry(context, &tmp);
655 : }
656 917 : krb5_kt_end_seq_get (context, id, &cursor);
657 917 : if (entry->vno == 0)
658 903 : return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
659 : id, principal, enctype, kvno);
660 14 : return 0;
661 : }
662 :
663 : /**
664 : * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
665 : * from the keytab `id'. Matching is done like krb5_kt_compare().
666 : *
667 : * @param context a Keberos context.
668 : * @param id a keytab.
669 : * @param principal principal to match, NULL matches all principals.
670 : * @param kvno key version to match, 0 matches all key version numbers.
671 : * @param enctype encryption type to match, 0 matches all encryption types.
672 : * @param entry the returned entry, free with krb5_kt_free_entry().
673 : *
674 : * @return Return an error code or 0, see krb5_get_error_message().
675 : *
676 : * @ingroup krb5_keytab
677 : */
678 :
679 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
680 53483 : krb5_kt_get_entry(krb5_context context,
681 : krb5_keytab id,
682 : krb5_const_principal principal,
683 : krb5_kvno kvno,
684 : krb5_enctype enctype,
685 : krb5_keytab_entry *entry)
686 : {
687 881 : krb5_error_code ret;
688 881 : krb5_const_principal try_princ;
689 881 : krb5_name_canon_iterator name_canon_iter;
690 :
691 53483 : if (!principal)
692 : /* Use `NULL' instead of `principal' to quiet static analizers */
693 0 : return krb5_kt_get_entry_wrapped(context, id, NULL, kvno, enctype,
694 : entry);
695 :
696 53483 : ret = krb5_name_canon_iterator_start(context, principal, &name_canon_iter);
697 53483 : if (ret)
698 0 : return ret;
699 :
700 881 : do {
701 54390 : ret = krb5_name_canon_iterate(context, &name_canon_iter, &try_princ,
702 : NULL);
703 54390 : if (ret)
704 0 : break;
705 54390 : if (try_princ == NULL) {
706 907 : ret = KRB5_KT_NOTFOUND;
707 907 : continue;
708 : }
709 53483 : ret = krb5_kt_get_entry_wrapped(context, id, try_princ, kvno,
710 : enctype, entry);
711 54390 : } while (ret == KRB5_KT_NOTFOUND && name_canon_iter);
712 :
713 53483 : if (ret && ret != KRB5_KT_NOTFOUND)
714 0 : krb5_set_error_message(context, ret,
715 0 : N_("Name canon failed while searching keytab",
716 : ""));
717 53483 : krb5_free_name_canon_iterator(context, name_canon_iter);
718 53483 : return ret;
719 : }
720 :
721 : /**
722 : * Copy the contents of `in' into `out'.
723 : *
724 : * @param context a Keberos context.
725 : * @param in the keytab entry to copy.
726 : * @param out the copy of the keytab entry, free with krb5_kt_free_entry().
727 : *
728 : * @return Return an error code or 0, see krb5_get_error_message().
729 : *
730 : * @ingroup krb5_keytab
731 : */
732 :
733 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
734 75617 : krb5_kt_copy_entry_contents(krb5_context context,
735 : const krb5_keytab_entry *in,
736 : krb5_keytab_entry *out)
737 : {
738 983 : krb5_error_code ret;
739 :
740 75617 : memset(out, 0, sizeof(*out));
741 :
742 75617 : ret = krb5_copy_principal (context, in->principal, &out->principal);
743 75617 : if (ret)
744 0 : return ret;
745 75617 : ret = krb5_copy_keyblock_contents (context,
746 : &in->keyblock,
747 : &out->keyblock);
748 75617 : if (ret) {
749 0 : krb5_free_principal(context, out->principal);
750 0 : memset(out, 0, sizeof(*out));
751 0 : return ret;
752 : }
753 75617 : out->vno = in->vno;
754 75617 : out->timestamp = in->timestamp;
755 75617 : return 0;
756 : }
757 :
758 : /**
759 : * Free the contents of `entry'.
760 : *
761 : * @param context a Keberos context.
762 : * @param entry the entry to free
763 : *
764 : * @return Return an error code or 0, see krb5_get_error_message().
765 : *
766 : * @ingroup krb5_keytab
767 : */
768 :
769 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
770 287522 : krb5_kt_free_entry(krb5_context context,
771 : krb5_keytab_entry *entry)
772 : {
773 287522 : krb5_free_principal (context, entry->principal);
774 287522 : krb5_free_keyblock_contents (context, &entry->keyblock);
775 287522 : memset(entry, 0, sizeof(*entry));
776 287522 : return 0;
777 : }
778 :
779 : /**
780 : * Set `cursor' to point at the beginning of `id'.
781 : *
782 : * @param context a Keberos context.
783 : * @param id a keytab.
784 : * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get().
785 : *
786 : * @return Return an error code or 0, see krb5_get_error_message().
787 : *
788 : * @ingroup krb5_keytab
789 : */
790 :
791 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
792 60314 : krb5_kt_start_seq_get(krb5_context context,
793 : krb5_keytab id,
794 : krb5_kt_cursor *cursor)
795 : {
796 60314 : if(id->start_seq_get == NULL) {
797 0 : krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
798 0 : N_("start_seq_get is not supported "
799 : "in the %s keytab type", ""),
800 : id->prefix);
801 0 : return HEIM_ERR_OPNOTSUPP;
802 : }
803 60314 : return (*id->start_seq_get)(context, id, cursor);
804 : }
805 :
806 : /**
807 : * Get the next entry from keytab, advance the cursor. On last entry
808 : * the function will return KRB5_KT_END.
809 : *
810 : * @param context a Keberos context.
811 : * @param id a keytab.
812 : * @param entry the returned entry, free with krb5_kt_free_entry().
813 : * @param cursor the cursor of the iteration.
814 : *
815 : * @return Return an error code or 0, see krb5_get_error_message().
816 : *
817 : * @ingroup krb5_keytab
818 : */
819 :
820 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
821 216569 : krb5_kt_next_entry(krb5_context context,
822 : krb5_keytab id,
823 : krb5_keytab_entry *entry,
824 : krb5_kt_cursor *cursor)
825 : {
826 216569 : if(id->next_entry == NULL) {
827 0 : krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
828 0 : N_("next_entry is not supported in the %s "
829 : " keytab", ""),
830 : id->prefix);
831 0 : return HEIM_ERR_OPNOTSUPP;
832 : }
833 216569 : memset(entry, 0x0, sizeof(*entry));
834 216569 : return (*id->next_entry)(context, id, entry, cursor);
835 : }
836 :
837 : /**
838 : * Release all resources associated with `cursor'.
839 : *
840 : * @param context a Keberos context.
841 : * @param id a keytab.
842 : * @param cursor the cursor to free.
843 : *
844 : * @return Return an error code or 0, see krb5_get_error_message().
845 : *
846 : * @ingroup krb5_keytab
847 : */
848 :
849 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
850 60460 : krb5_kt_end_seq_get(krb5_context context,
851 : krb5_keytab id,
852 : krb5_kt_cursor *cursor)
853 : {
854 60460 : if(id->end_seq_get == NULL) {
855 0 : krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
856 : "end_seq_get is not supported in the %s "
857 : " keytab", id->prefix);
858 0 : return HEIM_ERR_OPNOTSUPP;
859 : }
860 60460 : return (*id->end_seq_get)(context, id, cursor);
861 : }
862 :
863 : /**
864 : * Add the entry in `entry' to the keytab `id'.
865 : *
866 : * @param context a Keberos context.
867 : * @param id a keytab.
868 : * @param entry the entry to add
869 : *
870 : * @return Return an error code or 0, see krb5_get_error_message().
871 : *
872 : * @ingroup krb5_keytab
873 : */
874 :
875 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
876 18233 : krb5_kt_add_entry(krb5_context context,
877 : krb5_keytab id,
878 : krb5_keytab_entry *entry)
879 : {
880 18233 : if(id->add == NULL) {
881 0 : krb5_set_error_message(context, KRB5_KT_NOWRITE,
882 0 : N_("Add is not supported in the %s keytab", ""),
883 : id->prefix);
884 0 : return KRB5_KT_NOWRITE;
885 : }
886 18233 : if (entry->timestamp == 0)
887 16893 : entry->timestamp = time(NULL);
888 18233 : return (*id->add)(context, id,entry);
889 : }
890 :
891 : /**
892 : * Remove an entry from the keytab, matching is done using
893 : * krb5_kt_compare().
894 :
895 : * @param context a Keberos context.
896 : * @param id a keytab.
897 : * @param entry the entry to remove
898 : *
899 : * @return Return an error code or 0, see krb5_get_error_message().
900 : *
901 : * @ingroup krb5_keytab
902 : */
903 :
904 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
905 525 : krb5_kt_remove_entry(krb5_context context,
906 : krb5_keytab id,
907 : krb5_keytab_entry *entry)
908 : {
909 525 : if(id->remove == NULL) {
910 0 : krb5_set_error_message(context, KRB5_KT_NOWRITE,
911 0 : N_("Remove is not supported in the %s keytab", ""),
912 : id->prefix);
913 0 : return KRB5_KT_NOWRITE;
914 : }
915 525 : return (*id->remove)(context, id, entry);
916 : }
917 :
918 : /**
919 : * Return true if the keytab exists and have entries
920 : *
921 : * @param context a Keberos context.
922 : * @param id a keytab.
923 : *
924 : * @return Return an error code or 0, see krb5_get_error_message().
925 : *
926 : * @ingroup krb5_keytab
927 : */
928 :
929 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
930 0 : krb5_kt_have_content(krb5_context context,
931 : krb5_keytab id)
932 : {
933 0 : krb5_keytab_entry entry;
934 0 : krb5_kt_cursor cursor;
935 0 : krb5_error_code ret;
936 0 : char *name;
937 :
938 0 : memset(&entry, 0, sizeof(entry));
939 0 : ret = krb5_kt_start_seq_get(context, id, &cursor);
940 0 : if (ret)
941 0 : goto notfound;
942 :
943 0 : ret = krb5_kt_next_entry(context, id, &entry, &cursor);
944 0 : krb5_kt_end_seq_get(context, id, &cursor);
945 0 : if (ret)
946 0 : goto notfound;
947 :
948 0 : krb5_kt_free_entry(context, &entry);
949 :
950 0 : return 0;
951 :
952 0 : notfound:
953 0 : ret = krb5_kt_get_full_name(context, id, &name);
954 0 : if (ret == 0) {
955 0 : krb5_set_error_message(context, KRB5_KT_NOTFOUND,
956 0 : N_("No entry in keytab: %s", ""), name);
957 0 : free(name);
958 : }
959 0 : return KRB5_KT_NOTFOUND;
960 : }
961 :
962 : KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
963 0 : _krb5_kt_client_default_name(krb5_context context, char **name)
964 : {
965 0 : const char *tmp;
966 :
967 0 : tmp = secure_getenv("KRB5_CLIENT_KTNAME");
968 0 : if (tmp == NULL)
969 0 : tmp = krb5_config_get_string(context, NULL,
970 : "libdefaults",
971 : "default_client_keytab_name", NULL);
972 0 : if (tmp == NULL)
973 0 : tmp = CLIENT_KEYTAB_DEFAULT;
974 :
975 0 : return _krb5_expand_path_tokens(context, tmp, 1, name);
976 : }
|