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