1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * Copyright 2006, 2009, 2010, 2016 by the Massachusetts Institute of
4 * Technology.
5 * All Rights Reserved.
6 *
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
11 *
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
25 */
26
27 /*
28 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
29 * Use is subject to license terms.
30 */
31
32 /*
33 * This code was based on code donated to MIT by Novell for
34 * distribution under the MIT license.
35 */
36
37 /*
38 * Include files
39 */
40
41 #include <k5-int.h>
42 #include "kdb5.h"
43 #include "kdb_log.h"
44 #include "kdb5int.h"
45
46 /* Currently DB2 policy related errors are exported from DAL. But
47 other databases should set_err function to return string. */
48 #include "adb_err.h"
49
50 /*
51 * internal static variable
52 */
53
54 static k5_mutex_t db_lock = K5_MUTEX_PARTIAL_INITIALIZER;
55
56 static db_library lib_list;
57
58 /*
59 * Helper Functions
60 */
61
62 MAKE_INIT_FUNCTION(kdb_init_lock_list);
63 MAKE_FINI_FUNCTION(kdb_fini_lock_list);
64
65 static void
free_mkey_list(krb5_context context,krb5_keylist_node * mkey_list)66 free_mkey_list(krb5_context context, krb5_keylist_node *mkey_list)
67 {
68 krb5_keylist_node *cur, *next;
69
70 for (cur = mkey_list; cur != NULL; cur = next) {
71 next = cur->next;
72 krb5_free_keyblock_contents(context, &cur->keyblock);
73 free(cur);
74 }
75 }
76
77 int
kdb_init_lock_list(void)78 kdb_init_lock_list(void)
79 {
80 return k5_mutex_finish_init(&db_lock);
81 }
82
83 static int
kdb_lock_list(void)84 kdb_lock_list(void)
85 {
86 int err;
87 err = CALL_INIT_FUNCTION (kdb_init_lock_list);
88 if (err)
89 return err;
90 k5_mutex_lock(&db_lock);
91 return 0;
92 }
93
94 void
kdb_fini_lock_list(void)95 kdb_fini_lock_list(void)
96 {
97 if (INITIALIZER_RAN(kdb_init_lock_list))
98 k5_mutex_destroy(&db_lock);
99 }
100
101 static void
kdb_unlock_list(void)102 kdb_unlock_list(void)
103 {
104 k5_mutex_unlock(&db_lock);
105 }
106
107 /* Return true if the ulog is mapped in the primary role. */
108 static inline krb5_boolean
logging(krb5_context context)109 logging(krb5_context context)
110 {
111 kdb_log_context *log_ctx = context->kdblog_context;
112
113 return log_ctx != NULL && log_ctx->iproprole == IPROP_PRIMARY &&
114 log_ctx->ulog != NULL;
115 }
116
117 void
krb5_dbe_free_key_data_contents(krb5_context context,krb5_key_data * key)118 krb5_dbe_free_key_data_contents(krb5_context context, krb5_key_data *key)
119 {
120 int i, idx;
121
122 if (key) {
123 idx = (key->key_data_ver == 1 ? 1 : 2);
124 for (i = 0; i < idx; i++) {
125 if (key->key_data_contents[i]) {
126 zap(key->key_data_contents[i], key->key_data_length[i]);
127 free(key->key_data_contents[i]);
128 }
129 }
130 }
131 return;
132 }
133
134 void
krb5_dbe_free_key_list(krb5_context context,krb5_keylist_node * val)135 krb5_dbe_free_key_list(krb5_context context, krb5_keylist_node *val)
136 {
137 krb5_keylist_node *temp = val, *prev;
138
139 while (temp != NULL) {
140 prev = temp;
141 temp = temp->next;
142 krb5_free_keyblock_contents(context, &(prev->keyblock));
143 free(prev);
144 }
145 }
146
147 void
krb5_dbe_free_actkvno_list(krb5_context context,krb5_actkvno_node * val)148 krb5_dbe_free_actkvno_list(krb5_context context, krb5_actkvno_node *val)
149 {
150 krb5_actkvno_node *temp = val, *prev;
151
152 while (temp != NULL) {
153 prev = temp;
154 temp = temp->next;
155 free(prev);
156 }
157 }
158
159 void
krb5_dbe_free_mkey_aux_list(krb5_context context,krb5_mkey_aux_node * val)160 krb5_dbe_free_mkey_aux_list(krb5_context context, krb5_mkey_aux_node *val)
161 {
162 krb5_mkey_aux_node *temp = val, *prev;
163
164 while (temp != NULL) {
165 prev = temp;
166 temp = temp->next;
167 krb5_dbe_free_key_data_contents(context, &prev->latest_mkey);
168 free(prev);
169 }
170 }
171
172 void
krb5_dbe_free_tl_data(krb5_context context,krb5_tl_data * tl_data)173 krb5_dbe_free_tl_data(krb5_context context, krb5_tl_data *tl_data)
174 {
175 if (tl_data) {
176 if (tl_data->tl_data_contents)
177 free(tl_data->tl_data_contents);
178 free(tl_data);
179 }
180 }
181
182 void
krb5_dbe_free_strings(krb5_context context,krb5_string_attr * strings,int count)183 krb5_dbe_free_strings(krb5_context context, krb5_string_attr *strings,
184 int count)
185 {
186 int i;
187
188 if (strings == NULL)
189 return;
190 for (i = 0; i < count; i++) {
191 free(strings[i].key);
192 free(strings[i].value);
193 }
194 free(strings);
195 }
196
197 void
krb5_dbe_free_string(krb5_context context,char * string)198 krb5_dbe_free_string(krb5_context context, char *string)
199 {
200 free(string);
201 }
202
203 /* Set *section to the appropriate section to use for a database module's
204 * profile queries. The caller must free the result. */
205 static krb5_error_code
get_conf_section(krb5_context context,char ** section)206 get_conf_section(krb5_context context, char **section)
207 {
208 krb5_error_code status;
209 char *result = NULL, *value = NULL, *defrealm;
210
211 *section = NULL;
212
213 status = krb5_get_default_realm(context, &defrealm);
214 if (status) {
215 k5_setmsg(context, KRB5_KDB_SERVER_INTERNAL_ERR,
216 _("No default realm set; cannot initialize KDB"));
217 return KRB5_KDB_SERVER_INTERNAL_ERR;
218 }
219 status = profile_get_string(context->profile,
220 /* realms */
221 KDB_REALM_SECTION,
222 defrealm,
223 /* under the realm name, database_module */
224 KDB_MODULE_POINTER,
225 /* default value is the realm name itself */
226 defrealm,
227 &value);
228 krb5_free_default_realm(context, defrealm);
229 if (status)
230 return status;
231 result = strdup(value);
232 profile_release_string(value);
233 if (result == NULL)
234 return ENOMEM;
235 *section = result;
236 return 0;
237 }
238
239 static krb5_error_code
kdb_get_library_name(krb5_context kcontext,char ** libname_out)240 kdb_get_library_name(krb5_context kcontext, char **libname_out)
241 {
242 krb5_error_code status = 0;
243 char *value = NULL, *lib = NULL, *defrealm = NULL;
244
245 *libname_out = NULL;
246
247 status = krb5_get_default_realm(kcontext, &defrealm);
248 if (status)
249 goto clean_n_exit;
250 status = profile_get_string(kcontext->profile,
251 /* realms */
252 KDB_REALM_SECTION,
253 defrealm,
254 /* under the realm name, database_module */
255 KDB_MODULE_POINTER,
256 /* default value is the realm name itself */
257 defrealm,
258 &value);
259 if (status)
260 goto clean_n_exit;
261
262 #define DB2_NAME "db2"
263 /* we got the module section. Get the library name from the module */
264 status = profile_get_string(kcontext->profile, KDB_MODULE_SECTION, value,
265 KDB_LIB_POINTER,
266 /* default to db2 */
267 DB2_NAME,
268 &lib);
269
270 if (status) {
271 goto clean_n_exit;
272 }
273
274 *libname_out = strdup(lib);
275 if (*libname_out == NULL)
276 status = ENOMEM;
277
278 clean_n_exit:
279 krb5_free_default_realm(kcontext, defrealm);
280 profile_release_string(value);
281 profile_release_string(lib);
282 return status;
283 }
284
285 static void
copy_vtable(const kdb_vftabl * in,kdb_vftabl * out)286 copy_vtable(const kdb_vftabl *in, kdb_vftabl *out)
287 {
288 /* Copy fields for minor version 0. */
289 out->maj_ver = in->maj_ver;
290 out->min_ver = in->min_ver;
291 out->init_library = in->init_library;
292 out->fini_library = in->fini_library;
293 out->init_module = in->init_module;
294 out->fini_module = in->fini_module;
295 out->create = in->create;
296 out->destroy = in->destroy;
297 out->get_age = in->get_age;
298 out->lock = in->lock;
299 out->unlock = in->unlock;
300 out->get_principal = in->get_principal;
301 out->put_principal = in->put_principal;
302 out->delete_principal = in->delete_principal;
303 out->rename_principal = in->rename_principal;
304 out->iterate = in->iterate;
305 out->create_policy = in->create_policy;
306 out->get_policy = in->get_policy;
307 out->put_policy = in->put_policy;
308 out->iter_policy = in->iter_policy;
309 out->delete_policy = in->delete_policy;
310 out->fetch_master_key = in->fetch_master_key;
311 out->fetch_master_key_list = in->fetch_master_key_list;
312 out->store_master_key_list = in->store_master_key_list;
313 out->dbe_search_enctype = in->dbe_search_enctype;
314 out->change_pwd = in->change_pwd;
315 out->promote_db = in->promote_db;
316 out->decrypt_key_data = in->decrypt_key_data;
317 out->encrypt_key_data = in->encrypt_key_data;
318 out->check_transited_realms = in->check_transited_realms;
319 out->check_policy_as = in->check_policy_as;
320 out->check_policy_tgs = in->check_policy_tgs;
321 out->audit_as_req = in->audit_as_req;
322 out->refresh_config = in->refresh_config;
323 out->check_allowed_to_delegate = in->check_allowed_to_delegate;
324 out->free_principal_e_data = in->free_principal_e_data;
325 out->get_s4u_x509_principal = in->get_s4u_x509_principal;
326 out->allowed_to_delegate_from = in->allowed_to_delegate_from;
327 out->issue_pac = in->issue_pac;
328
329 /* Set defaults for optional fields. */
330 if (out->fetch_master_key == NULL)
331 out->fetch_master_key = krb5_db_def_fetch_mkey;
332 if (out->fetch_master_key_list == NULL)
333 out->fetch_master_key_list = krb5_def_fetch_mkey_list;
334 if (out->store_master_key_list == NULL)
335 out->store_master_key_list = krb5_def_store_mkey_list;
336 if (out->dbe_search_enctype == NULL)
337 out->dbe_search_enctype = krb5_dbe_def_search_enctype;
338 if (out->change_pwd == NULL)
339 out->change_pwd = krb5_dbe_def_cpw;
340 if (out->decrypt_key_data == NULL)
341 out->decrypt_key_data = krb5_dbe_def_decrypt_key_data;
342 if (out->encrypt_key_data == NULL)
343 out->encrypt_key_data = krb5_dbe_def_encrypt_key_data;
344 if (out->rename_principal == NULL)
345 out->rename_principal = krb5_db_def_rename_principal;
346 }
347
348 #ifdef STATIC_PLUGINS
349
350 extern kdb_vftabl krb5_db2_kdb_function_table;
351 #ifdef ENABLE_LDAP
352 extern kdb_vftabl krb5_ldap_kdb_function_table;
353 #endif
354
355 static krb5_error_code
load_library(krb5_context kcontext,const char * lib_name,db_library * libptr)356 load_library(krb5_context kcontext, const char *lib_name, db_library *libptr)
357 {
358 krb5_error_code status;
359 db_library lib;
360 kdb_vftabl *vftabl_addr = NULL;
361
362 if (strcmp(lib_name, "db2") == 0)
363 vftabl_addr = &krb5_db2_kdb_function_table;
364 #ifdef ENABLE_LDAP
365 if (strcmp(lib_name, "kldap") == 0)
366 vftabl_addr = &krb5_ldap_kdb_function_table;
367 #endif
368 if (!vftabl_addr) {
369 k5_setmsg(kcontext, KRB5_KDB_DBTYPE_NOTFOUND,
370 _("Unable to find requested database type: %s"), lib_name);
371 return KRB5_PLUGIN_OP_NOTSUPP;
372 }
373
374 lib = calloc(1, sizeof(*lib));
375 if (lib == NULL)
376 return ENOMEM;
377
378 strlcpy(lib->name, lib_name, sizeof(lib->name));
379 copy_vtable(vftabl_addr, &lib->vftabl);
380
381 status = lib->vftabl.init_library();
382 if (status)
383 goto cleanup;
384
385 *libptr = lib;
386 return 0;
387
388 cleanup:
389 free(lib);
390 return status;
391 }
392
393 #else /* KDB5_STATIC_LINK*/
394
395 static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH;
396 #define db_dl_n_locations (sizeof(db_dl_location) / sizeof(db_dl_location[0]))
397
398 static krb5_error_code
load_library(krb5_context kcontext,const char * lib_name,db_library * lib)399 load_library(krb5_context kcontext, const char *lib_name, db_library *lib)
400 {
401 krb5_error_code status = 0;
402 int ndx;
403 void **vftabl_addrs = NULL;
404 /* N.B.: If this is "const" but not "static", the Solaris 10
405 native compiler has trouble building the library because of
406 absolute relocations needed in read-only section ".rodata".
407 When it's static, it goes into ".picdata", which is
408 read-write. */
409 static const char *const dbpath_names[] = {
410 KDB_MODULE_SECTION, KRB5_CONF_DB_MODULE_DIR, NULL,
411 };
412 const char *filebases[2];
413 char **profpath = NULL;
414 char **path = NULL;
415
416 filebases[0] = lib_name;
417 filebases[1] = NULL;
418
419 *lib = calloc((size_t) 1, sizeof(**lib));
420 if (*lib == NULL)
421 return ENOMEM;
422
423 strlcpy((*lib)->name, lib_name, sizeof((*lib)->name));
424
425 /* Fetch the list of directories specified in the config
426 file(s) first. */
427 status = profile_get_values(kcontext->profile, dbpath_names, &profpath);
428 if (status != 0 && status != PROF_NO_RELATION)
429 goto clean_n_exit;
430 ndx = 0;
431 if (profpath)
432 while (profpath[ndx] != NULL)
433 ndx++;
434
435 path = calloc(ndx + db_dl_n_locations, sizeof (char *));
436 if (path == NULL) {
437 status = ENOMEM;
438 goto clean_n_exit;
439 }
440 if (ndx)
441 memcpy(path, profpath, ndx * sizeof(profpath[0]));
442 memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *));
443 status = 0;
444
445 if ((status = krb5int_open_plugin_dirs ((const char **) path,
446 filebases,
447 &(*lib)->dl_dir_handle, &kcontext->err))) {
448 status = KRB5_KDB_DBTYPE_NOTFOUND;
449 k5_prependmsg(kcontext, status,
450 _("Unable to find requested database type"));
451 goto clean_n_exit;
452 }
453
454 if ((status = krb5int_get_plugin_dir_data (&(*lib)->dl_dir_handle, "kdb_function_table",
455 &vftabl_addrs, &kcontext->err))) {
456 status = KRB5_KDB_DBTYPE_INIT;
457 k5_prependmsg(kcontext, status,
458 _("plugin symbol 'kdb_function_table' lookup failed"));
459 goto clean_n_exit;
460 }
461
462 if (vftabl_addrs[0] == NULL) {
463 /* No plugins! */
464 status = KRB5_KDB_DBTYPE_NOTFOUND;
465 k5_setmsg(kcontext, status,
466 _("Unable to load requested database module '%s': plugin "
467 "symbol 'kdb_function_table' not found"), lib_name);
468 goto clean_n_exit;
469 }
470
471 if (((kdb_vftabl *)vftabl_addrs[0])->maj_ver !=
472 KRB5_KDB_DAL_MAJOR_VERSION) {
473 status = KRB5_KDB_DBTYPE_MISMATCH;
474 goto clean_n_exit;
475 }
476
477 copy_vtable(vftabl_addrs[0], &(*lib)->vftabl);
478
479 if ((status = (*lib)->vftabl.init_library()))
480 goto clean_n_exit;
481
482 clean_n_exit:
483 krb5int_free_plugin_dir_data(vftabl_addrs);
484 /* Both of these DTRT with NULL. */
485 profile_free_list(profpath);
486 free(path);
487 if (status && *lib) {
488 if (PLUGIN_DIR_OPEN((&(*lib)->dl_dir_handle)))
489 krb5int_close_plugin_dirs (&(*lib)->dl_dir_handle);
490 free(*lib);
491 *lib = NULL;
492 }
493 return status;
494 }
495
496 #endif /* end of _KDB5_STATIC_LINK */
497
498 static krb5_error_code
find_library(krb5_context kcontext,const char * lib_name,db_library * lib)499 find_library(krb5_context kcontext, const char *lib_name, db_library *lib)
500 {
501 /* lock here so that no two threads try to do the same at the same time */
502 krb5_error_code status = 0;
503 int locked = 0;
504 db_library curr_elt, prev_elt = NULL;
505 static int kdb_db2_pol_err_loaded = 0;
506
507 if (!strcmp(DB2_NAME, lib_name) && (kdb_db2_pol_err_loaded == 0)) {
508 initialize_adb_error_table();
509 kdb_db2_pol_err_loaded = 1;
510 }
511
512 if ((status = kdb_lock_list()) != 0)
513 goto clean_n_exit;
514 locked = 1;
515
516 curr_elt = lib_list;
517 while (curr_elt != NULL) {
518 if (strcmp(lib_name, curr_elt->name) == 0) {
519 *lib = curr_elt;
520 goto clean_n_exit;
521 }
522 prev_elt = curr_elt;
523 curr_elt = curr_elt->next;
524 }
525
526 /* module not found. create and add to list */
527 status = load_library(kcontext, lib_name, lib);
528 if (status)
529 goto clean_n_exit;
530
531 if (prev_elt) {
532 /* prev_elt points to the last element in the list */
533 prev_elt->next = *lib;
534 (*lib)->prev = prev_elt;
535 } else {
536 lib_list = *lib;
537 }
538
539 clean_n_exit:
540 if (*lib)
541 (*lib)->reference_cnt++;
542
543 if (locked)
544 kdb_unlock_list();
545
546 return status;
547 }
548
549 static krb5_error_code
kdb_free_library(db_library lib)550 kdb_free_library(db_library lib)
551 {
552 krb5_error_code status = 0;
553 int locked = 0;
554
555 if ((status = kdb_lock_list()) != 0)
556 goto clean_n_exit;
557 locked = 1;
558
559 lib->reference_cnt--;
560
561 if (lib->reference_cnt == 0) {
562 status = lib->vftabl.fini_library();
563 if (status)
564 goto clean_n_exit;
565
566 /* close the library */
567 if (PLUGIN_DIR_OPEN((&lib->dl_dir_handle)))
568 krb5int_close_plugin_dirs (&lib->dl_dir_handle);
569
570 if (lib->prev == NULL)
571 lib_list = lib->next; /* first element in the list */
572 else
573 lib->prev->next = lib->next;
574
575 if (lib->next)
576 lib->next->prev = lib->prev;
577 free(lib);
578 }
579
580 clean_n_exit:
581 if (locked)
582 kdb_unlock_list();
583
584 return status;
585 }
586
587 krb5_error_code
krb5_db_load_module(krb5_context kcontext,const char * name)588 krb5_db_load_module(krb5_context kcontext, const char *name)
589 {
590 krb5_error_code ret;
591 db_library lib = NULL;
592 kdb5_dal_handle *dal_handle = NULL;
593
594 if (name == NULL)
595 return EINVAL;
596 if (kcontext->dal_handle != NULL)
597 return EEXIST;
598
599 dal_handle = k5alloc(sizeof(*dal_handle), &ret);
600 if (dal_handle == NULL)
601 goto cleanup;
602
603 ret = find_library(kcontext, name, &lib);
604 if (ret)
605 goto cleanup;
606
607 dal_handle->lib_handle = lib;
608 kcontext->dal_handle = dal_handle;
609 lib = NULL;
610 dal_handle = NULL;
611
612 cleanup:
613 free(dal_handle);
614 if (lib != NULL)
615 kdb_free_library(lib);
616 return ret;
617 }
618
619 krb5_error_code
krb5_db_setup_lib_handle(krb5_context kcontext)620 krb5_db_setup_lib_handle(krb5_context kcontext)
621 {
622 char *library = NULL;
623 krb5_error_code ret;
624
625 ret = kdb_get_library_name(kcontext, &library);
626 if (library == NULL) {
627 k5_prependmsg(kcontext, ret, _("Cannot initialize database library"));
628 return ret;
629 }
630
631 ret = krb5_db_load_module(kcontext, library);
632 free(library);
633 return ret;
634 }
635
636 static krb5_error_code
kdb_free_lib_handle(krb5_context kcontext)637 kdb_free_lib_handle(krb5_context kcontext)
638 {
639 krb5_error_code status = 0;
640
641 status = kdb_free_library(kcontext->dal_handle->lib_handle);
642 if (status)
643 return status;
644
645 free_mkey_list(kcontext, kcontext->dal_handle->master_keylist);
646 krb5_free_principal(kcontext, kcontext->dal_handle->master_princ);
647 free(kcontext->dal_handle);
648 kcontext->dal_handle = NULL;
649 return 0;
650 }
651
652 static krb5_error_code
get_vftabl(krb5_context kcontext,kdb_vftabl ** vftabl_ptr)653 get_vftabl(krb5_context kcontext, kdb_vftabl **vftabl_ptr)
654 {
655 krb5_error_code status;
656
657 *vftabl_ptr = NULL;
658 if (kcontext->dal_handle == NULL) {
659 status = krb5_db_setup_lib_handle(kcontext);
660 if (status)
661 return status;
662 }
663 *vftabl_ptr = &kcontext->dal_handle->lib_handle->vftabl;
664 return 0;
665 }
666
667 /*
668 * External functions... DAL API
669 */
670 krb5_error_code
krb5_db_open(krb5_context kcontext,char ** db_args,int mode)671 krb5_db_open(krb5_context kcontext, char **db_args, int mode)
672 {
673 krb5_error_code status;
674 char *section;
675 kdb_vftabl *v;
676
677 status = get_vftabl(kcontext, &v);
678 if (status)
679 return status;
680 status = get_conf_section(kcontext, §ion);
681 if (status)
682 return status;
683 status = v->init_module(kcontext, section, db_args, mode);
684 free(section);
685 if (status)
686 (void)krb5_db_fini(kcontext);
687 return status;
688 }
689
690 krb5_error_code
krb5_db_inited(krb5_context kcontext)691 krb5_db_inited(krb5_context kcontext)
692 {
693 return !(kcontext && kcontext->dal_handle &&
694 kcontext->dal_handle->db_context);
695 }
696
697 krb5_error_code
krb5_db_create(krb5_context kcontext,char ** db_args)698 krb5_db_create(krb5_context kcontext, char **db_args)
699 {
700 krb5_error_code status;
701 char *section;
702 kdb_vftabl *v;
703
704 status = get_vftabl(kcontext, &v);
705 if (status)
706 return status;
707 if (v->create == NULL)
708 return KRB5_PLUGIN_OP_NOTSUPP;
709 status = get_conf_section(kcontext, §ion);
710 if (status)
711 return status;
712 status = v->create(kcontext, section, db_args);
713 free(section);
714 if (status)
715 (void)krb5_db_fini(kcontext);
716 return status;
717 }
718
719 krb5_error_code
krb5_db_fini(krb5_context kcontext)720 krb5_db_fini(krb5_context kcontext)
721 {
722 krb5_error_code status = 0;
723 kdb_vftabl *v;
724
725 /* Do nothing if module was never loaded. */
726 if (kcontext->dal_handle == NULL)
727 return 0;
728
729 v = &kcontext->dal_handle->lib_handle->vftabl;
730 status = v->fini_module(kcontext);
731
732 if (status)
733 return status;
734
735 return kdb_free_lib_handle(kcontext);
736 }
737
738 krb5_error_code
krb5_db_destroy(krb5_context kcontext,char ** db_args)739 krb5_db_destroy(krb5_context kcontext, char **db_args)
740 {
741 krb5_error_code status;
742 char *section;
743 kdb_vftabl *v;
744
745 status = get_vftabl(kcontext, &v);
746 if (status)
747 return status;
748 if (v->destroy == NULL)
749 return KRB5_PLUGIN_OP_NOTSUPP;
750 status = get_conf_section(kcontext, §ion);
751 if (status)
752 return status;
753 status = v->destroy(kcontext, section, db_args);
754 free(section);
755 return status;
756 }
757
758 krb5_error_code
krb5_db_get_age(krb5_context kcontext,char * db_name,time_t * t)759 krb5_db_get_age(krb5_context kcontext, char *db_name, time_t *t)
760 {
761 krb5_error_code status = 0;
762 kdb_vftabl *v;
763
764 status = get_vftabl(kcontext, &v);
765 if (status)
766 return status;
767 if (v->get_age == NULL)
768 return KRB5_PLUGIN_OP_NOTSUPP;
769 return v->get_age(kcontext, db_name, t);
770 }
771
772 krb5_error_code
krb5_db_lock(krb5_context kcontext,int lock_mode)773 krb5_db_lock(krb5_context kcontext, int lock_mode)
774 {
775 krb5_error_code status = 0;
776 kdb_vftabl *v;
777
778 status = get_vftabl(kcontext, &v);
779 if (status)
780 return status;
781 if (v->lock == NULL)
782 return KRB5_PLUGIN_OP_NOTSUPP;
783 return v->lock(kcontext, lock_mode);
784 }
785
786 krb5_error_code
krb5_db_unlock(krb5_context kcontext)787 krb5_db_unlock(krb5_context kcontext)
788 {
789 krb5_error_code status = 0;
790 kdb_vftabl *v;
791
792 status = get_vftabl(kcontext, &v);
793 if (status)
794 return status;
795 if (v->unlock == NULL)
796 return KRB5_PLUGIN_OP_NOTSUPP;
797 return v->unlock(kcontext);
798 }
799
800 #define MAX_ALIAS_DEPTH 10
801
802 krb5_error_code
krb5_db_get_principal(krb5_context kcontext,krb5_const_principal search_for,unsigned int flags,krb5_db_entry ** entry_out)803 krb5_db_get_principal(krb5_context kcontext, krb5_const_principal search_for,
804 unsigned int flags, krb5_db_entry **entry_out)
805 {
806 krb5_error_code status = 0;
807 kdb_vftabl *v;
808 krb5_db_entry *entry;
809 krb5_principal alias_target;
810 int alias_depth = 0;
811
812 *entry_out = NULL;
813 status = get_vftabl(kcontext, &v);
814 if (status)
815 return status;
816 if (v->get_principal == NULL)
817 return KRB5_PLUGIN_OP_NOTSUPP;
818
819 status = v->get_principal(kcontext, search_for, flags, &entry);
820 if (status)
821 return status;
822
823 /* Resolve any aliases up to the maximum depth. */
824 for (;;) {
825 status = krb5_dbe_read_alias(kcontext, entry, &alias_target);
826 if (status)
827 return status;
828 if (alias_target == NULL)
829 break;
830 krb5_db_free_principal(kcontext, entry);
831 status = (++alias_depth > MAX_ALIAS_DEPTH) ? KRB5_KDB_NOENTRY :
832 v->get_principal(kcontext, alias_target, flags, &entry);
833 krb5_free_principal(kcontext, alias_target);
834 if (status)
835 return status;
836 }
837
838 /* Sort the keys in the db entry as some parts of krb5 expect it to be. */
839 if (entry->key_data != NULL)
840 krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data);
841
842 *entry_out = entry;
843 return 0;
844 }
845
846 static void
free_tl_data(krb5_tl_data * list)847 free_tl_data(krb5_tl_data *list)
848 {
849 krb5_tl_data *next;
850
851 for (; list != NULL; list = next) {
852 next = list->tl_data_next;
853 free(list->tl_data_contents);
854 free(list);
855 }
856 }
857
858 void
krb5_db_free_principal(krb5_context kcontext,krb5_db_entry * entry)859 krb5_db_free_principal(krb5_context kcontext, krb5_db_entry *entry)
860 {
861 kdb_vftabl *v;
862 int i;
863
864 if (entry == NULL)
865 return;
866 if (entry->e_data != NULL) {
867 if (get_vftabl(kcontext, &v) == 0 && v->free_principal_e_data != NULL)
868 v->free_principal_e_data(kcontext, entry->e_data);
869 else
870 free(entry->e_data);
871 }
872 krb5_free_principal(kcontext, entry->princ);
873 free_tl_data(entry->tl_data);
874 for (i = 0; i < entry->n_key_data; i++)
875 krb5_dbe_free_key_data_contents(kcontext, &entry->key_data[i]);
876 free(entry->key_data);
877 free(entry);
878 }
879
880 static void
free_db_args(char ** db_args)881 free_db_args(char **db_args)
882 {
883 size_t i;
884
885 if (db_args) {
886 for (i = 0; db_args[i]; i++)
887 free(db_args[i]);
888 free(db_args);
889 }
890 }
891
892 static krb5_error_code
extract_db_args_from_tl_data(krb5_context kcontext,krb5_tl_data ** start,krb5_int16 * count,char *** db_argsp)893 extract_db_args_from_tl_data(krb5_context kcontext, krb5_tl_data **start,
894 krb5_int16 *count, char ***db_argsp)
895 {
896 char **db_args = NULL;
897 size_t db_args_size = 0;
898 krb5_tl_data *prev, *curr, *next;
899 krb5_error_code status;
900
901 /* Giving db_args as part of tl data causes db2 to store the
902 tl_data as such. To prevent this, tl_data is collated and
903 passed as a separate argument. Currently supports only one
904 principal, but passing it as a separate argument makes it
905 difficult for kadmin remote to pass arguments to server. */
906 prev = NULL, curr = *start;
907 while (curr) {
908 if (curr->tl_data_type == KRB5_TL_DB_ARGS) {
909 char **t;
910 /* Since this is expected to be NULL terminated string and
911 this could come from any client, do a check before
912 passing it to db. */
913 if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] !=
914 '\0') {
915 /* Not null terminated. Dangerous input. */
916 status = EINVAL;
917 goto clean_n_exit;
918 }
919
920 db_args_size++;
921 t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */
922 if (t == NULL) {
923 status = ENOMEM;
924 goto clean_n_exit;
925 }
926
927 db_args = t;
928 db_args[db_args_size - 1] = (char *) curr->tl_data_contents;
929 db_args[db_args_size] = NULL;
930
931 next = curr->tl_data_next;
932 if (prev == NULL) {
933 /* current node is the first in the linked list. remove it */
934 *start = curr->tl_data_next;
935 } else {
936 prev->tl_data_next = curr->tl_data_next;
937 }
938 (*count)--;
939 free(curr);
940
941 /* previous does not change */
942 curr = next;
943 } else {
944 prev = curr;
945 curr = curr->tl_data_next;
946 }
947 }
948 status = 0;
949 clean_n_exit:
950 if (status != 0) {
951 free_db_args(db_args);
952 db_args = NULL;
953 }
954 *db_argsp = db_args;
955 return status;
956 }
957
958 krb5_error_code
krb5int_put_principal_no_log(krb5_context kcontext,krb5_db_entry * entry)959 krb5int_put_principal_no_log(krb5_context kcontext, krb5_db_entry *entry)
960 {
961 kdb_vftabl *v;
962 krb5_error_code status;
963 char **db_args;
964
965 status = get_vftabl(kcontext, &v);
966 if (status)
967 return status;
968 if (v->put_principal == NULL)
969 return KRB5_PLUGIN_OP_NOTSUPP;
970 status = extract_db_args_from_tl_data(kcontext, &entry->tl_data,
971 &entry->n_tl_data,
972 &db_args);
973 if (status)
974 return status;
975 status = v->put_principal(kcontext, entry, db_args);
976 free_db_args(db_args);
977 return status;
978 }
979
980 krb5_error_code
krb5_db_put_principal(krb5_context kcontext,krb5_db_entry * entry)981 krb5_db_put_principal(krb5_context kcontext, krb5_db_entry *entry)
982 {
983 krb5_error_code status = 0;
984 kdb_incr_update_t *upd = NULL;
985 char *princ_name = NULL;
986
987 if (logging(kcontext)) {
988 upd = k5alloc(sizeof(*upd), &status);
989 if (upd == NULL)
990 goto cleanup;
991 if ((status = ulog_conv_2logentry(kcontext, entry, upd)))
992 goto cleanup;
993
994 status = krb5_unparse_name(kcontext, entry->princ, &princ_name);
995 if (status != 0)
996 goto cleanup;
997
998 upd->kdb_princ_name.utf8str_t_val = princ_name;
999 upd->kdb_princ_name.utf8str_t_len = strlen(princ_name);
1000 }
1001
1002 status = krb5int_put_principal_no_log(kcontext, entry);
1003 if (status)
1004 goto cleanup;
1005
1006 if (logging(kcontext))
1007 status = ulog_add_update(kcontext, upd);
1008
1009 cleanup:
1010 ulog_free_entries(upd, 1);
1011 return status;
1012 }
1013
1014 krb5_error_code
krb5int_delete_principal_no_log(krb5_context kcontext,krb5_principal search_for)1015 krb5int_delete_principal_no_log(krb5_context kcontext,
1016 krb5_principal search_for)
1017 {
1018 kdb_vftabl *v;
1019 krb5_error_code status;
1020
1021 status = get_vftabl(kcontext, &v);
1022 if (status)
1023 return status;
1024 if (v->delete_principal == NULL)
1025 return KRB5_PLUGIN_OP_NOTSUPP;
1026 return v->delete_principal(kcontext, search_for);
1027 }
1028
1029 krb5_error_code
krb5_db_delete_principal(krb5_context kcontext,krb5_principal search_for)1030 krb5_db_delete_principal(krb5_context kcontext, krb5_principal search_for)
1031 {
1032 krb5_error_code status = 0;
1033 kdb_incr_update_t upd;
1034 char *princ_name = NULL;
1035
1036 status = krb5int_delete_principal_no_log(kcontext, search_for);
1037 if (status || !logging(kcontext))
1038 return status;
1039
1040 status = krb5_unparse_name(kcontext, search_for, &princ_name);
1041 if (status)
1042 return status;
1043
1044 memset(&upd, 0, sizeof(kdb_incr_update_t));
1045 upd.kdb_princ_name.utf8str_t_val = princ_name;
1046 upd.kdb_princ_name.utf8str_t_len = strlen(princ_name);
1047 upd.kdb_deleted = TRUE;
1048
1049 status = ulog_add_update(kcontext, &upd);
1050 free(princ_name);
1051 return status;
1052 }
1053
1054 krb5_error_code
krb5_db_rename_principal(krb5_context kcontext,krb5_principal source,krb5_principal target)1055 krb5_db_rename_principal(krb5_context kcontext, krb5_principal source,
1056 krb5_principal target)
1057 {
1058 kdb_vftabl *v;
1059 krb5_error_code status;
1060 krb5_db_entry *entry;
1061 krb5_boolean eq;
1062
1063 status = get_vftabl(kcontext, &v);
1064 if (status)
1065 return status;
1066
1067 /*
1068 * If the default rename function isn't used and logging is enabled, iprop
1069 * would fail since it doesn't formally support renaming. In that case
1070 * return KRB5_PLUGIN_OP_NOTSUPP.
1071 */
1072 if (v->rename_principal != krb5_db_def_rename_principal &&
1073 logging(kcontext))
1074 return KRB5_PLUGIN_OP_NOTSUPP;
1075
1076 /* Disallow the operation if source is an alias. */
1077 status = krb5_db_get_principal(kcontext, source, 0, &entry);
1078 if (status)
1079 return status;
1080 eq = krb5_principal_compare(kcontext, entry->princ, source);
1081 krb5_db_free_principal(kcontext, entry);
1082 if (!eq)
1083 return KRB5_KDB_ALIAS_UNSUPPORTED;
1084
1085 status = krb5_db_get_principal(kcontext, target, 0, &entry);
1086 if (status == 0) {
1087 krb5_db_free_principal(kcontext, entry);
1088 return KRB5_KDB_INUSE;
1089 }
1090
1091 return v->rename_principal(kcontext, source, target);
1092 }
1093
1094 /*
1095 * Use a proxy function for iterate so that we can sort the keys before sending
1096 * them to the callback.
1097 */
1098 struct callback_proxy_args {
1099 int (*func)(krb5_pointer, krb5_db_entry *);
1100 krb5_pointer func_arg;
1101 };
1102
1103 static int
sort_entry_callback_proxy(krb5_pointer func_arg,krb5_db_entry * entry)1104 sort_entry_callback_proxy(krb5_pointer func_arg, krb5_db_entry *entry)
1105 {
1106 struct callback_proxy_args *args = (struct callback_proxy_args *)func_arg;
1107
1108 /* Sort the keys in the db entry as some parts of krb5 expect it to be. */
1109 if (entry && entry->key_data)
1110 krb5_dbe_sort_key_data(entry->key_data, entry->n_key_data);
1111 return args->func(args->func_arg, entry);
1112 }
1113
1114 krb5_error_code
krb5_db_iterate(krb5_context kcontext,char * match_entry,int (* func)(krb5_pointer,krb5_db_entry *),krb5_pointer func_arg,krb5_flags iterflags)1115 krb5_db_iterate(krb5_context kcontext, char *match_entry,
1116 int (*func)(krb5_pointer, krb5_db_entry *),
1117 krb5_pointer func_arg, krb5_flags iterflags)
1118 {
1119 krb5_error_code status = 0;
1120 kdb_vftabl *v;
1121 struct callback_proxy_args proxy_args;
1122
1123 status = get_vftabl(kcontext, &v);
1124 if (status)
1125 return status;
1126 if (v->iterate == NULL)
1127 return KRB5_PLUGIN_OP_NOTSUPP;
1128
1129 /* Use the proxy function to sort key data before passing entries to
1130 * callback. */
1131 proxy_args.func = func;
1132 proxy_args.func_arg = func_arg;
1133 return v->iterate(kcontext, match_entry, sort_entry_callback_proxy,
1134 &proxy_args, iterflags);
1135 }
1136
1137 /* Return a read only pointer alias to mkey list. Do not free this! */
1138 krb5_keylist_node *
krb5_db_mkey_list_alias(krb5_context kcontext)1139 krb5_db_mkey_list_alias(krb5_context kcontext)
1140 {
1141 return kcontext->dal_handle->master_keylist;
1142 }
1143
1144 krb5_error_code
krb5_db_fetch_mkey_list(krb5_context context,krb5_principal mname,const krb5_keyblock * mkey)1145 krb5_db_fetch_mkey_list(krb5_context context, krb5_principal mname,
1146 const krb5_keyblock *mkey)
1147 {
1148 kdb_vftabl *v;
1149 krb5_error_code status = 0;
1150 krb5_keylist_node *local_keylist;
1151
1152 status = get_vftabl(context, &v);
1153 if (status)
1154 return status;
1155
1156 if (!context->dal_handle->master_princ) {
1157 status = krb5_copy_principal(context, mname,
1158 &context->dal_handle->master_princ);
1159 if (status)
1160 return status;
1161 }
1162
1163 status = v->fetch_master_key_list(context, mname, mkey, &local_keylist);
1164 if (status == 0) {
1165 free_mkey_list(context, context->dal_handle->master_keylist);
1166 context->dal_handle->master_keylist = local_keylist;
1167 }
1168 return status;
1169 }
1170
1171 krb5_error_code
krb5_db_store_master_key(krb5_context kcontext,char * keyfile,krb5_principal mname,krb5_kvno kvno,krb5_keyblock * key,char * master_pwd)1172 krb5_db_store_master_key(krb5_context kcontext, char *keyfile,
1173 krb5_principal mname, krb5_kvno kvno,
1174 krb5_keyblock * key, char *master_pwd)
1175 {
1176 krb5_error_code status = 0;
1177 kdb_vftabl *v;
1178 krb5_keylist_node list;
1179
1180 status = get_vftabl(kcontext, &v);
1181 if (status)
1182 return status;
1183
1184 if (v->store_master_key_list == NULL)
1185 return KRB5_KDB_DBTYPE_NOSUP;
1186
1187 list.kvno = kvno;
1188 list.keyblock = *key;
1189 list.next = NULL;
1190
1191 return v->store_master_key_list(kcontext, keyfile, mname,
1192 &list, master_pwd);
1193 }
1194
1195 krb5_error_code
krb5_db_store_master_key_list(krb5_context kcontext,char * keyfile,krb5_principal mname,char * master_pwd)1196 krb5_db_store_master_key_list(krb5_context kcontext, char *keyfile,
1197 krb5_principal mname, char *master_pwd)
1198 {
1199 krb5_error_code status = 0;
1200 kdb_vftabl *v;
1201
1202 status = get_vftabl(kcontext, &v);
1203 if (status)
1204 return status;
1205
1206 if (v->store_master_key_list == NULL)
1207 return KRB5_KDB_DBTYPE_NOSUP;
1208
1209 if (kcontext->dal_handle->master_keylist == NULL)
1210 return KRB5_KDB_DBNOTINITED;
1211
1212 return v->store_master_key_list(kcontext, keyfile, mname,
1213 kcontext->dal_handle->master_keylist,
1214 master_pwd);
1215 }
1216
1217 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1;
1218 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2;
1219
1220 krb5_error_code
krb5_db_fetch_mkey(krb5_context context,krb5_principal mname,krb5_enctype etype,krb5_boolean fromkeyboard,krb5_boolean twice,char * db_args,krb5_kvno * kvno,krb5_data * salt,krb5_keyblock * key)1221 krb5_db_fetch_mkey(krb5_context context, krb5_principal mname,
1222 krb5_enctype etype, krb5_boolean fromkeyboard,
1223 krb5_boolean twice, char *db_args, krb5_kvno *kvno,
1224 krb5_data *salt, krb5_keyblock *key)
1225 {
1226 krb5_error_code retval;
1227 char password[BUFSIZ];
1228 krb5_data pwd;
1229 unsigned int size = sizeof(password);
1230 krb5_keyblock tmp_key;
1231
1232 memset(&tmp_key, 0, sizeof(tmp_key));
1233
1234 if (fromkeyboard) {
1235 krb5_data scratch;
1236
1237 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1,
1238 twice ? krb5_mkey_pwd_prompt2 : 0,
1239 password, &size))) {
1240 goto clean_n_exit;
1241 }
1242
1243 pwd.data = password;
1244 pwd.length = size;
1245 if (!salt) {
1246 retval = krb5_principal2salt(context, mname, &scratch);
1247 if (retval)
1248 goto clean_n_exit;
1249 }
1250 retval =
1251 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch,
1252 key);
1253 /*
1254 * If a kvno pointer was passed in and it dereferences the IGNORE_VNO
1255 * value then it should be assigned the value of the kvno associated
1256 * with the current mkey princ key if that princ entry is available
1257 * otherwise assign 1 which is the default kvno value for the mkey
1258 * princ.
1259 */
1260 if (kvno != NULL && *kvno == IGNORE_VNO) {
1261 krb5_error_code rc;
1262 krb5_db_entry *master_entry;
1263
1264 rc = krb5_db_get_principal(context, mname, 0, &master_entry);
1265 if (rc == 0 && master_entry->n_key_data > 0)
1266 *kvno = (krb5_kvno) master_entry->key_data->key_data_kvno;
1267 else
1268 *kvno = 1;
1269 if (rc == 0)
1270 krb5_db_free_principal(context, master_entry);
1271 }
1272
1273 if (!salt)
1274 free(scratch.data);
1275 zap(password, sizeof(password)); /* erase it */
1276
1277 } else {
1278 kdb_vftabl *v;
1279
1280 if (context->dal_handle == NULL) {
1281 retval = krb5_db_setup_lib_handle(context);
1282 if (retval)
1283 goto clean_n_exit;
1284 }
1285
1286 /* get the enctype from the stash */
1287 tmp_key.enctype = ENCTYPE_UNKNOWN;
1288
1289 v = &context->dal_handle->lib_handle->vftabl;
1290 retval = v->fetch_master_key(context, mname, &tmp_key, kvno, db_args);
1291
1292 if (retval)
1293 goto clean_n_exit;
1294
1295 key->contents = k5memdup(tmp_key.contents, tmp_key.length, &retval);
1296 if (key->contents == NULL)
1297 goto clean_n_exit;
1298
1299 key->magic = tmp_key.magic;
1300 key->enctype = tmp_key.enctype;
1301 key->length = tmp_key.length;
1302 }
1303
1304 clean_n_exit:
1305 zapfree(tmp_key.contents, tmp_key.length);
1306 return retval;
1307 }
1308
1309 krb5_error_code
krb5_dbe_fetch_act_key_list(krb5_context context,krb5_principal princ,krb5_actkvno_node ** act_key_list)1310 krb5_dbe_fetch_act_key_list(krb5_context context, krb5_principal princ,
1311 krb5_actkvno_node **act_key_list)
1312 {
1313 krb5_error_code retval = 0;
1314 krb5_db_entry *entry;
1315
1316 if (act_key_list == NULL)
1317 return (EINVAL);
1318
1319 retval = krb5_db_get_principal(context, princ, 0, &entry);
1320 if (retval == KRB5_KDB_NOENTRY)
1321 return KRB5_KDB_NOMASTERKEY;
1322 else if (retval)
1323 return retval;
1324
1325 retval = krb5_dbe_lookup_actkvno(context, entry, act_key_list);
1326 krb5_db_free_principal(context, entry);
1327 return retval;
1328 }
1329
1330 /* Find the most recent entry in list (which must not be empty) for the given
1331 * timestamp, and return its kvno. */
1332 static krb5_kvno
find_actkvno(krb5_actkvno_node * list,krb5_timestamp now)1333 find_actkvno(krb5_actkvno_node *list, krb5_timestamp now)
1334 {
1335 /*
1336 * The list is sorted in ascending order of time. Return the kvno of the
1337 * predecessor of the first entry whose time is in the future. If
1338 * (contrary to the safety checks in kdb5_util use_mkey) all of the entries
1339 * are in the future, we will return the first node; if all are in the
1340 * past, we will return the last node.
1341 */
1342 while (list->next != NULL && !ts_after(list->next->act_time, now))
1343 list = list->next;
1344 return list->act_kvno;
1345 }
1346
1347 /* Search the master keylist for the master key with the specified kvno.
1348 * Return the keyblock of the matching entry or NULL if it does not exist. */
1349 static krb5_keyblock *
find_master_key(krb5_context context,krb5_kvno kvno)1350 find_master_key(krb5_context context, krb5_kvno kvno)
1351 {
1352 krb5_keylist_node *n;
1353
1354 for (n = context->dal_handle->master_keylist; n != NULL; n = n->next) {
1355 if (n->kvno == kvno)
1356 return &n->keyblock;
1357 }
1358 return NULL;
1359 }
1360
1361 /*
1362 * Locates the "active" mkey used when encrypting a princ's keys. Note, the
1363 * caller must NOT free the output act_mkey.
1364 */
1365
1366 krb5_error_code
krb5_dbe_find_act_mkey(krb5_context context,krb5_actkvno_node * act_mkey_list,krb5_kvno * act_kvno,krb5_keyblock ** act_mkey)1367 krb5_dbe_find_act_mkey(krb5_context context, krb5_actkvno_node *act_mkey_list,
1368 krb5_kvno *act_kvno, krb5_keyblock **act_mkey)
1369 {
1370 krb5_kvno kvno;
1371 krb5_error_code retval;
1372 krb5_keyblock *mkey, *cur_mkey;
1373 krb5_timestamp now;
1374
1375 if (act_mkey_list == NULL) {
1376 *act_kvno = 0;
1377 *act_mkey = NULL;
1378 return 0;
1379 }
1380
1381 if (context->dal_handle->master_keylist == NULL)
1382 return KRB5_KDB_DBNOTINITED;
1383
1384 /* Find the currently active master key version. */
1385 if ((retval = krb5_timeofday(context, &now)))
1386 return (retval);
1387 kvno = find_actkvno(act_mkey_list, now);
1388
1389 /* Find the corresponding master key. */
1390 mkey = find_master_key(context, kvno);
1391 if (mkey == NULL) {
1392 /* Reload the master key list and try again. */
1393 cur_mkey = &context->dal_handle->master_keylist->keyblock;
1394 if (krb5_db_fetch_mkey_list(context, context->dal_handle->master_princ,
1395 cur_mkey) == 0)
1396 mkey = find_master_key(context, kvno);
1397 }
1398 if (mkey == NULL)
1399 return KRB5_KDB_NO_MATCHING_KEY;
1400
1401 *act_mkey = mkey;
1402 if (act_kvno != NULL)
1403 *act_kvno = kvno;
1404 return 0;
1405 }
1406
1407 /*
1408 * Locates the mkey used to protect a princ's keys. Note, the caller must not
1409 * free the output key.
1410 */
1411 krb5_error_code
krb5_dbe_find_mkey(krb5_context context,krb5_db_entry * entry,krb5_keyblock ** mkey)1412 krb5_dbe_find_mkey(krb5_context context, krb5_db_entry *entry,
1413 krb5_keyblock **mkey)
1414 {
1415 krb5_kvno mkvno;
1416 krb5_error_code retval;
1417 krb5_keylist_node *cur_keyblock = context->dal_handle->master_keylist;
1418
1419 if (!cur_keyblock)
1420 return KRB5_KDB_DBNOTINITED;
1421
1422 retval = krb5_dbe_get_mkvno(context, entry, &mkvno);
1423 if (retval)
1424 return (retval);
1425
1426 while (cur_keyblock && cur_keyblock->kvno != mkvno)
1427 cur_keyblock = cur_keyblock->next;
1428
1429 if (cur_keyblock) {
1430 *mkey = &cur_keyblock->keyblock;
1431 return (0);
1432 } else {
1433 return KRB5_KDB_NO_MATCHING_KEY;
1434 }
1435 }
1436
1437 void *
krb5_db_alloc(krb5_context kcontext,void * ptr,size_t size)1438 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size)
1439 {
1440 return realloc(ptr, size);
1441 }
1442
1443 void
krb5_db_free(krb5_context kcontext,void * ptr)1444 krb5_db_free(krb5_context kcontext, void *ptr)
1445 {
1446 free(ptr);
1447 }
1448
1449 /* has to be modified */
1450
1451 krb5_error_code
krb5_dbe_find_enctype(krb5_context kcontext,krb5_db_entry * dbentp,krb5_int32 ktype,krb5_int32 stype,krb5_int32 kvno,krb5_key_data ** kdatap)1452 krb5_dbe_find_enctype(krb5_context kcontext, krb5_db_entry *dbentp,
1453 krb5_int32 ktype, krb5_int32 stype, krb5_int32 kvno,
1454 krb5_key_data **kdatap)
1455 {
1456 krb5_int32 start = 0;
1457 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype,
1458 kvno, kdatap);
1459 }
1460
1461 krb5_error_code
krb5_dbe_search_enctype(krb5_context kcontext,krb5_db_entry * dbentp,krb5_int32 * start,krb5_int32 ktype,krb5_int32 stype,krb5_int32 kvno,krb5_key_data ** kdatap)1462 krb5_dbe_search_enctype(krb5_context kcontext, krb5_db_entry *dbentp,
1463 krb5_int32 *start, krb5_int32 ktype, krb5_int32 stype,
1464 krb5_int32 kvno, krb5_key_data ** kdatap)
1465 {
1466 krb5_error_code status = 0;
1467 kdb_vftabl *v;
1468
1469 status = get_vftabl(kcontext, &v);
1470 if (status)
1471 return status;
1472 return v->dbe_search_enctype(kcontext, dbentp, start, ktype, stype, kvno,
1473 kdatap);
1474 }
1475
1476 #define REALM_SEP_STRING "@"
1477
1478 krb5_error_code
krb5_db_setup_mkey_name(krb5_context context,const char * keyname,const char * realm,char ** fullname,krb5_principal * principal)1479 krb5_db_setup_mkey_name(krb5_context context, const char *keyname,
1480 const char *realm, char **fullname,
1481 krb5_principal *principal)
1482 {
1483 krb5_error_code retval;
1484 char *fname;
1485
1486 if (!keyname)
1487 keyname = KRB5_KDB_M_NAME; /* XXX external? */
1488
1489 if (asprintf(&fname, "%s%s%s", keyname, REALM_SEP_STRING, realm) < 0)
1490 return ENOMEM;
1491
1492 retval = krb5_parse_name(context, fname, principal);
1493 if (retval) {
1494 free(fname);
1495 return retval;
1496 }
1497 if (fullname)
1498 *fullname = fname;
1499 else
1500 free(fname);
1501 return 0;
1502 }
1503
1504 krb5_error_code
krb5_dbe_lookup_last_pwd_change(krb5_context context,krb5_db_entry * entry,krb5_timestamp * stamp)1505 krb5_dbe_lookup_last_pwd_change(krb5_context context, krb5_db_entry *entry,
1506 krb5_timestamp *stamp)
1507 {
1508 krb5_tl_data tl_data;
1509 krb5_error_code code;
1510 krb5_int32 tmp;
1511
1512 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
1513
1514 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1515 return (code);
1516
1517 if (tl_data.tl_data_length != 4) {
1518 *stamp = 0;
1519 return (0);
1520 }
1521
1522 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
1523
1524 *stamp = (krb5_timestamp) tmp;
1525
1526 return (0);
1527 }
1528
1529 krb5_error_code
krb5_dbe_lookup_last_admin_unlock(krb5_context context,krb5_db_entry * entry,krb5_timestamp * stamp)1530 krb5_dbe_lookup_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
1531 krb5_timestamp *stamp)
1532 {
1533 krb5_tl_data tl_data;
1534 krb5_error_code code;
1535 krb5_int32 tmp;
1536
1537 tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK;
1538
1539 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1540 return (code);
1541
1542 if (tl_data.tl_data_length != 4) {
1543 *stamp = 0;
1544 return (0);
1545 }
1546
1547 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
1548
1549 *stamp = (krb5_timestamp) tmp;
1550
1551 return (0);
1552 }
1553
1554 krb5_error_code
krb5_dbe_lookup_tl_data(krb5_context context,krb5_db_entry * entry,krb5_tl_data * ret_tl_data)1555 krb5_dbe_lookup_tl_data(krb5_context context, krb5_db_entry *entry,
1556 krb5_tl_data *ret_tl_data)
1557 {
1558 krb5_tl_data *tl_data;
1559
1560 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
1561 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) {
1562 *ret_tl_data = *tl_data;
1563 return (0);
1564 }
1565 }
1566
1567 /*
1568 * If the requested record isn't found, return zero bytes. If it
1569 * ever means something to have a zero-length tl_data, this code
1570 * and its callers will have to be changed.
1571 */
1572
1573 ret_tl_data->tl_data_length = 0;
1574 ret_tl_data->tl_data_contents = NULL;
1575 return (0);
1576 }
1577
1578 krb5_error_code
krb5_dbe_create_key_data(krb5_context context,krb5_db_entry * entry)1579 krb5_dbe_create_key_data(krb5_context context, krb5_db_entry *entry)
1580 {
1581 krb5_key_data *newptr;
1582
1583 newptr = realloc(entry->key_data,
1584 (entry->n_key_data + 1) * sizeof(*entry->key_data));
1585 if (newptr == NULL)
1586 return ENOMEM;
1587 entry->key_data = newptr;
1588
1589 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
1590 entry->n_key_data++;
1591
1592 return 0;
1593 }
1594
1595 krb5_error_code
krb5_dbe_update_mod_princ_data(krb5_context context,krb5_db_entry * entry,krb5_timestamp mod_date,krb5_const_principal mod_princ)1596 krb5_dbe_update_mod_princ_data(krb5_context context, krb5_db_entry *entry,
1597 krb5_timestamp mod_date,
1598 krb5_const_principal mod_princ)
1599 {
1600 krb5_tl_data tl_data;
1601
1602 krb5_error_code retval = 0;
1603 krb5_octet *nextloc = 0;
1604 char *unparse_mod_princ = 0;
1605 unsigned int unparse_mod_princ_size;
1606
1607 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ)))
1608 return (retval);
1609
1610 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;
1611
1612 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
1613 == NULL) {
1614 free(unparse_mod_princ);
1615 return (ENOMEM);
1616 }
1617
1618 tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
1619 tl_data.tl_data_length = unparse_mod_princ_size + 4;
1620 tl_data.tl_data_contents = nextloc;
1621
1622 /* Mod Date */
1623 krb5_kdb_encode_int32(mod_date, nextloc);
1624
1625 /* Mod Princ */
1626 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size);
1627
1628 retval = krb5_dbe_update_tl_data(context, entry, &tl_data);
1629
1630 free(unparse_mod_princ);
1631 free(nextloc);
1632
1633 return (retval);
1634 }
1635
1636 krb5_error_code
krb5_dbe_lookup_mod_princ_data(krb5_context context,krb5_db_entry * entry,krb5_timestamp * mod_time,krb5_principal * mod_princ)1637 krb5_dbe_lookup_mod_princ_data(krb5_context context, krb5_db_entry *entry,
1638 krb5_timestamp *mod_time,
1639 krb5_principal *mod_princ)
1640 {
1641 krb5_tl_data tl_data;
1642 krb5_error_code code;
1643
1644 *mod_princ = NULL;
1645 *mod_time = 0;
1646
1647 tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
1648
1649 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1650 return (code);
1651
1652 if ((tl_data.tl_data_length < 5) ||
1653 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0'))
1654 return (KRB5_KDB_TRUNCATED_RECORD);
1655
1656 /* Mod Date */
1657 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time);
1658
1659 /* Mod Princ */
1660 if ((code = krb5_parse_name(context,
1661 (const char *) (tl_data.tl_data_contents + 4),
1662 mod_princ)))
1663 return (code);
1664
1665 return (0);
1666 }
1667
1668 krb5_error_code
krb5_dbe_lookup_mkvno(krb5_context context,krb5_db_entry * entry,krb5_kvno * mkvno)1669 krb5_dbe_lookup_mkvno(krb5_context context, krb5_db_entry *entry,
1670 krb5_kvno *mkvno)
1671 {
1672 krb5_tl_data tl_data;
1673 krb5_error_code code;
1674 krb5_int16 tmp;
1675
1676 tl_data.tl_data_type = KRB5_TL_MKVNO;
1677
1678 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1679 return (code);
1680
1681 if (tl_data.tl_data_length == 0) {
1682 *mkvno = 0; /* Indicates KRB5_TL_MKVNO data not present */
1683 return (0);
1684 } else if (tl_data.tl_data_length != 2) {
1685 return (KRB5_KDB_TRUNCATED_RECORD);
1686 }
1687
1688 krb5_kdb_decode_int16(tl_data.tl_data_contents, tmp);
1689 *mkvno = (krb5_kvno) tmp;
1690 return (0);
1691 }
1692
1693 krb5_error_code
krb5_dbe_get_mkvno(krb5_context context,krb5_db_entry * entry,krb5_kvno * mkvno)1694 krb5_dbe_get_mkvno(krb5_context context, krb5_db_entry *entry,
1695 krb5_kvno *mkvno)
1696 {
1697 krb5_error_code code;
1698 krb5_kvno kvno;
1699 krb5_keylist_node *mkey_list = context->dal_handle->master_keylist;
1700
1701 if (mkey_list == NULL)
1702 return KRB5_KDB_DBNOTINITED;
1703
1704 /* Output the value from entry tl_data if present. */
1705 code = krb5_dbe_lookup_mkvno(context, entry, &kvno);
1706 if (code != 0)
1707 return code;
1708 if (kvno != 0) {
1709 *mkvno = kvno;
1710 return 0;
1711 }
1712
1713 /* Determine the minimum kvno in mkey_list and output that. */
1714 kvno = (krb5_kvno) -1;
1715 while (mkey_list != NULL) {
1716 if (mkey_list->kvno < kvno)
1717 kvno = mkey_list->kvno;
1718 mkey_list = mkey_list->next;
1719 }
1720 *mkvno = kvno;
1721 return 0;
1722 }
1723
1724 krb5_error_code
krb5_dbe_update_mkvno(krb5_context context,krb5_db_entry * entry,krb5_kvno mkvno)1725 krb5_dbe_update_mkvno(krb5_context context, krb5_db_entry *entry,
1726 krb5_kvno mkvno)
1727 {
1728 krb5_tl_data tl_data;
1729 krb5_octet buf[2]; /* this is the encoded size of an int16 */
1730 krb5_int16 tmp_kvno = (krb5_int16) mkvno;
1731
1732 tl_data.tl_data_type = KRB5_TL_MKVNO;
1733 tl_data.tl_data_length = sizeof(buf);
1734 krb5_kdb_encode_int16(tmp_kvno, buf);
1735 tl_data.tl_data_contents = buf;
1736
1737 return (krb5_dbe_update_tl_data(context, entry, &tl_data));
1738 }
1739
1740 krb5_error_code
krb5_dbe_lookup_mkey_aux(krb5_context context,krb5_db_entry * entry,krb5_mkey_aux_node ** mkey_aux_data_list)1741 krb5_dbe_lookup_mkey_aux(krb5_context context, krb5_db_entry *entry,
1742 krb5_mkey_aux_node **mkey_aux_data_list)
1743 {
1744 krb5_tl_data tl_data;
1745 krb5_int16 version, mkey_kvno;
1746 krb5_mkey_aux_node *head_data = NULL, *new_data = NULL,
1747 *prev_data = NULL;
1748 krb5_octet *curloc; /* current location pointer */
1749 krb5_error_code code;
1750
1751 tl_data.tl_data_type = KRB5_TL_MKEY_AUX;
1752 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1753 return (code);
1754
1755 if (tl_data.tl_data_contents == NULL) {
1756 *mkey_aux_data_list = NULL;
1757 return (0);
1758 } else {
1759 /* get version to determine how to parse the data */
1760 krb5_kdb_decode_int16(tl_data.tl_data_contents, version);
1761 if (version == 1) {
1762 /* variable size, must be at least 10 bytes */
1763 if (tl_data.tl_data_length < 10)
1764 return (KRB5_KDB_TRUNCATED_RECORD);
1765
1766 /* curloc points to first tuple entry in the tl_data_contents */
1767 curloc = tl_data.tl_data_contents + sizeof(version);
1768
1769 while (curloc < (tl_data.tl_data_contents + tl_data.tl_data_length)) {
1770
1771 new_data = (krb5_mkey_aux_node *) malloc(sizeof(krb5_mkey_aux_node));
1772 if (new_data == NULL) {
1773 krb5_dbe_free_mkey_aux_list(context, head_data);
1774 return (ENOMEM);
1775 }
1776 memset(new_data, 0, sizeof(krb5_mkey_aux_node));
1777
1778 krb5_kdb_decode_int16(curloc, mkey_kvno);
1779 new_data->mkey_kvno = mkey_kvno;
1780 curloc += sizeof(krb5_ui_2);
1781 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_kvno);
1782 curloc += sizeof(krb5_ui_2);
1783 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_type[0]);
1784 curloc += sizeof(krb5_ui_2);
1785 krb5_kdb_decode_int16(curloc, new_data->latest_mkey.key_data_length[0]);
1786 curloc += sizeof(krb5_ui_2);
1787
1788 new_data->latest_mkey.key_data_contents[0] = (krb5_octet *)
1789 malloc(new_data->latest_mkey.key_data_length[0]);
1790
1791 if (new_data->latest_mkey.key_data_contents[0] == NULL) {
1792 krb5_dbe_free_mkey_aux_list(context, head_data);
1793 free(new_data);
1794 return (ENOMEM);
1795 }
1796 memcpy(new_data->latest_mkey.key_data_contents[0], curloc,
1797 new_data->latest_mkey.key_data_length[0]);
1798 curloc += new_data->latest_mkey.key_data_length[0];
1799
1800 /* always using key data ver 1 for mkeys */
1801 new_data->latest_mkey.key_data_ver = 1;
1802
1803 new_data->next = NULL;
1804 if (prev_data != NULL)
1805 prev_data->next = new_data;
1806 else
1807 head_data = new_data;
1808 prev_data = new_data;
1809 }
1810 } else {
1811 k5_setmsg(context, KRB5_KDB_BAD_VERSION,
1812 _("Illegal version number for KRB5_TL_MKEY_AUX %d\n"),
1813 version);
1814 return (KRB5_KDB_BAD_VERSION);
1815 }
1816 }
1817 *mkey_aux_data_list = head_data;
1818 return (0);
1819 }
1820
1821 #if KRB5_TL_MKEY_AUX_VER == 1
1822 krb5_error_code
krb5_dbe_update_mkey_aux(krb5_context context,krb5_db_entry * entry,krb5_mkey_aux_node * mkey_aux_data_list)1823 krb5_dbe_update_mkey_aux(krb5_context context, krb5_db_entry *entry,
1824 krb5_mkey_aux_node *mkey_aux_data_list)
1825 {
1826 krb5_error_code status;
1827 krb5_tl_data tl_data;
1828 krb5_int16 version, tmp_kvno;
1829 unsigned char *nextloc;
1830 krb5_mkey_aux_node *aux_data_entry;
1831
1832 if (!mkey_aux_data_list) {
1833 /* delete the KRB5_TL_MKEY_AUX from the entry */
1834 krb5_dbe_delete_tl_data(context, entry, KRB5_TL_MKEY_AUX);
1835 return (0);
1836 }
1837
1838 memset(&tl_data, 0, sizeof(tl_data));
1839 tl_data.tl_data_type = KRB5_TL_MKEY_AUX;
1840 /*
1841 * determine out how much space to allocate. Note key_data_ver not stored
1842 * as this is hard coded to one and is accounted for in
1843 * krb5_dbe_lookup_mkey_aux.
1844 */
1845 tl_data.tl_data_length = sizeof(version); /* version */
1846 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
1847 aux_data_entry = aux_data_entry->next) {
1848
1849 tl_data.tl_data_length += (sizeof(krb5_ui_2) + /* mkey_kvno */
1850 sizeof(krb5_ui_2) + /* latest_mkey kvno */
1851 sizeof(krb5_ui_2) + /* latest_mkey enctype */
1852 sizeof(krb5_ui_2) + /* latest_mkey length */
1853 aux_data_entry->latest_mkey.key_data_length[0]);
1854 }
1855
1856 tl_data.tl_data_contents = (krb5_octet *) malloc(tl_data.tl_data_length);
1857 if (tl_data.tl_data_contents == NULL)
1858 return (ENOMEM);
1859
1860 nextloc = tl_data.tl_data_contents;
1861 version = KRB5_TL_MKEY_AUX_VER;
1862 krb5_kdb_encode_int16(version, nextloc);
1863 nextloc += sizeof(krb5_ui_2);
1864
1865 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
1866 aux_data_entry = aux_data_entry->next) {
1867
1868 tmp_kvno = (krb5_int16) aux_data_entry->mkey_kvno;
1869 krb5_kdb_encode_int16(tmp_kvno, nextloc);
1870 nextloc += sizeof(krb5_ui_2);
1871
1872 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_kvno,
1873 nextloc);
1874 nextloc += sizeof(krb5_ui_2);
1875
1876 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_type[0],
1877 nextloc);
1878 nextloc += sizeof(krb5_ui_2);
1879
1880 krb5_kdb_encode_int16(aux_data_entry->latest_mkey.key_data_length[0],
1881 nextloc);
1882 nextloc += sizeof(krb5_ui_2);
1883
1884 if (aux_data_entry->latest_mkey.key_data_length[0] > 0) {
1885 memcpy(nextloc, aux_data_entry->latest_mkey.key_data_contents[0],
1886 aux_data_entry->latest_mkey.key_data_length[0]);
1887 nextloc += aux_data_entry->latest_mkey.key_data_length[0];
1888 }
1889 }
1890
1891 status = krb5_dbe_update_tl_data(context, entry, &tl_data);
1892 free(tl_data.tl_data_contents);
1893 return status;
1894 }
1895 #endif /* KRB5_TL_MKEY_AUX_VER == 1 */
1896
1897 #if KRB5_TL_ACTKVNO_VER == 1
1898 /*
1899 * If version of the KRB5_TL_ACTKVNO data is KRB5_TL_ACTKVNO_VER == 1 then size of
1900 * a actkvno tuple {act_kvno, act_time} entry is:
1901 */
1902 #define ACTKVNO_TUPLE_SIZE (sizeof(krb5_int16) + sizeof(krb5_int32))
1903 #define act_kvno(cp) (cp) /* return pointer to start of act_kvno data */
1904 #define act_time(cp) ((cp) + sizeof(krb5_int16)) /* return pointer to start of act_time data */
1905 #endif
1906
1907 krb5_error_code
krb5_dbe_lookup_actkvno(krb5_context context,krb5_db_entry * entry,krb5_actkvno_node ** actkvno_list)1908 krb5_dbe_lookup_actkvno(krb5_context context, krb5_db_entry *entry,
1909 krb5_actkvno_node **actkvno_list)
1910 {
1911 krb5_tl_data tl_data;
1912 krb5_error_code code;
1913 krb5_int16 version, tmp_kvno;
1914 krb5_actkvno_node *head_data = NULL, *new_data = NULL, *prev_data = NULL;
1915 unsigned int num_actkvno, i;
1916 krb5_octet *next_tuple;
1917 krb5_kvno earliest_kvno;
1918
1919 memset(&tl_data, 0, sizeof(tl_data));
1920 tl_data.tl_data_type = KRB5_TL_ACTKVNO;
1921
1922 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1923 return (code);
1924
1925 if (tl_data.tl_data_contents == NULL) {
1926 /*
1927 * If there is no KRB5_TL_ACTKVNO data (likely because the KDB was
1928 * created prior to 1.7), synthesize the list which should have been
1929 * created at KDB initialization, making the earliest master key
1930 * active.
1931 */
1932
1933 /* Get the earliest master key version. */
1934 if (entry->n_key_data == 0)
1935 return KRB5_KDB_NOMASTERKEY;
1936 earliest_kvno = entry->key_data[entry->n_key_data - 1].key_data_kvno;
1937
1938 head_data = malloc(sizeof(*head_data));
1939 if (head_data == NULL)
1940 return ENOMEM;
1941 memset(head_data, 0, sizeof(*head_data));
1942 head_data->act_time = 0; /* earliest time possible */
1943 head_data->act_kvno = earliest_kvno;
1944 } else {
1945 /* get version to determine how to parse the data */
1946 krb5_kdb_decode_int16(tl_data.tl_data_contents, version);
1947 if (version == 1) {
1948
1949 /* variable size, must be at least 8 bytes */
1950 if (tl_data.tl_data_length < 8)
1951 return (KRB5_KDB_TRUNCATED_RECORD);
1952
1953 /*
1954 * Find number of tuple entries, remembering to account for version
1955 * field.
1956 */
1957 num_actkvno = (tl_data.tl_data_length - sizeof(version)) /
1958 ACTKVNO_TUPLE_SIZE;
1959 prev_data = NULL;
1960 /* next_tuple points to first tuple entry in the tl_data_contents */
1961 next_tuple = tl_data.tl_data_contents + sizeof(version);
1962 for (i = 0; i < num_actkvno; i++) {
1963 new_data = (krb5_actkvno_node *) malloc(sizeof(krb5_actkvno_node));
1964 if (new_data == NULL) {
1965 krb5_dbe_free_actkvno_list(context, head_data);
1966 return (ENOMEM);
1967 }
1968 memset(new_data, 0, sizeof(krb5_actkvno_node));
1969
1970 /* using tmp_kvno to avoid type mismatch */
1971 krb5_kdb_decode_int16(act_kvno(next_tuple), tmp_kvno);
1972 new_data->act_kvno = (krb5_kvno) tmp_kvno;
1973 krb5_kdb_decode_int32(act_time(next_tuple), new_data->act_time);
1974
1975 if (prev_data != NULL)
1976 prev_data->next = new_data;
1977 else
1978 head_data = new_data;
1979 prev_data = new_data;
1980 next_tuple += ACTKVNO_TUPLE_SIZE;
1981 }
1982 } else {
1983 k5_setmsg(context, KRB5_KDB_BAD_VERSION,
1984 _("Illegal version number for KRB5_TL_ACTKVNO %d\n"),
1985 version);
1986 return (KRB5_KDB_BAD_VERSION);
1987 }
1988 }
1989 *actkvno_list = head_data;
1990 return (0);
1991 }
1992
1993 /*
1994 * Add KRB5_TL_ACTKVNO TL data entries to krb5_db_entry *entry
1995 */
1996 #if KRB5_TL_ACTKVNO_VER == 1
1997 krb5_error_code
krb5_dbe_update_actkvno(krb5_context context,krb5_db_entry * entry,const krb5_actkvno_node * actkvno_list)1998 krb5_dbe_update_actkvno(krb5_context context, krb5_db_entry *entry,
1999 const krb5_actkvno_node *actkvno_list)
2000 {
2001 krb5_error_code retval = 0;
2002 krb5_int16 version, tmp_kvno;
2003 krb5_tl_data new_tl_data;
2004 unsigned char *nextloc;
2005 const krb5_actkvno_node *cur_actkvno;
2006 krb5_octet *tmpptr;
2007
2008 if (actkvno_list == NULL)
2009 return EINVAL;
2010
2011 memset(&new_tl_data, 0, sizeof(new_tl_data));
2012 /* allocate initial KRB5_TL_ACTKVNO tl_data entry */
2013 new_tl_data.tl_data_length = sizeof(version);
2014 new_tl_data.tl_data_contents = (krb5_octet *) malloc(new_tl_data.tl_data_length);
2015 if (new_tl_data.tl_data_contents == NULL)
2016 return ENOMEM;
2017
2018 /* add the current version # for the data format used for KRB5_TL_ACTKVNO */
2019 version = KRB5_TL_ACTKVNO_VER;
2020 krb5_kdb_encode_int16(version, (unsigned char *) new_tl_data.tl_data_contents);
2021
2022 for (cur_actkvno = actkvno_list; cur_actkvno != NULL;
2023 cur_actkvno = cur_actkvno->next) {
2024
2025 new_tl_data.tl_data_length += ACTKVNO_TUPLE_SIZE;
2026 tmpptr = realloc(new_tl_data.tl_data_contents, new_tl_data.tl_data_length);
2027 if (tmpptr == NULL) {
2028 free(new_tl_data.tl_data_contents);
2029 return ENOMEM;
2030 } else {
2031 new_tl_data.tl_data_contents = tmpptr;
2032 }
2033
2034 /*
2035 * Using realloc so tl_data_contents is required to correctly calculate
2036 * next location to store new tuple.
2037 */
2038 nextloc = new_tl_data.tl_data_contents + new_tl_data.tl_data_length - ACTKVNO_TUPLE_SIZE;
2039 /* using tmp_kvno to avoid type mismatch issues */
2040 tmp_kvno = (krb5_int16) cur_actkvno->act_kvno;
2041 krb5_kdb_encode_int16(tmp_kvno, nextloc);
2042 nextloc += sizeof(krb5_ui_2);
2043 krb5_kdb_encode_int32((krb5_ui_4)cur_actkvno->act_time, nextloc);
2044 }
2045
2046 new_tl_data.tl_data_type = KRB5_TL_ACTKVNO;
2047 retval = krb5_dbe_update_tl_data(context, entry, &new_tl_data);
2048 free(new_tl_data.tl_data_contents);
2049
2050 return (retval);
2051 }
2052 #endif /* KRB5_TL_ACTKVNO_VER == 1 */
2053
2054 krb5_error_code
krb5_dbe_update_last_pwd_change(krb5_context context,krb5_db_entry * entry,krb5_timestamp stamp)2055 krb5_dbe_update_last_pwd_change(krb5_context context, krb5_db_entry *entry,
2056 krb5_timestamp stamp)
2057 {
2058 krb5_tl_data tl_data;
2059 krb5_octet buf[4]; /* this is the encoded size of an int32 */
2060
2061 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
2062 tl_data.tl_data_length = sizeof(buf);
2063 krb5_kdb_encode_int32((krb5_int32) stamp, buf);
2064 tl_data.tl_data_contents = buf;
2065
2066 return (krb5_dbe_update_tl_data(context, entry, &tl_data));
2067 }
2068
2069 krb5_error_code
krb5_dbe_update_last_admin_unlock(krb5_context context,krb5_db_entry * entry,krb5_timestamp stamp)2070 krb5_dbe_update_last_admin_unlock(krb5_context context, krb5_db_entry *entry,
2071 krb5_timestamp stamp)
2072 {
2073 krb5_tl_data tl_data;
2074 krb5_octet buf[4]; /* this is the encoded size of an int32 */
2075
2076 tl_data.tl_data_type = KRB5_TL_LAST_ADMIN_UNLOCK;
2077 tl_data.tl_data_length = sizeof(buf);
2078 krb5_kdb_encode_int32((krb5_int32) stamp, buf);
2079 tl_data.tl_data_contents = buf;
2080
2081 return (krb5_dbe_update_tl_data(context, entry, &tl_data));
2082 }
2083
2084 /*
2085 * Prepare to iterate over the string attributes of entry. The returned
2086 * pointers are aliases into entry's tl_data (or into an empty string literal)
2087 * and remain valid until the entry's tl_data is changed.
2088 */
2089 static krb5_error_code
begin_attrs(krb5_context context,krb5_db_entry * entry,const char ** pos_out,const char ** end_out)2090 begin_attrs(krb5_context context, krb5_db_entry *entry, const char **pos_out,
2091 const char **end_out)
2092 {
2093 krb5_error_code code;
2094 krb5_tl_data tl_data;
2095
2096 *pos_out = *end_out = NULL;
2097 tl_data.tl_data_type = KRB5_TL_STRING_ATTRS;
2098 code = krb5_dbe_lookup_tl_data(context, entry, &tl_data);
2099 if (code)
2100 return code;
2101
2102 /* Copy the current mapping to buf, updating key with value if found. */
2103 *pos_out = (const char *)tl_data.tl_data_contents;
2104 *end_out = *pos_out + tl_data.tl_data_length;
2105 return 0;
2106 }
2107
2108 /* Find the next key and value pair in *pos and update *pos. */
2109 static krb5_boolean
next_attr(const char ** pos,const char * end,const char ** key_out,const char ** val_out)2110 next_attr(const char **pos, const char *end, const char **key_out,
2111 const char **val_out)
2112 {
2113 const char *key, *key_end, *val, *val_end;
2114
2115 *key_out = *val_out = NULL;
2116 if (*pos == end)
2117 return FALSE;
2118 key = *pos;
2119 key_end = memchr(key, '\0', end - key);
2120 if (key_end == NULL) /* Malformed representation; give up. */
2121 return FALSE;
2122 val = key_end + 1;
2123 val_end = memchr(val, '\0', end - val);
2124 if (val_end == NULL) /* Malformed representation; give up. */
2125 return FALSE;
2126
2127 *key_out = key;
2128 *val_out = val;
2129 *pos = val_end + 1;
2130 return TRUE;
2131 }
2132
2133 krb5_error_code
krb5_dbe_get_strings(krb5_context context,krb5_db_entry * entry,krb5_string_attr ** strings_out,int * count_out)2134 krb5_dbe_get_strings(krb5_context context, krb5_db_entry *entry,
2135 krb5_string_attr **strings_out, int *count_out)
2136 {
2137 krb5_error_code code;
2138 const char *pos, *end, *mapkey, *mapval;
2139 char *key = NULL, *val = NULL;
2140 krb5_string_attr *strings = NULL, *newstrings;
2141 int count = 0;
2142
2143 *strings_out = NULL;
2144 *count_out = 0;
2145 code = begin_attrs(context, entry, &pos, &end);
2146 if (code)
2147 return code;
2148
2149 while (next_attr(&pos, end, &mapkey, &mapval)) {
2150 /* Add a copy of mapkey and mapvalue to strings. */
2151 newstrings = realloc(strings, (count + 1) * sizeof(*strings));
2152 if (newstrings == NULL)
2153 goto oom;
2154 strings = newstrings;
2155 key = strdup(mapkey);
2156 val = strdup(mapval);
2157 if (key == NULL || val == NULL)
2158 goto oom;
2159 strings[count].key = key;
2160 strings[count].value = val;
2161 count++;
2162 }
2163
2164 *strings_out = strings;
2165 *count_out = count;
2166 return 0;
2167
2168 oom:
2169 free(key);
2170 free(val);
2171 krb5_dbe_free_strings(context, strings, count);
2172 return ENOMEM;
2173 }
2174
2175 krb5_error_code
krb5_dbe_get_string(krb5_context context,krb5_db_entry * entry,const char * key,char ** value_out)2176 krb5_dbe_get_string(krb5_context context, krb5_db_entry *entry,
2177 const char *key, char **value_out)
2178 {
2179 krb5_error_code code;
2180 const char *pos, *end, *mapkey, *mapval;
2181
2182 *value_out = NULL;
2183 code = begin_attrs(context, entry, &pos, &end);
2184 if (code)
2185 return code;
2186 while (next_attr(&pos, end, &mapkey, &mapval)) {
2187 if (strcmp(mapkey, key) == 0) {
2188 *value_out = strdup(mapval);
2189 return (*value_out == NULL) ? ENOMEM : 0;
2190 }
2191 }
2192
2193 return 0;
2194 }
2195
2196 krb5_error_code
krb5_dbe_set_string(krb5_context context,krb5_db_entry * entry,const char * key,const char * value)2197 krb5_dbe_set_string(krb5_context context, krb5_db_entry *entry,
2198 const char *key, const char *value)
2199 {
2200 krb5_error_code code;
2201 const char *pos, *end, *mapkey, *mapval;
2202 struct k5buf buf = EMPTY_K5BUF;
2203 krb5_boolean found = FALSE;
2204 krb5_tl_data tl_data;
2205
2206 /* Copy the current mapping to buf, updating key with value if found. */
2207 code = begin_attrs(context, entry, &pos, &end);
2208 if (code)
2209 return code;
2210 k5_buf_init_dynamic(&buf);
2211 while (next_attr(&pos, end, &mapkey, &mapval)) {
2212 if (strcmp(mapkey, key) == 0) {
2213 if (value != NULL) {
2214 k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1);
2215 k5_buf_add_len(&buf, value, strlen(value) + 1);
2216 }
2217 found = TRUE;
2218 } else {
2219 k5_buf_add_len(&buf, mapkey, strlen(mapkey) + 1);
2220 k5_buf_add_len(&buf, mapval, strlen(mapval) + 1);
2221 }
2222 }
2223
2224 /* If key wasn't found in the map, add a new entry for it. */
2225 if (!found && value != NULL) {
2226 k5_buf_add_len(&buf, key, strlen(key) + 1);
2227 k5_buf_add_len(&buf, value, strlen(value) + 1);
2228 }
2229
2230 if (k5_buf_status(&buf) != 0)
2231 return ENOMEM;
2232 if (buf.len > 65535) {
2233 code = KRB5_KDB_STRINGS_TOOLONG;
2234 goto cleanup;
2235 }
2236 tl_data.tl_data_type = KRB5_TL_STRING_ATTRS;
2237 tl_data.tl_data_contents = buf.data;
2238 tl_data.tl_data_length = buf.len;
2239
2240 code = krb5_dbe_update_tl_data(context, entry, &tl_data);
2241
2242 cleanup:
2243 k5_buf_free(&buf);
2244 return code;
2245 }
2246
2247 krb5_error_code
krb5_dbe_delete_tl_data(krb5_context context,krb5_db_entry * entry,krb5_int16 tl_data_type)2248 krb5_dbe_delete_tl_data(krb5_context context, krb5_db_entry *entry,
2249 krb5_int16 tl_data_type)
2250 {
2251 krb5_tl_data *tl_data, *prev_tl_data, *free_tl_data;
2252
2253 /*
2254 * Find existing entries of the specified type and remove them from the
2255 * entry's tl_data list.
2256 */
2257
2258 for (prev_tl_data = tl_data = entry->tl_data; tl_data != NULL;) {
2259 if (tl_data->tl_data_type == tl_data_type) {
2260 if (tl_data == entry->tl_data) {
2261 /* remove from head */
2262 entry->tl_data = tl_data->tl_data_next;
2263 prev_tl_data = entry->tl_data;
2264 } else if (tl_data->tl_data_next == NULL) {
2265 /* remove from tail */
2266 prev_tl_data->tl_data_next = NULL;
2267 } else {
2268 /* remove in between */
2269 prev_tl_data->tl_data_next = tl_data->tl_data_next;
2270 }
2271 free_tl_data = tl_data;
2272 tl_data = tl_data->tl_data_next;
2273 krb5_dbe_free_tl_data(context, free_tl_data);
2274 entry->n_tl_data--;
2275 } else {
2276 prev_tl_data = tl_data;
2277 tl_data = tl_data->tl_data_next;
2278 }
2279 }
2280
2281 return (0);
2282 }
2283
2284 krb5_error_code
krb5_db_update_tl_data(krb5_context context,krb5_int16 * n_tl_datap,krb5_tl_data ** tl_datap,krb5_tl_data * new_tl_data)2285 krb5_db_update_tl_data(krb5_context context, krb5_int16 *n_tl_datap,
2286 krb5_tl_data **tl_datap, krb5_tl_data *new_tl_data)
2287 {
2288 krb5_tl_data *tl_data = NULL;
2289 krb5_octet *tmp;
2290
2291 /*
2292 * Copy the new data first, so we can fail cleanly if malloc()
2293 * fails.
2294 */
2295 tmp = malloc(new_tl_data->tl_data_length);
2296 if (tmp == NULL)
2297 return (ENOMEM);
2298
2299 /*
2300 * Find an existing entry of the specified type and point at
2301 * it, or NULL if not found.
2302 */
2303
2304 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */
2305 for (tl_data = *tl_datap; tl_data;
2306 tl_data = tl_data->tl_data_next)
2307 if (tl_data->tl_data_type == new_tl_data->tl_data_type)
2308 break;
2309 }
2310
2311 /* If necessary, chain a new record in the beginning and point at it. */
2312
2313 if (!tl_data) {
2314 tl_data = calloc(1, sizeof(*tl_data));
2315 if (tl_data == NULL) {
2316 free(tmp);
2317 return (ENOMEM);
2318 }
2319 tl_data->tl_data_next = *tl_datap;
2320 *tl_datap = tl_data;
2321 (*n_tl_datap)++;
2322 }
2323
2324 /* fill in the record */
2325
2326 free(tl_data->tl_data_contents);
2327
2328 tl_data->tl_data_type = new_tl_data->tl_data_type;
2329 tl_data->tl_data_length = new_tl_data->tl_data_length;
2330 tl_data->tl_data_contents = tmp;
2331 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
2332
2333 return (0);
2334 }
2335
2336 krb5_error_code
krb5_dbe_update_tl_data(krb5_context context,krb5_db_entry * entry,krb5_tl_data * new_tl_data)2337 krb5_dbe_update_tl_data(krb5_context context, krb5_db_entry *entry,
2338 krb5_tl_data *new_tl_data)
2339 {
2340 return krb5_db_update_tl_data(context, &entry->n_tl_data, &entry->tl_data,
2341 new_tl_data);
2342 }
2343
2344 krb5_error_code
krb5_dbe_compute_salt(krb5_context context,const krb5_key_data * key,krb5_const_principal princ,krb5_int16 * salttype_out,krb5_data ** salt_out)2345 krb5_dbe_compute_salt(krb5_context context, const krb5_key_data *key,
2346 krb5_const_principal princ, krb5_int16 *salttype_out,
2347 krb5_data **salt_out)
2348 {
2349 krb5_error_code retval;
2350 krb5_int16 stype;
2351 krb5_data *salt, sdata;
2352
2353 stype = (key->key_data_ver < 2) ? KRB5_KDB_SALTTYPE_NORMAL :
2354 key->key_data_type[1];
2355 *salttype_out = stype;
2356 *salt_out = NULL;
2357
2358 /* Place computed salt into sdata, or directly into salt_out and return. */
2359 switch (stype) {
2360 case KRB5_KDB_SALTTYPE_NORMAL:
2361 retval = krb5_principal2salt(context, princ, &sdata);
2362 if (retval)
2363 return retval;
2364 break;
2365 case KRB5_KDB_SALTTYPE_NOREALM:
2366 retval = krb5_principal2salt_norealm(context, princ, &sdata);
2367 if (retval)
2368 return retval;
2369 break;
2370 case KRB5_KDB_SALTTYPE_ONLYREALM:
2371 return krb5_copy_data(context, &princ->realm, salt_out);
2372 case KRB5_KDB_SALTTYPE_SPECIAL:
2373 sdata = make_data(key->key_data_contents[1], key->key_data_length[1]);
2374 return krb5_copy_data(context, &sdata, salt_out);
2375 default:
2376 return KRB5_KDB_BAD_SALTTYPE;
2377 }
2378
2379 /* Make a container for sdata. */
2380 salt = malloc(sizeof(*salt));
2381 if (salt == NULL) {
2382 free(sdata.data);
2383 return ENOMEM;
2384 }
2385 *salt = sdata;
2386 *salt_out = salt;
2387 return 0;
2388 }
2389
2390 krb5_error_code
krb5_dbe_specialize_salt(krb5_context context,krb5_db_entry * entry)2391 krb5_dbe_specialize_salt(krb5_context context, krb5_db_entry *entry)
2392 {
2393 krb5_int16 stype, i;
2394 krb5_data *salt;
2395 krb5_error_code ret;
2396
2397 if (context == NULL || entry == NULL)
2398 return EINVAL;
2399
2400 /*
2401 * Store salt values explicitly so that they don't depend on the principal
2402 * name.
2403 */
2404 for (i = 0; i < entry->n_key_data; i++) {
2405 ret = krb5_dbe_compute_salt(context, &entry->key_data[i], entry->princ,
2406 &stype, &salt);
2407 if (ret)
2408 return ret;
2409
2410 /* Steal the data pointer from salt and free the container. */
2411 if (entry->key_data[i].key_data_ver >= 2)
2412 free(entry->key_data[i].key_data_contents[1]);
2413 entry->key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_SPECIAL;
2414 entry->key_data[i].key_data_contents[1] = (uint8_t *)salt->data;
2415 entry->key_data[i].key_data_length[1] = salt->length;
2416 entry->key_data[i].key_data_ver = 2;
2417 free(salt);
2418 }
2419
2420 return 0;
2421 }
2422
2423 /* change password functions */
2424 krb5_error_code
krb5_dbe_cpw(krb5_context kcontext,krb5_keyblock * master_key,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,char * passwd,int new_kvno,krb5_boolean keepold,krb5_db_entry * db_entry)2425 krb5_dbe_cpw(krb5_context kcontext, krb5_keyblock *master_key,
2426 krb5_key_salt_tuple *ks_tuple, int ks_tuple_count, char *passwd,
2427 int new_kvno, krb5_boolean keepold, krb5_db_entry *db_entry)
2428 {
2429 krb5_error_code status = 0;
2430 kdb_vftabl *v;
2431
2432 status = get_vftabl(kcontext, &v);
2433 if (status)
2434 return status;
2435 return v->change_pwd(kcontext, master_key, ks_tuple, ks_tuple_count,
2436 passwd, new_kvno, keepold, db_entry);
2437 }
2438
2439 /* policy management functions */
2440 krb5_error_code
krb5_db_create_policy(krb5_context kcontext,osa_policy_ent_t policy)2441 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
2442 {
2443 krb5_error_code status = 0;
2444 kdb_vftabl *v;
2445
2446 status = get_vftabl(kcontext, &v);
2447 if (status)
2448 return status;
2449 if (v->create_policy == NULL)
2450 return KRB5_PLUGIN_OP_NOTSUPP;
2451
2452 status = v->create_policy(kcontext, policy);
2453 /* iprop does not support policy mods; force full resync. */
2454 if (!status && logging(kcontext))
2455 status = ulog_init_header(kcontext);
2456 return status;
2457 }
2458
2459 krb5_error_code
krb5_db_get_policy(krb5_context kcontext,char * name,osa_policy_ent_t * policy)2460 krb5_db_get_policy(krb5_context kcontext, char *name, osa_policy_ent_t *policy)
2461 {
2462 krb5_error_code status = 0;
2463 kdb_vftabl *v;
2464
2465 status = get_vftabl(kcontext, &v);
2466 if (status)
2467 return status;
2468 if (v->get_policy == NULL)
2469 return KRB5_PLUGIN_OP_NOTSUPP;
2470 return v->get_policy(kcontext, name, policy);
2471 }
2472
2473 krb5_error_code
krb5_db_put_policy(krb5_context kcontext,osa_policy_ent_t policy)2474 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
2475 {
2476 krb5_error_code status = 0;
2477 kdb_vftabl *v;
2478
2479 status = get_vftabl(kcontext, &v);
2480 if (status)
2481 return status;
2482 if (v->put_policy == NULL)
2483 return KRB5_PLUGIN_OP_NOTSUPP;
2484
2485 status = v->put_policy(kcontext, policy);
2486 /* iprop does not support policy mods; force full resync. */
2487 if (!status && logging(kcontext))
2488 status = ulog_init_header(kcontext);
2489 return status;
2490 }
2491
2492 krb5_error_code
krb5_db_iter_policy(krb5_context kcontext,char * match_entry,osa_adb_iter_policy_func func,void * data)2493 krb5_db_iter_policy(krb5_context kcontext, char *match_entry,
2494 osa_adb_iter_policy_func func, void *data)
2495 {
2496 krb5_error_code status = 0;
2497 kdb_vftabl *v;
2498
2499 status = get_vftabl(kcontext, &v);
2500 if (status)
2501 return status;
2502 if (v->iter_policy == NULL)
2503 return 0;
2504 return v->iter_policy(kcontext, match_entry, func, data);
2505 }
2506
2507 krb5_error_code
krb5_db_delete_policy(krb5_context kcontext,char * policy)2508 krb5_db_delete_policy(krb5_context kcontext, char *policy)
2509 {
2510 krb5_error_code status = 0;
2511 kdb_vftabl *v;
2512
2513 status = get_vftabl(kcontext, &v);
2514 if (status)
2515 return status;
2516 if (v->delete_policy == NULL)
2517 return KRB5_PLUGIN_OP_NOTSUPP;
2518
2519 status = v->delete_policy(kcontext, policy);
2520 /* iprop does not support policy mods; force full resync. */
2521 if (!status && logging(kcontext))
2522 status = ulog_init_header(kcontext);
2523 return status;
2524 }
2525
2526 void
krb5_db_free_policy(krb5_context kcontext,osa_policy_ent_t policy)2527 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy)
2528 {
2529 if (policy == NULL)
2530 return;
2531 free(policy->name);
2532 free(policy->allowed_keysalts);
2533 free_tl_data(policy->tl_data);
2534 free(policy);
2535 }
2536
2537 krb5_error_code
krb5_db_promote(krb5_context kcontext,char ** db_args)2538 krb5_db_promote(krb5_context kcontext, char **db_args)
2539 {
2540 krb5_error_code status;
2541 char *section;
2542 kdb_vftabl *v;
2543
2544 status = get_vftabl(kcontext, &v);
2545 if (status)
2546 return status;
2547 if (v->promote_db == NULL)
2548 return KRB5_PLUGIN_OP_NOTSUPP;
2549 status = get_conf_section(kcontext, §ion);
2550 if (status)
2551 return status;
2552 status = v->promote_db(kcontext, section, db_args);
2553 free(section);
2554 return status;
2555 }
2556
2557 static krb5_error_code
decrypt_iterator(krb5_context kcontext,const krb5_key_data * key_data,krb5_keyblock * dbkey,krb5_keysalt * keysalt)2558 decrypt_iterator(krb5_context kcontext, const krb5_key_data * key_data,
2559 krb5_keyblock *dbkey, krb5_keysalt *keysalt)
2560 {
2561 krb5_error_code status = 0;
2562 kdb_vftabl *v;
2563 krb5_keylist_node *n = kcontext->dal_handle->master_keylist;
2564
2565 status = get_vftabl(kcontext, &v);
2566 if (status)
2567 return status;
2568 for (; n; n = n->next) {
2569 krb5_clear_error_message(kcontext);
2570 status = v->decrypt_key_data(kcontext, &n->keyblock, key_data, dbkey,
2571 keysalt);
2572 if (status == 0)
2573 return 0;
2574 }
2575 return status;
2576 }
2577
2578 krb5_error_code
krb5_dbe_decrypt_key_data(krb5_context kcontext,const krb5_keyblock * mkey,const krb5_key_data * key_data,krb5_keyblock * dbkey,krb5_keysalt * keysalt)2579 krb5_dbe_decrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey,
2580 const krb5_key_data *key_data, krb5_keyblock *dbkey,
2581 krb5_keysalt *keysalt)
2582 {
2583 krb5_error_code status = 0;
2584 kdb_vftabl *v;
2585 krb5_keyblock *cur_mkey;
2586
2587 status = get_vftabl(kcontext, &v);
2588 if (status)
2589 return status;
2590 if (mkey || kcontext->dal_handle->master_keylist == NULL)
2591 return v->decrypt_key_data(kcontext, mkey, key_data, dbkey, keysalt);
2592 status = decrypt_iterator(kcontext, key_data, dbkey, keysalt);
2593 if (status == 0)
2594 return 0;
2595 if (kcontext->dal_handle->master_keylist) {
2596 /* Try reloading master keys. */
2597 cur_mkey = &kcontext->dal_handle->master_keylist->keyblock;
2598 if (krb5_db_fetch_mkey_list(kcontext,
2599 kcontext->dal_handle->master_princ,
2600 cur_mkey) == 0)
2601 return decrypt_iterator(kcontext, key_data, dbkey, keysalt);
2602 }
2603 return status;
2604 }
2605
2606 krb5_error_code
krb5_dbe_encrypt_key_data(krb5_context kcontext,const krb5_keyblock * mkey,const krb5_keyblock * dbkey,const krb5_keysalt * keysalt,int keyver,krb5_key_data * key_data)2607 krb5_dbe_encrypt_key_data(krb5_context kcontext, const krb5_keyblock *mkey,
2608 const krb5_keyblock *dbkey,
2609 const krb5_keysalt *keysalt, int keyver,
2610 krb5_key_data *key_data)
2611 {
2612 krb5_error_code status = 0;
2613 kdb_vftabl *v;
2614
2615 status = get_vftabl(kcontext, &v);
2616 if (status)
2617 return status;
2618 return v->encrypt_key_data(kcontext, mkey, dbkey, keysalt, keyver,
2619 key_data);
2620 }
2621
2622 krb5_error_code
krb5_db_get_context(krb5_context context,void ** db_context)2623 krb5_db_get_context(krb5_context context, void **db_context)
2624 {
2625 *db_context = KRB5_DB_GET_DB_CONTEXT(context);
2626 if (*db_context == NULL)
2627 return KRB5_KDB_DBNOTINITED;
2628 return 0;
2629 }
2630
2631 krb5_error_code
krb5_db_set_context(krb5_context context,void * db_context)2632 krb5_db_set_context(krb5_context context, void *db_context)
2633 {
2634 KRB5_DB_GET_DB_CONTEXT(context) = db_context;
2635
2636 return 0;
2637 }
2638
2639 krb5_error_code
krb5_db_check_transited_realms(krb5_context kcontext,const krb5_data * tr_contents,const krb5_data * client_realm,const krb5_data * server_realm)2640 krb5_db_check_transited_realms(krb5_context kcontext,
2641 const krb5_data *tr_contents,
2642 const krb5_data *client_realm,
2643 const krb5_data *server_realm)
2644 {
2645 krb5_error_code status;
2646 kdb_vftabl *v;
2647
2648 status = get_vftabl(kcontext, &v);
2649 if (status)
2650 return status;
2651 if (v->check_transited_realms == NULL)
2652 return KRB5_PLUGIN_OP_NOTSUPP;
2653 return v->check_transited_realms(kcontext, tr_contents, client_realm,
2654 server_realm);
2655 }
2656
2657 krb5_error_code
krb5_db_check_policy_as(krb5_context kcontext,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp kdc_time,const char ** status,krb5_pa_data *** e_data)2658 krb5_db_check_policy_as(krb5_context kcontext, krb5_kdc_req *request,
2659 krb5_db_entry *client, krb5_db_entry *server,
2660 krb5_timestamp kdc_time, const char **status,
2661 krb5_pa_data ***e_data)
2662 {
2663 krb5_error_code ret;
2664 kdb_vftabl *v;
2665
2666 *status = NULL;
2667 *e_data = NULL;
2668 ret = get_vftabl(kcontext, &v);
2669 if (ret)
2670 return ret;
2671 if (v->check_policy_as == NULL)
2672 return KRB5_PLUGIN_OP_NOTSUPP;
2673 return v->check_policy_as(kcontext, request, client, server, kdc_time,
2674 status, e_data);
2675 }
2676
2677 krb5_error_code
krb5_db_check_policy_tgs(krb5_context kcontext,krb5_kdc_req * request,krb5_db_entry * server,krb5_ticket * ticket,const char ** status,krb5_pa_data *** e_data)2678 krb5_db_check_policy_tgs(krb5_context kcontext, krb5_kdc_req *request,
2679 krb5_db_entry *server, krb5_ticket *ticket,
2680 const char **status, krb5_pa_data ***e_data)
2681 {
2682 krb5_error_code ret;
2683 kdb_vftabl *v;
2684
2685 *status = NULL;
2686 *e_data = NULL;
2687 ret = get_vftabl(kcontext, &v);
2688 if (ret)
2689 return ret;
2690 if (v->check_policy_tgs == NULL)
2691 return KRB5_PLUGIN_OP_NOTSUPP;
2692 return v->check_policy_tgs(kcontext, request, server, ticket, status,
2693 e_data);
2694 }
2695
2696 void
krb5_db_audit_as_req(krb5_context kcontext,krb5_kdc_req * request,const krb5_address * local_addr,const krb5_address * remote_addr,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp authtime,krb5_error_code error_code)2697 krb5_db_audit_as_req(krb5_context kcontext, krb5_kdc_req *request,
2698 const krb5_address *local_addr,
2699 const krb5_address *remote_addr, krb5_db_entry *client,
2700 krb5_db_entry *server, krb5_timestamp authtime,
2701 krb5_error_code error_code)
2702 {
2703 krb5_error_code status;
2704 kdb_vftabl *v;
2705
2706 status = get_vftabl(kcontext, &v);
2707 if (status || v->audit_as_req == NULL)
2708 return;
2709 v->audit_as_req(kcontext, request, local_addr, remote_addr,
2710 client, server, authtime, error_code);
2711 }
2712
2713 void
krb5_db_refresh_config(krb5_context kcontext)2714 krb5_db_refresh_config(krb5_context kcontext)
2715 {
2716 krb5_error_code status;
2717 kdb_vftabl *v;
2718
2719 status = get_vftabl(kcontext, &v);
2720 if (status || v->refresh_config == NULL)
2721 return;
2722 v->refresh_config(kcontext);
2723 }
2724
2725 krb5_error_code
krb5_db_check_allowed_to_delegate(krb5_context kcontext,krb5_const_principal client,const krb5_db_entry * server,krb5_const_principal proxy)2726 krb5_db_check_allowed_to_delegate(krb5_context kcontext,
2727 krb5_const_principal client,
2728 const krb5_db_entry *server,
2729 krb5_const_principal proxy)
2730 {
2731 krb5_error_code ret;
2732 kdb_vftabl *v;
2733
2734 ret = get_vftabl(kcontext, &v);
2735 if (ret)
2736 return ret;
2737 if (v->check_allowed_to_delegate == NULL)
2738 return KRB5_PLUGIN_OP_NOTSUPP;
2739 return v->check_allowed_to_delegate(kcontext, client, server, proxy);
2740 }
2741
2742 krb5_error_code
krb5_db_get_s4u_x509_principal(krb5_context kcontext,const krb5_data * client_cert,krb5_const_principal in_princ,unsigned int flags,krb5_db_entry ** entry)2743 krb5_db_get_s4u_x509_principal(krb5_context kcontext,
2744 const krb5_data *client_cert,
2745 krb5_const_principal in_princ,
2746 unsigned int flags, krb5_db_entry **entry)
2747 {
2748 krb5_error_code ret;
2749 kdb_vftabl *v;
2750
2751 ret = get_vftabl(kcontext, &v);
2752 if (ret)
2753 return ret;
2754 if (v->get_s4u_x509_principal == NULL)
2755 return KRB5_PLUGIN_OP_NOTSUPP;
2756 ret = v->get_s4u_x509_principal(kcontext, client_cert, in_princ, flags,
2757 entry);
2758 if (ret)
2759 return ret;
2760
2761 /* Sort the keys in the db entry, same as get_principal(). */
2762 if ((*entry)->key_data != NULL)
2763 krb5_dbe_sort_key_data((*entry)->key_data, (*entry)->n_key_data);
2764
2765 return 0;
2766 }
2767
2768 krb5_error_code
krb5_db_allowed_to_delegate_from(krb5_context kcontext,krb5_const_principal client,krb5_const_principal server,krb5_pac server_pac,const krb5_db_entry * proxy)2769 krb5_db_allowed_to_delegate_from(krb5_context kcontext,
2770 krb5_const_principal client,
2771 krb5_const_principal server,
2772 krb5_pac server_pac,
2773 const krb5_db_entry *proxy)
2774 {
2775 krb5_error_code ret;
2776 kdb_vftabl *v;
2777
2778 ret = get_vftabl(kcontext, &v);
2779 if (ret)
2780 return ret;
2781 if (v->allowed_to_delegate_from == NULL)
2782 return KRB5_PLUGIN_OP_NOTSUPP;
2783 return v->allowed_to_delegate_from(kcontext, client, server, server_pac,
2784 proxy);
2785 }
2786
2787 void
krb5_dbe_sort_key_data(krb5_key_data * key_data,size_t key_data_length)2788 krb5_dbe_sort_key_data(krb5_key_data *key_data, size_t key_data_length)
2789 {
2790 size_t i, j;
2791 krb5_key_data tmp;
2792
2793 /* Use insertion sort as a stable sort. */
2794 for (i = 1; i < key_data_length; i++) {
2795 j = i;
2796 while (j > 0 &&
2797 key_data[j - 1].key_data_kvno < key_data[j].key_data_kvno) {
2798 tmp = key_data[j];
2799 key_data[j] = key_data[j - 1];
2800 key_data[j - 1] = tmp;
2801 j--;
2802 }
2803 }
2804 }
2805
2806 krb5_error_code
krb5_db_issue_pac(krb5_context context,unsigned int flags,krb5_db_entry * client,krb5_keyblock * replaced_reply_key,krb5_db_entry * server,krb5_db_entry * krbtgt,krb5_timestamp authtime,krb5_pac old_pac,krb5_pac new_pac,krb5_data *** auth_indicators)2807 krb5_db_issue_pac(krb5_context context, unsigned int flags,
2808 krb5_db_entry *client, krb5_keyblock *replaced_reply_key,
2809 krb5_db_entry *server, krb5_db_entry *krbtgt,
2810 krb5_timestamp authtime, krb5_pac old_pac, krb5_pac new_pac,
2811 krb5_data ***auth_indicators)
2812 {
2813 krb5_error_code ret;
2814 kdb_vftabl *v;
2815
2816 ret = get_vftabl(context, &v);
2817 if (ret)
2818 return ret;
2819 if (v->issue_pac == NULL)
2820 return KRB5_PLUGIN_OP_NOTSUPP;
2821 return v->issue_pac(context, flags, client, replaced_reply_key, server,
2822 krbtgt, authtime, old_pac, new_pac, auth_indicators);
2823 }
2824
2825 krb5_error_code
krb5_dbe_make_alias_entry(krb5_context context,krb5_const_principal alias,krb5_const_principal target,krb5_db_entry ** out)2826 krb5_dbe_make_alias_entry(krb5_context context, krb5_const_principal alias,
2827 krb5_const_principal target, krb5_db_entry **out)
2828 {
2829 krb5_error_code ret;
2830 krb5_principal princ = NULL;
2831 char *target_str = NULL;
2832 krb5_tl_data *tl = NULL;
2833 krb5_db_entry *ent;
2834
2835 *out = NULL;
2836
2837 ret = krb5_copy_principal(context, alias, &princ);
2838 if (ret)
2839 goto cleanup;
2840
2841 ret = krb5_unparse_name(context, target, &target_str);
2842 if (ret)
2843 goto cleanup;
2844 tl = k5alloc(sizeof(*tl), &ret);
2845 if (tl == NULL)
2846 goto cleanup;
2847 tl->tl_data_next = NULL;
2848 tl->tl_data_type = KRB5_TL_ALIAS_TARGET;
2849 tl->tl_data_length = strlen(target_str) + 1;
2850 tl->tl_data_contents = (uint8_t *)target_str;
2851
2852 ent = k5alloc(sizeof(*ent), &ret);
2853 if (ent == NULL)
2854 goto cleanup;
2855 ent->len = KRB5_KDB_V1_BASE_LENGTH;
2856 ent->attributes = KRB5_KDB_DISALLOW_ALL_TIX;
2857 ent->princ = princ;
2858 ent->tl_data = tl;
2859 ent->n_tl_data = 1;
2860 princ = NULL;
2861 target_str = NULL;
2862 tl = NULL;
2863 *out = ent;
2864
2865 cleanup:
2866 krb5_free_principal(context, princ);
2867 krb5_free_unparsed_name(context, target_str);
2868 free(tl);
2869 return ret;
2870 }
2871
2872 krb5_error_code
krb5_dbe_read_alias(krb5_context context,krb5_db_entry * entry,krb5_principal * target_out)2873 krb5_dbe_read_alias(krb5_context context, krb5_db_entry *entry,
2874 krb5_principal *target_out)
2875 {
2876 krb5_error_code ret;
2877 krb5_tl_data tl;
2878
2879 *target_out = NULL;
2880
2881 tl.tl_data_type = KRB5_TL_ALIAS_TARGET;
2882 ret = krb5_dbe_lookup_tl_data(context, entry, &tl);
2883 if (ret)
2884 return ret;
2885
2886 if (tl.tl_data_length == 0)
2887 return 0;
2888
2889 if (tl.tl_data_contents[tl.tl_data_length - 1] != '\0')
2890 return KRB5_KDB_TRUNCATED_RECORD;
2891
2892 return krb5_parse_name(context, (char *)tl.tl_data_contents, target_out);
2893 }
2894