4 * Copyright 1997 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
29 * Copyright (C) 1998 by the FundsXpress, INC.
31 * All rights reserved.
33 * Export of this software from the United States of America may require
34 * a specific license from the United States Government. It is the
35 * responsibility of any person or organization contemplating export to
36 * obtain such a license before exporting.
38 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39 * distribute this software and its documentation for any purpose and
40 * without fee is hereby granted, provided that the above copyright
41 * notice appear in all copies and that both that copyright notice and
42 * this permission notice appear in supporting documentation, and that
43 * the name of FundsXpress. not be used in advertising or publicity pertaining
44 * to distribution of the software without specific, written prior
45 * permission. FundsXpress makes no representations about the suitability of
46 * this software for any purpose. It is provided "as is" without express
47 * or implied warranty.
49 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
50 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
51 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
66 #include "policy_db.h"
68 #define KDB_DB2_DATABASE_NAME "database_name"
70 #define OLD_COMPAT_VERSION_1
72 #ifdef OLD_COMPAT_VERSION_1
73 #include "kdb_compat.h"
78 static char *gen_dbsuffix
81 static krb5_error_code krb5_db2_db_start_update
83 static krb5_error_code krb5_db2_db_end_update
87 krb5_db2_db_set_name(krb5_context,char*);
89 krb5_error_code krb5_db2_db_lock
90 ( krb5_context, int );
92 static krb5_error_code krb5_db2_db_set_hashfirst
95 static char default_db_name[] = DEFAULT_KDB_FILE;
96 krb5_set_err_func_t krb5_db2_dal_err_funcp = NULL;
101 * There are two distinct locking protocols used. One is designed to
102 * lock against processes (the admin_server, for one) which make
103 * incremental changes to the database; the other is designed to lock
104 * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
105 * entire database in one fell swoop.
107 * The first locking protocol is implemented using flock() in the
108 * krb_dbl_lock() and krb_dbl_unlock routines.
110 * The second locking protocol is necessary because DBM "files" are
111 * actually implemented as two separate files, and it is impossible to
112 * atomically rename two files simultaneously. It assumes that the
113 * database is replaced only very infrequently in comparison to the time
114 * needed to do a database read operation.
116 * A third file is used as a "version" semaphore; the modification
117 * time of this file is the "version number" of the database.
118 * At the start of a read operation, the reader checks the version
119 * number; at the end of the read operation, it checks again. If the
120 * version number changed, or if the semaphore was nonexistant at
121 * either time, the reader sleeps for a second to let things
122 * stabilize, and then tries again; if it does not succeed after
123 * KRB5_DBM_MAX_RETRY attempts, it gives up.
125 * On update, the semaphore file is deleted (if it exists) before any
126 * update takes place; at the end of the update, it is replaced, with
127 * a version number strictly greater than the version number which
128 * existed at the start of the update.
130 * If the system crashes in the middle of an update, the semaphore
131 * file is not automatically created on reboot; this is a feature, not
132 * a bug, since the database may be inconsistant. Note that the
133 * absence of a semaphore file does not prevent another _update_ from
134 * taking place later. Database replacements take place automatically
135 * only on slave servers; a crash in the middle of an update will be
136 * fixed by the next slave propagation. A crash in the middle of an
137 * update on the master would be somewhat more serious, but this would
138 * likely be noticed by an administrator, who could fix the problem and
139 * retry the operation.
142 #define free_dbsuffix(name) free(name)
145 * Routines to deal with context.
147 #define k5db2_inited(c) (c && c->db_context \
148 && ((kdb5_dal_handle*)c->db_context)->db_context \
149 && ((krb5_db2_context *) ((kdb5_dal_handle*)c->db_context)->db_context)->db_inited)
154 krb5_db2_get_db_opt( char *input, char **opt, char **val )
156 char *pos = strchr(input, '=');
160 *val = strdup(input);
168 *opt = malloc( (pos - input) + 1 );
169 *val = strdup( pos + 1 );
174 memcpy( *opt, input, pos - input);
175 (*opt)[pos - input] = '\0';
182 * Restore the default context.
185 k5db2_clear_context(dbctx)
186 krb5_db2_context *dbctx;
189 * Free any dynamically allocated memory. File descriptors and locks
190 * are the caller's problem.
192 if (dbctx->db_lf_name)
193 free(dbctx->db_lf_name);
194 if (dbctx->db_name && (dbctx->db_name != default_db_name))
195 free(dbctx->db_name);
197 * Clear the structure and reset the defaults.
199 memset((char *) dbctx, 0, sizeof(krb5_db2_context));
200 dbctx->db_name = default_db_name;
201 dbctx->db_nb_locks = FALSE;
205 static krb5_error_code
206 k5db2_init_context(context)
207 krb5_context context;
209 krb5_db2_context *db_ctx;
210 kdb5_dal_handle *dal_handle;
212 dal_handle = (kdb5_dal_handle*) context->db_context;
214 if ( dal_handle->db_context == NULL) {
215 db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
219 memset((char *) db_ctx, 0, sizeof(krb5_db2_context));
220 k5db2_clear_context((krb5_db2_context *)db_ctx);
221 dal_handle->db_context = (void *) db_ctx;
229 * Utility routine: generate name of database file.
233 gen_dbsuffix(db_name, sfx)
240 return((char *) NULL);
242 dbsuffix = malloc (strlen(db_name) + strlen(sfx) + 1);
245 (void) strcpy(dbsuffix, db_name);
246 (void) strcat(dbsuffix, sfx);
252 k5db2_dbopen(dbc, fname, flags, mode)
253 krb5_db2_context *dbc;
277 db = dbopen(fname, flags, mode,
278 dbc->hashfirst ? DB_HASH : DB_BTREE,
279 dbc->hashfirst ? (void *) &hashi : (void *) &bti);
287 db = dbopen(fname, flags, mode,
288 dbc->hashfirst ? DB_BTREE : DB_HASH,
289 dbc->hashfirst ? (void *) &bti : (void *) &hashi);
291 dbc->hashfirst = !dbc->hashfirst;
297 static krb5_error_code
298 krb5_db2_db_set_hashfirst(context, hashfirst)
299 krb5_context context;
302 krb5_db2_context *dbc;
303 kdb5_dal_handle *dal_handle;
305 if (k5db2_inited(context))
306 return KRB5_KDB_DBNOTINITED;
307 dal_handle = (kdb5_dal_handle*) context->db_context;
308 dbc = (krb5_db2_context *) dal_handle->db_context;
309 dbc->hashfirst = hashfirst;
314 * initialization for data base routines.
318 krb5_db2_db_init(context)
319 krb5_context context;
321 char *filename = NULL;
322 krb5_db2_context *db_ctx;
323 krb5_error_code retval;
324 kdb5_dal_handle *dal_handle;
325 char policy_db_name[1024], policy_lock_name[1024];
327 if (k5db2_inited(context))
330 /* Check for presence of our context, if not present, allocate one. */
331 if ((retval = k5db2_init_context(context)))
334 dal_handle = (kdb5_dal_handle*) context->db_context;
335 db_ctx = dal_handle->db_context;
338 if (!(filename = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT)))
340 db_ctx->db_lf_name = filename; /* so it gets freed by clear_context */
343 * should be opened read/write so that write locking can work with
346 if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
347 if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
354 if ((retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time)))
357 sprintf( policy_db_name, "%s.kadm5", db_ctx->db_name );
358 sprintf( policy_lock_name, "%s.lock", policy_db_name );
360 if( (retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
361 policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)) )
369 k5db2_clear_context(db_ctx);
375 * gracefully shut down database--must be called by ANY program that does
379 krb5_db2_db_fini(context)
380 krb5_context context;
382 krb5_error_code retval = 0;
383 krb5_db2_context *db_ctx;
384 kdb5_dal_handle *dal_handle;
386 dal_handle = (kdb5_dal_handle*) context->db_context;
387 if( dal_handle == NULL )
392 db_ctx = (krb5_db2_context *) dal_handle->db_context;
394 if (k5db2_inited(context)) {
395 if (close(db_ctx->db_lf_file))
401 if( db_ctx->policy_db )
403 retval = osa_adb_fini_db(db_ctx->policy_db, OSA_ADB_POLICY_DB_MAGIC);
408 k5db2_clear_context(db_ctx);
409 /* free(dal_handle->db_context); */
410 dal_handle->db_context = NULL;
418 krb5_db2_db_open_database(context)
419 krb5_context context;
421 if (!k5db2_inited(context))
422 return KRB5_KDB_DBNOTINITED;
427 krb5_db2_db_close_database(context)
428 krb5_context context;
430 if (!k5db2_inited(context))
431 return KRB5_KDB_DBNOTINITED;
438 * Set/Get the master key associated with the database
441 krb5_db2_db_set_mkey(context, key)
442 krb5_context context;
445 krb5_db2_context *db_ctx;
446 kdb5_dal_handle *dal_handle;
448 if (!k5db2_inited(context))
449 return(KRB5_KDB_DBNOTINITED);
451 dal_handle = (kdb5_dal_handle*) context->db_context;
452 db_ctx = dal_handle->db_context;
453 db_ctx->db_master_key = key;
458 krb5_db2_db_get_mkey(context, key)
459 krb5_context context;
462 krb5_db2_context *db_ctx;
463 kdb5_dal_handle *dal_handle;
465 if (!k5db2_inited(context))
466 return(KRB5_KDB_DBNOTINITED);
468 dal_handle = (kdb5_dal_handle*)context->db_context;
469 db_ctx = dal_handle->db_context;
470 *key = db_ctx->db_master_key;
476 * Set the "name" of the current database to some alternate value.
478 * Passing a null pointer as "name" will set back to the default.
479 * If the alternate database doesn't exist, nothing is changed.
485 krb5_db2_db_set_name(context, name)
486 krb5_context context;
490 krb5_db2_context *db_ctx;
491 krb5_error_code kret;
492 kdb5_dal_handle *dal_handle;
494 if (k5db2_inited(context))
495 return KRB5_KDB_DBINITED;
497 /* Check for presence of our context, if not present, allocate one. */
498 if ((kret = k5db2_init_context(context)))
502 name = default_db_name;
504 dal_handle = (kdb5_dal_handle*)context->db_context;
505 db_ctx = dal_handle->db_context;
506 db = k5db2_dbopen(db_ctx, name, O_RDONLY, 0);
510 db_ctx->db_name = strdup(name);
516 * Return the last modification time of the database.
518 * Think about using fstat.
522 krb5_db2_db_get_age(context, db_name, age)
523 krb5_context context;
527 krb5_db2_context *db_ctx;
528 kdb5_dal_handle *dal_handle;
531 if (!k5db2_inited(context))
532 return(KRB5_KDB_DBNOTINITED);
533 dal_handle = (kdb5_dal_handle *) context->db_context;
534 db_ctx = (krb5_db2_context *) dal_handle->db_context;
536 if (fstat (db_ctx->db_lf_file, &st) < 0)
544 * Remove the semaphore file; indicates that database is currently
547 * This is only for use when moving the database out from underneath
548 * the server (for example, during slave updates).
551 static krb5_error_code
552 krb5_db2_db_start_update(context)
553 krb5_context context;
558 static krb5_error_code
559 krb5_db2_db_end_update(context)
560 krb5_context context;
562 krb5_error_code retval;
563 krb5_db2_context *db_ctx;
564 kdb5_dal_handle *dal_handle;
567 struct utimbuf utbuf;
569 if (!k5db2_inited(context))
570 return(KRB5_KDB_DBNOTINITED);
573 dal_handle = (kdb5_dal_handle*) context->db_context;
574 db_ctx = dal_handle->db_context;
575 now = time((time_t *) NULL);
576 if (fstat(db_ctx->db_lf_file, &st) == 0) {
577 if (st.st_mtime >= now) {
578 utbuf.actime = st.st_mtime+1;
579 utbuf.modtime = st.st_mtime+1;
580 if (utime(db_ctx->db_lf_name, &utbuf))
584 if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
591 if (fstat(db_ctx->db_lf_file, &st) == 0)
592 db_ctx->db_lf_time = st.st_mtime;
600 krb5_db2_db_lock(context, in_mode)
601 krb5_context context;
604 krb5_db2_context *db_ctx;
607 krb5_error_code retval;
609 kdb5_dal_handle *dal_handle;
610 int mode = in_mode & ~KRB5_DB_LOCKMODE_PERMANENT; /* permanent is not available for principal db */
614 case KRB5_DB_LOCKMODE_PERMANENT:
615 mode = KRB5_DB_LOCKMODE_EXCLUSIVE;
617 case KRB5_DB_LOCKMODE_EXCLUSIVE:
618 mode = KRB5_LOCKMODE_EXCLUSIVE;
621 case KRB5_DB_LOCKMODE_SHARED:
622 mode = KRB5_LOCKMODE_SHARED;
628 if (!k5db2_inited(context))
629 return KRB5_KDB_DBNOTINITED;
631 dal_handle = (kdb5_dal_handle*) context->db_context;
632 db_ctx = (krb5_db2_context *) dal_handle->db_context;
633 if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
634 /* No need to upgrade lock, just return */
635 db_ctx->db_locks_held++;
639 if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
640 return KRB5_KDB_BADLOCKMODE;
642 if (db_ctx->db_nb_locks)
643 krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
645 krb5_lock_mode = mode;
646 retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
649 if (mode == KRB5_LOCKMODE_EXCLUSIVE)
650 return KRB5_KDB_CANTLOCK_DB;
657 if ((retval = krb5_db2_db_get_age(context, NULL, &mod_time)))
660 db = k5db2_dbopen(db_ctx, db_ctx->db_name,
661 mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR,
664 db_ctx->db_lf_time = mod_time;
672 db_ctx->db_lock_mode = mode;
673 db_ctx->db_locks_held++;
676 if((retval=osa_adb_get_lock(db_ctx->policy_db, in_mode)))
678 krb5_db2_db_unlock(context);
683 db_ctx->db_lock_mode = 0;
684 db_ctx->db_locks_held = 0;
685 krb5_db2_db_unlock(context);
691 krb5_db2_db_unlock(context)
692 krb5_context context;
694 krb5_db2_context *db_ctx;
695 kdb5_dal_handle *dal_handle;
697 krb5_error_code retval;
699 if (!k5db2_inited(context))
700 return KRB5_KDB_DBNOTINITED;
702 dal_handle = (kdb5_dal_handle*) context->db_context;
703 db_ctx = (krb5_db2_context *) dal_handle->db_context;
705 if( (retval = osa_adb_release_lock(db_ctx->policy_db)) )
710 if (!db_ctx->db_locks_held) /* lock already unlocked */
711 return KRB5_KDB_NOTLOCKED;
713 if (--(db_ctx->db_locks_held) == 0) {
717 retval = krb5_lock_file(context, db_ctx->db_lf_file,
718 KRB5_LOCKMODE_UNLOCK);
719 db_ctx->db_lock_mode = 0;
726 * Create the database, assuming it's not there.
729 krb5_db2_db_create(context, db_name, flags)
730 krb5_context context;
734 register krb5_error_code retval = 0;
735 kdb5_dal_handle *dal_handle;
738 krb5_db2_context *db_ctx;
740 char policy_db_name[1024], policy_lock_name[1024];
742 if ((retval = k5db2_init_context(context)))
745 dal_handle = (kdb5_dal_handle*) context->db_context;
746 db_ctx = (krb5_db2_context *) dal_handle->db_context;
748 case KRB5_KDB_CREATE_HASH:
749 if ((retval = krb5_db2_db_set_hashfirst(context, TRUE)))
752 case KRB5_KDB_CREATE_BTREE:
754 if ((retval = krb5_db2_db_set_hashfirst(context, FALSE)))
758 return KRB5_KDB_BAD_CREATEFLAGS;
760 db = k5db2_dbopen(db_ctx, db_name, O_RDWR|O_CREAT|O_EXCL, 0600);
766 okname = gen_dbsuffix(db_name, KDB2_LOCK_EXT);
770 fd = open (okname, O_CREAT|O_RDWR|O_TRUNC, 0600);
775 free_dbsuffix(okname);
779 sprintf( policy_db_name, "%s.kadm5", db_name );
780 sprintf( policy_lock_name, "%s.lock", policy_db_name );
782 retval = osa_adb_create_db( policy_db_name,
783 policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
790 * Destroy the database. Zero's out all of the files, just to be sure.
792 static krb5_error_code
793 destroy_file_suffix(dbname, suffix)
806 filename = gen_dbsuffix(dbname, suffix);
809 if ((fd = open(filename, O_RDWR, 0)) < 0) {
813 /* fstat() will probably not fail unless using a remote filesystem
814 (which is inappropriate for the kerberos database) so this check
815 is mostly paranoia. */
816 if (fstat(fd, &statb) == -1) {
822 * Stroll through the file, reading in BUFSIZ chunks. If everything
823 * is zero, then we're done for that block, otherwise, zero the block.
824 * We would like to just blast through everything, but some DB
825 * implementations make holey files and writing data to the holes
826 * causes actual blocks to be allocated which is no good, since
827 * we're just about to unlink it anyways.
829 memset(zbuf, 0, BUFSIZ);
831 while (pos < statb.st_size) {
833 nb = read(fd, buf, BUFSIZ);
839 for (j=0; j<nb; j++) {
840 if (buf[j] != '\0') {
848 lseek(fd, pos, SEEK_SET);
849 nb = write(fd, zbuf, j);
858 /* ??? Is fsync really needed? I don't know of any non-networked
859 filesystem which will discard queued writes to disk if a file
860 is deleted after it is closed. --jfc */
866 if (unlink(filename)) {
875 * Since the destroy operation happens outside the init/fini bracket, we
876 * have some tomfoolery to undergo here. If we're operating under no
877 * database context, then we initialize with the default. If the caller
878 * wishes a different context (e.g. different dispatch table), it's their
879 * responsibility to call kdb5_db_set_dbops() before this call. That will
880 * set up the right dispatch table values (e.g. name extensions).
882 * Not quite valid due to ripping out of dbops...
885 krb5_db2_db_destroy(context, dbname)
886 krb5_context context;
889 krb5_error_code retval1, retval2;
890 krb5_boolean tmpcontext;
891 char policy_db_name[1024], policy_lock_name[1024];
894 if ( !context->db_context || !((kdb5_dal_handle*)context->db_context)->db_context ) {
896 if ((retval1 = k5db2_init_context(context)))
900 retval1 = retval2 = 0;
901 retval1 = destroy_file_suffix(dbname, "");
902 retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
905 k5db2_clear_context((krb5_db2_context *) ((kdb5_dal_handle*)context->db_context)->db_context );
906 free(((kdb5_dal_handle*)context->db_context)->db_context);
907 ((kdb5_dal_handle*)context->db_context)->db_context = NULL;
910 if (retval1 || retval2)
911 return (retval1 ? retval1 : retval2);
913 sprintf( policy_db_name, "%s.kadm5", dbname );
914 sprintf( policy_lock_name, "%s.lock", policy_db_name );
916 retval1 = osa_adb_destroy_db( policy_db_name,
917 policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
925 * "Atomically" rename the database in a way that locks out read
926 * access in the middle of the rename.
928 * Not perfect; if we crash in the middle of an update, we don't
929 * necessarily know to complete the transaction the rename, but...
931 * Since the rename operation happens outside the init/fini bracket, we
932 * have to go through the same stuff that we went through up in db_destroy.
935 krb5_db2_db_rename(context, from, to)
936 krb5_context context;
942 krb5_error_code retval;
943 kdb5_dal_handle *dal_handle;
944 krb5_db2_context *s_context, *db_ctx;
946 dal_handle = (kdb5_dal_handle*) context->db_context;
947 s_context = dal_handle->db_context;
948 dal_handle->db_context = NULL;
949 if ((retval = k5db2_init_context(context)))
951 db_ctx = (krb5_db2_context *) ((kdb5_dal_handle*)context->db_context)->db_context;
954 * Create the database if it does not already exist; the
955 * files must exist because krb5_db2_db_lock, called below,
956 * will fail otherwise.
958 db = k5db2_dbopen(db_ctx, to, O_RDWR|O_CREAT, 0600);
966 * Set the database to the target, so that other processes sharing
967 * the target will stop their activity, and notice the new database.
969 retval = krb5_db2_db_set_name(context, to);
973 db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT);
974 if (db_ctx->db_lf_name == NULL) {
978 db_ctx->db_lf_file = open(db_ctx->db_lf_name, O_RDWR|O_CREAT, 0600);
979 if (db_ctx->db_lf_file < 0) {
984 db_ctx->db_inited = 1;
986 retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time);
990 fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
991 if (fromok == NULL) {
996 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
999 if ((retval = krb5_db2_db_start_update(context)))
1002 if (rename(from, to)) {
1006 if (unlink(fromok)) {
1010 retval = krb5_db2_db_end_update(context);
1012 free_dbsuffix(fromok);
1014 if ( ((kdb5_dal_handle*)context->db_context)->db_context ) {
1015 if (db_ctx->db_lf_file >= 0) {
1016 krb5_db2_db_unlock(context);
1017 close(db_ctx->db_lf_file);
1019 k5db2_clear_context((krb5_db2_context *) ((kdb5_dal_handle*)context->db_context)->db_context);
1020 free(((kdb5_dal_handle*)context->db_context)->db_context);
1023 ((kdb5_dal_handle*)context->db_context)->db_context = s_context;
1024 (void) krb5_db2_db_unlock(context); /* unlock saved context db */
1032 * look up a principal in the data base.
1033 * returns number of entries found, and whether there were
1034 * more than requested.
1038 krb5_db2_db_get_principal(context, searchfor, entries, nentries, more)
1039 krb5_context context;
1040 krb5_const_principal searchfor;
1041 krb5_db_entry *entries; /* filled in */
1042 int *nentries; /* how much room/how many found */
1043 krb5_boolean *more; /* are there more? */
1045 krb5_db2_context *db_ctx;
1046 krb5_error_code retval;
1049 krb5_data keydata, contdata;
1051 kdb5_dal_handle *dal_handle;
1056 if (!k5db2_inited(context))
1057 return KRB5_KDB_DBNOTINITED;
1059 dal_handle = (kdb5_dal_handle*) context->db_context;
1060 db_ctx = (krb5_db2_context *) dal_handle->db_context;
1062 for (try = 0; try < KRB5_DB2_MAX_RETRY; try++) {
1063 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
1064 if (db_ctx->db_nb_locks)
1071 if (try == KRB5_DB2_MAX_RETRY)
1072 return KRB5_KDB_DB_INUSE;
1074 /* XXX deal with wildcard lookups */
1075 retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
1078 key.data = keydata.data;
1079 key.size = keydata.length;
1082 dbret = (*db->get)(db, &key, &contents, 0);
1084 krb5_free_data_contents(context, &keydata);
1093 contdata.data = contents.data;
1094 contdata.length = contents.size;
1095 retval = krb5_decode_princ_contents(context, &contdata, entries);
1102 (void) krb5_db2_db_unlock(context); /* unlock read lock */
1107 Free stuff returned by krb5_db2_db_get_principal.
1110 krb5_db2_db_free_principal(context, entries, nentries)
1111 krb5_context context;
1112 krb5_db_entry *entries;
1116 for (i = 0; i < nentries; i++)
1117 krb5_dbe_free_contents(context, &entries[i]);
1122 Stores the *"nentries" entry structures pointed to by "entries" in the
1125 *"nentries" is updated upon return to reflect the number of records
1126 acutally stored; the first *"nstored" records will have been stored in the
1127 database (even if an error occurs).
1132 krb5_db2_db_put_principal(context, entries, nentries, db_args)
1133 krb5_context context;
1134 krb5_db_entry *entries;
1135 register int *nentries; /* number of entry structs to update */
1141 krb5_data contdata, keydata;
1142 krb5_error_code retval;
1143 krb5_db2_context *db_ctx;
1144 kdb5_dal_handle *dal_handle;
1148 /* DB2 does not support db_args DB arguments for principal */
1149 char buf[KRB5_MAX_ERR_STR];
1150 sprintf(buf, "Unsupported argument \"%s\" for db2", db_args[0]);
1151 krb5_db2_dal_err_funcp( context, krb5_err_have_str, EINVAL, buf);
1157 if (!k5db2_inited(context))
1158 return KRB5_KDB_DBNOTINITED;
1160 dal_handle = (kdb5_dal_handle*) context->db_context;
1161 db_ctx = (krb5_db2_context *) dal_handle->db_context;
1162 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
1166 if ((retval = krb5_db2_db_start_update(context))) {
1167 (void)krb5_db2_db_unlock(context);
1171 /* for each one, stuff temps, and do replace/append */
1172 for (i = 0; i < n; i++) {
1173 retval = krb5_encode_princ_contents(context, &contdata, entries);
1176 contents.data = contdata.data;
1177 contents.size = contdata.length;
1178 retval = krb5_encode_princ_dbkey(context, &keydata, entries->princ);
1180 krb5_free_data_contents(context, &contdata);
1184 key.data = keydata.data;
1185 key.size = keydata.length;
1186 dbret = (*db->put)(db, &key, &contents, 0);
1187 retval = dbret ? errno : 0;
1188 krb5_free_data_contents(context, &keydata);
1189 krb5_free_data_contents(context, &contdata);
1192 entries++; /* bump to next struct */
1195 (void)krb5_db2_db_end_update(context);
1196 (void)krb5_db2_db_unlock(context); /* unlock database */
1202 * delete a principal from the data base.
1203 * returns number of entries removed
1207 krb5_db2_db_delete_principal(context, searchfor, nentries)
1208 krb5_context context;
1209 krb5_const_principal searchfor;
1210 int *nentries; /* how many found & deleted */
1212 krb5_error_code retval;
1213 krb5_db_entry entry;
1214 krb5_db2_context *db_ctx;
1217 krb5_data keydata, contdata;
1219 kdb5_dal_handle *dal_handle;
1221 if (!k5db2_inited(context))
1222 return KRB5_KDB_DBNOTINITED;
1224 dal_handle = (kdb5_dal_handle*) context->db_context;
1225 db_ctx = (krb5_db2_context *) dal_handle->db_context;
1226 if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
1229 if ((retval = krb5_db2_db_start_update(context))) {
1230 (void) krb5_db2_db_unlock(context); /* unlock write lock */
1234 if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
1236 key.data = keydata.data;
1237 key.size = keydata.length;
1240 dbret = (*db->get)(db, &key, &contents, 0);
1244 retval = KRB5_KDB_NOENTRY;
1252 memset((char *)&entry, 0, sizeof(entry));
1253 contdata.data = contents.data;
1254 contdata.length = contents.size;
1255 retval = krb5_decode_princ_contents(context, &contdata, &entry);
1260 /* Clear encrypted key contents */
1261 for (i = 0; i < entry.n_key_data; i++) {
1262 if (entry.key_data[i].key_data_length[0]) {
1263 memset((char *)entry.key_data[i].key_data_contents[0], 0,
1264 (unsigned) entry.key_data[i].key_data_length[0]);
1268 retval = krb5_encode_princ_contents(context, &contdata, &entry);
1269 krb5_dbe_free_contents(context, &entry);
1273 contents.data = contdata.data;
1274 contents.size = contdata.length;
1275 dbret = (*db->put)(db, &key, &contents, 0);
1276 retval = dbret ? errno : 0;
1277 krb5_free_data_contents(context, &contdata);
1280 dbret = (*db->del)(db, &key, 0);
1281 retval = dbret ? errno : 0;
1283 krb5_free_data_contents(context, &keydata);
1286 (void) krb5_db2_db_end_update(context);
1287 (void) krb5_db2_db_unlock(context); /* unlock write lock */
1292 krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive)
1293 krb5_context context;
1294 krb5_error_code (*func) (krb5_pointer, krb5_db_entry *);
1295 krb5_pointer func_arg;
1296 int backwards, recursive;
1298 krb5_db2_context *db_ctx;
1302 krb5_db_entry entries;
1303 krb5_error_code retval;
1304 kdb5_dal_handle *dal_handle;
1309 if (!k5db2_inited(context))
1310 return KRB5_KDB_DBNOTINITED;
1312 dal_handle = (kdb5_dal_handle*) context->db_context;
1313 db_ctx = (krb5_db2_context *) dal_handle->db_context;
1314 retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
1320 if (recursive && db->type != DB_BTREE) {
1321 (void)krb5_db2_db_unlock(context);
1322 return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1326 dbret = (*db->seq)(db, &key, &contents,
1327 backwards ? R_LAST : R_FIRST);
1330 dbret = bt_rseq(db, &key, &contents, &cookie,
1331 backwards ? R_LAST : R_FIRST);
1333 (void)krb5_db2_db_unlock(context);
1334 return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1337 while (dbret == 0) {
1338 contdata.data = contents.data;
1339 contdata.length = contents.size;
1340 retval = krb5_decode_princ_contents(context, &contdata, &entries);
1343 retval = (*func)(func_arg, &entries);
1344 krb5_dbe_free_contents(context, &entries);
1348 dbret = (*db->seq)(db, &key, &contents,
1349 backwards ? R_PREV : R_NEXT);
1352 dbret = bt_rseq(db, &key, &contents, &cookie,
1353 backwards ? R_PREV : R_NEXT);
1355 (void)krb5_db2_db_unlock(context);
1356 return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1368 (void) krb5_db2_db_unlock(context);
1373 krb5_db2_db_iterate( krb5_context context,
1375 krb5_error_code (*func) (krb5_pointer, krb5_db_entry *),
1376 krb5_pointer func_arg )
1378 return krb5_db2_db_iterate_ext(context, func, func_arg, 0, 0);
1383 krb5_db2_db_set_lockmode(context, mode)
1384 krb5_context context;
1388 krb5_db2_context *db_ctx;
1389 kdb5_dal_handle *dal_handle;
1391 dal_handle = (kdb5_dal_handle*) context->db_context;
1393 if ( dal_handle && (db_ctx = (krb5_db2_context *) dal_handle->db_context)) {
1394 old = db_ctx->db_nb_locks;
1395 db_ctx->db_nb_locks = mode;
1402 * Context serialization operations.
1404 * Ick, this is really gross. --- tlyu
1408 * kdb5_context_size() - Determine size required to serialize.
1410 static krb5_error_code
1411 kdb5_context_size(kcontext, arg, sizep)
1412 krb5_context kcontext;
1416 krb5_error_code kret;
1418 krb5_db2_context *dbctx;
1421 * The database context requires at minimum:
1422 * krb5_int32 for KV5M_DB_CONTEXT
1423 * krb5_int32 for db_inited
1424 * krb5_int32 for database lockfile non-blocking flag
1425 * krb5_int32 for database lockfile lock count
1426 * krb5_int32 for database lockfile lock mode
1427 * krb5_int32 for length of database name.
1428 * krb5_int32 for KV5M_DB_CONTEXT
1431 if ((dbctx = (krb5_db2_context *) arg)) {
1432 required = (sizeof(krb5_int32) * 7);
1433 if (dbctx->db_inited && dbctx->db_name)
1434 required += strlen(dbctx->db_name);
1442 * kdb5_context_externalize() - Externalize the database context.
1444 static krb5_error_code
1445 kdb5_context_externalize(kcontext, arg, buffer, lenremain)
1446 krb5_context kcontext;
1448 krb5_octet **buffer;
1451 krb5_error_code kret;
1452 krb5_db2_context *dbctx;
1459 remain = *lenremain;
1461 if ((dbctx = (krb5_db2_context *) arg)) {
1463 if (!kdb5_context_size(kcontext, arg, &required) &&
1464 (required <= remain)) {
1465 /* Write magic number */
1466 (void) krb5_ser_pack_int32(KV5M_DB_CONTEXT, &bp, &remain);
1468 /* Write inited flag */
1469 (void) krb5_ser_pack_int32((krb5_int32) dbctx->db_inited,
1472 /* Write blocking lock lockmode */
1473 (void) krb5_ser_pack_int32((krb5_int32) dbctx->db_nb_locks,
1476 /* Write lock count */
1477 (void) krb5_ser_pack_int32((krb5_int32)
1478 (dbctx->db_inited) ?
1479 dbctx->db_locks_held : 0,
1482 /* Write lock mode */
1483 (void) krb5_ser_pack_int32((krb5_int32)
1484 (dbctx->db_inited) ?
1485 dbctx->db_lock_mode : 0,
1488 /* Write length of database name */
1489 (void) krb5_ser_pack_int32((dbctx->db_inited && dbctx->db_name) ?
1490 (krb5_int32) strlen(dbctx->db_name) : 0,
1492 if (dbctx->db_inited && dbctx->db_name)
1493 (void) krb5_ser_pack_bytes((krb5_octet *) dbctx->db_name,
1494 strlen(dbctx->db_name),
1498 (void) krb5_ser_pack_int32(KV5M_DB_CONTEXT, &bp, &remain);
1501 *lenremain = remain;
1508 * kdb5_context_internalize() - Internalize the database context.
1510 static krb5_error_code
1511 kdb5_context_internalize(kcontext, argp, buffer, lenremain)
1512 krb5_context kcontext;
1514 krb5_octet **buffer;
1517 krb5_error_code kret;
1518 krb5_context tmpctx;
1519 krb5_db2_context *dbctx;
1524 krb5_int32 nb_lockmode;
1525 krb5_int32 lockcount;
1526 krb5_int32 lockmode;
1527 krb5_int32 dbnamelen;
1528 krb5_boolean nb_lock;
1532 remain = *lenremain;
1534 dbctx = (krb5_db2_context *) NULL;
1535 /* Read our magic number */
1536 if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
1538 if (ibuf == KV5M_DB_CONTEXT) {
1541 if (!(kret = krb5_ser_unpack_int32(&iflag, &bp, &remain)) &&
1542 !(kret = krb5_ser_unpack_int32(&nb_lockmode, &bp, &remain)) &&
1543 !(kret = krb5_ser_unpack_int32(&lockcount, &bp, &remain)) &&
1544 !(kret = krb5_ser_unpack_int32(&lockmode, &bp, &remain)) &&
1545 !(kret = krb5_ser_unpack_int32(&dbnamelen, &bp, &remain)) &&
1546 !(kret = krb5_init_context(&tmpctx))) {
1548 dbname = (char *) NULL;
1550 (dbname = (char *) malloc((size_t) (dbnamelen+1)))) {
1551 kret = krb5_ser_unpack_bytes((krb5_octet *) dbname,
1555 dbname[dbnamelen] = '\0';
1558 (!dbname || !(kret = krb5_db_set_name(tmpctx, dbname))) &&
1559 !(kret = krb5_db_init(tmpctx))) {
1560 dbctx = (krb5_db2_context *) tmpctx->db_context;
1561 (void) krb5_db2_db_set_lockmode(tmpctx, 0);
1563 kret = krb5_db2_db_lock(tmpctx, lockmode);
1564 if (!kret && lockmode)
1565 dbctx->db_locks_held = lockcount;
1566 nb_lock = nb_lockmode & 0xff;
1567 (void) krb5_db2_db_set_lockmode(tmpctx, nb_lock);
1573 kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
1574 if (kret || (ibuf != KV5M_DB_CONTEXT))
1579 krb5_db_fini(tmpctx);
1582 tmpctx->db_context = NULL;
1583 krb5_free_context(tmpctx);
1588 *lenremain = remain;
1589 *argp = (krb5_pointer) dbctx;
1594 /* Dispatch entry */
1595 static const krb5_ser_entry kdb5_context_ser_entry = {
1596 KV5M_DB_CONTEXT, /* Type */
1597 kdb5_context_size, /* Sizer routine */
1598 kdb5_context_externalize, /* Externalize routine */
1599 kdb5_context_internalize /* Externalize routine */
1603 * Register serializer.
1606 krb5_ser_db_context_init(kcontext)
1607 krb5_context kcontext;
1609 return(krb5_register_serializer(kcontext, &kdb5_context_ser_entry));
1617 krb5_error_code krb5_db2_lib_init(krb5_set_err_func_t set_err)
1619 krb5_db2_dal_err_funcp = set_err;
1623 krb5_error_code krb5_db2_lib_cleanup()
1625 /* right now, no cleanup required */
1629 krb5_error_code krb5_db2_open( krb5_context kcontext,
1634 krb5_error_code status = 0;
1635 char **t_ptr = db_args;
1636 char db_name_set = 0;
1638 if (k5db2_inited(kcontext))
1642 while ( t_ptr && *t_ptr )
1644 char *opt = NULL, *val = NULL;
1646 krb5_db2_get_db_opt( *t_ptr, &opt, &val );
1647 if( opt && !strcmp( opt, "dbname" ) )
1649 status = krb5_db2_db_set_name( kcontext, val );
1658 /* ignore hash argument. Might have been passed from create */
1659 else if( !opt || strcmp( opt, "hash") )
1661 char buf[KRB5_MAX_ERR_STR];
1662 sprintf(buf, "Unsupported argument \"%s\" for db2", opt?opt:val);
1663 krb5_db2_dal_err_funcp( kcontext, krb5_err_have_str, EINVAL, buf);
1677 status = profile_get_string( KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION,
1678 conf_section, KDB_DB2_DATABASE_NAME, /* under given conf section */
1684 /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
1685 status = profile_get_string( KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION,
1686 KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME, /* under given realm */
1687 default_db_name, &value );
1694 status = krb5_db2_db_set_name( kcontext, value );
1695 profile_release_string( value );
1703 status = krb5_db2_db_init( kcontext );
1710 krb5_error_code krb5_db2_create( krb5_context kcontext,
1714 krb5_error_code status = 0;
1715 char **t_ptr = db_args;
1716 char db_name_set = 0;
1717 krb5_int32 flags = KRB5_KDB_CREATE_BTREE;
1718 char *db_name = NULL;
1720 if (k5db2_inited(kcontext))
1724 while ( t_ptr && *t_ptr )
1726 char *opt = NULL, *val = NULL;
1728 krb5_db2_get_db_opt( *t_ptr, &opt, &val );
1729 if( opt && !strcmp( opt, "dbname" ) )
1731 db_name = strdup(val);
1732 status = krb5_db2_db_set_name( kcontext, val );
1742 /* ignore hash argument. Might have been passed from create */
1743 else if( opt && !strcmp( opt, "hash") )
1745 flags=KRB5_KDB_CREATE_HASH;
1749 char buf[KRB5_MAX_ERR_STR];
1750 sprintf(buf, "Unsupported argument \"%s\" for db2", opt?opt:val);
1751 krb5_db2_dal_err_funcp( kcontext, krb5_err_have_str, EINVAL, buf);
1765 status = profile_get_string( KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION,
1766 conf_section, KDB_DB2_DATABASE_NAME, /* under given conf section */
1772 /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
1773 status = profile_get_string( KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION,
1774 KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME, /* under given realm */
1775 default_db_name, &value );
1782 db_name = strdup( value );
1783 status = krb5_db2_db_set_name( kcontext, value );
1784 profile_release_string( value );
1793 status = krb5_db2_db_create( kcontext, db_name, flags );
1796 /* db2 has a problem of needing to close and open the database again. This removes that need */
1797 status = krb5_db2_db_fini(kcontext);
1801 status = krb5_db2_open( kcontext, conf_section, db_args, KRB5_KDB_OPEN_RW );
1809 krb5_error_code krb5_db2_destroy( krb5_context kcontext,
1813 krb5_error_code status = 0;
1814 char **t_ptr = db_args;
1815 char db_name_set = 0;
1816 char *db_name = NULL;
1818 while ( t_ptr && *t_ptr )
1820 char *opt = NULL, *val = NULL;
1822 krb5_db2_get_db_opt( *t_ptr, &opt, &val );
1823 if( opt && !strcmp( opt, "dbname" ) )
1825 db_name = strdup(val);
1826 status = krb5_db2_db_set_name( kcontext, val );
1835 /* ignore hash argument. Might have been passed from create */
1836 else if( !opt || strcmp( opt, "hash") )
1851 status = profile_get_string( KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION,
1852 conf_section, KDB_DB2_DATABASE_NAME, /* under given conf section */
1858 /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
1859 status = profile_get_string( KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION,
1860 KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME, /* under given realm */
1861 default_db_name, &value );
1868 db_name = strdup(value);
1869 status = krb5_db2_db_set_name( kcontext, value );
1870 profile_release_string( value );
1878 status = krb5_db2_db_destroy( kcontext, db_name );
1886 krb5_error_code krb5_db2_set_master_key_ext ( krb5_context kcontext,
1890 return krb5_db2_db_set_mkey( kcontext, key );
1893 krb5_error_code krb5_db2_db_set_option ( krb5_context kcontext, int option, void *value )
1895 krb5_error_code status = 0;
1896 krb5_boolean oldval;
1900 case KRB5_KDB_OPT_SET_DB_NAME:
1901 status = krb5_db2_db_set_name( kcontext, (char *)value);
1904 case KRB5_KDB_OPT_SET_LOCK_MODE:
1905 oldval = krb5_db2_db_set_lockmode( kcontext, *((krb5_boolean*)value) );
1906 *((krb5_boolean*)value) = oldval;
1910 status = -1; /* TBD */
1917 void * krb5_db2_alloc( krb5_context kcontext, void *ptr, size_t size )
1919 return realloc(ptr, size);
1922 void krb5_db2_free( krb5_context kcontext, void *ptr )
1928 /* policy functions */
1929 krb5_error_code krb5_db2_create_policy( krb5_context kcontext,
1930 osa_policy_ent_t policy )
1932 kdb5_dal_handle *dal_handle;
1933 krb5_db2_context *dbc;
1935 dal_handle = (kdb5_dal_handle*) kcontext->db_context;
1936 dbc = (krb5_db2_context*) dal_handle->db_context;
1938 return osa_adb_create_policy( dbc->policy_db, policy );
1941 krb5_error_code krb5_db2_get_policy ( krb5_context kcontext,
1943 osa_policy_ent_t *policy,
1946 kdb5_dal_handle *dal_handle;
1947 krb5_db2_context *dbc;
1949 dal_handle = (kdb5_dal_handle*) kcontext->db_context;
1950 dbc = (krb5_db2_context*) dal_handle->db_context;
1952 return osa_adb_get_policy( dbc->policy_db, name, policy, cnt );
1955 krb5_error_code krb5_db2_put_policy ( krb5_context kcontext,
1956 osa_policy_ent_t policy )
1958 kdb5_dal_handle *dal_handle;
1959 krb5_db2_context *dbc;
1961 dal_handle = (kdb5_dal_handle*) kcontext->db_context;
1962 dbc = (krb5_db2_context*) dal_handle->db_context;
1964 return osa_adb_put_policy( dbc->policy_db, policy );
1967 krb5_error_code krb5_db2_iter_policy ( krb5_context kcontext,
1969 osa_adb_iter_policy_func func,
1972 kdb5_dal_handle *dal_handle;
1973 krb5_db2_context *dbc;
1975 dal_handle = (kdb5_dal_handle*) kcontext->db_context;
1976 dbc = (krb5_db2_context*) dal_handle->db_context;
1978 return osa_adb_iter_policy( dbc->policy_db, func, data );
1982 krb5_error_code krb5_db2_delete_policy ( krb5_context kcontext,
1985 kdb5_dal_handle *dal_handle;
1986 krb5_db2_context *dbc;
1988 dal_handle = (kdb5_dal_handle*) kcontext->db_context;
1989 dbc = (krb5_db2_context*) dal_handle->db_context;
1991 return osa_adb_destroy_policy( dbc->policy_db, policy );
1995 void krb5_db2_free_policy( krb5_context kcontext,
1996 osa_policy_ent_t entry )
1998 osa_free_policy_ent(entry);