1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * Copyright 2006 by the Massachusetts Institute of Technology.
8 * All Rights Reserved.
9 *
10 * Export of this software from the United States of America may
11 * require a specific license from the United States Government.
12 * It is the responsibility of any person or organization contemplating
13 * export to obtain such a license before exporting.
14 *
15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
16 * distribute this software and its documentation for any purpose and
17 * without fee is hereby granted, provided that the above copyright
18 * notice appear in all copies and that both that copyright notice and
19 * this permission notice appear in supporting documentation, and that
20 * the name of M.I.T. not be used in advertising or publicity pertaining
21 * to distribution of the software without specific, written prior
22 * permission. Furthermore if you modify this software you must label
23 * your software as modified software and not distribute it in such a
24 * fashion that it might be confused with the original M.I.T. software.
25 * M.I.T. makes no representations about the suitability of
26 * this software for any purpose. It is provided "as is" without express
27 * or implied warranty.
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 "k5-platform.h"
46 #include <libintl.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
kdb_init_lock_list(void)81 kdb_init_lock_list(void)
82 {
83 return k5_mutex_finish_init(&db_lock);
84 }
85
86 static int
kdb_lock_list()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
kdb_fini_lock_list(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
kdb_unlock_list()104 kdb_unlock_list()
105 {
106 return k5_mutex_unlock(&db_lock);
107 }
108
109 #define kdb_init_lib_lock(a) 0
110 #define kdb_destroy_lib_lock(a) (void)0
111 #define kdb_lock_lib_lock(a, b) 0
112 #define kdb_unlock_lib_lock(a, b) (void)0
113
114 /* Caller must free result*/
115
116 static char *
kdb_get_conf_section(krb5_context kcontext)117 kdb_get_conf_section(krb5_context kcontext)
118 {
119 krb5_error_code status = 0;
120 char *result = NULL;
121 char *value = NULL;
122
123 if (kcontext->default_realm == NULL)
124 return NULL;
125 /* The profile has to have been initialized. If the profile was
126 not initialized, expect nothing less than a crash. */
127 status = profile_get_string(kcontext->profile,
128 /* realms */
129 KDB_REALM_SECTION,
130 kcontext->default_realm,
131 /* under the realm name, database_module */
132 KDB_MODULE_POINTER,
133 /* default value is the realm name itself */
134 kcontext->default_realm,
135 &value);
136
137 if (status) {
138 /* some problem */
139 result = strdup(kcontext->default_realm);
140 /* let NULL be handled by the caller */
141 } else {
142 result = strdup(value);
143 /* free profile string */
144 profile_release_string(value);
145 }
146
147 return result;
148 }
149
150 static char *
kdb_get_library_name(krb5_context kcontext)151 kdb_get_library_name(krb5_context kcontext)
152 {
153 krb5_error_code status = 0;
154 char *result = NULL;
155 char *value = NULL;
156 char *lib = NULL;
157
158 status = profile_get_string(kcontext->profile,
159 /* realms */
160 KDB_REALM_SECTION,
161 kcontext->default_realm,
162 /* under the realm name, database_module */
163 KDB_MODULE_POINTER,
164 /* default value is the realm name itself */
165 kcontext->default_realm,
166 &value);
167 if (status) {
168 goto clean_n_exit;
169 }
170
171 #define DB2_NAME "db2"
172 /* we got the module section. Get the library name from the module */
173 status = profile_get_string(kcontext->profile, KDB_MODULE_SECTION, value,
174 KDB_LIB_POINTER,
175 /* default to db2 */
176 DB2_NAME,
177 &lib);
178
179 if (status) {
180 goto clean_n_exit;
181 }
182
183 result = strdup(lib);
184 clean_n_exit:
185 if (value) {
186 /* free profile string */
187 profile_release_string(value);
188 }
189
190 if (lib) {
191 /* free profile string */
192 profile_release_string(lib);
193 }
194 return result;
195 }
196
197 static void
kdb_setup_opt_functions(db_library lib)198 kdb_setup_opt_functions(db_library lib)
199 {
200 if (lib->vftabl.set_master_key == NULL) {
201 lib->vftabl.set_master_key = kdb_def_set_mkey;
202 }
203
204 if (lib->vftabl.get_master_key == NULL) {
205 lib->vftabl.get_master_key = kdb_def_get_mkey;
206 }
207
208 if (lib->vftabl.fetch_master_key == NULL) {
209 lib->vftabl.fetch_master_key = krb5_db_def_fetch_mkey;
210 }
211
212 if (lib->vftabl.verify_master_key == NULL) {
213 lib->vftabl.verify_master_key = krb5_def_verify_master_key;
214 }
215
216 if (lib->vftabl.dbe_search_enctype == NULL) {
217 lib->vftabl.dbe_search_enctype = krb5_dbe_def_search_enctype;
218 }
219
220 if (lib->vftabl.db_change_pwd == NULL) {
221 lib->vftabl.db_change_pwd = krb5_dbe_def_cpw;
222 }
223
224 if (lib->vftabl.store_master_key == NULL) {
225 lib->vftabl.store_master_key = krb5_def_store_mkey;
226 }
227
228 if (lib->vftabl.promote_db == NULL) {
229 lib->vftabl.promote_db = krb5_def_promote_db;
230 }
231 }
232
233 static int kdb_db2_pol_err_loaded = 0;
234 #ifdef _KDB5_STATIC_LINK
235 #define DEF_SYMBOL(a) extern kdb_vftabl krb5_db_vftabl_ ## a
236 #define GET_SYMBOL(a) (krb5_db_vftabl_ ## a)
237 static krb5_error_code
kdb_load_library(krb5_context kcontext,char * lib_name,db_library * lib)238 kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib)
239 {
240 krb5_error_code status;
241 void *vftabl_addr = NULL;
242 char buf[KRB5_MAX_ERR_STR];
243
244 if (!strcmp("kdb_db2", lib_name) && (kdb_db2_pol_err_loaded == 0)) {
245 initialize_adb_error_table();
246 kdb_db2_pol_err_loaded = 1;
247 }
248
249 *lib = calloc((size_t) 1, sizeof(**lib));
250 if (*lib == NULL) {
251 status = ENOMEM;
252 goto clean_n_exit;
253 }
254
255 status = kdb_init_lib_lock(*lib);
256 if (status) {
257 goto clean_n_exit;
258 }
259
260 strcpy((*lib)->name, lib_name);
261
262 #if !defined(KDB5_USE_LIB_KDB_DB2) && !defined(KDB5_USE_LIB_TEST)
263 #error No database module defined
264 #endif
265
266 #ifdef KDB5_USE_LIB_KDB_DB2
267 if (strcmp(lib_name, "kdb_db2") == 0) {
268 DEF_SYMBOL(kdb_db2);
269 vftabl_addr = (void *) &GET_SYMBOL(kdb_db2);
270 } else
271 #endif
272 #ifdef KDB5_USE_LIB_TEST
273 if (strcmp(lib_name, "test") == 0) {
274 DEF_SYMBOL(test);
275 vftabl_addr = (void *) &GET_SYMBOL(test);
276 } else
277 #endif
278 {
279 snprintf(buf, sizeof(buf), gettext("Program not built to support %s database type\n"),
280 lib_name);
281 status = KRB5_KDB_DBTYPE_NOSUP;
282 krb5_db_set_err(kcontext, krb5_err_have_str, status, buf);
283 goto clean_n_exit;
284 }
285
286 memcpy(&(*lib)->vftabl, vftabl_addr, sizeof(kdb_vftabl));
287
288 kdb_setup_opt_functions(*lib);
289
290 if ((status = (*lib)->vftabl.init_library())) {
291 /* ERROR. library not initialized cleanly */
292 snprintf(buf, sizeof(buf), gettext("%s library initialization failed, error code %ld\n"),
293 lib_name, status);
294 status = KRB5_KDB_DBTYPE_INIT;
295 krb5_db_set_err(kcontext, krb5_err_have_str, status, buf);
296 goto clean_n_exit;
297 }
298
299 clean_n_exit:
300 if (status) {
301 free(*lib), *lib = NULL;
302 }
303 return status;
304 }
305
306 #else /* KDB5_STATIC_LINK*/
307
308 static char *db_dl_location[] = DEFAULT_KDB_LIB_PATH;
309 #define db_dl_n_locations (sizeof(db_dl_location) / sizeof(db_dl_location[0]))
310
311 static krb5_error_code
kdb_load_library(krb5_context kcontext,char * lib_name,db_library * lib)312 kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib)
313 {
314 krb5_error_code status = 0;
315 int ndx;
316 void **vftabl_addrs = NULL;
317 /* N.B.: If this is "const" but not "static", the Solaris 10
318 native compiler has trouble building the library because of
319 absolute relocations needed in read-only section ".rodata".
320 When it's static, it goes into ".picdata", which is
321 read-write. */
322 static const char *const dbpath_names[] = {
323 KDB_MODULE_SECTION, "db_module_dir", NULL,
324 };
325 const char *filebases[2];
326 char **profpath = NULL;
327 char **path = NULL;
328
329 filebases[0] = lib_name;
330 filebases[1] = NULL;
331
332 if (!strcmp(DB2_NAME, lib_name) && (kdb_db2_pol_err_loaded == 0)) {
333 initialize_adb_error_table();
334 kdb_db2_pol_err_loaded = 1;
335 }
336
337 *lib = calloc((size_t) 1, sizeof(**lib));
338 if (*lib == NULL) {
339 status = ENOMEM;
340 goto clean_n_exit;
341 }
342
343 status = kdb_init_lib_lock(*lib);
344 if (status) {
345 goto clean_n_exit;
346 }
347
348 strcpy((*lib)->name, lib_name);
349
350 /* Fetch the list of directories specified in the config
351 file(s) first. */
352 status = profile_get_values(kcontext->profile, dbpath_names, &profpath);
353 if (status != 0 && status != PROF_NO_RELATION)
354 goto clean_n_exit;
355 ndx = 0;
356 if (profpath)
357 while (profpath[ndx] != NULL)
358 ndx++;
359
360 path = calloc(ndx + db_dl_n_locations, sizeof (char *));
361 if (path == NULL) {
362 status = errno;
363 goto clean_n_exit;
364 }
365 if (ndx)
366 memcpy(path, profpath, ndx * sizeof(profpath[0]));
367 memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *));
368 status = 0;
369
370 if ((status = krb5int_open_plugin_dirs ((const char **) path,
371 filebases,
372 &(*lib)->dl_dir_handle, &kcontext->err))) {
373 const char *err_str = krb5_get_error_message(kcontext, status);
374 status = KRB5_KDB_DBTYPE_NOTFOUND;
375 krb5_set_error_message (kcontext, status,
376 gettext("Unable to find requested database type: %s"), err_str);
377 krb5_free_error_message (kcontext, err_str);
378 goto clean_n_exit;
379 }
380
381 if ((status = krb5int_get_plugin_dir_data (&(*lib)->dl_dir_handle, "kdb_function_table",
382 &vftabl_addrs, &kcontext->err))) {
383 const char *err_str = krb5_get_error_message(kcontext, status);
384 status = KRB5_KDB_DBTYPE_INIT;
385 krb5_set_error_message (kcontext, status,
386 gettext("plugin symbol 'kdb_function_table' lookup failed: %s"), err_str);
387 krb5_free_error_message (kcontext, err_str);
388 goto clean_n_exit;
389 }
390
391 if (vftabl_addrs[0] == NULL) {
392 /* No plugins! */
393 status = KRB5_KDB_DBTYPE_NOTFOUND;
394 krb5_set_error_message (kcontext, status,
395 gettext("Unable to load requested database module '%s': plugin symbol 'kdb_function_table' not found"),
396 lib_name);
397 goto clean_n_exit;
398 }
399
400 memcpy(&(*lib)->vftabl, vftabl_addrs[0], sizeof(kdb_vftabl));
401 kdb_setup_opt_functions(*lib);
402
403 if ((status = (*lib)->vftabl.init_library())) {
404 /* ERROR. library not initialized cleanly */
405 goto clean_n_exit;
406 }
407
408 clean_n_exit:
409 if (vftabl_addrs != NULL) { krb5int_free_plugin_dir_data (vftabl_addrs); }
410 /* Both of these DTRT with NULL. */
411 profile_free_list(profpath);
412 free(path);
413 if (status) {
414 if (*lib) {
415 kdb_destroy_lib_lock(*lib);
416 if (PLUGIN_DIR_OPEN((&(*lib)->dl_dir_handle))) {
417 krb5int_close_plugin_dirs (&(*lib)->dl_dir_handle);
418 }
419 free(*lib);
420 *lib = NULL;
421 }
422 }
423 return status;
424 }
425
426 #endif /* end of _KDB5_STATIC_LINK */
427
428 static krb5_error_code
kdb_find_library(krb5_context kcontext,char * lib_name,db_library * lib)429 kdb_find_library(krb5_context kcontext, char *lib_name, db_library * lib)
430 {
431 /* lock here so that no two threads try to do the same at the same time */
432 krb5_error_code status = 0;
433 int locked = 0;
434 db_library curr_elt, prev_elt = NULL;
435
436 if ((status = kdb_lock_list()) != 0) {
437 goto clean_n_exit;
438 }
439 locked = 1;
440
441 curr_elt = lib_list;
442 while (curr_elt != NULL) {
443 if (strcmp(lib_name, curr_elt->name) == 0) {
444 *lib = curr_elt;
445 goto clean_n_exit;
446 }
447 prev_elt = curr_elt;
448 curr_elt = curr_elt->next;
449 }
450
451 /* module not found. create and add to list */
452 status = kdb_load_library(kcontext, lib_name, lib);
453 if (status) {
454 goto clean_n_exit;
455 }
456
457 if (prev_elt) {
458 /* prev_elt points to the last element in the list */
459 prev_elt->next = *lib;
460 (*lib)->prev = prev_elt;
461 } else {
462 lib_list = *lib;
463 }
464
465 clean_n_exit:
466 if (*lib) {
467 (*lib)->reference_cnt++;
468 }
469
470 if (locked) {
471 (void)kdb_unlock_list();
472 }
473
474 return status;
475 }
476
477 static krb5_error_code
kdb_free_library(db_library lib)478 kdb_free_library(db_library lib)
479 {
480 krb5_error_code status = 0;
481 int locked = 0;
482
483 if ((status = kdb_lock_list()) != 0) {
484 goto clean_n_exit;
485 }
486 locked = 1;
487
488 lib->reference_cnt--;
489
490 if (lib->reference_cnt == 0) {
491 status = lib->vftabl.fini_library();
492 if (status) {
493 goto clean_n_exit;
494 }
495
496 /* close the library */
497 if (PLUGIN_DIR_OPEN((&lib->dl_dir_handle))) {
498 krb5int_close_plugin_dirs (&lib->dl_dir_handle);
499 }
500
501 kdb_destroy_lib_lock(lib);
502
503 if (lib->prev == NULL) {
504 /* first element in the list */
505 lib_list = lib->next;
506 } else {
507 lib->prev->next = lib->next;
508 }
509
510 if (lib->next) {
511 lib->next->prev = lib->prev;
512 }
513 free(lib);
514 }
515
516 clean_n_exit:
517 if (locked) {
518 (void)kdb_unlock_list();
519 }
520
521 return status;
522 }
523
524 static krb5_error_code
kdb_setup_lib_handle(krb5_context kcontext)525 kdb_setup_lib_handle(krb5_context kcontext)
526 {
527 char *library = NULL;
528 krb5_error_code status = 0;
529 db_library lib = NULL;
530 kdb5_dal_handle *dal_handle = NULL;
531
532 dal_handle = calloc((size_t) 1, sizeof(kdb5_dal_handle));
533 if (dal_handle == NULL) {
534 status = ENOMEM;
535 goto clean_n_exit;
536 }
537
538 library = kdb_get_library_name(kcontext);
539 if (library == NULL) {
540 status = KRB5_KDB_DBTYPE_NOTFOUND;
541 goto clean_n_exit;
542 }
543
544 status = kdb_find_library(kcontext, library, &lib);
545 if (status) {
546 goto clean_n_exit;
547 }
548
549 dal_handle->lib_handle = lib;
550 kcontext->db_context = (void *) dal_handle;
551
552 clean_n_exit:
553 free(library);
554
555 if (status) {
556 free(dal_handle);
557 if (lib) {
558 (void)kdb_free_library(lib);
559 }
560 }
561
562 return status;
563 }
564
565 static krb5_error_code
kdb_free_lib_handle(krb5_context kcontext)566 kdb_free_lib_handle(krb5_context kcontext)
567 {
568 krb5_error_code status = 0;
569
570 status =
571 kdb_free_library(((kdb5_dal_handle *) kcontext->db_context)->
572 lib_handle);
573 if (status) {
574 goto clean_n_exit;
575 }
576
577 free(kcontext->db_context);
578 kcontext->db_context = NULL;
579
580 clean_n_exit:
581 return status;
582 }
583
584 static void
get_errmsg(krb5_context kcontext,krb5_error_code err_code)585 get_errmsg (krb5_context kcontext, krb5_error_code err_code)
586 {
587 kdb5_dal_handle *dal_handle;
588 const char *e;
589 if (err_code == 0)
590 return;
591 assert(kcontext != NULL);
592 /* Must be called with dal_handle->lib_handle locked! */
593 assert(kcontext->db_context != NULL);
594 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
595 if (dal_handle->lib_handle->vftabl.errcode_2_string == NULL)
596 return;
597 e = dal_handle->lib_handle->vftabl.errcode_2_string(kcontext, err_code);
598 assert (e != NULL);
599 krb5_set_error_message(kcontext, err_code, "%s", e);
600 if (dal_handle->lib_handle->vftabl.release_errcode_string)
601 dal_handle->lib_handle->vftabl.release_errcode_string(kcontext, e);
602 }
603
604 /*
605 * External functions... DAL API
606 */
607 krb5_error_code
krb5_db_open(krb5_context kcontext,char ** db_args,int mode)608 krb5_db_open(krb5_context kcontext, char **db_args, int mode)
609 {
610 krb5_error_code status = 0;
611 char *section = NULL;
612 kdb5_dal_handle *dal_handle;
613
614 section = kdb_get_conf_section(kcontext);
615 if (section == NULL) {
616 status = KRB5_KDB_SERVER_INTERNAL_ERR;
617 krb5_set_error_message (kcontext, status,
618 gettext("unable to determine configuration section for realm %s\n"),
619 kcontext->default_realm ? kcontext->default_realm : "[UNSET]");
620 goto clean_n_exit;
621 }
622
623 if (kcontext->db_context == NULL) {
624 status = kdb_setup_lib_handle(kcontext);
625 if (status) {
626 goto clean_n_exit;
627 }
628 }
629
630 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
631 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
632 if (status) {
633 /* Solaris Kerberos */
634 kdb_free_lib_handle(kcontext);
635 goto clean_n_exit;
636 }
637
638 status =
639 dal_handle->lib_handle->vftabl.init_module(kcontext, section, db_args,
640 mode);
641 get_errmsg(kcontext, status);
642
643 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
644
645 /* Solaris Kerberos */
646 if (status)
647 kdb_free_lib_handle(kcontext);
648
649 clean_n_exit:
650 if (section)
651 free(section);
652 return status;
653 }
654
655 krb5_error_code
krb5_db_inited(krb5_context kcontext)656 krb5_db_inited(krb5_context kcontext)
657 {
658 return !(kcontext && kcontext->db_context &&
659 ((kdb5_dal_handle *) kcontext->db_context)->db_context);
660 }
661
662 krb5_error_code
krb5_db_create(krb5_context kcontext,char ** db_args)663 krb5_db_create(krb5_context kcontext, char **db_args)
664 {
665 krb5_error_code status = 0;
666 char *section = NULL;
667 kdb5_dal_handle *dal_handle;
668
669 section = kdb_get_conf_section(kcontext);
670 if (section == NULL) {
671 status = KRB5_KDB_SERVER_INTERNAL_ERR;
672 krb5_set_error_message (kcontext, status,
673 gettext("unable to determine configuration section for realm %s\n"),
674 kcontext->default_realm);
675 goto clean_n_exit;
676 }
677
678 if (kcontext->db_context == NULL) {
679 status = kdb_setup_lib_handle(kcontext);
680 if (status) {
681 goto clean_n_exit;
682 }
683 }
684
685 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
686 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
687 if (status) {
688 goto clean_n_exit;
689 }
690
691 status =
692 dal_handle->lib_handle->vftabl.db_create(kcontext, section, db_args);
693 get_errmsg(kcontext, status);
694
695 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
696
697 clean_n_exit:
698 if (section)
699 free(section);
700 return status;
701 }
702
703 krb5_error_code
krb5_db_fini(krb5_context kcontext)704 krb5_db_fini(krb5_context kcontext)
705 {
706 krb5_error_code status = 0;
707 kdb5_dal_handle *dal_handle;
708
709 if (kcontext->db_context == NULL) {
710 /* module not loaded. So nothing to be done */
711 goto clean_n_exit;
712 }
713
714 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
715 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
716 if (status) {
717 goto clean_n_exit;
718 }
719
720 status = dal_handle->lib_handle->vftabl.fini_module(kcontext);
721 get_errmsg(kcontext, status);
722
723 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
724
725 if (status) {
726 goto clean_n_exit;
727 }
728
729 status = kdb_free_lib_handle(kcontext);
730
731 clean_n_exit:
732 return status;
733 }
734
735 krb5_error_code
krb5_db_destroy(krb5_context kcontext,char ** db_args)736 krb5_db_destroy(krb5_context kcontext, char **db_args)
737 {
738 krb5_error_code status = 0;
739 char *section = NULL;
740 kdb5_dal_handle *dal_handle;
741
742 section = kdb_get_conf_section(kcontext);
743 if (section == NULL) {
744 status = KRB5_KDB_SERVER_INTERNAL_ERR;
745 krb5_set_error_message (kcontext, status,
746 gettext("unable to determine configuration section for realm %s\n"),
747 kcontext->default_realm);
748 goto clean_n_exit;
749 }
750
751 if (kcontext->db_context == NULL) {
752 status = kdb_setup_lib_handle(kcontext);
753 if (status) {
754 goto clean_n_exit;
755 }
756 }
757
758 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
759 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
760 if (status) {
761 goto clean_n_exit;
762 }
763
764 status =
765 dal_handle->lib_handle->vftabl.db_destroy(kcontext, section, db_args);
766 get_errmsg(kcontext, status);
767 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
768
769 clean_n_exit:
770 if (section)
771 free(section);
772 return status;
773 }
774
775 krb5_error_code
krb5_db_get_age(krb5_context kcontext,char * db_name,time_t * t)776 krb5_db_get_age(krb5_context kcontext, char *db_name, time_t * t)
777 {
778 krb5_error_code status = 0;
779 kdb5_dal_handle *dal_handle;
780
781 if (kcontext->db_context == NULL) {
782 status = kdb_setup_lib_handle(kcontext);
783 if (status) {
784 goto clean_n_exit;
785 }
786 }
787
788 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
789 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
790 if (status) {
791 goto clean_n_exit;
792 }
793
794 status = dal_handle->lib_handle->vftabl.db_get_age(kcontext, db_name, t);
795 get_errmsg(kcontext, status);
796 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
797
798 clean_n_exit:
799 return status;
800 }
801
802 krb5_error_code
krb5_db_set_option(krb5_context kcontext,int option,void * value)803 krb5_db_set_option(krb5_context kcontext, int option, void *value)
804 {
805 krb5_error_code status = 0;
806 kdb5_dal_handle *dal_handle;
807
808 if (kcontext->db_context == NULL) {
809 status = kdb_setup_lib_handle(kcontext);
810 if (status) {
811 goto clean_n_exit;
812 }
813 }
814
815 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
816 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
817 if (status) {
818 goto clean_n_exit;
819 }
820
821 status =
822 dal_handle->lib_handle->vftabl.db_set_option(kcontext, option, value);
823 get_errmsg(kcontext, status);
824 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
825
826 clean_n_exit:
827 return status;
828 }
829
830 krb5_error_code
krb5_db_lock(krb5_context kcontext,int lock_mode)831 krb5_db_lock(krb5_context kcontext, int lock_mode)
832 {
833 krb5_error_code status = 0;
834 kdb5_dal_handle *dal_handle;
835
836 if (kcontext->db_context == NULL) {
837 status = kdb_setup_lib_handle(kcontext);
838 if (status) {
839 goto clean_n_exit;
840 }
841 }
842
843 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
844 /* acquire an exclusive lock, ensures no other thread uses this context */
845 status = kdb_lock_lib_lock(dal_handle->lib_handle, TRUE);
846 if (status) {
847 goto clean_n_exit;
848 }
849
850 status = dal_handle->lib_handle->vftabl.db_lock(kcontext, lock_mode);
851 get_errmsg(kcontext, status);
852
853 /* exclusive lock is still held, so no other thread could use this context */
854 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
855
856 clean_n_exit:
857 return status;
858 }
859
860 krb5_error_code
krb5_db_unlock(krb5_context kcontext)861 krb5_db_unlock(krb5_context kcontext)
862 {
863 krb5_error_code status = 0;
864 kdb5_dal_handle *dal_handle;
865
866 if (kcontext->db_context == NULL) {
867 status = kdb_setup_lib_handle(kcontext);
868 if (status) {
869 goto clean_n_exit;
870 }
871 }
872
873 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
874 /* normal lock acquired and exclusive lock released */
875 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
876 if (status) {
877 goto clean_n_exit;
878 }
879
880 status = dal_handle->lib_handle->vftabl.db_unlock(kcontext);
881 get_errmsg(kcontext, status);
882
883 kdb_unlock_lib_lock(dal_handle->lib_handle, TRUE);
884
885 clean_n_exit:
886 return status;
887 }
888
889 krb5_error_code
krb5_db_get_principal(krb5_context kcontext,krb5_const_principal search_for,krb5_db_entry * entries,int * nentries,krb5_boolean * more)890 krb5_db_get_principal(krb5_context kcontext,
891 krb5_const_principal search_for,
892 krb5_db_entry * entries,
893 int *nentries, krb5_boolean * more)
894 {
895 krb5_error_code status = 0;
896 kdb5_dal_handle *dal_handle;
897
898 if (kcontext->db_context == NULL) {
899 status = kdb_setup_lib_handle(kcontext);
900 if (status) {
901 goto clean_n_exit;
902 }
903 }
904
905 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
906 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
907 if (status) {
908 goto clean_n_exit;
909 }
910
911 status =
912 dal_handle->lib_handle->vftabl.db_get_principal(kcontext, search_for,
913 entries, nentries,
914 more);
915 get_errmsg(kcontext, status);
916 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
917
918 clean_n_exit:
919 return status;
920 }
921
922 krb5_error_code
krb5_db_get_principal_nolock(krb5_context kcontext,krb5_const_principal search_for,krb5_db_entry * entries,int * nentries,krb5_boolean * more)923 krb5_db_get_principal_nolock(krb5_context kcontext,
924 krb5_const_principal search_for,
925 krb5_db_entry * entries,
926 int *nentries, krb5_boolean * more)
927 {
928 krb5_error_code status = 0;
929 kdb5_dal_handle *dal_handle;
930
931 if (kcontext->db_context == NULL) {
932 status = kdb_setup_lib_handle(kcontext);
933 if (status) {
934 goto clean_n_exit;
935 }
936 }
937
938 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
939 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
940 if (status) {
941 goto clean_n_exit;
942 }
943
944 status =
945 dal_handle->lib_handle->vftabl.db_get_principal_nolock(kcontext,
946 search_for,
947 entries, nentries,
948 more);
949 get_errmsg(kcontext, status);
950 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
951
952 clean_n_exit:
953 return status;
954 }
955
956 krb5_error_code
krb5_db_free_principal(krb5_context kcontext,krb5_db_entry * entry,int count)957 krb5_db_free_principal(krb5_context kcontext, krb5_db_entry * entry, int count)
958 {
959 krb5_error_code status = 0;
960 kdb5_dal_handle *dal_handle;
961
962 if (kcontext->db_context == NULL) {
963 status = kdb_setup_lib_handle(kcontext);
964 if (status) {
965 goto clean_n_exit;
966 }
967 }
968
969 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
970 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
971 if (status) {
972 goto clean_n_exit;
973 }
974
975 status =
976 dal_handle->lib_handle->vftabl.db_free_principal(kcontext, entry,
977 count);
978 get_errmsg(kcontext, status);
979 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
980
981 clean_n_exit:
982 return status;
983 }
984
985 krb5_error_code
krb5_db_put_principal(krb5_context kcontext,krb5_db_entry * entries,int * nentries)986 krb5_db_put_principal(krb5_context kcontext,
987 krb5_db_entry * entries, int *nentries)
988 {
989 krb5_error_code status = 0;
990 kdb5_dal_handle *dal_handle;
991 char **db_args = NULL;
992 krb5_tl_data *prev, *curr, *next;
993 int db_args_size = 0;
994
995 if (kcontext->db_context == NULL) {
996 status = kdb_setup_lib_handle(kcontext);
997 if (status) {
998 goto clean_n_exit;
999 }
1000 }
1001
1002 /* Giving db_args as part of tl data causes, db2 to store the
1003 tl_data as such. To prevent this, tl_data is collated and
1004 passed as a sepearte argument. Currently supports only one
1005 principal. but passing it as a seperate argument makes it
1006 difficult for kadmin remote to pass arguments to server. */
1007 prev = NULL, curr = entries->tl_data;
1008 while (curr) {
1009 if (curr->tl_data_type == KRB5_TL_DB_ARGS) {
1010 char **t;
1011 /* Since this is expected to be NULL terminated string and
1012 this could come from any client, do a check before
1013 passing it to db. */
1014 if (((char *) curr->tl_data_contents)[curr->tl_data_length - 1] !=
1015 '\0') {
1016 /* not null terminated. Dangerous input */
1017 status = EINVAL;
1018 goto clean_n_exit;
1019 }
1020
1021 db_args_size++;
1022 t = realloc(db_args, sizeof(char *) * (db_args_size + 1)); /* 1 for NULL */
1023 if (t == NULL) {
1024 status = ENOMEM;
1025 goto clean_n_exit;
1026 }
1027
1028 db_args = t;
1029 db_args[db_args_size - 1] = (char *) curr->tl_data_contents;
1030 db_args[db_args_size] = NULL;
1031
1032 next = curr->tl_data_next;
1033 if (prev == NULL) {
1034 /* current node is the first in the linked list. remove it */
1035 entries->tl_data = curr->tl_data_next;
1036 } else {
1037 prev->tl_data_next = curr->tl_data_next;
1038 }
1039 entries->n_tl_data--;
1040 krb5_db_free(kcontext, curr);
1041
1042 /* previous does not change */
1043 curr = next;
1044 } else {
1045 prev = curr;
1046 curr = curr->tl_data_next;
1047 }
1048 }
1049
1050 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1051 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1052 if (status) {
1053 goto clean_n_exit;
1054 }
1055
1056 status = dal_handle->lib_handle->vftabl.db_put_principal(kcontext, entries,
1057 nentries,
1058 db_args);
1059 get_errmsg(kcontext, status);
1060 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1061
1062 clean_n_exit:
1063 while (db_args_size) {
1064 if (db_args[db_args_size - 1])
1065 krb5_db_free(kcontext, db_args[db_args_size - 1]);
1066
1067 db_args_size--;
1068 }
1069
1070 if (db_args)
1071 free(db_args);
1072
1073 return status;
1074 }
1075
1076 krb5_error_code
krb5_db_delete_principal(krb5_context kcontext,krb5_principal search_for,int * nentries)1077 krb5_db_delete_principal(krb5_context kcontext,
1078 krb5_principal search_for, int *nentries)
1079 {
1080 krb5_error_code status = 0;
1081 kdb5_dal_handle *dal_handle;
1082
1083 if (kcontext->db_context == NULL) {
1084 status = kdb_setup_lib_handle(kcontext);
1085 if (status) {
1086 goto clean_n_exit;
1087 }
1088 }
1089
1090 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1091 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1092 if (status) {
1093 goto clean_n_exit;
1094 }
1095
1096 status =
1097 dal_handle->lib_handle->vftabl.db_delete_principal(kcontext,
1098 search_for,
1099 nentries);
1100 get_errmsg(kcontext, status);
1101 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1102
1103 clean_n_exit:
1104 return status;
1105 }
1106
1107 krb5_error_code
krb5_db_iterate(krb5_context kcontext,char * match_entry,int (* func)(krb5_pointer,krb5_db_entry *),krb5_pointer func_arg,char ** db_args)1108 krb5_db_iterate(krb5_context kcontext,
1109 char *match_entry,
1110 int (*func) (krb5_pointer, krb5_db_entry *),
1111 krb5_pointer func_arg,
1112 /* Solaris Kerberos: adding support for db_args */
1113 char **db_args)
1114 {
1115 krb5_error_code status = 0;
1116 kdb5_dal_handle *dal_handle;
1117
1118 if (kcontext->db_context == NULL) {
1119 status = kdb_setup_lib_handle(kcontext);
1120 if (status) {
1121 goto clean_n_exit;
1122 }
1123 }
1124
1125 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1126 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1127 if (status) {
1128 goto clean_n_exit;
1129 }
1130
1131 /* Solaris Kerberos: adding support for db_args */
1132 status = dal_handle->lib_handle->vftabl.db_iterate(kcontext,
1133 match_entry,
1134 func, func_arg,
1135 db_args);
1136 get_errmsg(kcontext, status);
1137 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1138
1139 clean_n_exit:
1140 return status;
1141 }
1142
1143 krb5_error_code
krb5_supported_realms(krb5_context kcontext,char ** realms)1144 krb5_supported_realms(krb5_context kcontext, char **realms)
1145 {
1146 krb5_error_code status = 0;
1147 kdb5_dal_handle *dal_handle;
1148
1149 if (kcontext->db_context == NULL) {
1150 status = kdb_setup_lib_handle(kcontext);
1151 if (status) {
1152 goto clean_n_exit;
1153 }
1154 }
1155
1156 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1157 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1158 if (status) {
1159 goto clean_n_exit;
1160 }
1161
1162 status =
1163 dal_handle->lib_handle->vftabl.db_supported_realms(kcontext, realms);
1164 get_errmsg(kcontext, status);
1165 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1166
1167 clean_n_exit:
1168 return status;
1169 }
1170
1171 krb5_error_code
krb5_free_supported_realms(krb5_context kcontext,char ** realms)1172 krb5_free_supported_realms(krb5_context kcontext, char **realms)
1173 {
1174 krb5_error_code status = 0;
1175 kdb5_dal_handle *dal_handle;
1176
1177 if (kcontext->db_context == NULL) {
1178 status = kdb_setup_lib_handle(kcontext);
1179 if (status) {
1180 goto clean_n_exit;
1181 }
1182 }
1183
1184 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1185 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1186 if (status) {
1187 goto clean_n_exit;
1188 }
1189
1190 status =
1191 dal_handle->lib_handle->vftabl.db_free_supported_realms(kcontext,
1192 realms);
1193 get_errmsg(kcontext, status);
1194 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1195
1196 clean_n_exit:
1197 return status;
1198 }
1199
1200 krb5_error_code
krb5_db_set_master_key_ext(krb5_context kcontext,char * pwd,krb5_keyblock * key)1201 krb5_db_set_master_key_ext(krb5_context kcontext,
1202 char *pwd, krb5_keyblock * key)
1203 {
1204 krb5_error_code status = 0;
1205 kdb5_dal_handle *dal_handle;
1206
1207 if (kcontext->db_context == NULL) {
1208 status = kdb_setup_lib_handle(kcontext);
1209 if (status) {
1210 goto clean_n_exit;
1211 }
1212 }
1213
1214 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1215 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1216 if (status) {
1217 goto clean_n_exit;
1218 }
1219
1220 status = dal_handle->lib_handle->vftabl.set_master_key(kcontext, pwd, key);
1221 get_errmsg(kcontext, status);
1222
1223 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1224
1225 clean_n_exit:
1226 return status;
1227 }
1228
1229 krb5_error_code
krb5_db_set_mkey(krb5_context context,krb5_keyblock * key)1230 krb5_db_set_mkey(krb5_context context, krb5_keyblock * key)
1231 {
1232 return krb5_db_set_master_key_ext(context, NULL, key);
1233 }
1234
1235 krb5_error_code
krb5_db_get_mkey(krb5_context kcontext,krb5_keyblock ** key)1236 krb5_db_get_mkey(krb5_context kcontext, krb5_keyblock ** key)
1237 {
1238 krb5_error_code status = 0;
1239 kdb5_dal_handle *dal_handle;
1240
1241 if (kcontext->db_context == NULL) {
1242 status = kdb_setup_lib_handle(kcontext);
1243 if (status) {
1244 goto clean_n_exit;
1245 }
1246 }
1247
1248 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1249 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1250 if (status) {
1251 goto clean_n_exit;
1252 }
1253
1254 /* Lets use temp key and copy it later to avoid memory problems
1255 when freed by the caller. */
1256 status = dal_handle->lib_handle->vftabl.get_master_key(kcontext, key);
1257 get_errmsg(kcontext, status);
1258 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1259
1260 clean_n_exit:
1261 return status;
1262 }
1263
1264 krb5_error_code
krb5_db_store_master_key(krb5_context kcontext,char * db_arg,krb5_principal mname,krb5_keyblock * key,char * master_pwd)1265 krb5_db_store_master_key(krb5_context kcontext,
1266 char *db_arg,
1267 krb5_principal mname,
1268 krb5_keyblock * key, char *master_pwd)
1269 {
1270 krb5_error_code status = 0;
1271 kdb5_dal_handle *dal_handle;
1272
1273 if (kcontext->db_context == NULL) {
1274 status = kdb_setup_lib_handle(kcontext);
1275 if (status) {
1276 goto clean_n_exit;
1277 }
1278 }
1279
1280 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1281 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1282 if (status) {
1283 goto clean_n_exit;
1284 }
1285
1286 status = dal_handle->lib_handle->vftabl.store_master_key(kcontext,
1287 db_arg,
1288 mname,
1289 key, master_pwd);
1290 get_errmsg(kcontext, status);
1291 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1292
1293 clean_n_exit:
1294 return status;
1295 }
1296
1297 char *krb5_mkey_pwd_prompt1 = KRB5_KDC_MKEY_1;
1298 char *krb5_mkey_pwd_prompt2 = KRB5_KDC_MKEY_2;
1299
1300 krb5_error_code
krb5_db_fetch_mkey(krb5_context context,krb5_principal mname,krb5_enctype etype,krb5_boolean fromkeyboard,krb5_boolean twice,char * db_args,krb5_data * salt,krb5_keyblock * key)1301 krb5_db_fetch_mkey(krb5_context context,
1302 krb5_principal mname,
1303 krb5_enctype etype,
1304 krb5_boolean fromkeyboard,
1305 krb5_boolean twice,
1306 char *db_args, krb5_data * salt, krb5_keyblock * key)
1307 {
1308 krb5_error_code retval;
1309 char password[BUFSIZ];
1310 krb5_data pwd;
1311 unsigned int size = sizeof(password);
1312 int kvno;
1313 krb5_keyblock tmp_key;
1314
1315 memset(&tmp_key, 0, sizeof(tmp_key));
1316
1317 if (fromkeyboard) {
1318 krb5_data scratch;
1319
1320 if ((retval = krb5_read_password(context, krb5_mkey_pwd_prompt1,
1321 twice ? krb5_mkey_pwd_prompt2 : 0,
1322 password, &size))) {
1323 goto clean_n_exit;
1324 }
1325
1326 pwd.data = password;
1327 pwd.length = size;
1328 if (!salt) {
1329 retval = krb5_principal2salt(context, mname, &scratch);
1330 if (retval)
1331 goto clean_n_exit;
1332 }
1333 retval =
1334 krb5_c_string_to_key(context, etype, &pwd, salt ? salt : &scratch,
1335 key);
1336
1337 if (!salt)
1338 krb5_xfree(scratch.data);
1339 memset(password, 0, sizeof(password)); /* erase it */
1340
1341 } else {
1342 kdb5_dal_handle *dal_handle;
1343
1344 if (context->db_context == NULL) {
1345 retval = kdb_setup_lib_handle(context);
1346 if (retval) {
1347 goto clean_n_exit;
1348 }
1349 }
1350
1351 dal_handle = (kdb5_dal_handle *) context->db_context;
1352 retval = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1353 if (retval) {
1354 goto clean_n_exit;
1355 }
1356 #if 0 /************** Begin IFDEF'ed OUT *******************************/
1357 /* Orig MIT */
1358 tmp_key.enctype = key->enctype;
1359 #else
1360 /* Solaris Kerberos: need to use etype */
1361 tmp_key.enctype = etype;
1362 #endif /**************** END IFDEF'ed OUT *******************************/
1363 retval = dal_handle->lib_handle->vftabl.fetch_master_key(context,
1364 mname,
1365 &tmp_key,
1366 &kvno,
1367 db_args);
1368 get_errmsg(context, retval);
1369 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1370
1371 if (retval) {
1372 goto clean_n_exit;
1373 }
1374
1375 key->contents = malloc(tmp_key.length);
1376 if (key->contents == NULL) {
1377 retval = ENOMEM;
1378 goto clean_n_exit;
1379 }
1380
1381 key->magic = tmp_key.magic;
1382 key->enctype = tmp_key.enctype;
1383 key->length = tmp_key.length;
1384 memcpy(key->contents, tmp_key.contents, tmp_key.length);
1385 }
1386
1387 clean_n_exit:
1388 if (tmp_key.contents) {
1389 memset(tmp_key.contents, 0, tmp_key.length);
1390 krb5_db_free(context, tmp_key.contents);
1391 }
1392 return retval;
1393 }
1394
1395 krb5_error_code
krb5_db_verify_master_key(krb5_context kcontext,krb5_principal mprinc,krb5_keyblock * mkey)1396 krb5_db_verify_master_key(krb5_context kcontext,
1397 krb5_principal mprinc, krb5_keyblock * mkey)
1398 {
1399 krb5_error_code status = 0;
1400 kdb5_dal_handle *dal_handle;
1401
1402 if (kcontext->db_context == NULL) {
1403 status = kdb_setup_lib_handle(kcontext);
1404 if (status) {
1405 goto clean_n_exit;
1406 }
1407 }
1408
1409 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1410 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1411 if (status) {
1412 goto clean_n_exit;
1413 }
1414
1415 status = dal_handle->lib_handle->vftabl.verify_master_key(kcontext,
1416 mprinc, mkey);
1417 get_errmsg(kcontext, status);
1418 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1419
1420 clean_n_exit:
1421 return status;
1422 }
1423
1424 void *
krb5_db_alloc(krb5_context kcontext,void * ptr,size_t size)1425 krb5_db_alloc(krb5_context kcontext, void *ptr, size_t size)
1426 {
1427 krb5_error_code status;
1428 kdb5_dal_handle *dal_handle;
1429 void *new_ptr = NULL;
1430
1431 if (kcontext->db_context == NULL) {
1432 status = kdb_setup_lib_handle(kcontext);
1433 if (status) {
1434 goto clean_n_exit;
1435 }
1436 }
1437
1438 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1439
1440 new_ptr = dal_handle->lib_handle->vftabl.db_alloc(kcontext, ptr, size);
1441
1442 clean_n_exit:
1443 return new_ptr;
1444 }
1445
1446 void
krb5_db_free(krb5_context kcontext,void * ptr)1447 krb5_db_free(krb5_context kcontext, void *ptr)
1448 {
1449 krb5_error_code status;
1450 kdb5_dal_handle *dal_handle;
1451
1452 if (kcontext->db_context == NULL) {
1453 status = kdb_setup_lib_handle(kcontext);
1454 if (status) {
1455 goto clean_n_exit;
1456 }
1457 }
1458
1459 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1460
1461 dal_handle->lib_handle->vftabl.db_free(kcontext, ptr);
1462
1463 clean_n_exit:
1464 return;
1465 }
1466
1467 /* has to be modified */
1468
1469 krb5_error_code
krb5_dbe_find_enctype(krb5_context kcontext,krb5_db_entry * dbentp,krb5_int32 ktype,krb5_int32 stype,krb5_int32 kvno,krb5_key_data ** kdatap)1470 krb5_dbe_find_enctype(krb5_context kcontext,
1471 krb5_db_entry * dbentp,
1472 krb5_int32 ktype,
1473 krb5_int32 stype,
1474 krb5_int32 kvno, krb5_key_data ** kdatap)
1475 {
1476 krb5_int32 start = 0;
1477 return krb5_dbe_search_enctype(kcontext, dbentp, &start, ktype, stype,
1478 kvno, kdatap);
1479 }
1480
1481 krb5_error_code
krb5_dbe_search_enctype(krb5_context kcontext,krb5_db_entry * dbentp,krb5_int32 * start,krb5_int32 ktype,krb5_int32 stype,krb5_int32 kvno,krb5_key_data ** kdatap)1482 krb5_dbe_search_enctype(krb5_context kcontext,
1483 krb5_db_entry * dbentp,
1484 krb5_int32 * start,
1485 krb5_int32 ktype,
1486 krb5_int32 stype,
1487 krb5_int32 kvno, krb5_key_data ** kdatap)
1488 {
1489 krb5_error_code status = 0;
1490 kdb5_dal_handle *dal_handle;
1491
1492 if (kcontext->db_context == NULL) {
1493 status = kdb_setup_lib_handle(kcontext);
1494 if (status) {
1495 goto clean_n_exit;
1496 }
1497 }
1498
1499 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1500 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1501 if (status) {
1502 goto clean_n_exit;
1503 }
1504
1505 status = dal_handle->lib_handle->vftabl.dbe_search_enctype(kcontext,
1506 dbentp,
1507 start,
1508 ktype,
1509 stype,
1510 kvno, kdatap);
1511 get_errmsg(kcontext, status);
1512 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1513
1514 clean_n_exit:
1515 return status;
1516 }
1517
1518 #define REALM_SEP_STRING "@"
1519
1520 krb5_error_code
krb5_db_setup_mkey_name(krb5_context context,const char * keyname,const char * realm,char ** fullname,krb5_principal * principal)1521 krb5_db_setup_mkey_name(krb5_context context,
1522 const char *keyname,
1523 const char *realm,
1524 char **fullname, krb5_principal * principal)
1525 {
1526 krb5_error_code retval;
1527 size_t keylen;
1528 size_t rlen = strlen(realm);
1529 char *fname;
1530
1531 if (!keyname)
1532 keyname = KRB5_KDB_M_NAME; /* XXX external? */
1533
1534 keylen = strlen(keyname);
1535
1536 fname = malloc(keylen + rlen + strlen(REALM_SEP_STRING) + 1);
1537 if (!fname)
1538 return ENOMEM;
1539
1540 strcpy(fname, keyname);
1541 (void)strcat(fname, REALM_SEP_STRING);
1542 (void)strcat(fname, realm);
1543
1544 if ((retval = krb5_parse_name(context, fname, principal)))
1545 return retval;
1546 if (fullname)
1547 *fullname = fname;
1548 else
1549 free(fname);
1550 return 0;
1551 }
1552
1553 krb5_error_code
krb5_dbe_lookup_last_pwd_change(context,entry,stamp)1554 krb5_dbe_lookup_last_pwd_change(context, entry, stamp)
1555 krb5_context context;
1556 krb5_db_entry *entry;
1557 krb5_timestamp *stamp;
1558 {
1559 krb5_tl_data tl_data;
1560 krb5_error_code code;
1561 krb5_int32 tmp;
1562
1563 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
1564
1565 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1566 return (code);
1567
1568 if (tl_data.tl_data_length != 4) {
1569 *stamp = 0;
1570 return (0);
1571 }
1572
1573 krb5_kdb_decode_int32(tl_data.tl_data_contents, tmp);
1574
1575 *stamp = (krb5_timestamp) tmp;
1576
1577 return (0);
1578 }
1579
1580 /*ARGSUSED*/
1581 krb5_error_code
krb5_dbe_lookup_tl_data(context,entry,ret_tl_data)1582 krb5_dbe_lookup_tl_data(context, entry, ret_tl_data)
1583 krb5_context context;
1584 krb5_db_entry *entry;
1585 krb5_tl_data *ret_tl_data;
1586 {
1587 krb5_tl_data *tl_data;
1588
1589 for (tl_data = entry->tl_data; tl_data; tl_data = tl_data->tl_data_next) {
1590 if (tl_data->tl_data_type == ret_tl_data->tl_data_type) {
1591 *ret_tl_data = *tl_data;
1592 return (0);
1593 }
1594 }
1595
1596 /* if the requested record isn't found, return zero bytes.
1597 * if it ever means something to have a zero-length tl_data,
1598 * this code and its callers will have to be changed */
1599
1600 ret_tl_data->tl_data_length = 0;
1601 ret_tl_data->tl_data_contents = NULL;
1602 return (0);
1603 }
1604
1605 krb5_error_code
krb5_dbe_create_key_data(context,entry)1606 krb5_dbe_create_key_data(context, entry)
1607 krb5_context context;
1608 krb5_db_entry *entry;
1609 {
1610 if ((entry->key_data =
1611 (krb5_key_data *) krb5_db_alloc(context, entry->key_data,
1612 (sizeof(krb5_key_data) *
1613 (entry->n_key_data + 1)))) == NULL)
1614 return (ENOMEM);
1615
1616 memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
1617 entry->n_key_data++;
1618
1619 return 0;
1620 }
1621
1622 krb5_error_code
krb5_dbe_update_mod_princ_data(context,entry,mod_date,mod_princ)1623 krb5_dbe_update_mod_princ_data(context, entry, mod_date, mod_princ)
1624 krb5_context context;
1625 krb5_db_entry *entry;
1626 krb5_timestamp mod_date;
1627 krb5_const_principal mod_princ;
1628 {
1629 krb5_tl_data tl_data;
1630
1631 krb5_error_code retval = 0;
1632 krb5_octet *nextloc = 0;
1633 char *unparse_mod_princ = 0;
1634 unsigned int unparse_mod_princ_size;
1635
1636 if ((retval = krb5_unparse_name(context, mod_princ, &unparse_mod_princ)))
1637 return (retval);
1638
1639 unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;
1640
1641 if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
1642 == NULL) {
1643 free(unparse_mod_princ);
1644 return (ENOMEM);
1645 }
1646
1647 tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
1648 tl_data.tl_data_length = unparse_mod_princ_size + 4;
1649 tl_data.tl_data_contents = nextloc;
1650
1651 /* Mod Date */
1652 krb5_kdb_encode_int32(mod_date, nextloc);
1653
1654 /* Mod Princ */
1655 memcpy(nextloc + 4, unparse_mod_princ, unparse_mod_princ_size);
1656
1657 retval = krb5_dbe_update_tl_data(context, entry, &tl_data);
1658
1659 free(unparse_mod_princ);
1660 free(nextloc);
1661
1662 return (retval);
1663 }
1664
1665 krb5_error_code
krb5_dbe_lookup_mod_princ_data(context,entry,mod_time,mod_princ)1666 krb5_dbe_lookup_mod_princ_data(context, entry, mod_time, mod_princ)
1667 krb5_context context;
1668 krb5_db_entry *entry;
1669 krb5_timestamp *mod_time;
1670 krb5_principal *mod_princ;
1671 {
1672 krb5_tl_data tl_data;
1673 krb5_error_code code;
1674
1675 tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
1676
1677 if ((code = krb5_dbe_lookup_tl_data(context, entry, &tl_data)))
1678 return (code);
1679
1680 if ((tl_data.tl_data_length < 5) ||
1681 (tl_data.tl_data_contents[tl_data.tl_data_length - 1] != '\0'))
1682 return (KRB5_KDB_TRUNCATED_RECORD);
1683
1684 /* Mod Date */
1685 krb5_kdb_decode_int32(tl_data.tl_data_contents, *mod_time);
1686
1687 /* Mod Princ */
1688 if ((code = krb5_parse_name(context,
1689 (const char *) (tl_data.tl_data_contents + 4),
1690 mod_princ)))
1691 return (code);
1692
1693 return (0);
1694 }
1695
1696 krb5_error_code
krb5_dbe_update_last_pwd_change(context,entry,stamp)1697 krb5_dbe_update_last_pwd_change(context, entry, stamp)
1698 krb5_context context;
1699 krb5_db_entry *entry;
1700 krb5_timestamp stamp;
1701 {
1702 krb5_tl_data tl_data;
1703 krb5_octet buf[4]; /* this is the encoded size of an int32 */
1704
1705 tl_data.tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
1706 tl_data.tl_data_length = sizeof(buf);
1707 krb5_kdb_encode_int32((krb5_int32) stamp, buf);
1708 tl_data.tl_data_contents = buf;
1709
1710 return (krb5_dbe_update_tl_data(context, entry, &tl_data));
1711 }
1712
1713 krb5_error_code
krb5_dbe_update_tl_data(context,entry,new_tl_data)1714 krb5_dbe_update_tl_data(context, entry, new_tl_data)
1715 krb5_context context;
1716 krb5_db_entry *entry;
1717 krb5_tl_data *new_tl_data;
1718 {
1719 krb5_tl_data *tl_data = NULL;
1720 krb5_octet *tmp;
1721
1722 /* copy the new data first, so we can fail cleanly if malloc()
1723 * fails */
1724 if ((tmp =
1725 (krb5_octet *) krb5_db_alloc(context, NULL,
1726 new_tl_data->tl_data_length)) == NULL)
1727 return (ENOMEM);
1728
1729 /* Find an existing entry of the specified type and point at
1730 * it, or NULL if not found */
1731
1732 if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */
1733 for (tl_data = entry->tl_data; tl_data;
1734 tl_data = tl_data->tl_data_next)
1735 if (tl_data->tl_data_type == new_tl_data->tl_data_type)
1736 break;
1737 }
1738
1739 /* if necessary, chain a new record in the beginning and point at it */
1740
1741 if (!tl_data) {
1742 if ((tl_data =
1743 (krb5_tl_data *) krb5_db_alloc(context, NULL,
1744 sizeof(krb5_tl_data)))
1745 == NULL) {
1746 free(tmp);
1747 return (ENOMEM);
1748 }
1749 memset(tl_data, 0, sizeof(krb5_tl_data));
1750 tl_data->tl_data_next = entry->tl_data;
1751 entry->tl_data = tl_data;
1752 entry->n_tl_data++;
1753 }
1754
1755 /* fill in the record */
1756
1757 if (tl_data->tl_data_contents)
1758 krb5_db_free(context, tl_data->tl_data_contents);
1759
1760 tl_data->tl_data_type = new_tl_data->tl_data_type;
1761 tl_data->tl_data_length = new_tl_data->tl_data_length;
1762 tl_data->tl_data_contents = tmp;
1763 memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);
1764
1765 return (0);
1766 }
1767
1768 /* change password functions */
1769 krb5_error_code
krb5_dbe_cpw(krb5_context kcontext,krb5_keyblock * master_key,krb5_key_salt_tuple * ks_tuple,int ks_tuple_count,char * passwd,int new_kvno,krb5_boolean keepold,krb5_db_entry * db_entry)1770 krb5_dbe_cpw(krb5_context kcontext,
1771 krb5_keyblock * master_key,
1772 krb5_key_salt_tuple * ks_tuple,
1773 int ks_tuple_count,
1774 char *passwd,
1775 int new_kvno, krb5_boolean keepold, krb5_db_entry * db_entry)
1776 {
1777 krb5_error_code status = 0;
1778 kdb5_dal_handle *dal_handle;
1779
1780 if (kcontext->db_context == NULL) {
1781 status = kdb_setup_lib_handle(kcontext);
1782 if (status) {
1783 goto clean_n_exit;
1784 }
1785 }
1786
1787 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1788 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1789 if (status) {
1790 goto clean_n_exit;
1791 }
1792
1793 status = dal_handle->lib_handle->vftabl.db_change_pwd(kcontext,
1794 master_key,
1795 ks_tuple,
1796 ks_tuple_count,
1797 passwd,
1798 new_kvno,
1799 keepold, db_entry);
1800 get_errmsg(kcontext, status);
1801 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1802
1803 clean_n_exit:
1804 return status;
1805 }
1806
1807 /* policy management functions */
1808 krb5_error_code
krb5_db_create_policy(krb5_context kcontext,osa_policy_ent_t policy)1809 krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
1810 {
1811 krb5_error_code status = 0;
1812 kdb5_dal_handle *dal_handle;
1813
1814 if (kcontext->db_context == NULL) {
1815 status = kdb_setup_lib_handle(kcontext);
1816 if (status) {
1817 goto clean_n_exit;
1818 }
1819 }
1820
1821 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1822 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1823 if (status) {
1824 goto clean_n_exit;
1825 }
1826
1827 status = dal_handle->lib_handle->vftabl.db_create_policy(kcontext, policy);
1828 get_errmsg(kcontext, status);
1829 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1830
1831 clean_n_exit:
1832 return status;
1833 }
1834
1835 krb5_error_code
krb5_db_get_policy(krb5_context kcontext,char * name,osa_policy_ent_t * policy,int * cnt)1836 krb5_db_get_policy(krb5_context kcontext, char *name,
1837 osa_policy_ent_t * policy, int *cnt)
1838 {
1839 krb5_error_code status = 0;
1840 kdb5_dal_handle *dal_handle;
1841
1842 if (kcontext->db_context == NULL) {
1843 status = kdb_setup_lib_handle(kcontext);
1844 if (status) {
1845 goto clean_n_exit;
1846 }
1847 }
1848
1849 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1850 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1851 if (status) {
1852 goto clean_n_exit;
1853 }
1854
1855 status =
1856 dal_handle->lib_handle->vftabl.db_get_policy(kcontext, name, policy,
1857 cnt);
1858 get_errmsg(kcontext, status);
1859 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1860
1861 clean_n_exit:
1862 return status;
1863 }
1864
1865 krb5_error_code
krb5_db_put_policy(krb5_context kcontext,osa_policy_ent_t policy)1866 krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
1867 {
1868 krb5_error_code status = 0;
1869 kdb5_dal_handle *dal_handle;
1870
1871 if (kcontext->db_context == NULL) {
1872 status = kdb_setup_lib_handle(kcontext);
1873 if (status) {
1874 goto clean_n_exit;
1875 }
1876 }
1877
1878 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1879 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1880 if (status) {
1881 goto clean_n_exit;
1882 }
1883
1884 status = dal_handle->lib_handle->vftabl.db_put_policy(kcontext, policy);
1885 get_errmsg(kcontext, status);
1886 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1887
1888 clean_n_exit:
1889 return status;
1890 }
1891
1892 krb5_error_code
krb5_db_iter_policy(krb5_context kcontext,char * match_entry,osa_adb_iter_policy_func func,void * data)1893 krb5_db_iter_policy(krb5_context kcontext, char *match_entry,
1894 osa_adb_iter_policy_func func, void *data)
1895 {
1896 krb5_error_code status = 0;
1897 kdb5_dal_handle *dal_handle;
1898
1899 if (kcontext->db_context == NULL) {
1900 status = kdb_setup_lib_handle(kcontext);
1901 if (status) {
1902 goto clean_n_exit;
1903 }
1904 }
1905
1906 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1907 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1908 if (status) {
1909 goto clean_n_exit;
1910 }
1911
1912 status =
1913 dal_handle->lib_handle->vftabl.db_iter_policy(kcontext, match_entry,
1914 func, data);
1915 get_errmsg(kcontext, status);
1916 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1917
1918 clean_n_exit:
1919 return status;
1920 }
1921
1922 krb5_error_code
krb5_db_delete_policy(krb5_context kcontext,char * policy)1923 krb5_db_delete_policy(krb5_context kcontext, char *policy)
1924 {
1925 krb5_error_code status = 0;
1926 kdb5_dal_handle *dal_handle;
1927
1928 if (kcontext->db_context == NULL) {
1929 status = kdb_setup_lib_handle(kcontext);
1930 if (status) {
1931 goto clean_n_exit;
1932 }
1933 }
1934
1935 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1936 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1937 if (status) {
1938 goto clean_n_exit;
1939 }
1940
1941 status = dal_handle->lib_handle->vftabl.db_delete_policy(kcontext, policy);
1942 get_errmsg(kcontext, status);
1943 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1944
1945 clean_n_exit:
1946 return status;
1947 }
1948
1949 void
krb5_db_free_policy(krb5_context kcontext,osa_policy_ent_t policy)1950 krb5_db_free_policy(krb5_context kcontext, osa_policy_ent_t policy)
1951 {
1952 krb5_error_code status = 0;
1953 kdb5_dal_handle *dal_handle;
1954
1955 if (kcontext->db_context == NULL) {
1956 status = kdb_setup_lib_handle(kcontext);
1957 if (status) {
1958 goto clean_n_exit;
1959 }
1960 }
1961
1962 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
1963 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
1964 if (status) {
1965 goto clean_n_exit;
1966 }
1967
1968 dal_handle->lib_handle->vftabl.db_free_policy(kcontext, policy);
1969 get_errmsg(kcontext, status);
1970 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
1971
1972 clean_n_exit:
1973 return;
1974 }
1975
1976 krb5_error_code
krb5_db_promote(krb5_context kcontext,char ** db_args)1977 krb5_db_promote(krb5_context kcontext, char **db_args)
1978 {
1979 krb5_error_code status = 0;
1980 char *section = NULL;
1981 kdb5_dal_handle *dal_handle;
1982
1983 section = kdb_get_conf_section(kcontext);
1984 if (section == NULL) {
1985 status = KRB5_KDB_SERVER_INTERNAL_ERR;
1986 krb5_set_error_message (kcontext, status,
1987 gettext("unable to determine configuration section for realm %s\n"),
1988 kcontext->default_realm);
1989 goto clean_n_exit;
1990 }
1991
1992 if (kcontext->db_context == NULL) {
1993 status = kdb_setup_lib_handle(kcontext);
1994 if (status) {
1995 goto clean_n_exit;
1996 }
1997 }
1998
1999 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
2000 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
2001 if (status) {
2002 goto clean_n_exit;
2003 }
2004
2005 status =
2006 dal_handle->lib_handle->vftabl.promote_db(kcontext, section, db_args);
2007 get_errmsg(kcontext, status);
2008 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
2009
2010 clean_n_exit:
2011 if (section)
2012 free(section);
2013 return status;
2014 }
2015
2016 /*
2017 * Solaris Kerberos: support for iprop
2018 *
2019 * Not all KDB plugins support iprop.
2020 *
2021 * sets iprop_supported to 1 if iprop supportd, 0 otherwise.
2022 */
2023 krb5_error_code
krb5_db_supports_iprop(krb5_context kcontext,int * iprop_supported)2024 krb5_db_supports_iprop(krb5_context kcontext, int *iprop_supported)
2025 {
2026 krb5_error_code status = 0;
2027 kdb5_dal_handle *dal_handle;
2028
2029 if (kcontext->db_context == NULL) {
2030 status = kdb_setup_lib_handle(kcontext);
2031 if (status) {
2032 goto clean_n_exit;
2033 }
2034 }
2035
2036 dal_handle = (kdb5_dal_handle *) kcontext->db_context;
2037 status = kdb_lock_lib_lock(dal_handle->lib_handle, FALSE);
2038 if (status) {
2039 goto clean_n_exit;
2040 }
2041
2042 *iprop_supported = dal_handle->lib_handle->vftabl.iprop_supported;
2043 kdb_unlock_lib_lock(dal_handle->lib_handle, FALSE);
2044
2045 clean_n_exit:
2046 return status;
2047 }
2048