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