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