154925bf6Swillf /*
2fad1d705SPeter Shoults  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
354925bf6Swillf  * Use is subject to license terms.
454925bf6Swillf  */
554925bf6Swillf 
654925bf6Swillf 
754925bf6Swillf /*
854925bf6Swillf  * lib/kdb/kdb_db2.c
954925bf6Swillf  *
1054925bf6Swillf  * Copyright 1997,2006 by the Massachusetts Institute of Technology.
1154925bf6Swillf  * All Rights Reserved.
1254925bf6Swillf  *
1354925bf6Swillf  * Export of this software from the United States of America may
1454925bf6Swillf  *   require a specific license from the United States Government.
1554925bf6Swillf  *   It is the responsibility of any person or organization contemplating
1654925bf6Swillf  *   export to obtain such a license before exporting.
1754925bf6Swillf  *
1854925bf6Swillf  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
1954925bf6Swillf  * distribute this software and its documentation for any purpose and
2054925bf6Swillf  * without fee is hereby granted, provided that the above copyright
2154925bf6Swillf  * notice appear in all copies and that both that copyright notice and
2254925bf6Swillf  * this permission notice appear in supporting documentation, and that
2354925bf6Swillf  * the name of M.I.T. not be used in advertising or publicity pertaining
2454925bf6Swillf  * to distribution of the software without specific, written prior
2554925bf6Swillf  * permission.  Furthermore if you modify this software you must label
2654925bf6Swillf  * your software as modified software and not distribute it in such a
2754925bf6Swillf  * fashion that it might be confused with the original M.I.T. software.
2854925bf6Swillf  * M.I.T. makes no representations about the suitability of
2954925bf6Swillf  * this software for any purpose.  It is provided "as is" without express
3054925bf6Swillf  * or implied warranty.
3154925bf6Swillf  *
3254925bf6Swillf  */
3354925bf6Swillf 
3454925bf6Swillf /*
3554925bf6Swillf  * Copyright (C) 1998 by the FundsXpress, INC.
3654925bf6Swillf  *
3754925bf6Swillf  * All rights reserved.
3854925bf6Swillf  *
3954925bf6Swillf  * Export of this software from the United States of America may require
4054925bf6Swillf  * a specific license from the United States Government.  It is the
4154925bf6Swillf  * responsibility of any person or organization contemplating export to
4254925bf6Swillf  * obtain such a license before exporting.
4354925bf6Swillf  *
4454925bf6Swillf  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
4554925bf6Swillf  * distribute this software and its documentation for any purpose and
4654925bf6Swillf  * without fee is hereby granted, provided that the above copyright
4754925bf6Swillf  * notice appear in all copies and that both that copyright notice and
4854925bf6Swillf  * this permission notice appear in supporting documentation, and that
4954925bf6Swillf  * the name of FundsXpress. not be used in advertising or publicity pertaining
5054925bf6Swillf  * to distribution of the software without specific, written prior
5154925bf6Swillf  * permission.  FundsXpress makes no representations about the suitability of
5254925bf6Swillf  * this software for any purpose.  It is provided "as is" without express
5354925bf6Swillf  * or implied warranty.
5454925bf6Swillf  *
5554925bf6Swillf  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
5654925bf6Swillf  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
5754925bf6Swillf  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
5854925bf6Swillf  */
5954925bf6Swillf 
6054925bf6Swillf #include "k5-int.h"
6154925bf6Swillf #include <kdb_log.h>
6254925bf6Swillf 
6354925bf6Swillf #if HAVE_UNISTD_H
6454925bf6Swillf #include <unistd.h>
6554925bf6Swillf #endif
6654925bf6Swillf 
6754925bf6Swillf #include <db.h>
6854925bf6Swillf #include <stdio.h>
6954925bf6Swillf #include <errno.h>
7054925bf6Swillf #include <utime.h>
71159d09a2SMark Phalan #include "kdb5.h"
7254925bf6Swillf #include "kdb_db2.h"
7354925bf6Swillf #include "kdb_xdr.h"
7454925bf6Swillf #include "policy_db.h"
7554925bf6Swillf #include <libintl.h>
7654925bf6Swillf 
7754925bf6Swillf #define KDB_DB2_DATABASE_NAME "database_name"
7854925bf6Swillf 
7954925bf6Swillf #include "kdb_db2.h"
8054925bf6Swillf 
8154925bf6Swillf static char *gen_dbsuffix(char *, char *);
8254925bf6Swillf 
8354925bf6Swillf static krb5_error_code krb5_db2_db_start_update(krb5_context);
8454925bf6Swillf static krb5_error_code krb5_db2_db_end_update(krb5_context);
8554925bf6Swillf 
8654925bf6Swillf static krb5_error_code krb5_db2_db_set_name(krb5_context, char *, int);
8754925bf6Swillf 
8854925bf6Swillf krb5_error_code krb5_db2_db_lock(krb5_context, int);
8954925bf6Swillf 
9054925bf6Swillf static krb5_error_code krb5_db2_db_set_hashfirst(krb5_context, int);
9154925bf6Swillf 
927c64d375Smp /*
937c64d375Smp  * Solaris Kerberos
947c64d375Smp  * Extra error handling
957c64d375Smp  */
967c64d375Smp char errbuf[1024];
977c64d375Smp static void krb5_db2_prepend_err_str(krb5_context , const char *,
987c64d375Smp     krb5_error_code, krb5_error_code);
997c64d375Smp 
10054925bf6Swillf static char default_db_name[] = DEFAULT_KDB_FILE;
10154925bf6Swillf 
10254925bf6Swillf /*
10354925bf6Swillf  * Locking:
10454925bf6Swillf  *
10554925bf6Swillf  * There are two distinct locking protocols used.  One is designed to
10654925bf6Swillf  * lock against processes (the admin_server, for one) which make
10754925bf6Swillf  * incremental changes to the database; the other is designed to lock
10854925bf6Swillf  * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
10954925bf6Swillf  * entire database in one fell swoop.
11054925bf6Swillf  *
11154925bf6Swillf  * The first locking protocol is implemented using flock() in the
11254925bf6Swillf  * krb_dbl_lock() and krb_dbl_unlock routines.
11354925bf6Swillf  *
11454925bf6Swillf  * The second locking protocol is necessary because DBM "files" are
11554925bf6Swillf  * actually implemented as two separate files, and it is impossible to
11654925bf6Swillf  * atomically rename two files simultaneously.  It assumes that the
11754925bf6Swillf  * database is replaced only very infrequently in comparison to the time
11854925bf6Swillf  * needed to do a database read operation.
11954925bf6Swillf  *
12054925bf6Swillf  * A third file is used as a "version" semaphore; the modification
12154925bf6Swillf  * time of this file is the "version number" of the database.
12254925bf6Swillf  * At the start of a read operation, the reader checks the version
12354925bf6Swillf  * number; at the end of the read operation, it checks again.  If the
12454925bf6Swillf  * version number changed, or if the semaphore was nonexistant at
12554925bf6Swillf  * either time, the reader sleeps for a second to let things
12654925bf6Swillf  * stabilize, and then tries again; if it does not succeed after
12754925bf6Swillf  * KRB5_DBM_MAX_RETRY attempts, it gives up.
12854925bf6Swillf  *
12954925bf6Swillf  * On update, the semaphore file is deleted (if it exists) before any
13054925bf6Swillf  * update takes place; at the end of the update, it is replaced, with
13154925bf6Swillf  * a version number strictly greater than the version number which
13254925bf6Swillf  * existed at the start of the update.
13354925bf6Swillf  *
13454925bf6Swillf  * If the system crashes in the middle of an update, the semaphore
13554925bf6Swillf  * file is not automatically created on reboot; this is a feature, not
13654925bf6Swillf  * a bug, since the database may be inconsistant.  Note that the
13754925bf6Swillf  * absence of a semaphore file does not prevent another _update_ from
13854925bf6Swillf  * taking place later.  Database replacements take place automatically
13954925bf6Swillf  * only on slave servers; a crash in the middle of an update will be
14054925bf6Swillf  * fixed by the next slave propagation.  A crash in the middle of an
14154925bf6Swillf  * update on the master would be somewhat more serious, but this would
14254925bf6Swillf  * likely be noticed by an administrator, who could fix the problem and
14354925bf6Swillf  * retry the operation.
14454925bf6Swillf  */
14554925bf6Swillf 
14654925bf6Swillf #define free_dbsuffix(name) free(name)
14754925bf6Swillf 
14854925bf6Swillf /*
14954925bf6Swillf  * Routines to deal with context.
15054925bf6Swillf  */
15154925bf6Swillf #define	k5db2_inited(c)	(c && c->db_context \
15254925bf6Swillf 			 && ((kdb5_dal_handle*)c->db_context)->db_context \
15354925bf6Swillf                          && ((krb5_db2_context *) ((kdb5_dal_handle*)c->db_context)->db_context)->db_inited)
15454925bf6Swillf 
15554925bf6Swillf static krb5_error_code
krb5_db2_get_db_opt(char * input,char ** opt,char ** val)15654925bf6Swillf krb5_db2_get_db_opt(char *input, char **opt, char **val)
15754925bf6Swillf {
15854925bf6Swillf     char   *pos = strchr(input, '=');
15954925bf6Swillf     if (pos == NULL) {
16054925bf6Swillf 	*opt = NULL;
16154925bf6Swillf 	*val = strdup(input);
16254925bf6Swillf 	if (*val == NULL) {
16354925bf6Swillf 	    return ENOMEM;
16454925bf6Swillf 	}
16554925bf6Swillf     } else {
16654925bf6Swillf 	*opt = malloc((pos - input) + 1);
16754925bf6Swillf 	*val = strdup(pos + 1);
16854925bf6Swillf 	if (!*opt || !*val) {
16954925bf6Swillf 	    return ENOMEM;
17054925bf6Swillf 	}
17154925bf6Swillf 	memcpy(*opt, input, pos - input);
17254925bf6Swillf 	(*opt)[pos - input] = '\0';
17354925bf6Swillf     }
17454925bf6Swillf     return (0);
17554925bf6Swillf 
17654925bf6Swillf }
17754925bf6Swillf 
17854925bf6Swillf /*
17954925bf6Swillf  * Restore the default context.
18054925bf6Swillf  */
18154925bf6Swillf static void
k5db2_clear_context(krb5_db2_context * dbctx)18254925bf6Swillf k5db2_clear_context(krb5_db2_context *dbctx)
18354925bf6Swillf {
18454925bf6Swillf     /*
18554925bf6Swillf      * Free any dynamically allocated memory.  File descriptors and locks
18654925bf6Swillf      * are the caller's problem.
18754925bf6Swillf      */
18854925bf6Swillf     if (dbctx->db_lf_name)
18954925bf6Swillf 	free(dbctx->db_lf_name);
19054925bf6Swillf     if (dbctx->db_name && (dbctx->db_name != default_db_name))
19154925bf6Swillf 	free(dbctx->db_name);
19254925bf6Swillf     /*
19354925bf6Swillf      * Clear the structure and reset the defaults.
19454925bf6Swillf      */
19554925bf6Swillf     memset((char *) dbctx, 0, sizeof(krb5_db2_context));
19654925bf6Swillf     dbctx->db_name = default_db_name;
19754925bf6Swillf     dbctx->db_nb_locks = FALSE;
19854925bf6Swillf     dbctx->tempdb = FALSE;
19954925bf6Swillf }
20054925bf6Swillf 
20154925bf6Swillf static krb5_error_code
k5db2_init_context(krb5_context context)20254925bf6Swillf k5db2_init_context(krb5_context context)
20354925bf6Swillf {
20454925bf6Swillf     krb5_db2_context *db_ctx;
20554925bf6Swillf     kdb5_dal_handle *dal_handle;
20654925bf6Swillf 
20754925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
20854925bf6Swillf 
20954925bf6Swillf     if (dal_handle->db_context == NULL) {
21054925bf6Swillf 	db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
21154925bf6Swillf 	if (db_ctx == NULL)
21254925bf6Swillf 	    return ENOMEM;
21354925bf6Swillf 	else {
21454925bf6Swillf 	    memset((char *) db_ctx, 0, sizeof(krb5_db2_context));
21554925bf6Swillf 	    k5db2_clear_context((krb5_db2_context *) db_ctx);
21654925bf6Swillf 	    dal_handle->db_context = (void *) db_ctx;
21754925bf6Swillf 	}
21854925bf6Swillf     }
21954925bf6Swillf     return (0);
22054925bf6Swillf }
22154925bf6Swillf 
22254925bf6Swillf /*
22354925bf6Swillf  * Utility routine: generate name of database file.
22454925bf6Swillf  */
22554925bf6Swillf 
22654925bf6Swillf static char *
gen_dbsuffix(char * db_name,char * sfx)22754925bf6Swillf gen_dbsuffix(char *db_name, char *sfx)
22854925bf6Swillf {
22954925bf6Swillf     char   *dbsuffix;
23054925bf6Swillf 
23154925bf6Swillf     if (sfx == NULL)
23254925bf6Swillf 	return ((char *) NULL);
23354925bf6Swillf 
23454925bf6Swillf     dbsuffix = malloc(strlen(db_name) + strlen(sfx) + 1);
23554925bf6Swillf     if (!dbsuffix)
23654925bf6Swillf 	return (0);
23754925bf6Swillf     /*LINTED*/
23854925bf6Swillf     (void) strcpy(dbsuffix, db_name);
23954925bf6Swillf     /*LINTED*/
24054925bf6Swillf     (void) strcat(dbsuffix, sfx);
24154925bf6Swillf     return dbsuffix;
24254925bf6Swillf }
24354925bf6Swillf 
24454925bf6Swillf static DB *
k5db2_dbopen(krb5_db2_context * dbc,char * fname,int flags,int mode,int tempdb)24554925bf6Swillf k5db2_dbopen(krb5_db2_context *dbc, char *fname, int flags, int mode, int tempdb)
24654925bf6Swillf {
24754925bf6Swillf     DB     *db;
24854925bf6Swillf     BTREEINFO bti;
24954925bf6Swillf     HASHINFO hashi;
25054925bf6Swillf     bti.flags = 0;
25154925bf6Swillf     bti.cachesize = 0;
25254925bf6Swillf     bti.psize = 4096;
25354925bf6Swillf     bti.lorder = 0;
25454925bf6Swillf     bti.minkeypage = 0;
25554925bf6Swillf     bti.compare = NULL;
25654925bf6Swillf     bti.prefix = NULL;
25754925bf6Swillf 
25854925bf6Swillf     if (tempdb) {
25954925bf6Swillf 	fname = gen_dbsuffix(fname, "~");
26054925bf6Swillf     } else {
26154925bf6Swillf 	fname = strdup(fname);
26254925bf6Swillf     }
26354925bf6Swillf     if (fname == NULL)
26454925bf6Swillf     {
26554925bf6Swillf 	errno = ENOMEM;
26654925bf6Swillf 	return NULL;
26754925bf6Swillf     }
268*55fea89dSDan Cross 
26954925bf6Swillf 
27054925bf6Swillf     hashi.bsize = 4096;
27154925bf6Swillf     hashi.cachesize = 0;
27254925bf6Swillf     hashi.ffactor = 40;
27354925bf6Swillf     hashi.hash = NULL;
27454925bf6Swillf     hashi.lorder = 0;
27554925bf6Swillf     hashi.nelem = 1;
27654925bf6Swillf 
27754925bf6Swillf     db = dbopen(fname, flags, mode,
27854925bf6Swillf 		dbc->hashfirst ? DB_HASH : DB_BTREE,
27954925bf6Swillf 		dbc->hashfirst ? (void *) &hashi : (void *) &bti);
28054925bf6Swillf     if (db != NULL) {
28154925bf6Swillf 	free(fname);
28254925bf6Swillf 	return db;
28354925bf6Swillf     }
28454925bf6Swillf     switch (errno) {
28554925bf6Swillf #ifdef EFTYPE
28654925bf6Swillf     case EFTYPE:
28754925bf6Swillf #endif
28854925bf6Swillf     case EINVAL:
28954925bf6Swillf 	db = dbopen(fname, flags, mode,
29054925bf6Swillf 		    dbc->hashfirst ? DB_BTREE : DB_HASH,
29154925bf6Swillf 		    dbc->hashfirst ? (void *) &bti : (void *) &hashi);
29254925bf6Swillf 	if (db != NULL)
29354925bf6Swillf 	    dbc->hashfirst = !dbc->hashfirst;
2940b16192fSToomas Soome 	/* FALLTHROUGH */
29554925bf6Swillf     default:
29654925bf6Swillf 	free(fname);
29754925bf6Swillf 	return db;
29854925bf6Swillf     }
29954925bf6Swillf }
30054925bf6Swillf 
30154925bf6Swillf static krb5_error_code
krb5_db2_db_set_hashfirst(krb5_context context,int hashfirst)30254925bf6Swillf krb5_db2_db_set_hashfirst(krb5_context context, int hashfirst)
30354925bf6Swillf {
30454925bf6Swillf     krb5_db2_context *dbc;
30554925bf6Swillf     kdb5_dal_handle *dal_handle;
30654925bf6Swillf 
30754925bf6Swillf     if (k5db2_inited(context))
30854925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
30954925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
31054925bf6Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
31154925bf6Swillf     dbc->hashfirst = hashfirst;
31254925bf6Swillf     return 0;
31354925bf6Swillf }
31454925bf6Swillf 
31554925bf6Swillf /*
31654925bf6Swillf  * initialization for data base routines.
31754925bf6Swillf  */
31854925bf6Swillf 
31954925bf6Swillf krb5_error_code
krb5_db2_db_init(krb5_context context)32054925bf6Swillf krb5_db2_db_init(krb5_context context)
32154925bf6Swillf {
32254925bf6Swillf     char   *filename = NULL;
32354925bf6Swillf     krb5_db2_context *db_ctx;
32454925bf6Swillf     krb5_error_code retval;
32554925bf6Swillf     kdb5_dal_handle *dal_handle;
32654925bf6Swillf     char    policy_db_name[1024], policy_lock_name[1024];
32754925bf6Swillf 
32854925bf6Swillf     if (k5db2_inited(context))
32954925bf6Swillf 	return 0;
33054925bf6Swillf 
33154925bf6Swillf     /* Check for presence of our context, if not present, allocate one. */
33254925bf6Swillf     if ((retval = k5db2_init_context(context)))
33354925bf6Swillf 	return (retval);
33454925bf6Swillf 
33554925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
33654925bf6Swillf     db_ctx = dal_handle->db_context;
33754925bf6Swillf     db_ctx->db = NULL;
33854925bf6Swillf 
33954925bf6Swillf     if (!(filename = gen_dbsuffix(db_ctx->db_name, db_ctx->tempdb
34054925bf6Swillf 				  ?KDB2_TEMP_LOCK_EXT:KDB2_LOCK_EXT)))
34154925bf6Swillf 	return ENOMEM;
34254925bf6Swillf     db_ctx->db_lf_name = filename;	/* so it gets freed by clear_context */
34354925bf6Swillf 
34454925bf6Swillf     /*
34554925bf6Swillf      * should be opened read/write so that write locking can work with
34654925bf6Swillf      * POSIX systems
34754925bf6Swillf      */
34854925bf6Swillf     if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
34954925bf6Swillf 	if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
35054925bf6Swillf 	    retval = errno;
3517c64d375Smp 
3527c64d375Smp 	    /* Solaris Kerberos: Better error logging */
3537c64d375Smp   	    (void) snprintf(errbuf, sizeof(errbuf), gettext("Failed to open \"%s\": "), filename);
3547c64d375Smp 	    krb5_db2_prepend_err_str(context, errbuf, retval, retval);
3557c64d375Smp 
35654925bf6Swillf 	    goto err_out;
35754925bf6Swillf 	}
35854925bf6Swillf     }
35954925bf6Swillf     db_ctx->db_inited++;
36054925bf6Swillf 
36154925bf6Swillf     if ((retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time)))
36254925bf6Swillf 	goto err_out;
36354925bf6Swillf 
36454925bf6Swillf     sprintf(policy_db_name, db_ctx->tempdb ? "%s~.kadm5" : "%s.kadm5",
36554925bf6Swillf 	    db_ctx->db_name);
36654925bf6Swillf     sprintf(policy_lock_name, "%s.lock", policy_db_name);
36754925bf6Swillf 
36854925bf6Swillf     if ((retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
36954925bf6Swillf 				  policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)))
37054925bf6Swillf     {
3717c64d375Smp 	/* Solaris Kerberos: Better error logging */
3727c64d375Smp 	snprintf(errbuf, sizeof(errbuf),
3737c64d375Smp 	    gettext("Failed to initialize db, \"%s\", lockfile, \"%s\" : "),
3747c64d375Smp 	    policy_db_name, policy_lock_name);
3757c64d375Smp 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
3767c64d375Smp 
37754925bf6Swillf 	goto err_out;
37854925bf6Swillf     }
37954925bf6Swillf     return 0;
38054925bf6Swillf 
38154925bf6Swillf   err_out:
38254925bf6Swillf     db_ctx->db = NULL;
38354925bf6Swillf     k5db2_clear_context(db_ctx);
38454925bf6Swillf     return (retval);
38554925bf6Swillf }
38654925bf6Swillf 
38754925bf6Swillf /*
38854925bf6Swillf  * gracefully shut down database--must be called by ANY program that does
38954925bf6Swillf  * a krb5_db2_db_init
39054925bf6Swillf  */
39154925bf6Swillf krb5_error_code
krb5_db2_db_fini(krb5_context context)39254925bf6Swillf krb5_db2_db_fini(krb5_context context)
39354925bf6Swillf {
39454925bf6Swillf     krb5_error_code retval = 0;
39554925bf6Swillf     krb5_db2_context *db_ctx;
39654925bf6Swillf     kdb5_dal_handle *dal_handle;
39754925bf6Swillf 
39854925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
39954925bf6Swillf     if (dal_handle == NULL) {
40054925bf6Swillf 	return 0;
40154925bf6Swillf     }
40254925bf6Swillf 
40354925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
40454925bf6Swillf 
40554925bf6Swillf     if (k5db2_inited(context)) {
40654925bf6Swillf 	if (close(db_ctx->db_lf_file))
40754925bf6Swillf 	    retval = errno;
40854925bf6Swillf 	else
40954925bf6Swillf 	    retval = 0;
41054925bf6Swillf     }
41154925bf6Swillf     if (db_ctx) {
41254925bf6Swillf 	if (db_ctx->policy_db) {
41354925bf6Swillf 	    retval =
41454925bf6Swillf 		osa_adb_fini_db(db_ctx->policy_db, OSA_ADB_POLICY_DB_MAGIC);
41554925bf6Swillf 	    if (retval)
41654925bf6Swillf 		return retval;
41754925bf6Swillf 	}
41854925bf6Swillf 
41954925bf6Swillf 	k5db2_clear_context(db_ctx);
42054925bf6Swillf 	/*      free(dal_handle->db_context); */
42154925bf6Swillf 	dal_handle->db_context = NULL;
42254925bf6Swillf     }
42354925bf6Swillf     return retval;
42454925bf6Swillf }
42554925bf6Swillf 
42654925bf6Swillf /*
42754925bf6Swillf  * Set/Get the master key associated with the database
42854925bf6Swillf  */
42954925bf6Swillf krb5_error_code
krb5_db2_db_set_mkey(krb5_context context,krb5_keyblock * key)43054925bf6Swillf krb5_db2_db_set_mkey(krb5_context context, krb5_keyblock *key)
43154925bf6Swillf {
43254925bf6Swillf     krb5_db2_context *db_ctx;
43354925bf6Swillf     kdb5_dal_handle *dal_handle;
43454925bf6Swillf 
43554925bf6Swillf     if (!k5db2_inited(context))
43654925bf6Swillf 	return (KRB5_KDB_DBNOTINITED);
43754925bf6Swillf 
43854925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
43954925bf6Swillf     db_ctx = dal_handle->db_context;
44054925bf6Swillf     db_ctx->db_master_key = key;
44154925bf6Swillf     return 0;
44254925bf6Swillf }
44354925bf6Swillf 
44454925bf6Swillf krb5_error_code
krb5_db2_db_get_mkey(krb5_context context,krb5_keyblock ** key)44554925bf6Swillf krb5_db2_db_get_mkey(krb5_context context, krb5_keyblock **key)
44654925bf6Swillf {
44754925bf6Swillf     krb5_db2_context *db_ctx;
44854925bf6Swillf     kdb5_dal_handle *dal_handle;
44954925bf6Swillf 
45054925bf6Swillf     if (!k5db2_inited(context))
45154925bf6Swillf 	return (KRB5_KDB_DBNOTINITED);
45254925bf6Swillf 
45354925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
45454925bf6Swillf     db_ctx = dal_handle->db_context;
45554925bf6Swillf     *key = db_ctx->db_master_key;
45654925bf6Swillf 
45754925bf6Swillf     return 0;
45854925bf6Swillf }
45954925bf6Swillf 
46054925bf6Swillf /*
46154925bf6Swillf  * Set the "name" of the current database to some alternate value.
46254925bf6Swillf  *
46354925bf6Swillf  * Passing a null pointer as "name" will set back to the default.
46454925bf6Swillf  * If the alternate database doesn't exist, nothing is changed.
46554925bf6Swillf  *
46654925bf6Swillf  * XXX rethink this
46754925bf6Swillf  */
46854925bf6Swillf 
46954925bf6Swillf static krb5_error_code
krb5_db2_db_set_name(krb5_context context,char * name,int tempdb)47054925bf6Swillf krb5_db2_db_set_name(krb5_context context, char *name, int tempdb)
47154925bf6Swillf {
47254925bf6Swillf     DB     *db;
47354925bf6Swillf     krb5_db2_context *db_ctx;
47454925bf6Swillf     krb5_error_code kret;
47554925bf6Swillf     kdb5_dal_handle *dal_handle;
47654925bf6Swillf 
47754925bf6Swillf     if (k5db2_inited(context))
47854925bf6Swillf 	return KRB5_KDB_DBINITED;
47954925bf6Swillf 
48054925bf6Swillf     /* Check for presence of our context, if not present, allocate one. */
48154925bf6Swillf     if ((kret = k5db2_init_context(context)))
48254925bf6Swillf 	return (kret);
48354925bf6Swillf 
48454925bf6Swillf     if (name == NULL)
48554925bf6Swillf 	name = default_db_name;
48654925bf6Swillf 
48754925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
48854925bf6Swillf     db_ctx = dal_handle->db_context;
48954925bf6Swillf     db_ctx->tempdb = tempdb;
49054925bf6Swillf     db = k5db2_dbopen(db_ctx, name, O_RDONLY, 0, tempdb);
49154925bf6Swillf     if (db == NULL)
49254925bf6Swillf 	return errno;
49354925bf6Swillf 
49454925bf6Swillf     db_ctx->db_name = strdup(name);
49554925bf6Swillf     if (db_ctx->db_name == NULL) {
49654925bf6Swillf 	(*db->close) (db);
49754925bf6Swillf 	return ENOMEM;
49854925bf6Swillf     }
49954925bf6Swillf     (*db->close) (db);
50054925bf6Swillf     return 0;
50154925bf6Swillf }
50254925bf6Swillf 
50354925bf6Swillf /*
50454925bf6Swillf  * Return the last modification time of the database.
50554925bf6Swillf  *
50654925bf6Swillf  * Think about using fstat.
50754925bf6Swillf  */
50854925bf6Swillf 
50954925bf6Swillf krb5_error_code
krb5_db2_db_get_age(krb5_context context,char * db_name,time_t * age)51054925bf6Swillf krb5_db2_db_get_age(krb5_context context, char *db_name, time_t *age)
51154925bf6Swillf {
51254925bf6Swillf     krb5_db2_context *db_ctx;
51354925bf6Swillf     kdb5_dal_handle *dal_handle;
51454925bf6Swillf     struct stat st;
51554925bf6Swillf 
51654925bf6Swillf     if (!k5db2_inited(context))
51754925bf6Swillf 	return (KRB5_KDB_DBNOTINITED);
51854925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
51954925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
52054925bf6Swillf 
52154925bf6Swillf     if (fstat(db_ctx->db_lf_file, &st) < 0)
52254925bf6Swillf 	*age = -1;
52354925bf6Swillf     else
52454925bf6Swillf 	*age = st.st_mtime;
52554925bf6Swillf     return 0;
52654925bf6Swillf }
52754925bf6Swillf 
52854925bf6Swillf /*
52954925bf6Swillf  * Remove the semaphore file; indicates that database is currently
53054925bf6Swillf  * under renovation.
53154925bf6Swillf  *
53254925bf6Swillf  * This is only for use when moving the database out from underneath
53354925bf6Swillf  * the server (for example, during slave updates).
53454925bf6Swillf  */
53554925bf6Swillf 
53654925bf6Swillf static krb5_error_code
krb5_db2_db_start_update(krb5_context context)53754925bf6Swillf krb5_db2_db_start_update(krb5_context context)
53854925bf6Swillf {
53954925bf6Swillf     return 0;
54054925bf6Swillf }
54154925bf6Swillf 
54254925bf6Swillf static krb5_error_code
krb5_db2_db_end_update(krb5_context context)54354925bf6Swillf krb5_db2_db_end_update(krb5_context context)
54454925bf6Swillf {
54554925bf6Swillf     krb5_error_code retval;
54654925bf6Swillf     krb5_db2_context *db_ctx;
54754925bf6Swillf     kdb5_dal_handle *dal_handle;
54854925bf6Swillf     struct stat st;
54954925bf6Swillf     time_t  now;
55054925bf6Swillf     struct utimbuf utbuf;
55154925bf6Swillf 
55254925bf6Swillf     if (!k5db2_inited(context))
55354925bf6Swillf 	return (KRB5_KDB_DBNOTINITED);
55454925bf6Swillf 
55554925bf6Swillf     retval = 0;
55654925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
55754925bf6Swillf     db_ctx = dal_handle->db_context;
55854925bf6Swillf     now = time((time_t *) NULL);
55954925bf6Swillf     if (fstat(db_ctx->db_lf_file, &st) == 0) {
56054925bf6Swillf 	if (st.st_mtime >= now) {
56154925bf6Swillf 	    utbuf.actime = st.st_mtime + 1;
56254925bf6Swillf 	    utbuf.modtime = st.st_mtime + 1;
56354925bf6Swillf 	    if (utime(db_ctx->db_lf_name, &utbuf))
56454925bf6Swillf 		retval = errno;
56554925bf6Swillf 	} else {
56654925bf6Swillf 	    if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
56754925bf6Swillf 		retval = errno;
56854925bf6Swillf 	}
5697c64d375Smp 	if (retval) {
5707c64d375Smp 	    /* Solaris Kerberos: Better error logging */
5717c64d375Smp 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to modify "
5727c64d375Smp 	        "access and modification times for \"%s\": "),
573fad1d705SPeter Shoults 	        db_ctx->db_lf_name);
5747c64d375Smp 	    krb5_db2_prepend_err_str(context, errbuf, retval, retval);
5757c64d375Smp 	}
5767c64d375Smp     } else {
57754925bf6Swillf 	retval = errno;
5787c64d375Smp 	/* Solaris Kerberos: Better error logging */
5797c64d375Smp 	snprintf(errbuf, sizeof(errbuf), gettext("Failed to stat \"%s\": "),
580fad1d705SPeter Shoults 	    db_ctx->db_lf_name);
5817c64d375Smp 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
5827c64d375Smp     }
58354925bf6Swillf     if (!retval) {
58454925bf6Swillf 	if (fstat(db_ctx->db_lf_file, &st) == 0)
58554925bf6Swillf 	    db_ctx->db_lf_time = st.st_mtime;
5867c64d375Smp 	else {
58754925bf6Swillf 	    retval = errno;
5887c64d375Smp 	    /* Solaris Kerberos: Better error logging */
5897c64d375Smp 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to stat \"%s\": "),
590fad1d705SPeter Shoults 	        db_ctx->db_lf_name);
5917c64d375Smp 	    krb5_db2_prepend_err_str(context, errbuf, retval, retval);
5927c64d375Smp 	}
59354925bf6Swillf     }
59454925bf6Swillf     return (retval);
59554925bf6Swillf }
59654925bf6Swillf 
59754925bf6Swillf #define MAX_LOCK_TRIES 5
59854925bf6Swillf 
59954925bf6Swillf krb5_error_code
krb5_db2_db_lock(krb5_context context,int in_mode)60054925bf6Swillf krb5_db2_db_lock(krb5_context context, int in_mode)
60154925bf6Swillf {
60254925bf6Swillf     krb5_db2_context *db_ctx;
60354925bf6Swillf     int     krb5_lock_mode;
60454925bf6Swillf     DB     *db;
60554925bf6Swillf     krb5_error_code retval;
60654925bf6Swillf     time_t  mod_time;
60754925bf6Swillf     kdb5_dal_handle *dal_handle;
60854925bf6Swillf     int     mode, gotlock, tries;
60954925bf6Swillf 
61054925bf6Swillf     switch (in_mode) {
61154925bf6Swillf     case KRB5_DB_LOCKMODE_PERMANENT:
61254925bf6Swillf 	mode = KRB5_DB_LOCKMODE_EXCLUSIVE;
61354925bf6Swillf 	break;
61454925bf6Swillf     case KRB5_DB_LOCKMODE_EXCLUSIVE:
61554925bf6Swillf 	mode = KRB5_LOCKMODE_EXCLUSIVE;
61654925bf6Swillf 	break;
61754925bf6Swillf 
61854925bf6Swillf     case KRB5_DB_LOCKMODE_SHARED:
61954925bf6Swillf 	mode = KRB5_LOCKMODE_SHARED;
62054925bf6Swillf 	break;
62154925bf6Swillf     default:
62254925bf6Swillf 	return EINVAL;
62354925bf6Swillf     }
62454925bf6Swillf 
62554925bf6Swillf     if (!k5db2_inited(context))
62654925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
62754925bf6Swillf 
62854925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
62954925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
63054925bf6Swillf     if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
63154925bf6Swillf 	/* No need to upgrade lock, just return */
63254925bf6Swillf 	db_ctx->db_locks_held++;
63354925bf6Swillf 	goto policy_lock;
63454925bf6Swillf     }
63554925bf6Swillf 
63654925bf6Swillf     if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
63754925bf6Swillf 	return KRB5_KDB_BADLOCKMODE;
63854925bf6Swillf 
63954925bf6Swillf     krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
64054925bf6Swillf     for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
64154925bf6Swillf 	retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
64254925bf6Swillf 	if (retval == 0) {
64354925bf6Swillf 	    gotlock++;
64454925bf6Swillf 	    break;
6457c64d375Smp 	} else if (retval == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE) {
64654925bf6Swillf 	    /* tried to exclusive-lock something we don't have */
64754925bf6Swillf 	    /* write access to */
648*55fea89dSDan Cross 
6497c64d375Smp 	    /* Solaris Kerberos: Better error logging */
6507c64d375Smp 	    snprintf(errbuf, sizeof(errbuf),
6517c64d375Smp 	        gettext("Failed to exclusively lock \"%s\": "),
652fad1d705SPeter Shoults 	        db_ctx->db_lf_name);
6537c64d375Smp 	    krb5_db2_prepend_err_str(context, errbuf, EBADF, EBADF);
6547c64d375Smp 
65554925bf6Swillf 	    return KRB5_KDB_CANTLOCK_DB;
6567c64d375Smp 	}
65754925bf6Swillf 	sleep(1);
65854925bf6Swillf     }
6597c64d375Smp 
6607c64d375Smp     if (retval) {
6617c64d375Smp 	/* Solaris Kerberos: Better error logging */
6627c64d375Smp 	snprintf(errbuf, sizeof(errbuf),
6637c64d375Smp 	    gettext("Failed to lock \"%s\": "),
664fad1d705SPeter Shoults 	    db_ctx->db_lf_name);
6657c64d375Smp 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
6667c64d375Smp     }
6677c64d375Smp 
66854925bf6Swillf     if (retval == EACCES)
66954925bf6Swillf 	return KRB5_KDB_CANTLOCK_DB;
67054925bf6Swillf     else if (retval == EAGAIN || retval == EWOULDBLOCK)
67154925bf6Swillf 	return OSA_ADB_CANTLOCK_DB;
67254925bf6Swillf     else if (retval != 0)
67354925bf6Swillf 	return retval;
67454925bf6Swillf 
67554925bf6Swillf     if ((retval = krb5_db2_db_get_age(context, NULL, &mod_time)))
67654925bf6Swillf 	goto lock_error;
67754925bf6Swillf 
67854925bf6Swillf     db = k5db2_dbopen(db_ctx, db_ctx->db_name,
67954925bf6Swillf 		      mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600, db_ctx->tempdb);
68054925bf6Swillf     if (db) {
68154925bf6Swillf 	db_ctx->db_lf_time = mod_time;
68254925bf6Swillf 	db_ctx->db = db;
68354925bf6Swillf     } else {
68454925bf6Swillf 	retval = errno;
6857c64d375Smp 
6867c64d375Smp 	/* Solaris Kerberos: Better error logging */
6877c64d375Smp 	snprintf(errbuf, sizeof(errbuf),
6887c64d375Smp 	    gettext("Failed to open db \"%s\": "),
6897c64d375Smp 	    db_ctx->db_name);
6907c64d375Smp 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
6917c64d375Smp 
69254925bf6Swillf 	db_ctx->db = NULL;
69354925bf6Swillf 	goto lock_error;
69454925bf6Swillf     }
69554925bf6Swillf 
69654925bf6Swillf     db_ctx->db_lock_mode = mode;
69754925bf6Swillf     db_ctx->db_locks_held++;
69854925bf6Swillf 
69954925bf6Swillf   policy_lock:
70054925bf6Swillf     if ((retval = osa_adb_get_lock(db_ctx->policy_db, in_mode))) {
70154925bf6Swillf 	krb5_db2_db_unlock(context);
70254925bf6Swillf     }
70354925bf6Swillf     return retval;
70454925bf6Swillf 
70554925bf6Swillf   lock_error:;
70654925bf6Swillf     db_ctx->db_lock_mode = 0;
70754925bf6Swillf     db_ctx->db_locks_held = 0;
70854925bf6Swillf     krb5_db2_db_unlock(context);
70954925bf6Swillf     return retval;
71054925bf6Swillf }
71154925bf6Swillf 
71254925bf6Swillf krb5_error_code
krb5_db2_db_unlock(krb5_context context)71354925bf6Swillf krb5_db2_db_unlock(krb5_context context)
71454925bf6Swillf {
71554925bf6Swillf     krb5_db2_context *db_ctx;
71654925bf6Swillf     kdb5_dal_handle *dal_handle;
71754925bf6Swillf     DB     *db;
71854925bf6Swillf     krb5_error_code retval;
71954925bf6Swillf 
72054925bf6Swillf     if (!k5db2_inited(context))
72154925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
72254925bf6Swillf 
72354925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
72454925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
72554925bf6Swillf 
72654925bf6Swillf     if ((retval = osa_adb_release_lock(db_ctx->policy_db))) {
72754925bf6Swillf 	return retval;
72854925bf6Swillf     }
72954925bf6Swillf 
73054925bf6Swillf     if (!db_ctx->db_locks_held)	/* lock already unlocked */
73154925bf6Swillf 	return KRB5_KDB_NOTLOCKED;
73254925bf6Swillf     db = db_ctx->db;
73354925bf6Swillf     if (--(db_ctx->db_locks_held) == 0) {
73454925bf6Swillf 	(*db->close) (db);
73554925bf6Swillf 	db_ctx->db = NULL;
73654925bf6Swillf 
73754925bf6Swillf 	retval = krb5_lock_file(context, db_ctx->db_lf_file,
73854925bf6Swillf 				KRB5_LOCKMODE_UNLOCK);
73954925bf6Swillf 	db_ctx->db_lock_mode = 0;
74054925bf6Swillf 	return (retval);
74154925bf6Swillf     }
74254925bf6Swillf     return 0;
74354925bf6Swillf }
74454925bf6Swillf 
74554925bf6Swillf /*
74654925bf6Swillf  * Create the database, assuming it's not there.
74754925bf6Swillf  */
74854925bf6Swillf krb5_error_code
krb5_db2_db_create(krb5_context context,char * db_name,krb5_int32 flags)74954925bf6Swillf krb5_db2_db_create(krb5_context context, char *db_name, krb5_int32 flags)
75054925bf6Swillf {
75154925bf6Swillf     register krb5_error_code retval = 0;
75254925bf6Swillf     kdb5_dal_handle *dal_handle;
75354925bf6Swillf     char   *okname;
75454925bf6Swillf     char   *db_name2 = NULL;
75554925bf6Swillf     int     fd;
75654925bf6Swillf     krb5_db2_context *db_ctx;
75754925bf6Swillf     DB     *db;
75854925bf6Swillf     char    policy_db_name[1024], policy_lock_name[1024];
75954925bf6Swillf 
76054925bf6Swillf     if ((retval = k5db2_init_context(context)))
76154925bf6Swillf 	return (retval);
76254925bf6Swillf 
76354925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
76454925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
76554925bf6Swillf     switch (flags) {
76654925bf6Swillf     case KRB5_KDB_CREATE_HASH:
76754925bf6Swillf 	if ((retval = krb5_db2_db_set_hashfirst(context, TRUE)))
76854925bf6Swillf 	    return retval;
76954925bf6Swillf 	break;
77054925bf6Swillf     case KRB5_KDB_CREATE_BTREE:
77154925bf6Swillf     case 0:
77254925bf6Swillf 	if ((retval = krb5_db2_db_set_hashfirst(context, FALSE)))
77354925bf6Swillf 	    return retval;
77454925bf6Swillf 	break;
77554925bf6Swillf     default:
77654925bf6Swillf 	return KRB5_KDB_BAD_CREATEFLAGS;
77754925bf6Swillf     }
77854925bf6Swillf     db = k5db2_dbopen(db_ctx, db_name, O_RDWR | O_CREAT | O_EXCL, 0600, db_ctx->tempdb);
7797c64d375Smp     if (db == NULL) {
78054925bf6Swillf 	retval = errno;
7817c64d375Smp 
7827c64d375Smp 	/* Solaris Kerberos: Better error logging */
7837c64d375Smp   	snprintf(errbuf, sizeof(errbuf), gettext("Failed to open \"%s\": "), db_name);
7847c64d375Smp 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
7857c64d375Smp     }
78654925bf6Swillf     else
78754925bf6Swillf 	(*db->close) (db);
78854925bf6Swillf     if (retval == 0) {
78954925bf6Swillf 
79054925bf6Swillf 	db_name2 = db_ctx->tempdb ? gen_dbsuffix(db_name, "~") : strdup(db_name);
79154925bf6Swillf 	if (db_name2 == NULL)
79254925bf6Swillf 	    return ENOMEM;
79354925bf6Swillf 	okname = gen_dbsuffix(db_name2, KDB2_LOCK_EXT);
79454925bf6Swillf 	if (!okname)
79554925bf6Swillf 	    retval = ENOMEM;
79654925bf6Swillf 	else {
79754925bf6Swillf 	    fd = open(okname, O_CREAT | O_RDWR | O_TRUNC, 0600);
7987c64d375Smp 	    if (fd < 0) {
79954925bf6Swillf 		retval = errno;
8007c64d375Smp 		/* Solaris Kerberos: Better error logging */
8017c64d375Smp 		snprintf(errbuf, sizeof(errbuf), gettext("Failed to open \"%s\": "), okname);
8027c64d375Smp 		krb5_db2_prepend_err_str(context, errbuf, retval, retval);
8037c64d375Smp 	    }
80454925bf6Swillf 	    else
80554925bf6Swillf 		close(fd);
80654925bf6Swillf 	    free_dbsuffix(okname);
80754925bf6Swillf 	}
80854925bf6Swillf     }
80954925bf6Swillf 
81054925bf6Swillf     sprintf(policy_db_name, "%s.kadm5", db_name2);
81154925bf6Swillf     sprintf(policy_lock_name, "%s.lock", policy_db_name);
81254925bf6Swillf 
81354925bf6Swillf     retval = osa_adb_create_db(policy_db_name,
81454925bf6Swillf 			       policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
81554925bf6Swillf     free(db_name2);
81654925bf6Swillf     return retval;
81754925bf6Swillf }
81854925bf6Swillf 
81954925bf6Swillf /*
82054925bf6Swillf  * Destroy the database.  Zero's out all of the files, just to be sure.
82154925bf6Swillf  */
82254925bf6Swillf static krb5_error_code
destroy_file_suffix(char * dbname,char * suffix)82354925bf6Swillf destroy_file_suffix(char *dbname, char *suffix)
82454925bf6Swillf {
82554925bf6Swillf     char   *filename;
82654925bf6Swillf     struct stat statb;
82754925bf6Swillf     int     nb, fd;
82854925bf6Swillf     unsigned int j;
82954925bf6Swillf     off_t   pos;
83054925bf6Swillf     char    buf[BUFSIZ];
83154925bf6Swillf     char    zbuf[BUFSIZ];
83254925bf6Swillf     int     dowrite;
83354925bf6Swillf 
83454925bf6Swillf     filename = gen_dbsuffix(dbname, suffix);
83554925bf6Swillf     if (filename == 0)
83654925bf6Swillf 	return ENOMEM;
83754925bf6Swillf     if ((fd = open(filename, O_RDWR, 0)) < 0) {
83854925bf6Swillf 	free(filename);
83954925bf6Swillf 	return errno;
84054925bf6Swillf     }
84154925bf6Swillf     /* fstat() will probably not fail unless using a remote filesystem
84254925bf6Swillf      * (which is inappropriate for the kerberos database) so this check
84354925bf6Swillf      * is mostly paranoia.  */
84454925bf6Swillf     if (fstat(fd, &statb) == -1) {
84554925bf6Swillf 	int     retval = errno;
84654925bf6Swillf 	free(filename);
84754925bf6Swillf 	return retval;
84854925bf6Swillf     }
84954925bf6Swillf     /*
85054925bf6Swillf      * Stroll through the file, reading in BUFSIZ chunks.  If everything
85154925bf6Swillf      * is zero, then we're done for that block, otherwise, zero the block.
85254925bf6Swillf      * We would like to just blast through everything, but some DB
85354925bf6Swillf      * implementations make holey files and writing data to the holes
85454925bf6Swillf      * causes actual blocks to be allocated which is no good, since
85554925bf6Swillf      * we're just about to unlink it anyways.
85654925bf6Swillf      */
85754925bf6Swillf     memset(zbuf, 0, BUFSIZ);
85854925bf6Swillf     pos = 0;
85954925bf6Swillf     while (pos < statb.st_size) {
86054925bf6Swillf 	dowrite = 0;
86154925bf6Swillf 	nb = read(fd, buf, BUFSIZ);
86254925bf6Swillf 	if (nb < 0) {
86354925bf6Swillf 	    int     retval = errno;
86454925bf6Swillf 	    free(filename);
86554925bf6Swillf 	    return retval;
86654925bf6Swillf 	}
86754925bf6Swillf 	for (j = 0; j < nb; j++) {
86854925bf6Swillf 	    if (buf[j] != '\0') {
86954925bf6Swillf 		dowrite = 1;
87054925bf6Swillf 		break;
87154925bf6Swillf 	    }
87254925bf6Swillf 	}
87354925bf6Swillf 	/* For signedness */
87454925bf6Swillf 	j = nb;
87554925bf6Swillf 	if (dowrite) {
87654925bf6Swillf 	    lseek(fd, pos, SEEK_SET);
87754925bf6Swillf 	    nb = write(fd, zbuf, j);
87854925bf6Swillf 	    if (nb < 0) {
87954925bf6Swillf 		int     retval = errno;
88054925bf6Swillf 		free(filename);
88154925bf6Swillf 		return retval;
88254925bf6Swillf 	    }
88354925bf6Swillf 	}
88454925bf6Swillf 	pos += nb;
88554925bf6Swillf     }
88654925bf6Swillf     /* ??? Is fsync really needed?  I don't know of any non-networked
88754925bf6Swillf      * filesystem which will discard queued writes to disk if a file
88854925bf6Swillf      * is deleted after it is closed.  --jfc */
88954925bf6Swillf #ifndef NOFSYNC
89054925bf6Swillf     fsync(fd);
89154925bf6Swillf #endif
89254925bf6Swillf     close(fd);
89354925bf6Swillf 
89454925bf6Swillf     if (unlink(filename)) {
89554925bf6Swillf 	free(filename);
89654925bf6Swillf 	return (errno);
89754925bf6Swillf     }
89854925bf6Swillf     free(filename);
89954925bf6Swillf     return (0);
90054925bf6Swillf }
90154925bf6Swillf 
90254925bf6Swillf /*
90354925bf6Swillf  * Since the destroy operation happens outside the init/fini bracket, we
90454925bf6Swillf  * have some tomfoolery to undergo here.  If we're operating under no
90554925bf6Swillf  * database context, then we initialize with the default.  If the caller
90654925bf6Swillf  * wishes a different context (e.g. different dispatch table), it's their
90754925bf6Swillf  * responsibility to call kdb5_db_set_dbops() before this call.  That will
90854925bf6Swillf  * set up the right dispatch table values (e.g. name extensions).
90954925bf6Swillf  *
91054925bf6Swillf  * Not quite valid due to ripping out of dbops...
91154925bf6Swillf  */
91254925bf6Swillf krb5_error_code
krb5_db2_db_destroy(krb5_context context,char * dbname)91354925bf6Swillf krb5_db2_db_destroy(krb5_context context, char *dbname)
91454925bf6Swillf {
91554925bf6Swillf     krb5_error_code retval1, retval2;
91654925bf6Swillf     krb5_boolean tmpcontext;
91754925bf6Swillf     char    policy_db_name[1024], policy_lock_name[1024];
91854925bf6Swillf 
91954925bf6Swillf     tmpcontext = 0;
92054925bf6Swillf     if (!context->db_context
92154925bf6Swillf 	|| !((kdb5_dal_handle *) context->db_context)->db_context) {
92254925bf6Swillf 	tmpcontext = 1;
92354925bf6Swillf 	if ((retval1 = k5db2_init_context(context)))
92454925bf6Swillf 	    return (retval1);
92554925bf6Swillf     }
92654925bf6Swillf 
92754925bf6Swillf     retval1 = retval2 = 0;
92854925bf6Swillf     retval1 = destroy_file_suffix(dbname, "");
92954925bf6Swillf     retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
93054925bf6Swillf 
93154925bf6Swillf     if (tmpcontext) {
93254925bf6Swillf 	k5db2_clear_context((krb5_db2_context *) ((kdb5_dal_handle *) context->
93354925bf6Swillf 						  db_context)->db_context);
93454925bf6Swillf 	free(((kdb5_dal_handle *) context->db_context)->db_context);
93554925bf6Swillf 	((kdb5_dal_handle *) context->db_context)->db_context = NULL;
93654925bf6Swillf     }
93754925bf6Swillf 
93854925bf6Swillf     if (retval1 || retval2)
93954925bf6Swillf 	return (retval1 ? retval1 : retval2);
94054925bf6Swillf 
94154925bf6Swillf     assert (strlen(dbname) + strlen("%s.kadm5") < sizeof(policy_db_name));
94254925bf6Swillf     sprintf(policy_db_name, "%s.kadm5", dbname);
94354925bf6Swillf     /* XXX finish this */
94454925bf6Swillf     sprintf(policy_lock_name, "%s.lock", policy_db_name);
94554925bf6Swillf 
94654925bf6Swillf     retval1 = osa_adb_destroy_db(policy_db_name,
94754925bf6Swillf 				 policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
94854925bf6Swillf 
94954925bf6Swillf     return retval1;
95054925bf6Swillf }
95154925bf6Swillf 
95254925bf6Swillf /*
95354925bf6Swillf  * look up a principal in the data base.
95454925bf6Swillf  * returns number of entries found, and whether there were
95554925bf6Swillf  * more than requested.
95654925bf6Swillf  */
95754925bf6Swillf 
95854925bf6Swillf krb5_error_code
krb5_db2_db_get_principal(krb5_context context,krb5_const_principal searchfor,krb5_db_entry * entries,int * nentries,krb5_boolean * more)95954925bf6Swillf krb5_db2_db_get_principal(krb5_context context,
96054925bf6Swillf 			  krb5_const_principal searchfor,
96154925bf6Swillf 			  krb5_db_entry *entries, /* filled in */
96254925bf6Swillf 			  int *nentries, /* how much room/how many found */
96354925bf6Swillf 			  krb5_boolean *more) /* are there more? */
96454925bf6Swillf {
96554925bf6Swillf     krb5_db2_context *db_ctx;
96654925bf6Swillf     krb5_error_code retval;
96754925bf6Swillf     DB     *db;
96854925bf6Swillf     DBT     key, contents;
96954925bf6Swillf     krb5_data keydata, contdata;
97054925bf6Swillf     int     trynum, dbret;
97154925bf6Swillf     kdb5_dal_handle *dal_handle;
97254925bf6Swillf 
97354925bf6Swillf     *more = FALSE;
97454925bf6Swillf     *nentries = 0;
97554925bf6Swillf 
97654925bf6Swillf     if (!k5db2_inited(context))
97754925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
97854925bf6Swillf 
97954925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
98054925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
98154925bf6Swillf 
98254925bf6Swillf     for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) {
98354925bf6Swillf 	if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
98454925bf6Swillf 	    if (db_ctx->db_nb_locks)
98554925bf6Swillf 		return (retval);
98654925bf6Swillf 	    sleep(1);
98754925bf6Swillf 	    continue;
98854925bf6Swillf 	}
98954925bf6Swillf 	break;
99054925bf6Swillf     }
99154925bf6Swillf     if (trynum == KRB5_DB2_MAX_RETRY)
99254925bf6Swillf 	return KRB5_KDB_DB_INUSE;
99354925bf6Swillf 
99454925bf6Swillf     /* XXX deal with wildcard lookups */
99554925bf6Swillf     retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
99654925bf6Swillf     if (retval)
99754925bf6Swillf 	goto cleanup;
99854925bf6Swillf     key.data = keydata.data;
99954925bf6Swillf     key.size = keydata.length;
100054925bf6Swillf 
100154925bf6Swillf     db = db_ctx->db;
100254925bf6Swillf     dbret = (*db->get) (db, &key, &contents, 0);
100354925bf6Swillf     retval = errno;
100454925bf6Swillf     krb5_free_data_contents(context, &keydata);
100554925bf6Swillf     switch (dbret) {
100654925bf6Swillf     case 1:
100754925bf6Swillf 	retval = 0;
10080b16192fSToomas Soome 	/* FALLTHROUGH */
100954925bf6Swillf     case -1:
101054925bf6Swillf     default:
101154925bf6Swillf 	*nentries = 0;
101254925bf6Swillf 	goto cleanup;
101354925bf6Swillf     case 0:
101454925bf6Swillf 	contdata.data = contents.data;
101554925bf6Swillf 	contdata.length = contents.size;
101654925bf6Swillf 	retval = krb5_decode_princ_contents(context, &contdata, entries);
101754925bf6Swillf 	if (!retval)
101854925bf6Swillf 	    *nentries = 1;
101954925bf6Swillf 	break;
102054925bf6Swillf     }
102154925bf6Swillf 
102254925bf6Swillf   cleanup:
102354925bf6Swillf     (void) krb5_db2_db_unlock(context);	/* unlock read lock */
102454925bf6Swillf     return retval;
102554925bf6Swillf }
102654925bf6Swillf 
102754925bf6Swillf /*
102854925bf6Swillf   Free stuff returned by krb5_db2_db_get_principal.
102954925bf6Swillf  */
103054925bf6Swillf krb5_error_code
krb5_db2_db_free_principal(krb5_context context,krb5_db_entry * entries,int nentries)103154925bf6Swillf krb5_db2_db_free_principal(krb5_context context, krb5_db_entry *entries,
103254925bf6Swillf 			   int nentries)
103354925bf6Swillf {
103454925bf6Swillf     register int i;
103554925bf6Swillf     for (i = 0; i < nentries; i++)
103654925bf6Swillf 	krb5_dbe_free_contents(context, &entries[i]);
103754925bf6Swillf     return 0;
103854925bf6Swillf }
103954925bf6Swillf 
104054925bf6Swillf /*
104154925bf6Swillf   Stores the *"nentries" entry structures pointed to by "entries" in the
104254925bf6Swillf   database.
104354925bf6Swillf 
104454925bf6Swillf   *"nentries" is updated upon return to reflect the number of records
104554925bf6Swillf   acutally stored; the first *"nstored" records will have been stored in the
104654925bf6Swillf   database (even if an error occurs).
104754925bf6Swillf 
104854925bf6Swillf  */
104954925bf6Swillf 
105054925bf6Swillf krb5_error_code
krb5_db2_db_put_principal(krb5_context context,krb5_db_entry * entries,int * nentries,char ** db_args)105154925bf6Swillf krb5_db2_db_put_principal(krb5_context context,
105254925bf6Swillf 			  krb5_db_entry *entries,
105354925bf6Swillf 			  int *nentries, /* number of entry structs to update */
105454925bf6Swillf 			  char **db_args)
105554925bf6Swillf {
105654925bf6Swillf     int     i, n, dbret;
105754925bf6Swillf     DB     *db;
105854925bf6Swillf     DBT     key, contents;
105954925bf6Swillf     krb5_data contdata, keydata;
106054925bf6Swillf     krb5_error_code retval;
106154925bf6Swillf     krb5_db2_context *db_ctx;
106254925bf6Swillf     kdb5_dal_handle *dal_handle;
106354925bf6Swillf     kdb_incr_update_t *upd, *fupd;
106454925bf6Swillf     char *princ_name = NULL;
106554925bf6Swillf     kdb_log_context *log_ctx;
106654925bf6Swillf 
106754925bf6Swillf     krb5_clear_error_message (context);
106854925bf6Swillf     if (db_args) {
106954925bf6Swillf 	/* DB2 does not support db_args DB arguments for principal */
107054925bf6Swillf 	krb5_set_error_message(context, EINVAL,
107154925bf6Swillf 			       gettext("Unsupported argument \"%s\" for db2"),
107254925bf6Swillf 			       db_args[0]);
107354925bf6Swillf 	return EINVAL;
107454925bf6Swillf     }
107554925bf6Swillf 
107654925bf6Swillf     log_ctx = context->kdblog_context;
107754925bf6Swillf 
107854925bf6Swillf     n = *nentries;
107954925bf6Swillf     *nentries = 0;
108054925bf6Swillf     if (!k5db2_inited(context))
108154925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
108254925bf6Swillf 
108354925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
108454925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
108554925bf6Swillf     if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
108654925bf6Swillf 	return retval;
108754925bf6Swillf 
108854925bf6Swillf     /*
108954925bf6Swillf      * Solaris Kerberos: We need the lock since ulog_conv_2logentry() does a get
109054925bf6Swillf      */
109154925bf6Swillf     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
109254925bf6Swillf 	if (!(upd = (kdb_incr_update_t *)
109354925bf6Swillf 	  malloc(sizeof (kdb_incr_update_t)*n))) {
109454925bf6Swillf 	    retval = errno;
109554925bf6Swillf 	    goto err_lock;
109654925bf6Swillf 	}
109754925bf6Swillf 	fupd = upd;
109854925bf6Swillf 
109954925bf6Swillf 	(void) memset(upd, 0, sizeof(kdb_incr_update_t)*n);
110054925bf6Swillf 
110154925bf6Swillf         if ((retval = ulog_conv_2logentry(context, entries, upd, n))) {
110254925bf6Swillf 	    goto err_lock;
110354925bf6Swillf 	}
110454925bf6Swillf     }
110554925bf6Swillf 
110654925bf6Swillf     db = db_ctx->db;
110754925bf6Swillf     if ((retval = krb5_db2_db_start_update(context))) {
110854925bf6Swillf 	(void) krb5_db2_db_unlock(context);
110954925bf6Swillf 	goto err_lock;
111054925bf6Swillf     }
111154925bf6Swillf 
111254925bf6Swillf     /* for each one, stuff temps, and do replace/append */
111354925bf6Swillf     for (i = 0; i < n; i++) {
111454925bf6Swillf 	/*
111554925bf6Swillf 	 * Solaris Kerberos: We'll be sharing the same locks as db for logging
111654925bf6Swillf 	 */
111754925bf6Swillf         if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
111854925bf6Swillf 		if ((retval = krb5_unparse_name(context, entries->princ,
111954925bf6Swillf 		    &princ_name)))
112054925bf6Swillf 			goto err_lock;
112154925bf6Swillf 
112254925bf6Swillf 		upd->kdb_princ_name.utf8str_t_val = princ_name;
112354925bf6Swillf 		upd->kdb_princ_name.utf8str_t_len = strlen(princ_name);
112454925bf6Swillf 
112554925bf6Swillf                 if (retval = ulog_add_update(context, upd))
112654925bf6Swillf 			goto err_lock;
112754925bf6Swillf         }
112854925bf6Swillf 
112954925bf6Swillf 	retval = krb5_encode_princ_contents(context, &contdata, entries);
113054925bf6Swillf 	if (retval)
113154925bf6Swillf 	    break;
113254925bf6Swillf 	contents.data = contdata.data;
113354925bf6Swillf 	contents.size = contdata.length;
113454925bf6Swillf 	retval = krb5_encode_princ_dbkey(context, &keydata, entries->princ);
113554925bf6Swillf 	if (retval) {
113654925bf6Swillf 	    krb5_free_data_contents(context, &contdata);
113754925bf6Swillf 	    break;
113854925bf6Swillf 	}
113954925bf6Swillf 
114054925bf6Swillf 	key.data = keydata.data;
114154925bf6Swillf 	key.size = keydata.length;
114254925bf6Swillf 	dbret = (*db->put) (db, &key, &contents, 0);
114354925bf6Swillf 	retval = dbret ? errno : 0;
114454925bf6Swillf 	krb5_free_data_contents(context, &keydata);
114554925bf6Swillf 	krb5_free_data_contents(context, &contdata);
114654925bf6Swillf 	if (retval)
114754925bf6Swillf 	    break;
114854925bf6Swillf 	else if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
114954925bf6Swillf 	    /*
115054925bf6Swillf 	     * We need to make sure the db record is synced before we mark
115154925bf6Swillf 	     * it as committed via finish_update.
115254925bf6Swillf 	     */
115354925bf6Swillf 	    dbret = (*db->sync)(db, 0);
115454925bf6Swillf 	    if (dbret) {
115554925bf6Swillf 		retval = errno;
115654925bf6Swillf 		goto err_lock;
115754925bf6Swillf 	    }
115854925bf6Swillf 	    (void) ulog_finish_update(context, upd);
115954925bf6Swillf 	    upd++;
116054925bf6Swillf 	}
116154925bf6Swillf 	entries++;		/* bump to next struct */
116254925bf6Swillf     }
116354925bf6Swillf 
116454925bf6Swillf     (void) krb5_db2_db_end_update(context);
116554925bf6Swillf 
116654925bf6Swillf err_lock:
116754925bf6Swillf     (void) krb5_db2_db_unlock(context);	/* unlock database */
116854925bf6Swillf 
116954925bf6Swillf     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER))
117054925bf6Swillf         ulog_free_entries(fupd, n);
117154925bf6Swillf 
117254925bf6Swillf     *nentries = i;
117354925bf6Swillf     return (retval);
117454925bf6Swillf }
117554925bf6Swillf 
117654925bf6Swillf /*
117754925bf6Swillf  * delete a principal from the data base.
117854925bf6Swillf  * returns number of entries removed
117954925bf6Swillf  */
118054925bf6Swillf 
118154925bf6Swillf krb5_error_code
krb5_db2_db_delete_principal(krb5_context context,krb5_const_principal searchfor,int * nentries)118254925bf6Swillf krb5_db2_db_delete_principal(krb5_context context,
118354925bf6Swillf 			     krb5_const_principal searchfor,
118454925bf6Swillf 			     int *nentries) /* how many found & deleted */
118554925bf6Swillf {
118654925bf6Swillf     krb5_error_code retval;
118754925bf6Swillf     krb5_db_entry entry;
118854925bf6Swillf     krb5_db2_context *db_ctx;
118954925bf6Swillf     DB     *db;
119054925bf6Swillf     DBT     key, contents;
119154925bf6Swillf     krb5_data keydata, contdata;
119254925bf6Swillf     int     i, dbret;
119354925bf6Swillf     kdb5_dal_handle *dal_handle;
119454925bf6Swillf     kdb_incr_update_t upd;
119554925bf6Swillf     char *princ_name = NULL;
119654925bf6Swillf     kdb_log_context *log_ctx;
119754925bf6Swillf 
119854925bf6Swillf     log_ctx = context->kdblog_context;
119954925bf6Swillf 
120054925bf6Swillf     if (!k5db2_inited(context))
120154925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
120254925bf6Swillf 
120354925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
120454925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
120554925bf6Swillf     if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
120654925bf6Swillf 	return (retval);
120754925bf6Swillf 
120854925bf6Swillf     if ((retval = krb5_db2_db_start_update(context))) {
120954925bf6Swillf 	(void) krb5_db2_db_unlock(context);	/* unlock write lock */
121054925bf6Swillf 	return (retval);
121154925bf6Swillf     }
121254925bf6Swillf 
121354925bf6Swillf     if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
121454925bf6Swillf 	goto cleanup;
121554925bf6Swillf     key.data = keydata.data;
121654925bf6Swillf     key.size = keydata.length;
121754925bf6Swillf 
121854925bf6Swillf     db = db_ctx->db;
121954925bf6Swillf     dbret = (*db->get) (db, &key, &contents, 0);
122054925bf6Swillf     retval = errno;
122154925bf6Swillf     switch (dbret) {
122254925bf6Swillf     case 1:
122354925bf6Swillf 	retval = KRB5_KDB_NOENTRY;
12240b16192fSToomas Soome 	/* FALLTHROUGH */
122554925bf6Swillf     case -1:
122654925bf6Swillf     default:
122754925bf6Swillf 	*nentries = 0;
122854925bf6Swillf 	goto cleankey;
122954925bf6Swillf     case 0:
123054925bf6Swillf 	;
123154925bf6Swillf     }
123254925bf6Swillf     /*
123354925bf6Swillf      * Solaris Kerberos: We'll be sharing the same locks as db for logging
123454925bf6Swillf      */
123554925bf6Swillf     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
123654925bf6Swillf 	if ((retval = krb5_unparse_name(context, searchfor, &princ_name))) {
123754925bf6Swillf 		(void) krb5_db2_db_unlock(context);
123854925bf6Swillf 		return retval;
123954925bf6Swillf 	}
124054925bf6Swillf 
124154925bf6Swillf 	(void) memset(&upd, 0, sizeof (kdb_incr_update_t));
124254925bf6Swillf 
124354925bf6Swillf 	upd.kdb_princ_name.utf8str_t_val = princ_name;
124454925bf6Swillf 	upd.kdb_princ_name.utf8str_t_len = strlen(princ_name);
124554925bf6Swillf 
124654925bf6Swillf 	if (retval = ulog_delete_update(context, &upd)) {
124754925bf6Swillf 		free(princ_name);
124854925bf6Swillf 		(void) krb5_db2_db_unlock(context);
124954925bf6Swillf 		return retval;
125054925bf6Swillf 	}
125154925bf6Swillf 
125254925bf6Swillf 	free(princ_name);
125354925bf6Swillf     }
125454925bf6Swillf 
125554925bf6Swillf     memset((char *) &entry, 0, sizeof(entry));
125654925bf6Swillf     contdata.data = contents.data;
125754925bf6Swillf     contdata.length = contents.size;
125854925bf6Swillf     retval = krb5_decode_princ_contents(context, &contdata, &entry);
125954925bf6Swillf     if (retval)
126054925bf6Swillf 	goto cleankey;
126154925bf6Swillf     *nentries = 1;
126254925bf6Swillf 
126354925bf6Swillf     /* Clear encrypted key contents */
126454925bf6Swillf     for (i = 0; i < entry.n_key_data; i++) {
126554925bf6Swillf 	if (entry.key_data[i].key_data_length[0]) {
126654925bf6Swillf 	    memset((char *) entry.key_data[i].key_data_contents[0], 0,
126754925bf6Swillf 		   (unsigned) entry.key_data[i].key_data_length[0]);
126854925bf6Swillf 	}
126954925bf6Swillf     }
127054925bf6Swillf 
127154925bf6Swillf     retval = krb5_encode_princ_contents(context, &contdata, &entry);
127254925bf6Swillf     krb5_dbe_free_contents(context, &entry);
127354925bf6Swillf     if (retval)
127454925bf6Swillf 	goto cleankey;
127554925bf6Swillf 
127654925bf6Swillf     contents.data = contdata.data;
127754925bf6Swillf     contents.size = contdata.length;
127854925bf6Swillf     dbret = (*db->put) (db, &key, &contents, 0);
127954925bf6Swillf     retval = dbret ? errno : 0;
128054925bf6Swillf     krb5_free_data_contents(context, &contdata);
128154925bf6Swillf     if (retval)
128254925bf6Swillf 	goto cleankey;
128354925bf6Swillf     dbret = (*db->del) (db, &key, 0);
128454925bf6Swillf     retval = dbret ? errno : 0;
128554925bf6Swillf 
128654925bf6Swillf     /*
128754925bf6Swillf      * We need to commit our update upon success
128854925bf6Swillf      */
128954925bf6Swillf     if (!retval)
129054925bf6Swillf 	if (log_ctx && (log_ctx->iproprole == IPROP_MASTER))
129154925bf6Swillf 		(void) ulog_finish_update(context, &upd);
129254925bf6Swillf 
129354925bf6Swillf   cleankey:
129454925bf6Swillf     krb5_free_data_contents(context, &keydata);
129554925bf6Swillf 
129654925bf6Swillf   cleanup:
129754925bf6Swillf     (void) krb5_db2_db_end_update(context);
129854925bf6Swillf     (void) krb5_db2_db_unlock(context);	/* unlock write lock */
129954925bf6Swillf     return retval;
130054925bf6Swillf }
130154925bf6Swillf 
130254925bf6Swillf krb5_error_code
krb5_db2_db_iterate_ext(krb5_context context,krb5_error_code (* func)(krb5_pointer,krb5_db_entry *),krb5_pointer func_arg,int backwards,int recursive)130354925bf6Swillf krb5_db2_db_iterate_ext(krb5_context context,
130454925bf6Swillf 			krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
130554925bf6Swillf 			krb5_pointer func_arg,
130654925bf6Swillf 			int backwards, int recursive)
130754925bf6Swillf {
130854925bf6Swillf     krb5_db2_context *db_ctx;
130954925bf6Swillf     DB     *db;
131054925bf6Swillf     DBT     key, contents;
131154925bf6Swillf     krb5_data contdata;
131254925bf6Swillf     krb5_db_entry entries;
131354925bf6Swillf     krb5_error_code retval;
131454925bf6Swillf     kdb5_dal_handle *dal_handle;
131554925bf6Swillf     int     dbret;
131654925bf6Swillf     void   *cookie;
131754925bf6Swillf 
131854925bf6Swillf     cookie = NULL;
131954925bf6Swillf     if (!k5db2_inited(context))
132054925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
132154925bf6Swillf 
132254925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
132354925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
132454925bf6Swillf     retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
132554925bf6Swillf 
132654925bf6Swillf     if (retval)
132754925bf6Swillf 	return retval;
132854925bf6Swillf 
132954925bf6Swillf     db = db_ctx->db;
133054925bf6Swillf     if (recursive && db->type != DB_BTREE) {
133154925bf6Swillf 	(void) krb5_db2_db_unlock(context);
133254925bf6Swillf 	return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
133354925bf6Swillf     }
133454925bf6Swillf 
133554925bf6Swillf     if (!recursive) {
133654925bf6Swillf 	dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST);
133754925bf6Swillf     } else {
133854925bf6Swillf #ifdef HAVE_BT_RSEQ
133954925bf6Swillf 	dbret = bt_rseq(db, &key, &contents, &cookie,
134054925bf6Swillf 			backwards ? R_LAST : R_FIRST);
134154925bf6Swillf #else
134254925bf6Swillf 	(void) krb5_db2_db_unlock(context);
134354925bf6Swillf 	return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
134454925bf6Swillf #endif
134554925bf6Swillf     }
134654925bf6Swillf     while (dbret == 0) {
134754925bf6Swillf 	contdata.data = contents.data;
134854925bf6Swillf 	contdata.length = contents.size;
134954925bf6Swillf 	retval = krb5_decode_princ_contents(context, &contdata, &entries);
135054925bf6Swillf 	if (retval)
135154925bf6Swillf 	    break;
135254925bf6Swillf 	retval = (*func) (func_arg, &entries);
135354925bf6Swillf 	krb5_dbe_free_contents(context, &entries);
135454925bf6Swillf 	if (retval)
135554925bf6Swillf 	    break;
135654925bf6Swillf 	if (!recursive) {
135754925bf6Swillf 	    dbret = (*db->seq) (db, &key, &contents,
135854925bf6Swillf 				backwards ? R_PREV : R_NEXT);
135954925bf6Swillf 	} else {
136054925bf6Swillf #ifdef HAVE_BT_RSEQ
136154925bf6Swillf 	    dbret = bt_rseq(db, &key, &contents, &cookie,
136254925bf6Swillf 			    backwards ? R_PREV : R_NEXT);
136354925bf6Swillf #else
136454925bf6Swillf 	    (void) krb5_db2_db_unlock(context);
136554925bf6Swillf 	    return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
136654925bf6Swillf #endif
136754925bf6Swillf 	}
136854925bf6Swillf     }
136954925bf6Swillf     switch (dbret) {
137054925bf6Swillf     case 1:
137154925bf6Swillf     case 0:
137254925bf6Swillf 	break;
137354925bf6Swillf     case -1:
137454925bf6Swillf     default:
137554925bf6Swillf 	retval = errno;
137654925bf6Swillf     }
137754925bf6Swillf     (void) krb5_db2_db_unlock(context);
137854925bf6Swillf     return retval;
137954925bf6Swillf }
138054925bf6Swillf 
138154925bf6Swillf krb5_error_code
krb5_db2_db_iterate(krb5_context context,char * match_expr,krb5_error_code (* func)(krb5_pointer,krb5_db_entry *),krb5_pointer func_arg,char ** db_args)138254925bf6Swillf krb5_db2_db_iterate(krb5_context context,
138354925bf6Swillf 		    char *match_expr,
138454925bf6Swillf 		    krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
13852dd2efa5Swillf 		    krb5_pointer func_arg, char **db_args)
138654925bf6Swillf {
13872dd2efa5Swillf     char  **t_ptr = db_args;
13882dd2efa5Swillf     int backwards = 0, recursive = 0;
13892dd2efa5Swillf 
13902dd2efa5Swillf     while (t_ptr && *t_ptr) {
13912dd2efa5Swillf 	char   *opt = NULL, *val = NULL;
13922dd2efa5Swillf 
13932dd2efa5Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
13942dd2efa5Swillf 
13952dd2efa5Swillf 	/* Solaris Kerberos: adding support for -rev/recurse flags */
13962dd2efa5Swillf 	if (val && !strcmp(val, "rev"))
13972dd2efa5Swillf 	    backwards = 1;
13982dd2efa5Swillf 	else if (val && !strcmp(val, "recurse"))
13992dd2efa5Swillf 	    recursive = 1;
14002dd2efa5Swillf 	else {
14012dd2efa5Swillf 	    krb5_set_error_message(context, EINVAL,
14022dd2efa5Swillf 				   gettext("Unsupported argument \"%s\" for db2"),
14032dd2efa5Swillf 				   val);
14042dd2efa5Swillf 	    free(opt);
14052dd2efa5Swillf 	    free(val);
14062dd2efa5Swillf 	    return EINVAL;
14072dd2efa5Swillf 	}
14082dd2efa5Swillf 
14092dd2efa5Swillf 	free(opt);
14102dd2efa5Swillf 	free(val);
14112dd2efa5Swillf 	t_ptr++;
14122dd2efa5Swillf     }
14132dd2efa5Swillf 
14142dd2efa5Swillf     /* Solaris Kerberos: adding support for -rev/recurse flags */
14152dd2efa5Swillf     return krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive);
141654925bf6Swillf }
141754925bf6Swillf 
141854925bf6Swillf krb5_boolean
krb5_db2_db_set_lockmode(krb5_context context,krb5_boolean mode)141954925bf6Swillf krb5_db2_db_set_lockmode(krb5_context context, krb5_boolean mode)
142054925bf6Swillf {
142154925bf6Swillf     krb5_boolean old;
142254925bf6Swillf     krb5_db2_context *db_ctx;
142354925bf6Swillf     kdb5_dal_handle *dal_handle;
142454925bf6Swillf 
142554925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
142654925bf6Swillf     old = mode;
142754925bf6Swillf     if (dal_handle && (db_ctx = (krb5_db2_context *) dal_handle->db_context)) {
142854925bf6Swillf 	old = db_ctx->db_nb_locks;
142954925bf6Swillf 	db_ctx->db_nb_locks = mode;
143054925bf6Swillf     }
143154925bf6Swillf     return old;
143254925bf6Swillf }
143354925bf6Swillf 
143454925bf6Swillf /*
143554925bf6Swillf  *     DAL API functions
143654925bf6Swillf  */
143754925bf6Swillf krb5_error_code
krb5_db2_lib_init()143854925bf6Swillf krb5_db2_lib_init()
143954925bf6Swillf {
144054925bf6Swillf     return 0;
144154925bf6Swillf }
144254925bf6Swillf 
144354925bf6Swillf krb5_error_code
krb5_db2_lib_cleanup()144454925bf6Swillf krb5_db2_lib_cleanup()
144554925bf6Swillf {
144654925bf6Swillf     /* right now, no cleanup required */
144754925bf6Swillf     return 0;
144854925bf6Swillf }
144954925bf6Swillf 
145054925bf6Swillf krb5_error_code
krb5_db2_open(krb5_context kcontext,char * conf_section,char ** db_args,int mode)145154925bf6Swillf krb5_db2_open(krb5_context kcontext,
145254925bf6Swillf 	      char *conf_section, char **db_args, int mode)
145354925bf6Swillf {
145454925bf6Swillf     krb5_error_code status = 0;
145554925bf6Swillf     char  **t_ptr = db_args;
145654925bf6Swillf     int     db_name_set = 0, tempdb=0;
145754925bf6Swillf     char *dbname = NULL;
145854925bf6Swillf 
145954925bf6Swillf     krb5_clear_error_message (kcontext);
146054925bf6Swillf 
146154925bf6Swillf     if (k5db2_inited(kcontext))
146254925bf6Swillf 	return 0;
146354925bf6Swillf 
146454925bf6Swillf     while (t_ptr && *t_ptr) {
146554925bf6Swillf 	char   *opt = NULL, *val = NULL;
146654925bf6Swillf 
146754925bf6Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
146854925bf6Swillf 	if (opt && !strcmp(opt, "dbname")) {
146954925bf6Swillf 	    if (dbname) free(dbname);
147054925bf6Swillf 	    dbname = strdup(val);
147154925bf6Swillf 	}
147254925bf6Swillf 	else if (!opt && !strcmp(val, "temporary") ) {
147354925bf6Swillf 	    tempdb = 1;
147454925bf6Swillf 	}
147554925bf6Swillf 	/* ignore hash argument. Might have been passed from create */
147654925bf6Swillf 	else if (!opt || strcmp(opt, "hash")) {
147754925bf6Swillf 	    krb5_set_error_message(kcontext, EINVAL,
147854925bf6Swillf 				   gettext("Unsupported argument \"%s\" for db2"),
147954925bf6Swillf 				   opt ? opt : val);
148054925bf6Swillf 	    free(opt);
148154925bf6Swillf 	    free(val);
148254925bf6Swillf 	    return EINVAL;
148354925bf6Swillf 	}
148454925bf6Swillf 
148554925bf6Swillf 	free(opt);
148654925bf6Swillf 	free(val);
148754925bf6Swillf 	t_ptr++;
148854925bf6Swillf     }
148954925bf6Swillf 
149054925bf6Swillf     if(dbname) {
149154925bf6Swillf 	status = krb5_db2_db_set_name(kcontext, dbname, tempdb);
149254925bf6Swillf 	free(dbname);
149354925bf6Swillf 	if (status) {
14947c64d375Smp 	    /* Solaris Kerberos: Better error logging */
14957c64d375Smp 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to set db2 name to \"%s\": "), dbname);
14967c64d375Smp 	    krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
14977c64d375Smp 
149854925bf6Swillf 	    goto clean_n_exit;
149954925bf6Swillf 	}
150054925bf6Swillf 	db_name_set = 1;
150154925bf6Swillf     }
150254925bf6Swillf     if (!db_name_set) {
150354925bf6Swillf 	char   *value = NULL;
150454925bf6Swillf 	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME,	/* under given conf section */
150554925bf6Swillf 				    NULL, &value);
150654925bf6Swillf 
150754925bf6Swillf 	if (value == NULL) {
150854925bf6Swillf 	    /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
150954925bf6Swillf 	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME,	/* under given realm */
15107c64d375Smp 	        default_db_name, &value);
15117c64d375Smp 
151254925bf6Swillf 	    if (status) {
15137c64d375Smp 		/* Solaris Kerberos: Better error logging */
15147c64d375Smp 		snprintf(errbuf, sizeof(errbuf), gettext("Failed when searching for "
15157c64d375Smp 		    "\"%s\", \"%s\", \"%s\" in profile: "), KDB_REALM_SECTION,
15167c64d375Smp 		    KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME);
15177c64d375Smp 		krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
15187c64d375Smp 
151954925bf6Swillf 		goto clean_n_exit;
152054925bf6Swillf 	    }
152154925bf6Swillf 	}
152254925bf6Swillf 
152354925bf6Swillf 	status = krb5_db2_db_set_name(kcontext, value, tempdb);
15247c64d375Smp 
152554925bf6Swillf 	if (status) {
15267c64d375Smp 
15277c64d375Smp 	    /* Solaris Kerberos: Better error logging */
15287c64d375Smp 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to set db2 name to \"%s\": "), value);
15297c64d375Smp 	    krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
15307c64d375Smp 	    profile_release_string(value);
153154925bf6Swillf 	    goto clean_n_exit;
153254925bf6Swillf 	}
15337c64d375Smp 	profile_release_string(value);
153454925bf6Swillf 
153554925bf6Swillf     }
153654925bf6Swillf 
153754925bf6Swillf     status = krb5_db2_db_init(kcontext);
15387c64d375Smp     if (status) {
15397c64d375Smp         /* Solaris Kerberos: Better error logging */
15407c64d375Smp         snprintf(errbuf, sizeof(errbuf), gettext("Failed to initialize db2 db: "));
15417c64d375Smp         krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
15427c64d375Smp     }
154354925bf6Swillf 
154454925bf6Swillf   clean_n_exit:
154554925bf6Swillf     return status;
154654925bf6Swillf }
154754925bf6Swillf 
154854925bf6Swillf krb5_error_code
krb5_db2_create(krb5_context kcontext,char * conf_section,char ** db_args)154954925bf6Swillf krb5_db2_create(krb5_context kcontext, char *conf_section, char **db_args)
155054925bf6Swillf {
155154925bf6Swillf     krb5_error_code status = 0;
155254925bf6Swillf     char  **t_ptr = db_args;
155354925bf6Swillf     int     db_name_set = 0, tempdb=0;
155454925bf6Swillf     krb5_int32 flags = KRB5_KDB_CREATE_BTREE;
155554925bf6Swillf     char   *db_name = NULL;
155654925bf6Swillf 
155754925bf6Swillf     krb5_clear_error_message (kcontext);
155854925bf6Swillf 
155954925bf6Swillf     if (k5db2_inited(kcontext))
156054925bf6Swillf 	return 0;
156154925bf6Swillf 
156254925bf6Swillf     while (t_ptr && *t_ptr) {
156354925bf6Swillf 	char   *opt = NULL, *val = NULL;
156454925bf6Swillf 
156554925bf6Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
156654925bf6Swillf 	if (opt && !strcmp(opt, "dbname")) {
156754925bf6Swillf 	    db_name = strdup(val);
156854925bf6Swillf 	    if (db_name == NULL)
156954925bf6Swillf 		return ENOMEM;
157054925bf6Swillf 	}
157154925bf6Swillf 	else if (!opt && !strcmp(val, "temporary")) {
157254925bf6Swillf 	    tempdb = 1;
157354925bf6Swillf 	}
157454925bf6Swillf 	else if (opt && !strcmp(opt, "hash")) {
157554925bf6Swillf 	    flags = KRB5_KDB_CREATE_HASH;
157654925bf6Swillf 	} else {
157754925bf6Swillf 	    krb5_set_error_message(kcontext, EINVAL,
157854925bf6Swillf 				   gettext("Unsupported argument \"%s\" for db2"),
157954925bf6Swillf 				   opt ? opt : val);
158054925bf6Swillf 	    free(opt);
158154925bf6Swillf 	    free(val);
158254925bf6Swillf 	    return EINVAL;
158354925bf6Swillf 	}
158454925bf6Swillf 
158554925bf6Swillf 	free(opt);
158654925bf6Swillf 	free(val);
158754925bf6Swillf 	t_ptr++;
158854925bf6Swillf     }
158954925bf6Swillf     if (db_name) {
159054925bf6Swillf 	    status = krb5_db2_db_set_name(kcontext, db_name, tempdb);
159154925bf6Swillf 	    if (!status) {
159254925bf6Swillf 		status = EEXIST;
159354925bf6Swillf 		goto clean_n_exit;
159454925bf6Swillf 	    }
159554925bf6Swillf 	    db_name_set = 1;
159654925bf6Swillf     }
159754925bf6Swillf     if (!db_name_set) {
159854925bf6Swillf 	char   *value = NULL;
159954925bf6Swillf 	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
160054925bf6Swillf 				    KDB_MODULE_SECTION, conf_section,
160154925bf6Swillf 				    /* under given conf section */
160254925bf6Swillf 				    KDB_DB2_DATABASE_NAME, NULL, &value);
160354925bf6Swillf 
160454925bf6Swillf 	if (value == NULL) {
160554925bf6Swillf 	    /* Special case for db2.  We might actually be looking at
160654925bf6Swillf 	     * old type config file where database is specified as
160754925bf6Swillf 	     * part of realm.  */
160854925bf6Swillf 	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
160954925bf6Swillf 					KDB_REALM_SECTION,
161054925bf6Swillf 					KRB5_DB_GET_REALM(kcontext),
161154925bf6Swillf 					/* under given realm */
161254925bf6Swillf 					KDB_DB2_DATABASE_NAME,
161354925bf6Swillf 					default_db_name, &value);
161454925bf6Swillf 	    if (status) {
161554925bf6Swillf 		goto clean_n_exit;
161654925bf6Swillf 	    }
161754925bf6Swillf 	}
161854925bf6Swillf 
161954925bf6Swillf 	db_name = strdup(value);
162054925bf6Swillf 	/* Solaris Kerberos: for safety */
162154925bf6Swillf 	if (db_name == NULL) {
162254925bf6Swillf 	    status = ENOMEM;
162354925bf6Swillf 	    goto clean_n_exit;
162454925bf6Swillf 	}
162554925bf6Swillf 	status = krb5_db2_db_set_name(kcontext, value, tempdb);
162654925bf6Swillf 	profile_release_string(value);
162754925bf6Swillf 	if (!status) {
162854925bf6Swillf 	    status = EEXIST;
162954925bf6Swillf 	    goto clean_n_exit;
163054925bf6Swillf 	}
163154925bf6Swillf 
163254925bf6Swillf     }
163354925bf6Swillf 
163454925bf6Swillf     status = krb5_db2_db_create(kcontext, db_name, flags);
163554925bf6Swillf     if (status)
163654925bf6Swillf 	goto clean_n_exit;
163754925bf6Swillf     /* db2 has a problem of needing to close and open the database again. This removes that need */
163854925bf6Swillf     status = krb5_db2_db_fini(kcontext);
163954925bf6Swillf     if (status)
164054925bf6Swillf 	goto clean_n_exit;
164154925bf6Swillf 
164254925bf6Swillf     status = krb5_db2_open(kcontext, conf_section, db_args, KRB5_KDB_OPEN_RW);
164354925bf6Swillf 
164454925bf6Swillf   clean_n_exit:
164554925bf6Swillf     if (db_name)
164654925bf6Swillf 	free(db_name);
164754925bf6Swillf     return status;
164854925bf6Swillf }
164954925bf6Swillf 
165054925bf6Swillf krb5_error_code
krb5_db2_destroy(krb5_context kcontext,char * conf_section,char ** db_args)165154925bf6Swillf krb5_db2_destroy(krb5_context kcontext, char *conf_section, char **db_args)
165254925bf6Swillf {
165354925bf6Swillf     krb5_error_code status = 0;
165454925bf6Swillf     char  **t_ptr = db_args;
165554925bf6Swillf     int     db_name_set = 0, tempdb=0;
165654925bf6Swillf     char   *db_name = NULL;
165754925bf6Swillf 
165854925bf6Swillf     while (t_ptr && *t_ptr) {
165954925bf6Swillf 	char   *opt = NULL, *val = NULL;
166054925bf6Swillf 
166154925bf6Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
166254925bf6Swillf 	if (opt && !strcmp(opt, "dbname")) {
166354925bf6Swillf 	    db_name = strdup(val);
166454925bf6Swillf 	    if (db_name == NULL)
166554925bf6Swillf 		return ENOMEM;
166654925bf6Swillf 	}
166754925bf6Swillf 	else if (!opt && !strcmp(val, "temporary")) {
166854925bf6Swillf 	    tempdb = 1;
166954925bf6Swillf 	}
167054925bf6Swillf 	/* ignore hash argument. Might have been passed from create */
167154925bf6Swillf 	else if (!opt || strcmp(opt, "hash")) {
167254925bf6Swillf 	    free(opt);
167354925bf6Swillf 	    free(val);
167454925bf6Swillf 	    return EINVAL;
167554925bf6Swillf 	}
167654925bf6Swillf 
167754925bf6Swillf 	free(opt);
167854925bf6Swillf 	free(val);
167954925bf6Swillf 	t_ptr++;
168054925bf6Swillf     }
168154925bf6Swillf 
168254925bf6Swillf     if (db_name) {
168354925bf6Swillf 	status = krb5_db2_db_set_name(kcontext, db_name, tempdb);
168454925bf6Swillf 	if (status) {
168554925bf6Swillf 	    goto clean_n_exit;
168654925bf6Swillf 	}
168754925bf6Swillf 	db_name_set = 1;
168854925bf6Swillf     }
168954925bf6Swillf     if (!db_name_set) {
169054925bf6Swillf 	char   *value = NULL;
169154925bf6Swillf 	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME,	/* under given conf section */
169254925bf6Swillf 				    NULL, &value);
169354925bf6Swillf 
169454925bf6Swillf 	if (value == NULL) {
169554925bf6Swillf 	    /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
169654925bf6Swillf 	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME,	/* under given realm */
169754925bf6Swillf 					default_db_name, &value);
169854925bf6Swillf 	    if (status) {
169954925bf6Swillf 		goto clean_n_exit;
170054925bf6Swillf 	    }
170154925bf6Swillf 	}
170254925bf6Swillf 
170354925bf6Swillf 	db_name = strdup(value);
170454925bf6Swillf 	if (db_name == NULL) {
170554925bf6Swillf 	    status = ENOMEM;
170654925bf6Swillf 	    goto clean_n_exit;
170754925bf6Swillf 	}
170854925bf6Swillf 	status = krb5_db2_db_set_name(kcontext, value, tempdb);
170954925bf6Swillf 	profile_release_string(value);
171054925bf6Swillf 	if (status) {
171154925bf6Swillf 	    goto clean_n_exit;
171254925bf6Swillf 	}
171354925bf6Swillf 
171454925bf6Swillf     }
171554925bf6Swillf 
171654925bf6Swillf     status = krb5_db2_db_destroy(kcontext, db_name);
171754925bf6Swillf 
171854925bf6Swillf   clean_n_exit:
171954925bf6Swillf     if (db_name)
172054925bf6Swillf 	free(db_name);
172154925bf6Swillf     return status;
172254925bf6Swillf }
172354925bf6Swillf 
172454925bf6Swillf krb5_error_code
krb5_db2_set_master_key_ext(krb5_context kcontext,char * pwd,krb5_keyblock * key)172554925bf6Swillf krb5_db2_set_master_key_ext(krb5_context kcontext,
172654925bf6Swillf 			    char *pwd, krb5_keyblock * key)
172754925bf6Swillf {
172854925bf6Swillf     return krb5_db2_db_set_mkey(kcontext, key);
172954925bf6Swillf }
173054925bf6Swillf 
173154925bf6Swillf krb5_error_code
krb5_db2_db_set_option(krb5_context kcontext,int option,void * value)173254925bf6Swillf krb5_db2_db_set_option(krb5_context kcontext, int option, void *value)
173354925bf6Swillf {
173454925bf6Swillf     krb5_error_code status = 0;
173554925bf6Swillf     krb5_boolean oldval;
173654925bf6Swillf     krb5_db2_context *db_ctx;
173754925bf6Swillf     kdb5_dal_handle *dal_handle;
173854925bf6Swillf 
173954925bf6Swillf         if (!k5db2_inited(kcontext))
174054925bf6Swillf 	return KRB5_KDB_DBNOTINITED;
174154925bf6Swillf 
174254925bf6Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
174354925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
174454925bf6Swillf 
174554925bf6Swillf 
174654925bf6Swillf     switch (option) {
174754925bf6Swillf     case KRB5_KDB_OPT_SET_DB_NAME:
174854925bf6Swillf 	status = krb5_db2_db_set_name(kcontext, (char *) value, db_ctx->tempdb);
174954925bf6Swillf 	break;
175054925bf6Swillf 
175154925bf6Swillf     case KRB5_KDB_OPT_SET_LOCK_MODE:
175254925bf6Swillf 	oldval = krb5_db2_db_set_lockmode(kcontext, *((krb5_boolean *) value));
175354925bf6Swillf 	*((krb5_boolean *) value) = oldval;
175454925bf6Swillf 	break;
175554925bf6Swillf 
175654925bf6Swillf     default:
175754925bf6Swillf 	status = -1;		/* TBD */
175854925bf6Swillf 	break;
175954925bf6Swillf     }
176054925bf6Swillf 
176154925bf6Swillf     return status;
176254925bf6Swillf }
176354925bf6Swillf 
176454925bf6Swillf void   *
krb5_db2_alloc(krb5_context kcontext,void * ptr,size_t size)176554925bf6Swillf krb5_db2_alloc(krb5_context kcontext, void *ptr, size_t size)
176654925bf6Swillf {
176754925bf6Swillf     return realloc(ptr, size);
176854925bf6Swillf }
176954925bf6Swillf 
177054925bf6Swillf void
krb5_db2_free(krb5_context kcontext,void * ptr)177154925bf6Swillf krb5_db2_free(krb5_context kcontext, void *ptr)
177254925bf6Swillf {
177354925bf6Swillf     free(ptr);
177454925bf6Swillf }
177554925bf6Swillf 
177654925bf6Swillf /* policy functions */
177754925bf6Swillf krb5_error_code
krb5_db2_create_policy(krb5_context kcontext,osa_policy_ent_t policy)177854925bf6Swillf krb5_db2_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
177954925bf6Swillf {
178054925bf6Swillf     kdb5_dal_handle *dal_handle;
178154925bf6Swillf     krb5_db2_context *dbc;
178254925bf6Swillf 
178354925bf6Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
178454925bf6Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
178554925bf6Swillf 
178654925bf6Swillf     return osa_adb_create_policy(dbc->policy_db, policy);
178754925bf6Swillf }
178854925bf6Swillf 
178954925bf6Swillf krb5_error_code
krb5_db2_get_policy(krb5_context kcontext,char * name,osa_policy_ent_t * policy,int * cnt)179054925bf6Swillf krb5_db2_get_policy(krb5_context kcontext,
179154925bf6Swillf 		    char *name, osa_policy_ent_t * policy, int *cnt)
179254925bf6Swillf {
179354925bf6Swillf     kdb5_dal_handle *dal_handle;
179454925bf6Swillf     krb5_db2_context *dbc;
179554925bf6Swillf 
179654925bf6Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
179754925bf6Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
179854925bf6Swillf 
179954925bf6Swillf     return osa_adb_get_policy(dbc->policy_db, name, policy, cnt);
180054925bf6Swillf }
180154925bf6Swillf 
180254925bf6Swillf krb5_error_code
krb5_db2_put_policy(krb5_context kcontext,osa_policy_ent_t policy)180354925bf6Swillf krb5_db2_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
180454925bf6Swillf {
180554925bf6Swillf     kdb5_dal_handle *dal_handle;
180654925bf6Swillf     krb5_db2_context *dbc;
180754925bf6Swillf 
180854925bf6Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
180954925bf6Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
181054925bf6Swillf 
181154925bf6Swillf     return osa_adb_put_policy(dbc->policy_db, policy);
181254925bf6Swillf }
181354925bf6Swillf 
181454925bf6Swillf krb5_error_code
krb5_db2_iter_policy(krb5_context kcontext,char * match_entry,osa_adb_iter_policy_func func,void * data)181554925bf6Swillf krb5_db2_iter_policy(krb5_context kcontext,
181654925bf6Swillf 		     char *match_entry,
181754925bf6Swillf 		     osa_adb_iter_policy_func func, void *data)
181854925bf6Swillf {
181954925bf6Swillf     kdb5_dal_handle *dal_handle;
182054925bf6Swillf     krb5_db2_context *dbc;
182154925bf6Swillf 
182254925bf6Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
182354925bf6Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
182454925bf6Swillf 
182554925bf6Swillf     return osa_adb_iter_policy(dbc->policy_db, func, data);
182654925bf6Swillf }
182754925bf6Swillf 
182854925bf6Swillf krb5_error_code
krb5_db2_delete_policy(krb5_context kcontext,char * policy)182954925bf6Swillf krb5_db2_delete_policy(krb5_context kcontext, char *policy)
183054925bf6Swillf {
183154925bf6Swillf     kdb5_dal_handle *dal_handle;
183254925bf6Swillf     krb5_db2_context *dbc;
183354925bf6Swillf 
183454925bf6Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
183554925bf6Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
183654925bf6Swillf 
183754925bf6Swillf     return osa_adb_destroy_policy(dbc->policy_db, policy);
183854925bf6Swillf }
183954925bf6Swillf 
184054925bf6Swillf void
krb5_db2_free_policy(krb5_context kcontext,osa_policy_ent_t entry)184154925bf6Swillf krb5_db2_free_policy(krb5_context kcontext, osa_policy_ent_t entry)
184254925bf6Swillf {
184354925bf6Swillf     osa_free_policy_ent(entry);
184454925bf6Swillf }
184554925bf6Swillf 
184654925bf6Swillf 
184754925bf6Swillf /* */
184854925bf6Swillf 
184954925bf6Swillf krb5_error_code
krb5_db2_promote_db(krb5_context kcontext,char * conf_section,char ** db_args)185054925bf6Swillf krb5_db2_promote_db(krb5_context kcontext, char *conf_section, char **db_args)
185154925bf6Swillf {
185254925bf6Swillf     krb5_error_code status = 0;
185354925bf6Swillf     char *db_name = NULL;
185454925bf6Swillf     char *temp_db_name = NULL;
185554925bf6Swillf 
185654925bf6Swillf     krb5_clear_error_message (kcontext);
185754925bf6Swillf 
185854925bf6Swillf     {
185954925bf6Swillf 	kdb5_dal_handle *dal_handle = kcontext->db_context;
186054925bf6Swillf 	krb5_db2_context *db_ctx = dal_handle->db_context;
186154925bf6Swillf 	db_name = strdup(db_ctx->db_name);
186254925bf6Swillf 	if (db_name == NULL) {
186354925bf6Swillf 	    status = ENOMEM;
186454925bf6Swillf 	    goto clean_n_exit;
186554925bf6Swillf 	}
186654925bf6Swillf     }
186754925bf6Swillf 
186854925bf6Swillf     assert(kcontext->db_context != NULL);
186954925bf6Swillf     temp_db_name = gen_dbsuffix(db_name, "~");
187054925bf6Swillf     if (temp_db_name == NULL) {
187154925bf6Swillf 	status = ENOMEM;
187254925bf6Swillf 	goto clean_n_exit;
187354925bf6Swillf     }
187454925bf6Swillf 
187554925bf6Swillf     status = krb5_db2_db_rename (kcontext, temp_db_name, db_name);
187654925bf6Swillf 
187754925bf6Swillf clean_n_exit:
187854925bf6Swillf     if (db_name)
187954925bf6Swillf 	free(db_name);
188054925bf6Swillf     if (temp_db_name)
188154925bf6Swillf 	free(temp_db_name);
188254925bf6Swillf     return status;
188354925bf6Swillf }
188454925bf6Swillf 
188554925bf6Swillf /* Retrieved from pre-DAL code base.  */
188654925bf6Swillf /*
188754925bf6Swillf  * "Atomically" rename the database in a way that locks out read
188854925bf6Swillf  * access in the middle of the rename.
188954925bf6Swillf  *
189054925bf6Swillf  * Not perfect; if we crash in the middle of an update, we don't
189154925bf6Swillf  * necessarily know to complete the transaction the rename, but...
189254925bf6Swillf  *
189354925bf6Swillf  * Since the rename operation happens outside the init/fini bracket, we
189454925bf6Swillf  * have to go through the same stuff that we went through up in db_destroy.
189554925bf6Swillf  */
189654925bf6Swillf krb5_error_code
krb5_db2_db_rename(context,from,to)189754925bf6Swillf krb5_db2_db_rename(context, from, to)
189854925bf6Swillf     krb5_context context;
189954925bf6Swillf     char *from;
190054925bf6Swillf     char *to;
190154925bf6Swillf {
190254925bf6Swillf     char *fromok;
190354925bf6Swillf     krb5_error_code retval;
190454925bf6Swillf     krb5_db2_context *s_context, *db_ctx;
190554925bf6Swillf     kdb5_dal_handle *dal_handle = context->db_context;
1906*55fea89dSDan Cross 
190754925bf6Swillf     s_context = dal_handle->db_context;
190854925bf6Swillf     dal_handle->db_context = NULL;
190954925bf6Swillf     if ((retval = k5db2_init_context(context)))
191054925bf6Swillf 	return retval;
191154925bf6Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
191254925bf6Swillf 
191354925bf6Swillf     /*
191454925bf6Swillf      * Create the database if it does not already exist; the
191554925bf6Swillf      * files must exist because krb5_db2_db_lock, called below,
191654925bf6Swillf      * will fail otherwise.
191754925bf6Swillf      */
191854925bf6Swillf     {
191954925bf6Swillf 	struct stat statbuf;
192054925bf6Swillf 
192154925bf6Swillf 	if (stat(to, &statbuf) == -1) {
192254925bf6Swillf 	    if (errno == ENOENT) {
192354925bf6Swillf 		retval = krb5_db2_db_create(context, to,
192454925bf6Swillf 					    KRB5_KDB_CREATE_BTREE);
192554925bf6Swillf 		if (retval)
192654925bf6Swillf 		    goto errout;
192754925bf6Swillf 	    }
192854925bf6Swillf 	    else {
1929*55fea89dSDan Cross 		/*
193054925bf6Swillf 		 * XXX assuming we should bail if there is some other stat error
193154925bf6Swillf 		 */
193254925bf6Swillf 		retval = errno;
193354925bf6Swillf 		goto errout;
193454925bf6Swillf 	    }
193554925bf6Swillf 	}
193654925bf6Swillf     }
193754925bf6Swillf     /*
193854925bf6Swillf      * Set the database to the target, so that other processes sharing
193954925bf6Swillf      * the target will stop their activity, and notice the new database.
194054925bf6Swillf      */
194154925bf6Swillf     retval = krb5_db2_db_set_name(context, to, 0);
194254925bf6Swillf     if (retval)
194354925bf6Swillf 	goto errout;
194454925bf6Swillf 
194554925bf6Swillf     retval = krb5_db2_db_init(context);
194654925bf6Swillf     if (retval)
194754925bf6Swillf 	goto errout;
194854925bf6Swillf 
194954925bf6Swillf     /* XXX WAF this needs to be redone (not lock safe)!!! */
195054925bf6Swillf     {
195154925bf6Swillf 	/* Ugly brute force hack.
195254925bf6Swillf 
195354925bf6Swillf 	   Should be going through nice friendly helper routines for
195454925bf6Swillf 	   this, but it's a mess of jumbled so-called interfaces right
195554925bf6Swillf 	   now.  */
195654925bf6Swillf 	char    policy[2048], new_policy[2048];
195754925bf6Swillf 	assert (strlen(db_ctx->db_name) < 2000);
195854925bf6Swillf 	/*LINTED*/
195954925bf6Swillf 	sprintf(policy, "%s.kadm5", db_ctx->db_name);
196054925bf6Swillf 	/*LINTED*/
196154925bf6Swillf 	sprintf(new_policy, "%s~.kadm5", db_ctx->db_name);
196254925bf6Swillf 	if (0 != rename(new_policy, policy)) {
196354925bf6Swillf 	    retval = errno;
196454925bf6Swillf 	    goto errout;
196554925bf6Swillf 	}
196654925bf6Swillf 	strcat(new_policy, ".lock");
196754925bf6Swillf 	(void) unlink(new_policy);
196854925bf6Swillf     }
196954925bf6Swillf 
197054925bf6Swillf     retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time);
197154925bf6Swillf     if (retval)
197254925bf6Swillf 	goto errout;
197354925bf6Swillf 
197454925bf6Swillf     fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
197554925bf6Swillf     if (fromok == NULL) {
197654925bf6Swillf 	retval = ENOMEM;
197754925bf6Swillf 	goto errout;
197854925bf6Swillf     }
197954925bf6Swillf 
198054925bf6Swillf     if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
198154925bf6Swillf 	goto errfromok;
198254925bf6Swillf 
198354925bf6Swillf     if ((retval = krb5_db2_db_start_update(context)))
198454925bf6Swillf 	goto errfromok;
198554925bf6Swillf 
198654925bf6Swillf     if (rename(from, to)) {
198754925bf6Swillf 	retval = errno;
198854925bf6Swillf 	goto errfromok;
198954925bf6Swillf     }
199054925bf6Swillf     if (unlink(fromok)) {
199154925bf6Swillf 	retval = errno;
199254925bf6Swillf 	goto errfromok;
199354925bf6Swillf     }
199454925bf6Swillf     retval = krb5_db2_db_end_update(context);
199554925bf6Swillf errfromok:
199654925bf6Swillf     free_dbsuffix(fromok);
199754925bf6Swillf errout:
199854925bf6Swillf     if (dal_handle->db_context) {
199954925bf6Swillf 	if (db_ctx->db_lf_file >= 0) {
200054925bf6Swillf 	    krb5_db2_db_unlock(context);
200154925bf6Swillf 	    close(db_ctx->db_lf_file);
200254925bf6Swillf 	}
200354925bf6Swillf 	k5db2_clear_context((krb5_db2_context *) dal_handle->db_context);
200454925bf6Swillf 	free(dal_handle->db_context);
200554925bf6Swillf     }
200654925bf6Swillf 
200754925bf6Swillf     dal_handle->db_context = s_context;
200854925bf6Swillf     (void) krb5_db2_db_unlock(context);	/* unlock saved context db */
200954925bf6Swillf 
201054925bf6Swillf     return retval;
201154925bf6Swillf }
20127c64d375Smp 
20137c64d375Smp const char *
krb5_db2_errcode_2_string(krb5_context kcontext,long err_code)20147c64d375Smp krb5_db2_errcode_2_string(krb5_context kcontext, long err_code)
20157c64d375Smp {
20167c64d375Smp     return krb5_get_error_message(kcontext, err_code);
20177c64d375Smp }
20187c64d375Smp 
20197c64d375Smp void
krb5_db2_release_errcode_string(krb5_context kcontext,const char * msg)20207c64d375Smp krb5_db2_release_errcode_string(krb5_context kcontext, const char *msg)
20217c64d375Smp {
20227c64d375Smp     krb5_free_error_message(kcontext, msg);
20237c64d375Smp }
20247c64d375Smp 
20257c64d375Smp 
20267c64d375Smp /*
20277c64d375Smp  * Solaris Kerberos:
20287c64d375Smp  * Similar to the ldap plugin.
20297c64d375Smp  */
20307c64d375Smp static void
krb5_db2_prepend_err_str(krb5_context ctx,const char * str,krb5_error_code err,krb5_error_code oerr)20317c64d375Smp krb5_db2_prepend_err_str(krb5_context ctx, const char *str, krb5_error_code err,
20327c64d375Smp     krb5_error_code oerr) {
20337c64d375Smp 	const char *omsg;
20347c64d375Smp 	if (oerr == 0)
20357c64d375Smp 		oerr = err;
20367c64d375Smp 	omsg = krb5_get_error_message (ctx, err);
20377c64d375Smp 	krb5_set_error_message (ctx, err, "%s %s", str, omsg);
20387c64d375Smp 	krb5_free_error_message(ctx, omsg);
20397c64d375Smp }
20407c64d375Smp 
2041