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