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