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