xref: /onnv-gate/usr/src/lib/krb5/plugins/kdb/db2/kdb_db2.c (revision 10288:b8d3a3ad018d)
14960Swillf /*
2*10288SPeter.Shoults@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
34960Swillf  * Use is subject to license terms.
44960Swillf  */
54960Swillf 
64960Swillf 
74960Swillf /*
84960Swillf  * lib/kdb/kdb_db2.c
94960Swillf  *
104960Swillf  * Copyright 1997,2006 by the Massachusetts Institute of Technology.
114960Swillf  * All Rights Reserved.
124960Swillf  *
134960Swillf  * Export of this software from the United States of America may
144960Swillf  *   require a specific license from the United States Government.
154960Swillf  *   It is the responsibility of any person or organization contemplating
164960Swillf  *   export to obtain such a license before exporting.
174960Swillf  *
184960Swillf  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
194960Swillf  * distribute this software and its documentation for any purpose and
204960Swillf  * without fee is hereby granted, provided that the above copyright
214960Swillf  * notice appear in all copies and that both that copyright notice and
224960Swillf  * this permission notice appear in supporting documentation, and that
234960Swillf  * the name of M.I.T. not be used in advertising or publicity pertaining
244960Swillf  * to distribution of the software without specific, written prior
254960Swillf  * permission.  Furthermore if you modify this software you must label
264960Swillf  * your software as modified software and not distribute it in such a
274960Swillf  * fashion that it might be confused with the original M.I.T. software.
284960Swillf  * M.I.T. makes no representations about the suitability of
294960Swillf  * this software for any purpose.  It is provided "as is" without express
304960Swillf  * or implied warranty.
314960Swillf  *
324960Swillf  */
334960Swillf 
344960Swillf /*
354960Swillf  * Copyright (C) 1998 by the FundsXpress, INC.
364960Swillf  *
374960Swillf  * All rights reserved.
384960Swillf  *
394960Swillf  * Export of this software from the United States of America may require
404960Swillf  * a specific license from the United States Government.  It is the
414960Swillf  * responsibility of any person or organization contemplating export to
424960Swillf  * obtain such a license before exporting.
434960Swillf  *
444960Swillf  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
454960Swillf  * distribute this software and its documentation for any purpose and
464960Swillf  * without fee is hereby granted, provided that the above copyright
474960Swillf  * notice appear in all copies and that both that copyright notice and
484960Swillf  * this permission notice appear in supporting documentation, and that
494960Swillf  * the name of FundsXpress. not be used in advertising or publicity pertaining
504960Swillf  * to distribution of the software without specific, written prior
514960Swillf  * permission.  FundsXpress makes no representations about the suitability of
524960Swillf  * this software for any purpose.  It is provided "as is" without express
534960Swillf  * or implied warranty.
544960Swillf  *
554960Swillf  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
564960Swillf  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
574960Swillf  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
584960Swillf  */
594960Swillf 
604960Swillf #include "k5-int.h"
614960Swillf #include <kdb_log.h>
624960Swillf 
634960Swillf #if HAVE_UNISTD_H
644960Swillf #include <unistd.h>
654960Swillf #endif
664960Swillf 
674960Swillf #include <db.h>
684960Swillf #include <stdio.h>
694960Swillf #include <errno.h>
704960Swillf #include <utime.h>
717934SMark.Phalan@Sun.COM #include "kdb5.h"
724960Swillf #include "kdb_db2.h"
734960Swillf #include "kdb_xdr.h"
744960Swillf #include "policy_db.h"
754960Swillf #include <libintl.h>
764960Swillf 
774960Swillf #define KDB_DB2_DATABASE_NAME "database_name"
784960Swillf 
794960Swillf #include "kdb_db2.h"
804960Swillf 
814960Swillf static char *gen_dbsuffix(char *, char *);
824960Swillf 
834960Swillf static krb5_error_code krb5_db2_db_start_update(krb5_context);
844960Swillf static krb5_error_code krb5_db2_db_end_update(krb5_context);
854960Swillf 
864960Swillf static krb5_error_code krb5_db2_db_set_name(krb5_context, char *, int);
874960Swillf 
884960Swillf krb5_error_code krb5_db2_db_lock(krb5_context, int);
894960Swillf 
904960Swillf static krb5_error_code krb5_db2_db_set_hashfirst(krb5_context, int);
914960Swillf 
926426Smp153739 /*
936426Smp153739  * Solaris Kerberos
946426Smp153739  * Extra error handling
956426Smp153739  */
966426Smp153739 char errbuf[1024];
976426Smp153739 static void krb5_db2_prepend_err_str(krb5_context , const char *,
986426Smp153739     krb5_error_code, krb5_error_code);
996426Smp153739 
1004960Swillf static char default_db_name[] = DEFAULT_KDB_FILE;
1014960Swillf 
1024960Swillf /*
1034960Swillf  * Locking:
1044960Swillf  *
1054960Swillf  * There are two distinct locking protocols used.  One is designed to
1064960Swillf  * lock against processes (the admin_server, for one) which make
1074960Swillf  * incremental changes to the database; the other is designed to lock
1084960Swillf  * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
1094960Swillf  * entire database in one fell swoop.
1104960Swillf  *
1114960Swillf  * The first locking protocol is implemented using flock() in the
1124960Swillf  * krb_dbl_lock() and krb_dbl_unlock routines.
1134960Swillf  *
1144960Swillf  * The second locking protocol is necessary because DBM "files" are
1154960Swillf  * actually implemented as two separate files, and it is impossible to
1164960Swillf  * atomically rename two files simultaneously.  It assumes that the
1174960Swillf  * database is replaced only very infrequently in comparison to the time
1184960Swillf  * needed to do a database read operation.
1194960Swillf  *
1204960Swillf  * A third file is used as a "version" semaphore; the modification
1214960Swillf  * time of this file is the "version number" of the database.
1224960Swillf  * At the start of a read operation, the reader checks the version
1234960Swillf  * number; at the end of the read operation, it checks again.  If the
1244960Swillf  * version number changed, or if the semaphore was nonexistant at
1254960Swillf  * either time, the reader sleeps for a second to let things
1264960Swillf  * stabilize, and then tries again; if it does not succeed after
1274960Swillf  * KRB5_DBM_MAX_RETRY attempts, it gives up.
1284960Swillf  *
1294960Swillf  * On update, the semaphore file is deleted (if it exists) before any
1304960Swillf  * update takes place; at the end of the update, it is replaced, with
1314960Swillf  * a version number strictly greater than the version number which
1324960Swillf  * existed at the start of the update.
1334960Swillf  *
1344960Swillf  * If the system crashes in the middle of an update, the semaphore
1354960Swillf  * file is not automatically created on reboot; this is a feature, not
1364960Swillf  * a bug, since the database may be inconsistant.  Note that the
1374960Swillf  * absence of a semaphore file does not prevent another _update_ from
1384960Swillf  * taking place later.  Database replacements take place automatically
1394960Swillf  * only on slave servers; a crash in the middle of an update will be
1404960Swillf  * fixed by the next slave propagation.  A crash in the middle of an
1414960Swillf  * update on the master would be somewhat more serious, but this would
1424960Swillf  * likely be noticed by an administrator, who could fix the problem and
1434960Swillf  * retry the operation.
1444960Swillf  */
1454960Swillf 
1464960Swillf #define free_dbsuffix(name) free(name)
1474960Swillf 
1484960Swillf /*
1494960Swillf  * Routines to deal with context.
1504960Swillf  */
1514960Swillf #define	k5db2_inited(c)	(c && c->db_context \
1524960Swillf 			 && ((kdb5_dal_handle*)c->db_context)->db_context \
1534960Swillf                          && ((krb5_db2_context *) ((kdb5_dal_handle*)c->db_context)->db_context)->db_inited)
1544960Swillf 
1554960Swillf static krb5_error_code
krb5_db2_get_db_opt(char * input,char ** opt,char ** val)1564960Swillf krb5_db2_get_db_opt(char *input, char **opt, char **val)
1574960Swillf {
1584960Swillf     char   *pos = strchr(input, '=');
1594960Swillf     if (pos == NULL) {
1604960Swillf 	*opt = NULL;
1614960Swillf 	*val = strdup(input);
1624960Swillf 	if (*val == NULL) {
1634960Swillf 	    return ENOMEM;
1644960Swillf 	}
1654960Swillf     } else {
1664960Swillf 	*opt = malloc((pos - input) + 1);
1674960Swillf 	*val = strdup(pos + 1);
1684960Swillf 	if (!*opt || !*val) {
1694960Swillf 	    return ENOMEM;
1704960Swillf 	}
1714960Swillf 	memcpy(*opt, input, pos - input);
1724960Swillf 	(*opt)[pos - input] = '\0';
1734960Swillf     }
1744960Swillf     return (0);
1754960Swillf 
1764960Swillf }
1774960Swillf 
1784960Swillf /*
1794960Swillf  * Restore the default context.
1804960Swillf  */
1814960Swillf static void
k5db2_clear_context(krb5_db2_context * dbctx)1824960Swillf k5db2_clear_context(krb5_db2_context *dbctx)
1834960Swillf {
1844960Swillf     /*
1854960Swillf      * Free any dynamically allocated memory.  File descriptors and locks
1864960Swillf      * are the caller's problem.
1874960Swillf      */
1884960Swillf     if (dbctx->db_lf_name)
1894960Swillf 	free(dbctx->db_lf_name);
1904960Swillf     if (dbctx->db_name && (dbctx->db_name != default_db_name))
1914960Swillf 	free(dbctx->db_name);
1924960Swillf     /*
1934960Swillf      * Clear the structure and reset the defaults.
1944960Swillf      */
1954960Swillf     memset((char *) dbctx, 0, sizeof(krb5_db2_context));
1964960Swillf     dbctx->db_name = default_db_name;
1974960Swillf     dbctx->db_nb_locks = FALSE;
1984960Swillf     dbctx->tempdb = FALSE;
1994960Swillf }
2004960Swillf 
2014960Swillf static krb5_error_code
k5db2_init_context(krb5_context context)2024960Swillf k5db2_init_context(krb5_context context)
2034960Swillf {
2044960Swillf     krb5_db2_context *db_ctx;
2054960Swillf     kdb5_dal_handle *dal_handle;
2064960Swillf 
2074960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
2084960Swillf 
2094960Swillf     if (dal_handle->db_context == NULL) {
2104960Swillf 	db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
2114960Swillf 	if (db_ctx == NULL)
2124960Swillf 	    return ENOMEM;
2134960Swillf 	else {
2144960Swillf 	    memset((char *) db_ctx, 0, sizeof(krb5_db2_context));
2154960Swillf 	    k5db2_clear_context((krb5_db2_context *) db_ctx);
2164960Swillf 	    dal_handle->db_context = (void *) db_ctx;
2174960Swillf 	}
2184960Swillf     }
2194960Swillf     return (0);
2204960Swillf }
2214960Swillf 
2224960Swillf /*
2234960Swillf  * Utility routine: generate name of database file.
2244960Swillf  */
2254960Swillf 
2264960Swillf static char *
gen_dbsuffix(char * db_name,char * sfx)2274960Swillf gen_dbsuffix(char *db_name, char *sfx)
2284960Swillf {
2294960Swillf     char   *dbsuffix;
2304960Swillf 
2314960Swillf     if (sfx == NULL)
2324960Swillf 	return ((char *) NULL);
2334960Swillf 
2344960Swillf     dbsuffix = malloc(strlen(db_name) + strlen(sfx) + 1);
2354960Swillf     if (!dbsuffix)
2364960Swillf 	return (0);
2374960Swillf     /*LINTED*/
2384960Swillf     (void) strcpy(dbsuffix, db_name);
2394960Swillf     /*LINTED*/
2404960Swillf     (void) strcat(dbsuffix, sfx);
2414960Swillf     return dbsuffix;
2424960Swillf }
2434960Swillf 
2444960Swillf static DB *
k5db2_dbopen(krb5_db2_context * dbc,char * fname,int flags,int mode,int tempdb)2454960Swillf k5db2_dbopen(krb5_db2_context *dbc, char *fname, int flags, int mode, int tempdb)
2464960Swillf {
2474960Swillf     DB     *db;
2484960Swillf     BTREEINFO bti;
2494960Swillf     HASHINFO hashi;
2504960Swillf     bti.flags = 0;
2514960Swillf     bti.cachesize = 0;
2524960Swillf     bti.psize = 4096;
2534960Swillf     bti.lorder = 0;
2544960Swillf     bti.minkeypage = 0;
2554960Swillf     bti.compare = NULL;
2564960Swillf     bti.prefix = NULL;
2574960Swillf 
2584960Swillf     if (tempdb) {
2594960Swillf 	fname = gen_dbsuffix(fname, "~");
2604960Swillf     } else {
2614960Swillf 	fname = strdup(fname);
2624960Swillf     }
2634960Swillf     if (fname == NULL)
2644960Swillf     {
2654960Swillf 	errno = ENOMEM;
2664960Swillf 	return NULL;
2674960Swillf     }
2684960Swillf 
2694960Swillf 
2704960Swillf     hashi.bsize = 4096;
2714960Swillf     hashi.cachesize = 0;
2724960Swillf     hashi.ffactor = 40;
2734960Swillf     hashi.hash = NULL;
2744960Swillf     hashi.lorder = 0;
2754960Swillf     hashi.nelem = 1;
2764960Swillf 
2774960Swillf     db = dbopen(fname, flags, mode,
2784960Swillf 		dbc->hashfirst ? DB_HASH : DB_BTREE,
2794960Swillf 		dbc->hashfirst ? (void *) &hashi : (void *) &bti);
2804960Swillf     if (db != NULL) {
2814960Swillf 	free(fname);
2824960Swillf 	return db;
2834960Swillf     }
2844960Swillf     switch (errno) {
2854960Swillf #ifdef EFTYPE
2864960Swillf     case EFTYPE:
2874960Swillf #endif
2884960Swillf     case EINVAL:
2894960Swillf 	db = dbopen(fname, flags, mode,
2904960Swillf 		    dbc->hashfirst ? DB_BTREE : DB_HASH,
2914960Swillf 		    dbc->hashfirst ? (void *) &bti : (void *) &hashi);
2924960Swillf 	if (db != NULL)
2934960Swillf 	    dbc->hashfirst = !dbc->hashfirst;
2944960Swillf     default:
2954960Swillf 	free(fname);
2964960Swillf 	return db;
2974960Swillf     }
2984960Swillf }
2994960Swillf 
3004960Swillf static krb5_error_code
krb5_db2_db_set_hashfirst(krb5_context context,int hashfirst)3014960Swillf krb5_db2_db_set_hashfirst(krb5_context context, int hashfirst)
3024960Swillf {
3034960Swillf     krb5_db2_context *dbc;
3044960Swillf     kdb5_dal_handle *dal_handle;
3054960Swillf 
3064960Swillf     if (k5db2_inited(context))
3074960Swillf 	return KRB5_KDB_DBNOTINITED;
3084960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
3094960Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
3104960Swillf     dbc->hashfirst = hashfirst;
3114960Swillf     return 0;
3124960Swillf }
3134960Swillf 
3144960Swillf /*
3154960Swillf  * initialization for data base routines.
3164960Swillf  */
3174960Swillf 
3184960Swillf krb5_error_code
krb5_db2_db_init(krb5_context context)3194960Swillf krb5_db2_db_init(krb5_context context)
3204960Swillf {
3214960Swillf     char   *filename = NULL;
3224960Swillf     krb5_db2_context *db_ctx;
3234960Swillf     krb5_error_code retval;
3244960Swillf     kdb5_dal_handle *dal_handle;
3254960Swillf     char    policy_db_name[1024], policy_lock_name[1024];
3264960Swillf 
3274960Swillf     if (k5db2_inited(context))
3284960Swillf 	return 0;
3294960Swillf 
3304960Swillf     /* Check for presence of our context, if not present, allocate one. */
3314960Swillf     if ((retval = k5db2_init_context(context)))
3324960Swillf 	return (retval);
3334960Swillf 
3344960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
3354960Swillf     db_ctx = dal_handle->db_context;
3364960Swillf     db_ctx->db = NULL;
3374960Swillf 
3384960Swillf     if (!(filename = gen_dbsuffix(db_ctx->db_name, db_ctx->tempdb
3394960Swillf 				  ?KDB2_TEMP_LOCK_EXT:KDB2_LOCK_EXT)))
3404960Swillf 	return ENOMEM;
3414960Swillf     db_ctx->db_lf_name = filename;	/* so it gets freed by clear_context */
3424960Swillf 
3434960Swillf     /*
3444960Swillf      * should be opened read/write so that write locking can work with
3454960Swillf      * POSIX systems
3464960Swillf      */
3474960Swillf     if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
3484960Swillf 	if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
3494960Swillf 	    retval = errno;
3506426Smp153739 
3516426Smp153739 	    /* Solaris Kerberos: Better error logging */
3526426Smp153739   	    (void) snprintf(errbuf, sizeof(errbuf), gettext("Failed to open \"%s\": "), filename);
3536426Smp153739 	    krb5_db2_prepend_err_str(context, errbuf, retval, retval);
3546426Smp153739 
3554960Swillf 	    goto err_out;
3564960Swillf 	}
3574960Swillf     }
3584960Swillf     db_ctx->db_inited++;
3594960Swillf 
3604960Swillf     if ((retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time)))
3614960Swillf 	goto err_out;
3624960Swillf 
3634960Swillf     sprintf(policy_db_name, db_ctx->tempdb ? "%s~.kadm5" : "%s.kadm5",
3644960Swillf 	    db_ctx->db_name);
3654960Swillf     sprintf(policy_lock_name, "%s.lock", policy_db_name);
3664960Swillf 
3674960Swillf     if ((retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
3684960Swillf 				  policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)))
3694960Swillf     {
3706426Smp153739 	/* Solaris Kerberos: Better error logging */
3716426Smp153739 	snprintf(errbuf, sizeof(errbuf),
3726426Smp153739 	    gettext("Failed to initialize db, \"%s\", lockfile, \"%s\" : "),
3736426Smp153739 	    policy_db_name, policy_lock_name);
3746426Smp153739 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
3756426Smp153739 
3764960Swillf 	goto err_out;
3774960Swillf     }
3784960Swillf     return 0;
3794960Swillf 
3804960Swillf   err_out:
3814960Swillf     db_ctx->db = NULL;
3824960Swillf     k5db2_clear_context(db_ctx);
3834960Swillf     return (retval);
3844960Swillf }
3854960Swillf 
3864960Swillf /*
3874960Swillf  * gracefully shut down database--must be called by ANY program that does
3884960Swillf  * a krb5_db2_db_init
3894960Swillf  */
3904960Swillf krb5_error_code
krb5_db2_db_fini(krb5_context context)3914960Swillf krb5_db2_db_fini(krb5_context context)
3924960Swillf {
3934960Swillf     krb5_error_code retval = 0;
3944960Swillf     krb5_db2_context *db_ctx;
3954960Swillf     kdb5_dal_handle *dal_handle;
3964960Swillf 
3974960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
3984960Swillf     if (dal_handle == NULL) {
3994960Swillf 	return 0;
4004960Swillf     }
4014960Swillf 
4024960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
4034960Swillf 
4044960Swillf     if (k5db2_inited(context)) {
4054960Swillf 	if (close(db_ctx->db_lf_file))
4064960Swillf 	    retval = errno;
4074960Swillf 	else
4084960Swillf 	    retval = 0;
4094960Swillf     }
4104960Swillf     if (db_ctx) {
4114960Swillf 	if (db_ctx->policy_db) {
4124960Swillf 	    retval =
4134960Swillf 		osa_adb_fini_db(db_ctx->policy_db, OSA_ADB_POLICY_DB_MAGIC);
4144960Swillf 	    if (retval)
4154960Swillf 		return retval;
4164960Swillf 	}
4174960Swillf 
4184960Swillf 	k5db2_clear_context(db_ctx);
4194960Swillf 	/*      free(dal_handle->db_context); */
4204960Swillf 	dal_handle->db_context = NULL;
4214960Swillf     }
4224960Swillf     return retval;
4234960Swillf }
4244960Swillf 
4254960Swillf /*
4264960Swillf  * Set/Get the master key associated with the database
4274960Swillf  */
4284960Swillf krb5_error_code
krb5_db2_db_set_mkey(krb5_context context,krb5_keyblock * key)4294960Swillf krb5_db2_db_set_mkey(krb5_context context, krb5_keyblock *key)
4304960Swillf {
4314960Swillf     krb5_db2_context *db_ctx;
4324960Swillf     kdb5_dal_handle *dal_handle;
4334960Swillf 
4344960Swillf     if (!k5db2_inited(context))
4354960Swillf 	return (KRB5_KDB_DBNOTINITED);
4364960Swillf 
4374960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
4384960Swillf     db_ctx = dal_handle->db_context;
4394960Swillf     db_ctx->db_master_key = key;
4404960Swillf     return 0;
4414960Swillf }
4424960Swillf 
4434960Swillf krb5_error_code
krb5_db2_db_get_mkey(krb5_context context,krb5_keyblock ** key)4444960Swillf krb5_db2_db_get_mkey(krb5_context context, krb5_keyblock **key)
4454960Swillf {
4464960Swillf     krb5_db2_context *db_ctx;
4474960Swillf     kdb5_dal_handle *dal_handle;
4484960Swillf 
4494960Swillf     if (!k5db2_inited(context))
4504960Swillf 	return (KRB5_KDB_DBNOTINITED);
4514960Swillf 
4524960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
4534960Swillf     db_ctx = dal_handle->db_context;
4544960Swillf     *key = db_ctx->db_master_key;
4554960Swillf 
4564960Swillf     return 0;
4574960Swillf }
4584960Swillf 
4594960Swillf /*
4604960Swillf  * Set the "name" of the current database to some alternate value.
4614960Swillf  *
4624960Swillf  * Passing a null pointer as "name" will set back to the default.
4634960Swillf  * If the alternate database doesn't exist, nothing is changed.
4644960Swillf  *
4654960Swillf  * XXX rethink this
4664960Swillf  */
4674960Swillf 
4684960Swillf static krb5_error_code
krb5_db2_db_set_name(krb5_context context,char * name,int tempdb)4694960Swillf krb5_db2_db_set_name(krb5_context context, char *name, int tempdb)
4704960Swillf {
4714960Swillf     DB     *db;
4724960Swillf     krb5_db2_context *db_ctx;
4734960Swillf     krb5_error_code kret;
4744960Swillf     kdb5_dal_handle *dal_handle;
4754960Swillf 
4764960Swillf     if (k5db2_inited(context))
4774960Swillf 	return KRB5_KDB_DBINITED;
4784960Swillf 
4794960Swillf     /* Check for presence of our context, if not present, allocate one. */
4804960Swillf     if ((kret = k5db2_init_context(context)))
4814960Swillf 	return (kret);
4824960Swillf 
4834960Swillf     if (name == NULL)
4844960Swillf 	name = default_db_name;
4854960Swillf 
4864960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
4874960Swillf     db_ctx = dal_handle->db_context;
4884960Swillf     db_ctx->tempdb = tempdb;
4894960Swillf     db = k5db2_dbopen(db_ctx, name, O_RDONLY, 0, tempdb);
4904960Swillf     if (db == NULL)
4914960Swillf 	return errno;
4924960Swillf 
4934960Swillf     db_ctx->db_name = strdup(name);
4944960Swillf     if (db_ctx->db_name == NULL) {
4954960Swillf 	(*db->close) (db);
4964960Swillf 	return ENOMEM;
4974960Swillf     }
4984960Swillf     (*db->close) (db);
4994960Swillf     return 0;
5004960Swillf }
5014960Swillf 
5024960Swillf /*
5034960Swillf  * Return the last modification time of the database.
5044960Swillf  *
5054960Swillf  * Think about using fstat.
5064960Swillf  */
5074960Swillf 
5084960Swillf krb5_error_code
krb5_db2_db_get_age(krb5_context context,char * db_name,time_t * age)5094960Swillf krb5_db2_db_get_age(krb5_context context, char *db_name, time_t *age)
5104960Swillf {
5114960Swillf     krb5_db2_context *db_ctx;
5124960Swillf     kdb5_dal_handle *dal_handle;
5134960Swillf     struct stat st;
5144960Swillf 
5154960Swillf     if (!k5db2_inited(context))
5164960Swillf 	return (KRB5_KDB_DBNOTINITED);
5174960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
5184960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
5194960Swillf 
5204960Swillf     if (fstat(db_ctx->db_lf_file, &st) < 0)
5214960Swillf 	*age = -1;
5224960Swillf     else
5234960Swillf 	*age = st.st_mtime;
5244960Swillf     return 0;
5254960Swillf }
5264960Swillf 
5274960Swillf /*
5284960Swillf  * Remove the semaphore file; indicates that database is currently
5294960Swillf  * under renovation.
5304960Swillf  *
5314960Swillf  * This is only for use when moving the database out from underneath
5324960Swillf  * the server (for example, during slave updates).
5334960Swillf  */
5344960Swillf 
5354960Swillf static krb5_error_code
krb5_db2_db_start_update(krb5_context context)5364960Swillf krb5_db2_db_start_update(krb5_context context)
5374960Swillf {
5384960Swillf     return 0;
5394960Swillf }
5404960Swillf 
5414960Swillf static krb5_error_code
krb5_db2_db_end_update(krb5_context context)5424960Swillf krb5_db2_db_end_update(krb5_context context)
5434960Swillf {
5444960Swillf     krb5_error_code retval;
5454960Swillf     krb5_db2_context *db_ctx;
5464960Swillf     kdb5_dal_handle *dal_handle;
5474960Swillf     struct stat st;
5484960Swillf     time_t  now;
5494960Swillf     struct utimbuf utbuf;
5504960Swillf 
5514960Swillf     if (!k5db2_inited(context))
5524960Swillf 	return (KRB5_KDB_DBNOTINITED);
5534960Swillf 
5544960Swillf     retval = 0;
5554960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
5564960Swillf     db_ctx = dal_handle->db_context;
5574960Swillf     now = time((time_t *) NULL);
5584960Swillf     if (fstat(db_ctx->db_lf_file, &st) == 0) {
5594960Swillf 	if (st.st_mtime >= now) {
5604960Swillf 	    utbuf.actime = st.st_mtime + 1;
5614960Swillf 	    utbuf.modtime = st.st_mtime + 1;
5624960Swillf 	    if (utime(db_ctx->db_lf_name, &utbuf))
5634960Swillf 		retval = errno;
5644960Swillf 	} else {
5654960Swillf 	    if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
5664960Swillf 		retval = errno;
5674960Swillf 	}
5686426Smp153739 	if (retval) {
5696426Smp153739 	    /* Solaris Kerberos: Better error logging */
5706426Smp153739 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to modify "
5716426Smp153739 	        "access and modification times for \"%s\": "),
572*10288SPeter.Shoults@Sun.COM 	        db_ctx->db_lf_name);
5736426Smp153739 	    krb5_db2_prepend_err_str(context, errbuf, retval, retval);
5746426Smp153739 	}
5756426Smp153739     } else {
5764960Swillf 	retval = errno;
5776426Smp153739 	/* Solaris Kerberos: Better error logging */
5786426Smp153739 	snprintf(errbuf, sizeof(errbuf), gettext("Failed to stat \"%s\": "),
579*10288SPeter.Shoults@Sun.COM 	    db_ctx->db_lf_name);
5806426Smp153739 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
5816426Smp153739     }
5824960Swillf     if (!retval) {
5834960Swillf 	if (fstat(db_ctx->db_lf_file, &st) == 0)
5844960Swillf 	    db_ctx->db_lf_time = st.st_mtime;
5856426Smp153739 	else {
5864960Swillf 	    retval = errno;
5876426Smp153739 	    /* Solaris Kerberos: Better error logging */
5886426Smp153739 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to stat \"%s\": "),
589*10288SPeter.Shoults@Sun.COM 	        db_ctx->db_lf_name);
5906426Smp153739 	    krb5_db2_prepend_err_str(context, errbuf, retval, retval);
5916426Smp153739 	}
5924960Swillf     }
5934960Swillf     return (retval);
5944960Swillf }
5954960Swillf 
5964960Swillf #define MAX_LOCK_TRIES 5
5974960Swillf 
5984960Swillf krb5_error_code
krb5_db2_db_lock(krb5_context context,int in_mode)5994960Swillf krb5_db2_db_lock(krb5_context context, int in_mode)
6004960Swillf {
6014960Swillf     krb5_db2_context *db_ctx;
6024960Swillf     int     krb5_lock_mode;
6034960Swillf     DB     *db;
6044960Swillf     krb5_error_code retval;
6054960Swillf     time_t  mod_time;
6064960Swillf     kdb5_dal_handle *dal_handle;
6074960Swillf     int     mode, gotlock, tries;
6084960Swillf 
6094960Swillf     switch (in_mode) {
6104960Swillf     case KRB5_DB_LOCKMODE_PERMANENT:
6114960Swillf 	mode = KRB5_DB_LOCKMODE_EXCLUSIVE;
6124960Swillf 	break;
6134960Swillf     case KRB5_DB_LOCKMODE_EXCLUSIVE:
6144960Swillf 	mode = KRB5_LOCKMODE_EXCLUSIVE;
6154960Swillf 	break;
6164960Swillf 
6174960Swillf     case KRB5_DB_LOCKMODE_SHARED:
6184960Swillf 	mode = KRB5_LOCKMODE_SHARED;
6194960Swillf 	break;
6204960Swillf     default:
6214960Swillf 	return EINVAL;
6224960Swillf     }
6234960Swillf 
6244960Swillf     if (!k5db2_inited(context))
6254960Swillf 	return KRB5_KDB_DBNOTINITED;
6264960Swillf 
6274960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
6284960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
6294960Swillf     if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
6304960Swillf 	/* No need to upgrade lock, just return */
6314960Swillf 	db_ctx->db_locks_held++;
6324960Swillf 	goto policy_lock;
6334960Swillf     }
6344960Swillf 
6354960Swillf     if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
6364960Swillf 	return KRB5_KDB_BADLOCKMODE;
6374960Swillf 
6384960Swillf     krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
6394960Swillf     for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
6404960Swillf 	retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
6414960Swillf 	if (retval == 0) {
6424960Swillf 	    gotlock++;
6434960Swillf 	    break;
6446426Smp153739 	} else if (retval == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE) {
6454960Swillf 	    /* tried to exclusive-lock something we don't have */
6464960Swillf 	    /* write access to */
6476426Smp153739 
6486426Smp153739 	    /* Solaris Kerberos: Better error logging */
6496426Smp153739 	    snprintf(errbuf, sizeof(errbuf),
6506426Smp153739 	        gettext("Failed to exclusively lock \"%s\": "),
651*10288SPeter.Shoults@Sun.COM 	        db_ctx->db_lf_name);
6526426Smp153739 	    krb5_db2_prepend_err_str(context, errbuf, EBADF, EBADF);
6536426Smp153739 
6544960Swillf 	    return KRB5_KDB_CANTLOCK_DB;
6556426Smp153739 	}
6564960Swillf 	sleep(1);
6574960Swillf     }
6586426Smp153739 
6596426Smp153739     if (retval) {
6606426Smp153739 	/* Solaris Kerberos: Better error logging */
6616426Smp153739 	snprintf(errbuf, sizeof(errbuf),
6626426Smp153739 	    gettext("Failed to lock \"%s\": "),
663*10288SPeter.Shoults@Sun.COM 	    db_ctx->db_lf_name);
6646426Smp153739 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
6656426Smp153739     }
6666426Smp153739 
6674960Swillf     if (retval == EACCES)
6684960Swillf 	return KRB5_KDB_CANTLOCK_DB;
6694960Swillf     else if (retval == EAGAIN || retval == EWOULDBLOCK)
6704960Swillf 	return OSA_ADB_CANTLOCK_DB;
6714960Swillf     else if (retval != 0)
6724960Swillf 	return retval;
6734960Swillf 
6744960Swillf     if ((retval = krb5_db2_db_get_age(context, NULL, &mod_time)))
6754960Swillf 	goto lock_error;
6764960Swillf 
6774960Swillf     db = k5db2_dbopen(db_ctx, db_ctx->db_name,
6784960Swillf 		      mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600, db_ctx->tempdb);
6794960Swillf     if (db) {
6804960Swillf 	db_ctx->db_lf_time = mod_time;
6814960Swillf 	db_ctx->db = db;
6824960Swillf     } else {
6834960Swillf 	retval = errno;
6846426Smp153739 
6856426Smp153739 	/* Solaris Kerberos: Better error logging */
6866426Smp153739 	snprintf(errbuf, sizeof(errbuf),
6876426Smp153739 	    gettext("Failed to open db \"%s\": "),
6886426Smp153739 	    db_ctx->db_name);
6896426Smp153739 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
6906426Smp153739 
6914960Swillf 	db_ctx->db = NULL;
6924960Swillf 	goto lock_error;
6934960Swillf     }
6944960Swillf 
6954960Swillf     db_ctx->db_lock_mode = mode;
6964960Swillf     db_ctx->db_locks_held++;
6974960Swillf 
6984960Swillf   policy_lock:
6994960Swillf     if ((retval = osa_adb_get_lock(db_ctx->policy_db, in_mode))) {
7004960Swillf 	krb5_db2_db_unlock(context);
7014960Swillf     }
7024960Swillf     return retval;
7034960Swillf 
7044960Swillf   lock_error:;
7054960Swillf     db_ctx->db_lock_mode = 0;
7064960Swillf     db_ctx->db_locks_held = 0;
7074960Swillf     krb5_db2_db_unlock(context);
7084960Swillf     return retval;
7094960Swillf }
7104960Swillf 
7114960Swillf krb5_error_code
krb5_db2_db_unlock(krb5_context context)7124960Swillf krb5_db2_db_unlock(krb5_context context)
7134960Swillf {
7144960Swillf     krb5_db2_context *db_ctx;
7154960Swillf     kdb5_dal_handle *dal_handle;
7164960Swillf     DB     *db;
7174960Swillf     krb5_error_code retval;
7184960Swillf 
7194960Swillf     if (!k5db2_inited(context))
7204960Swillf 	return KRB5_KDB_DBNOTINITED;
7214960Swillf 
7224960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
7234960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
7244960Swillf 
7254960Swillf     if ((retval = osa_adb_release_lock(db_ctx->policy_db))) {
7264960Swillf 	return retval;
7274960Swillf     }
7284960Swillf 
7294960Swillf     if (!db_ctx->db_locks_held)	/* lock already unlocked */
7304960Swillf 	return KRB5_KDB_NOTLOCKED;
7314960Swillf     db = db_ctx->db;
7324960Swillf     if (--(db_ctx->db_locks_held) == 0) {
7334960Swillf 	(*db->close) (db);
7344960Swillf 	db_ctx->db = NULL;
7354960Swillf 
7364960Swillf 	retval = krb5_lock_file(context, db_ctx->db_lf_file,
7374960Swillf 				KRB5_LOCKMODE_UNLOCK);
7384960Swillf 	db_ctx->db_lock_mode = 0;
7394960Swillf 	return (retval);
7404960Swillf     }
7414960Swillf     return 0;
7424960Swillf }
7434960Swillf 
7444960Swillf /*
7454960Swillf  * Create the database, assuming it's not there.
7464960Swillf  */
7474960Swillf krb5_error_code
krb5_db2_db_create(krb5_context context,char * db_name,krb5_int32 flags)7484960Swillf krb5_db2_db_create(krb5_context context, char *db_name, krb5_int32 flags)
7494960Swillf {
7504960Swillf     register krb5_error_code retval = 0;
7514960Swillf     kdb5_dal_handle *dal_handle;
7524960Swillf     char   *okname;
7534960Swillf     char   *db_name2 = NULL;
7544960Swillf     int     fd;
7554960Swillf     krb5_db2_context *db_ctx;
7564960Swillf     DB     *db;
7574960Swillf     char    policy_db_name[1024], policy_lock_name[1024];
7584960Swillf 
7594960Swillf     if ((retval = k5db2_init_context(context)))
7604960Swillf 	return (retval);
7614960Swillf 
7624960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
7634960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
7644960Swillf     switch (flags) {
7654960Swillf     case KRB5_KDB_CREATE_HASH:
7664960Swillf 	if ((retval = krb5_db2_db_set_hashfirst(context, TRUE)))
7674960Swillf 	    return retval;
7684960Swillf 	break;
7694960Swillf     case KRB5_KDB_CREATE_BTREE:
7704960Swillf     case 0:
7714960Swillf 	if ((retval = krb5_db2_db_set_hashfirst(context, FALSE)))
7724960Swillf 	    return retval;
7734960Swillf 	break;
7744960Swillf     default:
7754960Swillf 	return KRB5_KDB_BAD_CREATEFLAGS;
7764960Swillf     }
7774960Swillf     db = k5db2_dbopen(db_ctx, db_name, O_RDWR | O_CREAT | O_EXCL, 0600, db_ctx->tempdb);
7786426Smp153739     if (db == NULL) {
7794960Swillf 	retval = errno;
7806426Smp153739 
7816426Smp153739 	/* Solaris Kerberos: Better error logging */
7826426Smp153739   	snprintf(errbuf, sizeof(errbuf), gettext("Failed to open \"%s\": "), db_name);
7836426Smp153739 	krb5_db2_prepend_err_str(context, errbuf, retval, retval);
7846426Smp153739     }
7854960Swillf     else
7864960Swillf 	(*db->close) (db);
7874960Swillf     if (retval == 0) {
7884960Swillf 
7894960Swillf 	db_name2 = db_ctx->tempdb ? gen_dbsuffix(db_name, "~") : strdup(db_name);
7904960Swillf 	if (db_name2 == NULL)
7914960Swillf 	    return ENOMEM;
7924960Swillf 	okname = gen_dbsuffix(db_name2, KDB2_LOCK_EXT);
7934960Swillf 	if (!okname)
7944960Swillf 	    retval = ENOMEM;
7954960Swillf 	else {
7964960Swillf 	    fd = open(okname, O_CREAT | O_RDWR | O_TRUNC, 0600);
7976426Smp153739 	    if (fd < 0) {
7984960Swillf 		retval = errno;
7996426Smp153739 		/* Solaris Kerberos: Better error logging */
8006426Smp153739 		snprintf(errbuf, sizeof(errbuf), gettext("Failed to open \"%s\": "), okname);
8016426Smp153739 		krb5_db2_prepend_err_str(context, errbuf, retval, retval);
8026426Smp153739 	    }
8034960Swillf 	    else
8044960Swillf 		close(fd);
8054960Swillf 	    free_dbsuffix(okname);
8064960Swillf 	}
8074960Swillf     }
8084960Swillf 
8094960Swillf     sprintf(policy_db_name, "%s.kadm5", db_name2);
8104960Swillf     sprintf(policy_lock_name, "%s.lock", policy_db_name);
8114960Swillf 
8124960Swillf     retval = osa_adb_create_db(policy_db_name,
8134960Swillf 			       policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
8144960Swillf     free(db_name2);
8154960Swillf     return retval;
8164960Swillf }
8174960Swillf 
8184960Swillf /*
8194960Swillf  * Destroy the database.  Zero's out all of the files, just to be sure.
8204960Swillf  */
8214960Swillf static krb5_error_code
destroy_file_suffix(char * dbname,char * suffix)8224960Swillf destroy_file_suffix(char *dbname, char *suffix)
8234960Swillf {
8244960Swillf     char   *filename;
8254960Swillf     struct stat statb;
8264960Swillf     int     nb, fd;
8274960Swillf     unsigned int j;
8284960Swillf     off_t   pos;
8294960Swillf     char    buf[BUFSIZ];
8304960Swillf     char    zbuf[BUFSIZ];
8314960Swillf     int     dowrite;
8324960Swillf 
8334960Swillf     filename = gen_dbsuffix(dbname, suffix);
8344960Swillf     if (filename == 0)
8354960Swillf 	return ENOMEM;
8364960Swillf     if ((fd = open(filename, O_RDWR, 0)) < 0) {
8374960Swillf 	free(filename);
8384960Swillf 	return errno;
8394960Swillf     }
8404960Swillf     /* fstat() will probably not fail unless using a remote filesystem
8414960Swillf      * (which is inappropriate for the kerberos database) so this check
8424960Swillf      * is mostly paranoia.  */
8434960Swillf     if (fstat(fd, &statb) == -1) {
8444960Swillf 	int     retval = errno;
8454960Swillf 	free(filename);
8464960Swillf 	return retval;
8474960Swillf     }
8484960Swillf     /*
8494960Swillf      * Stroll through the file, reading in BUFSIZ chunks.  If everything
8504960Swillf      * is zero, then we're done for that block, otherwise, zero the block.
8514960Swillf      * We would like to just blast through everything, but some DB
8524960Swillf      * implementations make holey files and writing data to the holes
8534960Swillf      * causes actual blocks to be allocated which is no good, since
8544960Swillf      * we're just about to unlink it anyways.
8554960Swillf      */
8564960Swillf     memset(zbuf, 0, BUFSIZ);
8574960Swillf     pos = 0;
8584960Swillf     while (pos < statb.st_size) {
8594960Swillf 	dowrite = 0;
8604960Swillf 	nb = read(fd, buf, BUFSIZ);
8614960Swillf 	if (nb < 0) {
8624960Swillf 	    int     retval = errno;
8634960Swillf 	    free(filename);
8644960Swillf 	    return retval;
8654960Swillf 	}
8664960Swillf 	for (j = 0; j < nb; j++) {
8674960Swillf 	    if (buf[j] != '\0') {
8684960Swillf 		dowrite = 1;
8694960Swillf 		break;
8704960Swillf 	    }
8714960Swillf 	}
8724960Swillf 	/* For signedness */
8734960Swillf 	j = nb;
8744960Swillf 	if (dowrite) {
8754960Swillf 	    lseek(fd, pos, SEEK_SET);
8764960Swillf 	    nb = write(fd, zbuf, j);
8774960Swillf 	    if (nb < 0) {
8784960Swillf 		int     retval = errno;
8794960Swillf 		free(filename);
8804960Swillf 		return retval;
8814960Swillf 	    }
8824960Swillf 	}
8834960Swillf 	pos += nb;
8844960Swillf     }
8854960Swillf     /* ??? Is fsync really needed?  I don't know of any non-networked
8864960Swillf      * filesystem which will discard queued writes to disk if a file
8874960Swillf      * is deleted after it is closed.  --jfc */
8884960Swillf #ifndef NOFSYNC
8894960Swillf     fsync(fd);
8904960Swillf #endif
8914960Swillf     close(fd);
8924960Swillf 
8934960Swillf     if (unlink(filename)) {
8944960Swillf 	free(filename);
8954960Swillf 	return (errno);
8964960Swillf     }
8974960Swillf     free(filename);
8984960Swillf     return (0);
8994960Swillf }
9004960Swillf 
9014960Swillf /*
9024960Swillf  * Since the destroy operation happens outside the init/fini bracket, we
9034960Swillf  * have some tomfoolery to undergo here.  If we're operating under no
9044960Swillf  * database context, then we initialize with the default.  If the caller
9054960Swillf  * wishes a different context (e.g. different dispatch table), it's their
9064960Swillf  * responsibility to call kdb5_db_set_dbops() before this call.  That will
9074960Swillf  * set up the right dispatch table values (e.g. name extensions).
9084960Swillf  *
9094960Swillf  * Not quite valid due to ripping out of dbops...
9104960Swillf  */
9114960Swillf krb5_error_code
krb5_db2_db_destroy(krb5_context context,char * dbname)9124960Swillf krb5_db2_db_destroy(krb5_context context, char *dbname)
9134960Swillf {
9144960Swillf     krb5_error_code retval1, retval2;
9154960Swillf     krb5_boolean tmpcontext;
9164960Swillf     char    policy_db_name[1024], policy_lock_name[1024];
9174960Swillf 
9184960Swillf     tmpcontext = 0;
9194960Swillf     if (!context->db_context
9204960Swillf 	|| !((kdb5_dal_handle *) context->db_context)->db_context) {
9214960Swillf 	tmpcontext = 1;
9224960Swillf 	if ((retval1 = k5db2_init_context(context)))
9234960Swillf 	    return (retval1);
9244960Swillf     }
9254960Swillf 
9264960Swillf     retval1 = retval2 = 0;
9274960Swillf     retval1 = destroy_file_suffix(dbname, "");
9284960Swillf     retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
9294960Swillf 
9304960Swillf     if (tmpcontext) {
9314960Swillf 	k5db2_clear_context((krb5_db2_context *) ((kdb5_dal_handle *) context->
9324960Swillf 						  db_context)->db_context);
9334960Swillf 	free(((kdb5_dal_handle *) context->db_context)->db_context);
9344960Swillf 	((kdb5_dal_handle *) context->db_context)->db_context = NULL;
9354960Swillf     }
9364960Swillf 
9374960Swillf     if (retval1 || retval2)
9384960Swillf 	return (retval1 ? retval1 : retval2);
9394960Swillf 
9404960Swillf     assert (strlen(dbname) + strlen("%s.kadm5") < sizeof(policy_db_name));
9414960Swillf     sprintf(policy_db_name, "%s.kadm5", dbname);
9424960Swillf     /* XXX finish this */
9434960Swillf     sprintf(policy_lock_name, "%s.lock", policy_db_name);
9444960Swillf 
9454960Swillf     retval1 = osa_adb_destroy_db(policy_db_name,
9464960Swillf 				 policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
9474960Swillf 
9484960Swillf     return retval1;
9494960Swillf }
9504960Swillf 
9514960Swillf /*
9524960Swillf  * look up a principal in the data base.
9534960Swillf  * returns number of entries found, and whether there were
9544960Swillf  * more than requested.
9554960Swillf  */
9564960Swillf 
9574960Swillf krb5_error_code
krb5_db2_db_get_principal(krb5_context context,krb5_const_principal searchfor,krb5_db_entry * entries,int * nentries,krb5_boolean * more)9584960Swillf krb5_db2_db_get_principal(krb5_context context,
9594960Swillf 			  krb5_const_principal searchfor,
9604960Swillf 			  krb5_db_entry *entries, /* filled in */
9614960Swillf 			  int *nentries, /* how much room/how many found */
9624960Swillf 			  krb5_boolean *more) /* are there more? */
9634960Swillf {
9644960Swillf     krb5_db2_context *db_ctx;
9654960Swillf     krb5_error_code retval;
9664960Swillf     DB     *db;
9674960Swillf     DBT     key, contents;
9684960Swillf     krb5_data keydata, contdata;
9694960Swillf     int     trynum, dbret;
9704960Swillf     kdb5_dal_handle *dal_handle;
9714960Swillf 
9724960Swillf     *more = FALSE;
9734960Swillf     *nentries = 0;
9744960Swillf 
9754960Swillf     if (!k5db2_inited(context))
9764960Swillf 	return KRB5_KDB_DBNOTINITED;
9774960Swillf 
9784960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
9794960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
9804960Swillf 
9814960Swillf     for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) {
9824960Swillf 	if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED))) {
9834960Swillf 	    if (db_ctx->db_nb_locks)
9844960Swillf 		return (retval);
9854960Swillf 	    sleep(1);
9864960Swillf 	    continue;
9874960Swillf 	}
9884960Swillf 	break;
9894960Swillf     }
9904960Swillf     if (trynum == KRB5_DB2_MAX_RETRY)
9914960Swillf 	return KRB5_KDB_DB_INUSE;
9924960Swillf 
9934960Swillf     /* XXX deal with wildcard lookups */
9944960Swillf     retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
9954960Swillf     if (retval)
9964960Swillf 	goto cleanup;
9974960Swillf     key.data = keydata.data;
9984960Swillf     key.size = keydata.length;
9994960Swillf 
10004960Swillf     db = db_ctx->db;
10014960Swillf     dbret = (*db->get) (db, &key, &contents, 0);
10024960Swillf     retval = errno;
10034960Swillf     krb5_free_data_contents(context, &keydata);
10044960Swillf     switch (dbret) {
10054960Swillf     case 1:
10064960Swillf 	retval = 0;
10074960Swillf     /*LINTED*/
10084960Swillf     case -1:
10094960Swillf     default:
10104960Swillf 	*nentries = 0;
10114960Swillf 	goto cleanup;
10124960Swillf     case 0:
10134960Swillf 	contdata.data = contents.data;
10144960Swillf 	contdata.length = contents.size;
10154960Swillf 	retval = krb5_decode_princ_contents(context, &contdata, entries);
10164960Swillf 	if (!retval)
10174960Swillf 	    *nentries = 1;
10184960Swillf 	break;
10194960Swillf     }
10204960Swillf 
10214960Swillf   cleanup:
10224960Swillf     (void) krb5_db2_db_unlock(context);	/* unlock read lock */
10234960Swillf     return retval;
10244960Swillf }
10254960Swillf 
10264960Swillf /*
10274960Swillf   Free stuff returned by krb5_db2_db_get_principal.
10284960Swillf  */
10294960Swillf krb5_error_code
krb5_db2_db_free_principal(krb5_context context,krb5_db_entry * entries,int nentries)10304960Swillf krb5_db2_db_free_principal(krb5_context context, krb5_db_entry *entries,
10314960Swillf 			   int nentries)
10324960Swillf {
10334960Swillf     register int i;
10344960Swillf     for (i = 0; i < nentries; i++)
10354960Swillf 	krb5_dbe_free_contents(context, &entries[i]);
10364960Swillf     return 0;
10374960Swillf }
10384960Swillf 
10394960Swillf /*
10404960Swillf   Stores the *"nentries" entry structures pointed to by "entries" in the
10414960Swillf   database.
10424960Swillf 
10434960Swillf   *"nentries" is updated upon return to reflect the number of records
10444960Swillf   acutally stored; the first *"nstored" records will have been stored in the
10454960Swillf   database (even if an error occurs).
10464960Swillf 
10474960Swillf  */
10484960Swillf 
10494960Swillf krb5_error_code
krb5_db2_db_put_principal(krb5_context context,krb5_db_entry * entries,int * nentries,char ** db_args)10504960Swillf krb5_db2_db_put_principal(krb5_context context,
10514960Swillf 			  krb5_db_entry *entries,
10524960Swillf 			  int *nentries, /* number of entry structs to update */
10534960Swillf 			  char **db_args)
10544960Swillf {
10554960Swillf     int     i, n, dbret;
10564960Swillf     DB     *db;
10574960Swillf     DBT     key, contents;
10584960Swillf     krb5_data contdata, keydata;
10594960Swillf     krb5_error_code retval;
10604960Swillf     krb5_db2_context *db_ctx;
10614960Swillf     kdb5_dal_handle *dal_handle;
10624960Swillf     kdb_incr_update_t *upd, *fupd;
10634960Swillf     char *princ_name = NULL;
10644960Swillf     kdb_log_context *log_ctx;
10654960Swillf 
10664960Swillf     krb5_clear_error_message (context);
10674960Swillf     if (db_args) {
10684960Swillf 	/* DB2 does not support db_args DB arguments for principal */
10694960Swillf 	krb5_set_error_message(context, EINVAL,
10704960Swillf 			       gettext("Unsupported argument \"%s\" for db2"),
10714960Swillf 			       db_args[0]);
10724960Swillf 	return EINVAL;
10734960Swillf     }
10744960Swillf 
10754960Swillf     log_ctx = context->kdblog_context;
10764960Swillf 
10774960Swillf     n = *nentries;
10784960Swillf     *nentries = 0;
10794960Swillf     if (!k5db2_inited(context))
10804960Swillf 	return KRB5_KDB_DBNOTINITED;
10814960Swillf 
10824960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
10834960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
10844960Swillf     if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
10854960Swillf 	return retval;
10864960Swillf 
10874960Swillf     /*
10884960Swillf      * Solaris Kerberos: We need the lock since ulog_conv_2logentry() does a get
10894960Swillf      */
10904960Swillf     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
10914960Swillf 	if (!(upd = (kdb_incr_update_t *)
10924960Swillf 	  malloc(sizeof (kdb_incr_update_t)*n))) {
10934960Swillf 	    retval = errno;
10944960Swillf 	    goto err_lock;
10954960Swillf 	}
10964960Swillf 	fupd = upd;
10974960Swillf 
10984960Swillf 	(void) memset(upd, 0, sizeof(kdb_incr_update_t)*n);
10994960Swillf 
11004960Swillf         if ((retval = ulog_conv_2logentry(context, entries, upd, n))) {
11014960Swillf 	    goto err_lock;
11024960Swillf 	}
11034960Swillf     }
11044960Swillf 
11054960Swillf     db = db_ctx->db;
11064960Swillf     if ((retval = krb5_db2_db_start_update(context))) {
11074960Swillf 	(void) krb5_db2_db_unlock(context);
11084960Swillf 	goto err_lock;
11094960Swillf     }
11104960Swillf 
11114960Swillf     /* for each one, stuff temps, and do replace/append */
11124960Swillf     for (i = 0; i < n; i++) {
11134960Swillf 	/*
11144960Swillf 	 * Solaris Kerberos: We'll be sharing the same locks as db for logging
11154960Swillf 	 */
11164960Swillf         if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
11174960Swillf 		if ((retval = krb5_unparse_name(context, entries->princ,
11184960Swillf 		    &princ_name)))
11194960Swillf 			goto err_lock;
11204960Swillf 
11214960Swillf 		upd->kdb_princ_name.utf8str_t_val = princ_name;
11224960Swillf 		upd->kdb_princ_name.utf8str_t_len = strlen(princ_name);
11234960Swillf 
11244960Swillf                 if (retval = ulog_add_update(context, upd))
11254960Swillf 			goto err_lock;
11264960Swillf         }
11274960Swillf 
11284960Swillf 	retval = krb5_encode_princ_contents(context, &contdata, entries);
11294960Swillf 	if (retval)
11304960Swillf 	    break;
11314960Swillf 	contents.data = contdata.data;
11324960Swillf 	contents.size = contdata.length;
11334960Swillf 	retval = krb5_encode_princ_dbkey(context, &keydata, entries->princ);
11344960Swillf 	if (retval) {
11354960Swillf 	    krb5_free_data_contents(context, &contdata);
11364960Swillf 	    break;
11374960Swillf 	}
11384960Swillf 
11394960Swillf 	key.data = keydata.data;
11404960Swillf 	key.size = keydata.length;
11414960Swillf 	dbret = (*db->put) (db, &key, &contents, 0);
11424960Swillf 	retval = dbret ? errno : 0;
11434960Swillf 	krb5_free_data_contents(context, &keydata);
11444960Swillf 	krb5_free_data_contents(context, &contdata);
11454960Swillf 	if (retval)
11464960Swillf 	    break;
11474960Swillf 	else if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
11484960Swillf 	    /*
11494960Swillf 	     * We need to make sure the db record is synced before we mark
11504960Swillf 	     * it as committed via finish_update.
11514960Swillf 	     */
11524960Swillf 	    dbret = (*db->sync)(db, 0);
11534960Swillf 	    if (dbret) {
11544960Swillf 		retval = errno;
11554960Swillf 		goto err_lock;
11564960Swillf 	    }
11574960Swillf 	    (void) ulog_finish_update(context, upd);
11584960Swillf 	    upd++;
11594960Swillf 	}
11604960Swillf 	entries++;		/* bump to next struct */
11614960Swillf     }
11624960Swillf 
11634960Swillf     (void) krb5_db2_db_end_update(context);
11644960Swillf 
11654960Swillf err_lock:
11664960Swillf     (void) krb5_db2_db_unlock(context);	/* unlock database */
11674960Swillf 
11684960Swillf     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER))
11694960Swillf         ulog_free_entries(fupd, n);
11704960Swillf 
11714960Swillf     *nentries = i;
11724960Swillf     return (retval);
11734960Swillf }
11744960Swillf 
11754960Swillf /*
11764960Swillf  * delete a principal from the data base.
11774960Swillf  * returns number of entries removed
11784960Swillf  */
11794960Swillf 
11804960Swillf krb5_error_code
krb5_db2_db_delete_principal(krb5_context context,krb5_const_principal searchfor,int * nentries)11814960Swillf krb5_db2_db_delete_principal(krb5_context context,
11824960Swillf 			     krb5_const_principal searchfor,
11834960Swillf 			     int *nentries) /* how many found & deleted */
11844960Swillf {
11854960Swillf     krb5_error_code retval;
11864960Swillf     krb5_db_entry entry;
11874960Swillf     krb5_db2_context *db_ctx;
11884960Swillf     DB     *db;
11894960Swillf     DBT     key, contents;
11904960Swillf     krb5_data keydata, contdata;
11914960Swillf     int     i, dbret;
11924960Swillf     kdb5_dal_handle *dal_handle;
11934960Swillf     kdb_incr_update_t upd;
11944960Swillf     char *princ_name = NULL;
11954960Swillf     kdb_log_context *log_ctx;
11964960Swillf 
11974960Swillf     log_ctx = context->kdblog_context;
11984960Swillf 
11994960Swillf     if (!k5db2_inited(context))
12004960Swillf 	return KRB5_KDB_DBNOTINITED;
12014960Swillf 
12024960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
12034960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
12044960Swillf     if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
12054960Swillf 	return (retval);
12064960Swillf 
12074960Swillf     if ((retval = krb5_db2_db_start_update(context))) {
12084960Swillf 	(void) krb5_db2_db_unlock(context);	/* unlock write lock */
12094960Swillf 	return (retval);
12104960Swillf     }
12114960Swillf 
12124960Swillf     if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
12134960Swillf 	goto cleanup;
12144960Swillf     key.data = keydata.data;
12154960Swillf     key.size = keydata.length;
12164960Swillf 
12174960Swillf     db = db_ctx->db;
12184960Swillf     dbret = (*db->get) (db, &key, &contents, 0);
12194960Swillf     retval = errno;
12204960Swillf     switch (dbret) {
12214960Swillf     case 1:
12224960Swillf 	retval = KRB5_KDB_NOENTRY;
12234960Swillf     /*LINTED*/
12244960Swillf     case -1:
12254960Swillf     default:
12264960Swillf 	*nentries = 0;
12274960Swillf 	goto cleankey;
12284960Swillf     case 0:
12294960Swillf 	;
12304960Swillf     }
12314960Swillf     /*
12324960Swillf      * Solaris Kerberos: We'll be sharing the same locks as db for logging
12334960Swillf      */
12344960Swillf     if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
12354960Swillf 	if ((retval = krb5_unparse_name(context, searchfor, &princ_name))) {
12364960Swillf 		(void) krb5_db2_db_unlock(context);
12374960Swillf 		return retval;
12384960Swillf 	}
12394960Swillf 
12404960Swillf 	(void) memset(&upd, 0, sizeof (kdb_incr_update_t));
12414960Swillf 
12424960Swillf 	upd.kdb_princ_name.utf8str_t_val = princ_name;
12434960Swillf 	upd.kdb_princ_name.utf8str_t_len = strlen(princ_name);
12444960Swillf 
12454960Swillf 	if (retval = ulog_delete_update(context, &upd)) {
12464960Swillf 		free(princ_name);
12474960Swillf 		(void) krb5_db2_db_unlock(context);
12484960Swillf 		return retval;
12494960Swillf 	}
12504960Swillf 
12514960Swillf 	free(princ_name);
12524960Swillf     }
12534960Swillf 
12544960Swillf     memset((char *) &entry, 0, sizeof(entry));
12554960Swillf     contdata.data = contents.data;
12564960Swillf     contdata.length = contents.size;
12574960Swillf     retval = krb5_decode_princ_contents(context, &contdata, &entry);
12584960Swillf     if (retval)
12594960Swillf 	goto cleankey;
12604960Swillf     *nentries = 1;
12614960Swillf 
12624960Swillf     /* Clear encrypted key contents */
12634960Swillf     for (i = 0; i < entry.n_key_data; i++) {
12644960Swillf 	if (entry.key_data[i].key_data_length[0]) {
12654960Swillf 	    memset((char *) entry.key_data[i].key_data_contents[0], 0,
12664960Swillf 		   (unsigned) entry.key_data[i].key_data_length[0]);
12674960Swillf 	}
12684960Swillf     }
12694960Swillf 
12704960Swillf     retval = krb5_encode_princ_contents(context, &contdata, &entry);
12714960Swillf     krb5_dbe_free_contents(context, &entry);
12724960Swillf     if (retval)
12734960Swillf 	goto cleankey;
12744960Swillf 
12754960Swillf     contents.data = contdata.data;
12764960Swillf     contents.size = contdata.length;
12774960Swillf     dbret = (*db->put) (db, &key, &contents, 0);
12784960Swillf     retval = dbret ? errno : 0;
12794960Swillf     krb5_free_data_contents(context, &contdata);
12804960Swillf     if (retval)
12814960Swillf 	goto cleankey;
12824960Swillf     dbret = (*db->del) (db, &key, 0);
12834960Swillf     retval = dbret ? errno : 0;
12844960Swillf 
12854960Swillf     /*
12864960Swillf      * We need to commit our update upon success
12874960Swillf      */
12884960Swillf     if (!retval)
12894960Swillf 	if (log_ctx && (log_ctx->iproprole == IPROP_MASTER))
12904960Swillf 		(void) ulog_finish_update(context, &upd);
12914960Swillf 
12924960Swillf   cleankey:
12934960Swillf     krb5_free_data_contents(context, &keydata);
12944960Swillf 
12954960Swillf   cleanup:
12964960Swillf     (void) krb5_db2_db_end_update(context);
12974960Swillf     (void) krb5_db2_db_unlock(context);	/* unlock write lock */
12984960Swillf     return retval;
12994960Swillf }
13004960Swillf 
13014960Swillf 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)13024960Swillf krb5_db2_db_iterate_ext(krb5_context context,
13034960Swillf 			krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
13044960Swillf 			krb5_pointer func_arg,
13054960Swillf 			int backwards, int recursive)
13064960Swillf {
13074960Swillf     krb5_db2_context *db_ctx;
13084960Swillf     DB     *db;
13094960Swillf     DBT     key, contents;
13104960Swillf     krb5_data contdata;
13114960Swillf     krb5_db_entry entries;
13124960Swillf     krb5_error_code retval;
13134960Swillf     kdb5_dal_handle *dal_handle;
13144960Swillf     int     dbret;
13154960Swillf     void   *cookie;
13164960Swillf 
13174960Swillf     cookie = NULL;
13184960Swillf     if (!k5db2_inited(context))
13194960Swillf 	return KRB5_KDB_DBNOTINITED;
13204960Swillf 
13214960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
13224960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
13234960Swillf     retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_SHARED);
13244960Swillf 
13254960Swillf     if (retval)
13264960Swillf 	return retval;
13274960Swillf 
13284960Swillf     db = db_ctx->db;
13294960Swillf     if (recursive && db->type != DB_BTREE) {
13304960Swillf 	(void) krb5_db2_db_unlock(context);
13314960Swillf 	return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
13324960Swillf     }
13334960Swillf 
13344960Swillf     if (!recursive) {
13354960Swillf 	dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST);
13364960Swillf     } else {
13374960Swillf #ifdef HAVE_BT_RSEQ
13384960Swillf 	dbret = bt_rseq(db, &key, &contents, &cookie,
13394960Swillf 			backwards ? R_LAST : R_FIRST);
13404960Swillf #else
13414960Swillf 	(void) krb5_db2_db_unlock(context);
13424960Swillf 	return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
13434960Swillf #endif
13444960Swillf     }
13454960Swillf     while (dbret == 0) {
13464960Swillf 	contdata.data = contents.data;
13474960Swillf 	contdata.length = contents.size;
13484960Swillf 	retval = krb5_decode_princ_contents(context, &contdata, &entries);
13494960Swillf 	if (retval)
13504960Swillf 	    break;
13514960Swillf 	retval = (*func) (func_arg, &entries);
13524960Swillf 	krb5_dbe_free_contents(context, &entries);
13534960Swillf 	if (retval)
13544960Swillf 	    break;
13554960Swillf 	if (!recursive) {
13564960Swillf 	    dbret = (*db->seq) (db, &key, &contents,
13574960Swillf 				backwards ? R_PREV : R_NEXT);
13584960Swillf 	} else {
13594960Swillf #ifdef HAVE_BT_RSEQ
13604960Swillf 	    dbret = bt_rseq(db, &key, &contents, &cookie,
13614960Swillf 			    backwards ? R_PREV : R_NEXT);
13624960Swillf #else
13634960Swillf 	    (void) krb5_db2_db_unlock(context);
13644960Swillf 	    return KRB5_KDB_UK_RERROR;	/* Not optimal, but close enough. */
13654960Swillf #endif
13664960Swillf 	}
13674960Swillf     }
13684960Swillf     switch (dbret) {
13694960Swillf     case 1:
13704960Swillf     case 0:
13714960Swillf 	break;
13724960Swillf     case -1:
13734960Swillf     default:
13744960Swillf 	retval = errno;
13754960Swillf     }
13764960Swillf     (void) krb5_db2_db_unlock(context);
13774960Swillf     return retval;
13784960Swillf }
13794960Swillf 
13804960Swillf 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)13814960Swillf krb5_db2_db_iterate(krb5_context context,
13824960Swillf 		    char *match_expr,
13834960Swillf 		    krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
13845916Swillf 		    krb5_pointer func_arg, char **db_args)
13854960Swillf {
13865916Swillf     char  **t_ptr = db_args;
13875916Swillf     int backwards = 0, recursive = 0;
13885916Swillf 
13895916Swillf     while (t_ptr && *t_ptr) {
13905916Swillf 	char   *opt = NULL, *val = NULL;
13915916Swillf 
13925916Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
13935916Swillf 
13945916Swillf 	/* Solaris Kerberos: adding support for -rev/recurse flags */
13955916Swillf 	if (val && !strcmp(val, "rev"))
13965916Swillf 	    backwards = 1;
13975916Swillf 	else if (val && !strcmp(val, "recurse"))
13985916Swillf 	    recursive = 1;
13995916Swillf 	else {
14005916Swillf 	    krb5_set_error_message(context, EINVAL,
14015916Swillf 				   gettext("Unsupported argument \"%s\" for db2"),
14025916Swillf 				   val);
14035916Swillf 	    free(opt);
14045916Swillf 	    free(val);
14055916Swillf 	    return EINVAL;
14065916Swillf 	}
14075916Swillf 
14085916Swillf 	free(opt);
14095916Swillf 	free(val);
14105916Swillf 	t_ptr++;
14115916Swillf     }
14125916Swillf 
14135916Swillf     /* Solaris Kerberos: adding support for -rev/recurse flags */
14145916Swillf     return krb5_db2_db_iterate_ext(context, func, func_arg, backwards, recursive);
14154960Swillf }
14164960Swillf 
14174960Swillf krb5_boolean
krb5_db2_db_set_lockmode(krb5_context context,krb5_boolean mode)14184960Swillf krb5_db2_db_set_lockmode(krb5_context context, krb5_boolean mode)
14194960Swillf {
14204960Swillf     krb5_boolean old;
14214960Swillf     krb5_db2_context *db_ctx;
14224960Swillf     kdb5_dal_handle *dal_handle;
14234960Swillf 
14244960Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
14254960Swillf     old = mode;
14264960Swillf     if (dal_handle && (db_ctx = (krb5_db2_context *) dal_handle->db_context)) {
14274960Swillf 	old = db_ctx->db_nb_locks;
14284960Swillf 	db_ctx->db_nb_locks = mode;
14294960Swillf     }
14304960Swillf     return old;
14314960Swillf }
14324960Swillf 
14334960Swillf /*
14344960Swillf  *     DAL API functions
14354960Swillf  */
14364960Swillf krb5_error_code
krb5_db2_lib_init()14374960Swillf krb5_db2_lib_init()
14384960Swillf {
14394960Swillf     return 0;
14404960Swillf }
14414960Swillf 
14424960Swillf krb5_error_code
krb5_db2_lib_cleanup()14434960Swillf krb5_db2_lib_cleanup()
14444960Swillf {
14454960Swillf     /* right now, no cleanup required */
14464960Swillf     return 0;
14474960Swillf }
14484960Swillf 
14494960Swillf krb5_error_code
krb5_db2_open(krb5_context kcontext,char * conf_section,char ** db_args,int mode)14504960Swillf krb5_db2_open(krb5_context kcontext,
14514960Swillf 	      char *conf_section, char **db_args, int mode)
14524960Swillf {
14534960Swillf     krb5_error_code status = 0;
14544960Swillf     char  **t_ptr = db_args;
14554960Swillf     int     db_name_set = 0, tempdb=0;
14564960Swillf     char *dbname = NULL;
14574960Swillf 
14584960Swillf     krb5_clear_error_message (kcontext);
14594960Swillf 
14604960Swillf     if (k5db2_inited(kcontext))
14614960Swillf 	return 0;
14624960Swillf 
14634960Swillf     while (t_ptr && *t_ptr) {
14644960Swillf 	char   *opt = NULL, *val = NULL;
14654960Swillf 
14664960Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
14674960Swillf 	if (opt && !strcmp(opt, "dbname")) {
14684960Swillf 	    if (dbname) free(dbname);
14694960Swillf 	    dbname = strdup(val);
14704960Swillf 	}
14714960Swillf 	else if (!opt && !strcmp(val, "temporary") ) {
14724960Swillf 	    tempdb = 1;
14734960Swillf 	}
14744960Swillf 	/* ignore hash argument. Might have been passed from create */
14754960Swillf 	else if (!opt || strcmp(opt, "hash")) {
14764960Swillf 	    krb5_set_error_message(kcontext, EINVAL,
14774960Swillf 				   gettext("Unsupported argument \"%s\" for db2"),
14784960Swillf 				   opt ? opt : val);
14794960Swillf 	    free(opt);
14804960Swillf 	    free(val);
14814960Swillf 	    return EINVAL;
14824960Swillf 	}
14834960Swillf 
14844960Swillf 	free(opt);
14854960Swillf 	free(val);
14864960Swillf 	t_ptr++;
14874960Swillf     }
14884960Swillf 
14894960Swillf     if(dbname) {
14904960Swillf 	status = krb5_db2_db_set_name(kcontext, dbname, tempdb);
14914960Swillf 	free(dbname);
14924960Swillf 	if (status) {
14936426Smp153739 	    /* Solaris Kerberos: Better error logging */
14946426Smp153739 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to set db2 name to \"%s\": "), dbname);
14956426Smp153739 	    krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
14966426Smp153739 
14974960Swillf 	    goto clean_n_exit;
14984960Swillf 	}
14994960Swillf 	db_name_set = 1;
15004960Swillf     }
15014960Swillf     if (!db_name_set) {
15024960Swillf 	char   *value = NULL;
15034960Swillf 	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME,	/* under given conf section */
15044960Swillf 				    NULL, &value);
15054960Swillf 
15064960Swillf 	if (value == NULL) {
15074960Swillf 	    /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
15084960Swillf 	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME,	/* under given realm */
15096426Smp153739 	        default_db_name, &value);
15106426Smp153739 
15114960Swillf 	    if (status) {
15126426Smp153739 		/* Solaris Kerberos: Better error logging */
15136426Smp153739 		snprintf(errbuf, sizeof(errbuf), gettext("Failed when searching for "
15146426Smp153739 		    "\"%s\", \"%s\", \"%s\" in profile: "), KDB_REALM_SECTION,
15156426Smp153739 		    KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME);
15166426Smp153739 		krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
15176426Smp153739 
15184960Swillf 		goto clean_n_exit;
15194960Swillf 	    }
15204960Swillf 	}
15214960Swillf 
15224960Swillf 	status = krb5_db2_db_set_name(kcontext, value, tempdb);
15236426Smp153739 
15244960Swillf 	if (status) {
15256426Smp153739 
15266426Smp153739 	    /* Solaris Kerberos: Better error logging */
15276426Smp153739 	    snprintf(errbuf, sizeof(errbuf), gettext("Failed to set db2 name to \"%s\": "), value);
15286426Smp153739 	    krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
15296426Smp153739 	    profile_release_string(value);
15304960Swillf 	    goto clean_n_exit;
15314960Swillf 	}
15326426Smp153739 	profile_release_string(value);
15334960Swillf 
15344960Swillf     }
15354960Swillf 
15364960Swillf     status = krb5_db2_db_init(kcontext);
15376426Smp153739     if (status) {
15386426Smp153739         /* Solaris Kerberos: Better error logging */
15396426Smp153739         snprintf(errbuf, sizeof(errbuf), gettext("Failed to initialize db2 db: "));
15406426Smp153739         krb5_db2_prepend_err_str(kcontext, errbuf, status, status);
15416426Smp153739     }
15424960Swillf 
15434960Swillf   clean_n_exit:
15444960Swillf     return status;
15454960Swillf }
15464960Swillf 
15474960Swillf krb5_error_code
krb5_db2_create(krb5_context kcontext,char * conf_section,char ** db_args)15484960Swillf krb5_db2_create(krb5_context kcontext, char *conf_section, char **db_args)
15494960Swillf {
15504960Swillf     krb5_error_code status = 0;
15514960Swillf     char  **t_ptr = db_args;
15524960Swillf     int     db_name_set = 0, tempdb=0;
15534960Swillf     krb5_int32 flags = KRB5_KDB_CREATE_BTREE;
15544960Swillf     char   *db_name = NULL;
15554960Swillf 
15564960Swillf     krb5_clear_error_message (kcontext);
15574960Swillf 
15584960Swillf     if (k5db2_inited(kcontext))
15594960Swillf 	return 0;
15604960Swillf 
15614960Swillf     while (t_ptr && *t_ptr) {
15624960Swillf 	char   *opt = NULL, *val = NULL;
15634960Swillf 
15644960Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
15654960Swillf 	if (opt && !strcmp(opt, "dbname")) {
15664960Swillf 	    db_name = strdup(val);
15674960Swillf 	    if (db_name == NULL)
15684960Swillf 		return ENOMEM;
15694960Swillf 	}
15704960Swillf 	else if (!opt && !strcmp(val, "temporary")) {
15714960Swillf 	    tempdb = 1;
15724960Swillf 	}
15734960Swillf 	else if (opt && !strcmp(opt, "hash")) {
15744960Swillf 	    flags = KRB5_KDB_CREATE_HASH;
15754960Swillf 	} else {
15764960Swillf 	    krb5_set_error_message(kcontext, EINVAL,
15774960Swillf 				   gettext("Unsupported argument \"%s\" for db2"),
15784960Swillf 				   opt ? opt : val);
15794960Swillf 	    free(opt);
15804960Swillf 	    free(val);
15814960Swillf 	    return EINVAL;
15824960Swillf 	}
15834960Swillf 
15844960Swillf 	free(opt);
15854960Swillf 	free(val);
15864960Swillf 	t_ptr++;
15874960Swillf     }
15884960Swillf     if (db_name) {
15894960Swillf 	    status = krb5_db2_db_set_name(kcontext, db_name, tempdb);
15904960Swillf 	    if (!status) {
15914960Swillf 		status = EEXIST;
15924960Swillf 		goto clean_n_exit;
15934960Swillf 	    }
15944960Swillf 	    db_name_set = 1;
15954960Swillf     }
15964960Swillf     if (!db_name_set) {
15974960Swillf 	char   *value = NULL;
15984960Swillf 	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
15994960Swillf 				    KDB_MODULE_SECTION, conf_section,
16004960Swillf 				    /* under given conf section */
16014960Swillf 				    KDB_DB2_DATABASE_NAME, NULL, &value);
16024960Swillf 
16034960Swillf 	if (value == NULL) {
16044960Swillf 	    /* Special case for db2.  We might actually be looking at
16054960Swillf 	     * old type config file where database is specified as
16064960Swillf 	     * part of realm.  */
16074960Swillf 	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext),
16084960Swillf 					KDB_REALM_SECTION,
16094960Swillf 					KRB5_DB_GET_REALM(kcontext),
16104960Swillf 					/* under given realm */
16114960Swillf 					KDB_DB2_DATABASE_NAME,
16124960Swillf 					default_db_name, &value);
16134960Swillf 	    if (status) {
16144960Swillf 		goto clean_n_exit;
16154960Swillf 	    }
16164960Swillf 	}
16174960Swillf 
16184960Swillf 	db_name = strdup(value);
16194960Swillf 	/* Solaris Kerberos: for safety */
16204960Swillf 	if (db_name == NULL) {
16214960Swillf 	    status = ENOMEM;
16224960Swillf 	    goto clean_n_exit;
16234960Swillf 	}
16244960Swillf 	status = krb5_db2_db_set_name(kcontext, value, tempdb);
16254960Swillf 	profile_release_string(value);
16264960Swillf 	if (!status) {
16274960Swillf 	    status = EEXIST;
16284960Swillf 	    goto clean_n_exit;
16294960Swillf 	}
16304960Swillf 
16314960Swillf     }
16324960Swillf 
16334960Swillf     status = krb5_db2_db_create(kcontext, db_name, flags);
16344960Swillf     if (status)
16354960Swillf 	goto clean_n_exit;
16364960Swillf     /* db2 has a problem of needing to close and open the database again. This removes that need */
16374960Swillf     status = krb5_db2_db_fini(kcontext);
16384960Swillf     if (status)
16394960Swillf 	goto clean_n_exit;
16404960Swillf 
16414960Swillf     status = krb5_db2_open(kcontext, conf_section, db_args, KRB5_KDB_OPEN_RW);
16424960Swillf 
16434960Swillf   clean_n_exit:
16444960Swillf     if (db_name)
16454960Swillf 	free(db_name);
16464960Swillf     return status;
16474960Swillf }
16484960Swillf 
16494960Swillf krb5_error_code
krb5_db2_destroy(krb5_context kcontext,char * conf_section,char ** db_args)16504960Swillf krb5_db2_destroy(krb5_context kcontext, char *conf_section, char **db_args)
16514960Swillf {
16524960Swillf     krb5_error_code status = 0;
16534960Swillf     char  **t_ptr = db_args;
16544960Swillf     int     db_name_set = 0, tempdb=0;
16554960Swillf     char   *db_name = NULL;
16564960Swillf 
16574960Swillf     while (t_ptr && *t_ptr) {
16584960Swillf 	char   *opt = NULL, *val = NULL;
16594960Swillf 
16604960Swillf 	krb5_db2_get_db_opt(*t_ptr, &opt, &val);
16614960Swillf 	if (opt && !strcmp(opt, "dbname")) {
16624960Swillf 	    db_name = strdup(val);
16634960Swillf 	    if (db_name == NULL)
16644960Swillf 		return ENOMEM;
16654960Swillf 	}
16664960Swillf 	else if (!opt && !strcmp(val, "temporary")) {
16674960Swillf 	    tempdb = 1;
16684960Swillf 	}
16694960Swillf 	/* ignore hash argument. Might have been passed from create */
16704960Swillf 	else if (!opt || strcmp(opt, "hash")) {
16714960Swillf 	    free(opt);
16724960Swillf 	    free(val);
16734960Swillf 	    return EINVAL;
16744960Swillf 	}
16754960Swillf 
16764960Swillf 	free(opt);
16774960Swillf 	free(val);
16784960Swillf 	t_ptr++;
16794960Swillf     }
16804960Swillf 
16814960Swillf     if (db_name) {
16824960Swillf 	status = krb5_db2_db_set_name(kcontext, db_name, tempdb);
16834960Swillf 	if (status) {
16844960Swillf 	    goto clean_n_exit;
16854960Swillf 	}
16864960Swillf 	db_name_set = 1;
16874960Swillf     }
16884960Swillf     if (!db_name_set) {
16894960Swillf 	char   *value = NULL;
16904960Swillf 	status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_MODULE_SECTION, conf_section, KDB_DB2_DATABASE_NAME,	/* under given conf section */
16914960Swillf 				    NULL, &value);
16924960Swillf 
16934960Swillf 	if (value == NULL) {
16944960Swillf 	    /* special case for db2. We might actually be looking at old type config file where database is specified as part of realm */
16954960Swillf 	    status = profile_get_string(KRB5_DB_GET_PROFILE(kcontext), KDB_REALM_SECTION, KRB5_DB_GET_REALM(kcontext), KDB_DB2_DATABASE_NAME,	/* under given realm */
16964960Swillf 					default_db_name, &value);
16974960Swillf 	    if (status) {
16984960Swillf 		goto clean_n_exit;
16994960Swillf 	    }
17004960Swillf 	}
17014960Swillf 
17024960Swillf 	db_name = strdup(value);
17034960Swillf 	if (db_name == NULL) {
17044960Swillf 	    status = ENOMEM;
17054960Swillf 	    goto clean_n_exit;
17064960Swillf 	}
17074960Swillf 	status = krb5_db2_db_set_name(kcontext, value, tempdb);
17084960Swillf 	profile_release_string(value);
17094960Swillf 	if (status) {
17104960Swillf 	    goto clean_n_exit;
17114960Swillf 	}
17124960Swillf 
17134960Swillf     }
17144960Swillf 
17154960Swillf     status = krb5_db2_db_destroy(kcontext, db_name);
17164960Swillf 
17174960Swillf   clean_n_exit:
17184960Swillf     if (db_name)
17194960Swillf 	free(db_name);
17204960Swillf     return status;
17214960Swillf }
17224960Swillf 
17234960Swillf krb5_error_code
krb5_db2_set_master_key_ext(krb5_context kcontext,char * pwd,krb5_keyblock * key)17244960Swillf krb5_db2_set_master_key_ext(krb5_context kcontext,
17254960Swillf 			    char *pwd, krb5_keyblock * key)
17264960Swillf {
17274960Swillf     return krb5_db2_db_set_mkey(kcontext, key);
17284960Swillf }
17294960Swillf 
17304960Swillf krb5_error_code
krb5_db2_db_set_option(krb5_context kcontext,int option,void * value)17314960Swillf krb5_db2_db_set_option(krb5_context kcontext, int option, void *value)
17324960Swillf {
17334960Swillf     krb5_error_code status = 0;
17344960Swillf     krb5_boolean oldval;
17354960Swillf     krb5_db2_context *db_ctx;
17364960Swillf     kdb5_dal_handle *dal_handle;
17374960Swillf 
17384960Swillf         if (!k5db2_inited(kcontext))
17394960Swillf 	return KRB5_KDB_DBNOTINITED;
17404960Swillf 
17414960Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
17424960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
17434960Swillf 
17444960Swillf 
17454960Swillf     switch (option) {
17464960Swillf     case KRB5_KDB_OPT_SET_DB_NAME:
17474960Swillf 	status = krb5_db2_db_set_name(kcontext, (char *) value, db_ctx->tempdb);
17484960Swillf 	break;
17494960Swillf 
17504960Swillf     case KRB5_KDB_OPT_SET_LOCK_MODE:
17514960Swillf 	oldval = krb5_db2_db_set_lockmode(kcontext, *((krb5_boolean *) value));
17524960Swillf 	*((krb5_boolean *) value) = oldval;
17534960Swillf 	break;
17544960Swillf 
17554960Swillf     default:
17564960Swillf 	status = -1;		/* TBD */
17574960Swillf 	break;
17584960Swillf     }
17594960Swillf 
17604960Swillf     return status;
17614960Swillf }
17624960Swillf 
17634960Swillf void   *
krb5_db2_alloc(krb5_context kcontext,void * ptr,size_t size)17644960Swillf krb5_db2_alloc(krb5_context kcontext, void *ptr, size_t size)
17654960Swillf {
17664960Swillf     return realloc(ptr, size);
17674960Swillf }
17684960Swillf 
17694960Swillf void
krb5_db2_free(krb5_context kcontext,void * ptr)17704960Swillf krb5_db2_free(krb5_context kcontext, void *ptr)
17714960Swillf {
17724960Swillf     free(ptr);
17734960Swillf }
17744960Swillf 
17754960Swillf /* policy functions */
17764960Swillf krb5_error_code
krb5_db2_create_policy(krb5_context kcontext,osa_policy_ent_t policy)17774960Swillf krb5_db2_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
17784960Swillf {
17794960Swillf     kdb5_dal_handle *dal_handle;
17804960Swillf     krb5_db2_context *dbc;
17814960Swillf 
17824960Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
17834960Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
17844960Swillf 
17854960Swillf     return osa_adb_create_policy(dbc->policy_db, policy);
17864960Swillf }
17874960Swillf 
17884960Swillf krb5_error_code
krb5_db2_get_policy(krb5_context kcontext,char * name,osa_policy_ent_t * policy,int * cnt)17894960Swillf krb5_db2_get_policy(krb5_context kcontext,
17904960Swillf 		    char *name, osa_policy_ent_t * policy, int *cnt)
17914960Swillf {
17924960Swillf     kdb5_dal_handle *dal_handle;
17934960Swillf     krb5_db2_context *dbc;
17944960Swillf 
17954960Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
17964960Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
17974960Swillf 
17984960Swillf     return osa_adb_get_policy(dbc->policy_db, name, policy, cnt);
17994960Swillf }
18004960Swillf 
18014960Swillf krb5_error_code
krb5_db2_put_policy(krb5_context kcontext,osa_policy_ent_t policy)18024960Swillf krb5_db2_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
18034960Swillf {
18044960Swillf     kdb5_dal_handle *dal_handle;
18054960Swillf     krb5_db2_context *dbc;
18064960Swillf 
18074960Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
18084960Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
18094960Swillf 
18104960Swillf     return osa_adb_put_policy(dbc->policy_db, policy);
18114960Swillf }
18124960Swillf 
18134960Swillf krb5_error_code
krb5_db2_iter_policy(krb5_context kcontext,char * match_entry,osa_adb_iter_policy_func func,void * data)18144960Swillf krb5_db2_iter_policy(krb5_context kcontext,
18154960Swillf 		     char *match_entry,
18164960Swillf 		     osa_adb_iter_policy_func func, void *data)
18174960Swillf {
18184960Swillf     kdb5_dal_handle *dal_handle;
18194960Swillf     krb5_db2_context *dbc;
18204960Swillf 
18214960Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
18224960Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
18234960Swillf 
18244960Swillf     return osa_adb_iter_policy(dbc->policy_db, func, data);
18254960Swillf }
18264960Swillf 
18274960Swillf krb5_error_code
krb5_db2_delete_policy(krb5_context kcontext,char * policy)18284960Swillf krb5_db2_delete_policy(krb5_context kcontext, char *policy)
18294960Swillf {
18304960Swillf     kdb5_dal_handle *dal_handle;
18314960Swillf     krb5_db2_context *dbc;
18324960Swillf 
18334960Swillf     dal_handle = (kdb5_dal_handle *) kcontext->db_context;
18344960Swillf     dbc = (krb5_db2_context *) dal_handle->db_context;
18354960Swillf 
18364960Swillf     return osa_adb_destroy_policy(dbc->policy_db, policy);
18374960Swillf }
18384960Swillf 
18394960Swillf void
krb5_db2_free_policy(krb5_context kcontext,osa_policy_ent_t entry)18404960Swillf krb5_db2_free_policy(krb5_context kcontext, osa_policy_ent_t entry)
18414960Swillf {
18424960Swillf     osa_free_policy_ent(entry);
18434960Swillf }
18444960Swillf 
18454960Swillf 
18464960Swillf /* */
18474960Swillf 
18484960Swillf krb5_error_code
krb5_db2_promote_db(krb5_context kcontext,char * conf_section,char ** db_args)18494960Swillf krb5_db2_promote_db(krb5_context kcontext, char *conf_section, char **db_args)
18504960Swillf {
18514960Swillf     krb5_error_code status = 0;
18524960Swillf     char *db_name = NULL;
18534960Swillf     char *temp_db_name = NULL;
18544960Swillf 
18554960Swillf     krb5_clear_error_message (kcontext);
18564960Swillf 
18574960Swillf     {
18584960Swillf 	kdb5_dal_handle *dal_handle = kcontext->db_context;
18594960Swillf 	krb5_db2_context *db_ctx = dal_handle->db_context;
18604960Swillf 	db_name = strdup(db_ctx->db_name);
18614960Swillf 	if (db_name == NULL) {
18624960Swillf 	    status = ENOMEM;
18634960Swillf 	    goto clean_n_exit;
18644960Swillf 	}
18654960Swillf     }
18664960Swillf 
18674960Swillf     assert(kcontext->db_context != NULL);
18684960Swillf     temp_db_name = gen_dbsuffix(db_name, "~");
18694960Swillf     if (temp_db_name == NULL) {
18704960Swillf 	status = ENOMEM;
18714960Swillf 	goto clean_n_exit;
18724960Swillf     }
18734960Swillf 
18744960Swillf     status = krb5_db2_db_rename (kcontext, temp_db_name, db_name);
18754960Swillf 
18764960Swillf clean_n_exit:
18774960Swillf     if (db_name)
18784960Swillf 	free(db_name);
18794960Swillf     if (temp_db_name)
18804960Swillf 	free(temp_db_name);
18814960Swillf     return status;
18824960Swillf }
18834960Swillf 
18844960Swillf /* Retrieved from pre-DAL code base.  */
18854960Swillf /*
18864960Swillf  * "Atomically" rename the database in a way that locks out read
18874960Swillf  * access in the middle of the rename.
18884960Swillf  *
18894960Swillf  * Not perfect; if we crash in the middle of an update, we don't
18904960Swillf  * necessarily know to complete the transaction the rename, but...
18914960Swillf  *
18924960Swillf  * Since the rename operation happens outside the init/fini bracket, we
18934960Swillf  * have to go through the same stuff that we went through up in db_destroy.
18944960Swillf  */
18954960Swillf krb5_error_code
krb5_db2_db_rename(context,from,to)18964960Swillf krb5_db2_db_rename(context, from, to)
18974960Swillf     krb5_context context;
18984960Swillf     char *from;
18994960Swillf     char *to;
19004960Swillf {
19014960Swillf     char *fromok;
19024960Swillf     krb5_error_code retval;
19034960Swillf     krb5_db2_context *s_context, *db_ctx;
19044960Swillf     kdb5_dal_handle *dal_handle = context->db_context;
19056426Smp153739 
19064960Swillf     s_context = dal_handle->db_context;
19074960Swillf     dal_handle->db_context = NULL;
19084960Swillf     if ((retval = k5db2_init_context(context)))
19094960Swillf 	return retval;
19104960Swillf     db_ctx = (krb5_db2_context *) dal_handle->db_context;
19114960Swillf 
19124960Swillf     /*
19134960Swillf      * Create the database if it does not already exist; the
19144960Swillf      * files must exist because krb5_db2_db_lock, called below,
19154960Swillf      * will fail otherwise.
19164960Swillf      */
19174960Swillf     {
19184960Swillf 	struct stat statbuf;
19194960Swillf 
19204960Swillf 	if (stat(to, &statbuf) == -1) {
19214960Swillf 	    if (errno == ENOENT) {
19224960Swillf 		retval = krb5_db2_db_create(context, to,
19234960Swillf 					    KRB5_KDB_CREATE_BTREE);
19244960Swillf 		if (retval)
19254960Swillf 		    goto errout;
19264960Swillf 	    }
19274960Swillf 	    else {
19284960Swillf 		/*
19294960Swillf 		 * XXX assuming we should bail if there is some other stat error
19304960Swillf 		 */
19314960Swillf 		retval = errno;
19324960Swillf 		goto errout;
19334960Swillf 	    }
19344960Swillf 	}
19354960Swillf     }
19364960Swillf     /*
19374960Swillf      * Set the database to the target, so that other processes sharing
19384960Swillf      * the target will stop their activity, and notice the new database.
19394960Swillf      */
19404960Swillf     retval = krb5_db2_db_set_name(context, to, 0);
19414960Swillf     if (retval)
19424960Swillf 	goto errout;
19434960Swillf 
19444960Swillf     retval = krb5_db2_db_init(context);
19454960Swillf     if (retval)
19464960Swillf 	goto errout;
19474960Swillf 
19484960Swillf     /* XXX WAF this needs to be redone (not lock safe)!!! */
19494960Swillf     {
19504960Swillf 	/* Ugly brute force hack.
19514960Swillf 
19524960Swillf 	   Should be going through nice friendly helper routines for
19534960Swillf 	   this, but it's a mess of jumbled so-called interfaces right
19544960Swillf 	   now.  */
19554960Swillf 	char    policy[2048], new_policy[2048];
19564960Swillf 	assert (strlen(db_ctx->db_name) < 2000);
19574960Swillf 	/*LINTED*/
19584960Swillf 	sprintf(policy, "%s.kadm5", db_ctx->db_name);
19594960Swillf 	/*LINTED*/
19604960Swillf 	sprintf(new_policy, "%s~.kadm5", db_ctx->db_name);
19614960Swillf 	if (0 != rename(new_policy, policy)) {
19624960Swillf 	    retval = errno;
19634960Swillf 	    goto errout;
19644960Swillf 	}
19654960Swillf 	strcat(new_policy, ".lock");
19664960Swillf 	(void) unlink(new_policy);
19674960Swillf     }
19684960Swillf 
19694960Swillf     retval = krb5_db2_db_get_age(context, NULL, &db_ctx->db_lf_time);
19704960Swillf     if (retval)
19714960Swillf 	goto errout;
19724960Swillf 
19734960Swillf     fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
19744960Swillf     if (fromok == NULL) {
19754960Swillf 	retval = ENOMEM;
19764960Swillf 	goto errout;
19774960Swillf     }
19784960Swillf 
19794960Swillf     if ((retval = krb5_db2_db_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
19804960Swillf 	goto errfromok;
19814960Swillf 
19824960Swillf     if ((retval = krb5_db2_db_start_update(context)))
19834960Swillf 	goto errfromok;
19844960Swillf 
19854960Swillf     if (rename(from, to)) {
19864960Swillf 	retval = errno;
19874960Swillf 	goto errfromok;
19884960Swillf     }
19894960Swillf     if (unlink(fromok)) {
19904960Swillf 	retval = errno;
19914960Swillf 	goto errfromok;
19924960Swillf     }
19934960Swillf     retval = krb5_db2_db_end_update(context);
19944960Swillf errfromok:
19954960Swillf     free_dbsuffix(fromok);
19964960Swillf errout:
19974960Swillf     if (dal_handle->db_context) {
19984960Swillf 	if (db_ctx->db_lf_file >= 0) {
19994960Swillf 	    krb5_db2_db_unlock(context);
20004960Swillf 	    close(db_ctx->db_lf_file);
20014960Swillf 	}
20024960Swillf 	k5db2_clear_context((krb5_db2_context *) dal_handle->db_context);
20034960Swillf 	free(dal_handle->db_context);
20044960Swillf     }
20054960Swillf 
20064960Swillf     dal_handle->db_context = s_context;
20074960Swillf     (void) krb5_db2_db_unlock(context);	/* unlock saved context db */
20084960Swillf 
20094960Swillf     return retval;
20104960Swillf }
20116426Smp153739 
20126426Smp153739 const char *
krb5_db2_errcode_2_string(krb5_context kcontext,long err_code)20136426Smp153739 krb5_db2_errcode_2_string(krb5_context kcontext, long err_code)
20146426Smp153739 {
20156426Smp153739     return krb5_get_error_message(kcontext, err_code);
20166426Smp153739 }
20176426Smp153739 
20186426Smp153739 void
krb5_db2_release_errcode_string(krb5_context kcontext,const char * msg)20196426Smp153739 krb5_db2_release_errcode_string(krb5_context kcontext, const char *msg)
20206426Smp153739 {
20216426Smp153739     krb5_free_error_message(kcontext, msg);
20226426Smp153739 }
20236426Smp153739 
20246426Smp153739 
20256426Smp153739 /*
20266426Smp153739  * Solaris Kerberos:
20276426Smp153739  * Similar to the ldap plugin.
20286426Smp153739  */
20296426Smp153739 static void
krb5_db2_prepend_err_str(krb5_context ctx,const char * str,krb5_error_code err,krb5_error_code oerr)20306426Smp153739 krb5_db2_prepend_err_str(krb5_context ctx, const char *str, krb5_error_code err,
20316426Smp153739     krb5_error_code oerr) {
20326426Smp153739 	const char *omsg;
20336426Smp153739 	if (oerr == 0)
20346426Smp153739 		oerr = err;
20356426Smp153739 	omsg = krb5_get_error_message (ctx, err);
20366426Smp153739 	krb5_set_error_message (ctx, err, "%s %s", str, omsg);
20376426Smp153739 	krb5_free_error_message(ctx, omsg);
20386426Smp153739 }
20396426Smp153739 
2040