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