1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* plugins/kdb/db2/kdb_db2.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert * Copyright 1997,2006,2007-2009 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert * All Rights Reserved.
6*7f2fe78bSCy Schubert *
7*7f2fe78bSCy Schubert * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert * require a specific license from the United States Government.
9*7f2fe78bSCy Schubert * It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert * export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert *
12*7f2fe78bSCy Schubert * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert * permission. Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert * this software for any purpose. It is provided "as is" without express
24*7f2fe78bSCy Schubert * or implied warranty.
25*7f2fe78bSCy Schubert *
26*7f2fe78bSCy Schubert */
27*7f2fe78bSCy Schubert
28*7f2fe78bSCy Schubert /*
29*7f2fe78bSCy Schubert * Copyright (C) 1998 by the FundsXpress, INC.
30*7f2fe78bSCy Schubert *
31*7f2fe78bSCy Schubert * All rights reserved.
32*7f2fe78bSCy Schubert *
33*7f2fe78bSCy Schubert * Export of this software from the United States of America may require
34*7f2fe78bSCy Schubert * a specific license from the United States Government. It is the
35*7f2fe78bSCy Schubert * responsibility of any person or organization contemplating export to
36*7f2fe78bSCy Schubert * obtain such a license before exporting.
37*7f2fe78bSCy Schubert *
38*7f2fe78bSCy Schubert * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
39*7f2fe78bSCy Schubert * distribute this software and its documentation for any purpose and
40*7f2fe78bSCy Schubert * without fee is hereby granted, provided that the above copyright
41*7f2fe78bSCy Schubert * notice appear in all copies and that both that copyright notice and
42*7f2fe78bSCy Schubert * this permission notice appear in supporting documentation, and that
43*7f2fe78bSCy Schubert * the name of FundsXpress. not be used in advertising or publicity pertaining
44*7f2fe78bSCy Schubert * to distribution of the software without specific, written prior
45*7f2fe78bSCy Schubert * permission. FundsXpress makes no representations about the suitability of
46*7f2fe78bSCy Schubert * this software for any purpose. It is provided "as is" without express
47*7f2fe78bSCy Schubert * or implied warranty.
48*7f2fe78bSCy Schubert *
49*7f2fe78bSCy Schubert * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
50*7f2fe78bSCy Schubert * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
51*7f2fe78bSCy Schubert * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
52*7f2fe78bSCy Schubert */
53*7f2fe78bSCy Schubert
54*7f2fe78bSCy Schubert #include "k5-int.h"
55*7f2fe78bSCy Schubert
56*7f2fe78bSCy Schubert #if HAVE_UNISTD_H
57*7f2fe78bSCy Schubert #include <unistd.h>
58*7f2fe78bSCy Schubert #endif
59*7f2fe78bSCy Schubert
60*7f2fe78bSCy Schubert #include <db.h>
61*7f2fe78bSCy Schubert #include <stdio.h>
62*7f2fe78bSCy Schubert #include <errno.h>
63*7f2fe78bSCy Schubert #include <utime.h>
64*7f2fe78bSCy Schubert #include "kdb5.h"
65*7f2fe78bSCy Schubert #include "kdb_db2.h"
66*7f2fe78bSCy Schubert #include "kdb_xdr.h"
67*7f2fe78bSCy Schubert #include "policy_db.h"
68*7f2fe78bSCy Schubert
69*7f2fe78bSCy Schubert #define KDB_DB2_DATABASE_NAME "database_name"
70*7f2fe78bSCy Schubert
71*7f2fe78bSCy Schubert #define SUFFIX_DB ""
72*7f2fe78bSCy Schubert #define SUFFIX_LOCK ".ok"
73*7f2fe78bSCy Schubert #define SUFFIX_POLICY ".kadm5"
74*7f2fe78bSCy Schubert #define SUFFIX_POLICY_LOCK ".kadm5.lock"
75*7f2fe78bSCy Schubert
76*7f2fe78bSCy Schubert /*
77*7f2fe78bSCy Schubert * Locking:
78*7f2fe78bSCy Schubert *
79*7f2fe78bSCy Schubert * There are two distinct locking protocols used. One is designed to
80*7f2fe78bSCy Schubert * lock against processes (the admin_server, for one) which make
81*7f2fe78bSCy Schubert * incremental changes to the database; the other is designed to lock
82*7f2fe78bSCy Schubert * against utilities (kdb5_edit, kpropd, kdb5_convert) which replace the
83*7f2fe78bSCy Schubert * entire database in one fell swoop.
84*7f2fe78bSCy Schubert *
85*7f2fe78bSCy Schubert * The first locking protocol is implemented using flock() in the
86*7f2fe78bSCy Schubert * krb_dbl_lock() and krb_dbl_unlock routines.
87*7f2fe78bSCy Schubert *
88*7f2fe78bSCy Schubert * The second locking protocol is necessary because DBM "files" are
89*7f2fe78bSCy Schubert * actually implemented as two separate files, and it is impossible to
90*7f2fe78bSCy Schubert * atomically rename two files simultaneously. It assumes that the
91*7f2fe78bSCy Schubert * database is replaced only very infrequently in comparison to the time
92*7f2fe78bSCy Schubert * needed to do a database read operation.
93*7f2fe78bSCy Schubert *
94*7f2fe78bSCy Schubert * A third file is used as a "version" semaphore; the modification
95*7f2fe78bSCy Schubert * time of this file is the "version number" of the database.
96*7f2fe78bSCy Schubert * At the start of a read operation, the reader checks the version
97*7f2fe78bSCy Schubert * number; at the end of the read operation, it checks again. If the
98*7f2fe78bSCy Schubert * version number changed, or if the semaphore was nonexistent at
99*7f2fe78bSCy Schubert * either time, the reader sleeps for a second to let things
100*7f2fe78bSCy Schubert * stabilize, and then tries again; if it does not succeed after
101*7f2fe78bSCy Schubert * KRB5_DBM_MAX_RETRY attempts, it gives up.
102*7f2fe78bSCy Schubert *
103*7f2fe78bSCy Schubert * On update, the semaphore file is deleted (if it exists) before any
104*7f2fe78bSCy Schubert * update takes place; at the end of the update, it is replaced, with
105*7f2fe78bSCy Schubert * a version number strictly greater than the version number which
106*7f2fe78bSCy Schubert * existed at the start of the update.
107*7f2fe78bSCy Schubert *
108*7f2fe78bSCy Schubert * If the system crashes in the middle of an update, the semaphore
109*7f2fe78bSCy Schubert * file is not automatically created on reboot; this is a feature, not
110*7f2fe78bSCy Schubert * a bug, since the database may be inconsistent. Note that the
111*7f2fe78bSCy Schubert * absence of a semaphore file does not prevent another _update_ from
112*7f2fe78bSCy Schubert * taking place later. Database replacements take place automatically
113*7f2fe78bSCy Schubert * only on replica servers; a crash in the middle of an update will be
114*7f2fe78bSCy Schubert * fixed by the next propagation. A crash in the middle of an on the
115*7f2fe78bSCy Schubert * master would be somewhat more serious, but this would likely be
116*7f2fe78bSCy Schubert * noticed by an administrator, who could fix the problem and retry
117*7f2fe78bSCy Schubert * the operation.
118*7f2fe78bSCy Schubert */
119*7f2fe78bSCy Schubert
120*7f2fe78bSCy Schubert /* Evaluate to true if the krb5_context c contains an initialized db2
121*7f2fe78bSCy Schubert * context. */
122*7f2fe78bSCy Schubert #define inited(c) ((c)->dal_handle->db_context && \
123*7f2fe78bSCy Schubert ((krb5_db2_context *)(c)->dal_handle->db_context)-> \
124*7f2fe78bSCy Schubert db_inited)
125*7f2fe78bSCy Schubert
126*7f2fe78bSCy Schubert static krb5_error_code
get_db_opt(char * input,char ** opt,char ** val)127*7f2fe78bSCy Schubert get_db_opt(char *input, char **opt, char **val)
128*7f2fe78bSCy Schubert {
129*7f2fe78bSCy Schubert char *pos = strchr(input, '=');
130*7f2fe78bSCy Schubert if (pos == NULL) {
131*7f2fe78bSCy Schubert *opt = NULL;
132*7f2fe78bSCy Schubert *val = strdup(input);
133*7f2fe78bSCy Schubert if (*val == NULL) {
134*7f2fe78bSCy Schubert return ENOMEM;
135*7f2fe78bSCy Schubert }
136*7f2fe78bSCy Schubert } else {
137*7f2fe78bSCy Schubert *opt = malloc((pos - input) + 1);
138*7f2fe78bSCy Schubert *val = strdup(pos + 1);
139*7f2fe78bSCy Schubert if (!*opt || !*val) {
140*7f2fe78bSCy Schubert free(*opt);
141*7f2fe78bSCy Schubert *opt = NULL;
142*7f2fe78bSCy Schubert free(*val);
143*7f2fe78bSCy Schubert *val = NULL;
144*7f2fe78bSCy Schubert return ENOMEM;
145*7f2fe78bSCy Schubert }
146*7f2fe78bSCy Schubert memcpy(*opt, input, pos - input);
147*7f2fe78bSCy Schubert (*opt)[pos - input] = '\0';
148*7f2fe78bSCy Schubert }
149*7f2fe78bSCy Schubert return (0);
150*7f2fe78bSCy Schubert
151*7f2fe78bSCy Schubert }
152*7f2fe78bSCy Schubert
153*7f2fe78bSCy Schubert /* Restore dbctx to the uninitialized state. */
154*7f2fe78bSCy Schubert static void
ctx_clear(krb5_db2_context * dbc)155*7f2fe78bSCy Schubert ctx_clear(krb5_db2_context *dbc)
156*7f2fe78bSCy Schubert {
157*7f2fe78bSCy Schubert /*
158*7f2fe78bSCy Schubert * Free any dynamically allocated memory. File descriptors and locks
159*7f2fe78bSCy Schubert * are the caller's problem.
160*7f2fe78bSCy Schubert */
161*7f2fe78bSCy Schubert free(dbc->db_lf_name);
162*7f2fe78bSCy Schubert free(dbc->db_name);
163*7f2fe78bSCy Schubert /*
164*7f2fe78bSCy Schubert * Clear the structure and reset the defaults.
165*7f2fe78bSCy Schubert */
166*7f2fe78bSCy Schubert memset(dbc, 0, sizeof(krb5_db2_context));
167*7f2fe78bSCy Schubert dbc->db = NULL;
168*7f2fe78bSCy Schubert dbc->db_lf_name = NULL;
169*7f2fe78bSCy Schubert dbc->db_lf_file = -1;
170*7f2fe78bSCy Schubert dbc->db_name = NULL;
171*7f2fe78bSCy Schubert dbc->db_nb_locks = FALSE;
172*7f2fe78bSCy Schubert dbc->tempdb = FALSE;
173*7f2fe78bSCy Schubert }
174*7f2fe78bSCy Schubert
175*7f2fe78bSCy Schubert /* Set *dbc_out to the db2 database context for context. If one does not
176*7f2fe78bSCy Schubert * exist, create one in the uninitialized state. */
177*7f2fe78bSCy Schubert static krb5_error_code
ctx_get(krb5_context context,krb5_db2_context ** dbc_out)178*7f2fe78bSCy Schubert ctx_get(krb5_context context, krb5_db2_context **dbc_out)
179*7f2fe78bSCy Schubert {
180*7f2fe78bSCy Schubert krb5_db2_context *dbc;
181*7f2fe78bSCy Schubert kdb5_dal_handle *dal_handle;
182*7f2fe78bSCy Schubert
183*7f2fe78bSCy Schubert dal_handle = context->dal_handle;
184*7f2fe78bSCy Schubert
185*7f2fe78bSCy Schubert if (dal_handle->db_context == NULL) {
186*7f2fe78bSCy Schubert dbc = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
187*7f2fe78bSCy Schubert if (dbc == NULL)
188*7f2fe78bSCy Schubert return ENOMEM;
189*7f2fe78bSCy Schubert else {
190*7f2fe78bSCy Schubert memset(dbc, 0, sizeof(krb5_db2_context));
191*7f2fe78bSCy Schubert ctx_clear(dbc);
192*7f2fe78bSCy Schubert dal_handle->db_context = dbc;
193*7f2fe78bSCy Schubert }
194*7f2fe78bSCy Schubert }
195*7f2fe78bSCy Schubert *dbc_out = dal_handle->db_context;
196*7f2fe78bSCy Schubert return 0;
197*7f2fe78bSCy Schubert }
198*7f2fe78bSCy Schubert
199*7f2fe78bSCy Schubert /* Using db_args and the profile, initialize the configurable parameters of the
200*7f2fe78bSCy Schubert * DB context inside context. */
201*7f2fe78bSCy Schubert static krb5_error_code
configure_context(krb5_context context,char * conf_section,char ** db_args)202*7f2fe78bSCy Schubert configure_context(krb5_context context, char *conf_section, char **db_args)
203*7f2fe78bSCy Schubert {
204*7f2fe78bSCy Schubert krb5_error_code status;
205*7f2fe78bSCy Schubert krb5_db2_context *dbc;
206*7f2fe78bSCy Schubert char **t_ptr, *opt = NULL, *val = NULL, *pval = NULL;
207*7f2fe78bSCy Schubert profile_t profile = KRB5_DB_GET_PROFILE(context);
208*7f2fe78bSCy Schubert int bval;
209*7f2fe78bSCy Schubert
210*7f2fe78bSCy Schubert status = ctx_get(context, &dbc);
211*7f2fe78bSCy Schubert if (status != 0)
212*7f2fe78bSCy Schubert return status;
213*7f2fe78bSCy Schubert
214*7f2fe78bSCy Schubert /* Allow unlockiter to be overridden by command line db_args. */
215*7f2fe78bSCy Schubert status = profile_get_boolean(profile, KDB_MODULE_SECTION, conf_section,
216*7f2fe78bSCy Schubert KRB5_CONF_UNLOCKITER, FALSE, &bval);
217*7f2fe78bSCy Schubert if (status != 0)
218*7f2fe78bSCy Schubert goto cleanup;
219*7f2fe78bSCy Schubert dbc->unlockiter = bval;
220*7f2fe78bSCy Schubert
221*7f2fe78bSCy Schubert for (t_ptr = db_args; t_ptr && *t_ptr; t_ptr++) {
222*7f2fe78bSCy Schubert free(opt);
223*7f2fe78bSCy Schubert free(val);
224*7f2fe78bSCy Schubert status = get_db_opt(*t_ptr, &opt, &val);
225*7f2fe78bSCy Schubert if (opt && !strcmp(opt, "dbname")) {
226*7f2fe78bSCy Schubert dbc->db_name = strdup(val);
227*7f2fe78bSCy Schubert if (dbc->db_name == NULL) {
228*7f2fe78bSCy Schubert status = ENOMEM;
229*7f2fe78bSCy Schubert goto cleanup;
230*7f2fe78bSCy Schubert }
231*7f2fe78bSCy Schubert }
232*7f2fe78bSCy Schubert else if (!opt && !strcmp(val, "temporary")) {
233*7f2fe78bSCy Schubert dbc->tempdb = 1;
234*7f2fe78bSCy Schubert } else if (!opt && !strcmp(val, "merge_nra")) {
235*7f2fe78bSCy Schubert ;
236*7f2fe78bSCy Schubert } else if (opt && !strcmp(opt, "hash")) {
237*7f2fe78bSCy Schubert dbc->hashfirst = TRUE;
238*7f2fe78bSCy Schubert } else if (!opt && !strcmp(val, "unlockiter")) {
239*7f2fe78bSCy Schubert dbc->unlockiter = TRUE;
240*7f2fe78bSCy Schubert } else if (!opt && !strcmp(val, "lockiter")) {
241*7f2fe78bSCy Schubert dbc->unlockiter = FALSE;
242*7f2fe78bSCy Schubert } else {
243*7f2fe78bSCy Schubert status = EINVAL;
244*7f2fe78bSCy Schubert k5_setmsg(context, status,
245*7f2fe78bSCy Schubert _("Unsupported argument \"%s\" for db2"),
246*7f2fe78bSCy Schubert opt ? opt : val);
247*7f2fe78bSCy Schubert goto cleanup;
248*7f2fe78bSCy Schubert }
249*7f2fe78bSCy Schubert }
250*7f2fe78bSCy Schubert
251*7f2fe78bSCy Schubert if (dbc->db_name == NULL) {
252*7f2fe78bSCy Schubert /* Check for database_name in the db_module section. */
253*7f2fe78bSCy Schubert status = profile_get_string(profile, KDB_MODULE_SECTION, conf_section,
254*7f2fe78bSCy Schubert KDB_DB2_DATABASE_NAME, NULL, &pval);
255*7f2fe78bSCy Schubert if (status == 0 && pval == NULL) {
256*7f2fe78bSCy Schubert /* For compatibility, check for database_name in the realm. */
257*7f2fe78bSCy Schubert status = profile_get_string(profile, KDB_REALM_SECTION,
258*7f2fe78bSCy Schubert KRB5_DB_GET_REALM(context),
259*7f2fe78bSCy Schubert KDB_DB2_DATABASE_NAME,
260*7f2fe78bSCy Schubert DEFAULT_KDB_FILE, &pval);
261*7f2fe78bSCy Schubert }
262*7f2fe78bSCy Schubert if (status != 0)
263*7f2fe78bSCy Schubert goto cleanup;
264*7f2fe78bSCy Schubert dbc->db_name = strdup(pval);
265*7f2fe78bSCy Schubert }
266*7f2fe78bSCy Schubert
267*7f2fe78bSCy Schubert status = profile_get_boolean(profile, KDB_MODULE_SECTION, conf_section,
268*7f2fe78bSCy Schubert KRB5_CONF_DISABLE_LAST_SUCCESS, FALSE, &bval);
269*7f2fe78bSCy Schubert if (status != 0)
270*7f2fe78bSCy Schubert goto cleanup;
271*7f2fe78bSCy Schubert dbc->disable_last_success = bval;
272*7f2fe78bSCy Schubert
273*7f2fe78bSCy Schubert status = profile_get_boolean(profile, KDB_MODULE_SECTION, conf_section,
274*7f2fe78bSCy Schubert KRB5_CONF_DISABLE_LOCKOUT, FALSE, &bval);
275*7f2fe78bSCy Schubert if (status != 0)
276*7f2fe78bSCy Schubert goto cleanup;
277*7f2fe78bSCy Schubert dbc->disable_lockout = bval;
278*7f2fe78bSCy Schubert
279*7f2fe78bSCy Schubert cleanup:
280*7f2fe78bSCy Schubert free(opt);
281*7f2fe78bSCy Schubert free(val);
282*7f2fe78bSCy Schubert profile_release_string(pval);
283*7f2fe78bSCy Schubert return status;
284*7f2fe78bSCy Schubert }
285*7f2fe78bSCy Schubert
286*7f2fe78bSCy Schubert /*
287*7f2fe78bSCy Schubert * Set *out to one of the filenames used for the DB described by dbc. sfx
288*7f2fe78bSCy Schubert * should be one of SUFFIX_DB, SUFFIX_LOCK, SUFFIX_POLICY, or
289*7f2fe78bSCy Schubert * SUFFIX_POLICY_LOCK.
290*7f2fe78bSCy Schubert */
291*7f2fe78bSCy Schubert static krb5_error_code
ctx_dbsuffix(krb5_db2_context * dbc,const char * sfx,char ** out)292*7f2fe78bSCy Schubert ctx_dbsuffix(krb5_db2_context *dbc, const char *sfx, char **out)
293*7f2fe78bSCy Schubert {
294*7f2fe78bSCy Schubert char *result;
295*7f2fe78bSCy Schubert const char *tilde;
296*7f2fe78bSCy Schubert
297*7f2fe78bSCy Schubert *out = NULL;
298*7f2fe78bSCy Schubert tilde = dbc->tempdb ? "~" : "";
299*7f2fe78bSCy Schubert if (asprintf(&result, "%s%s%s", dbc->db_name, tilde, sfx) < 0)
300*7f2fe78bSCy Schubert return ENOMEM;
301*7f2fe78bSCy Schubert *out = result;
302*7f2fe78bSCy Schubert return 0;
303*7f2fe78bSCy Schubert }
304*7f2fe78bSCy Schubert
305*7f2fe78bSCy Schubert /* Generate all four files corresponding to dbc. */
306*7f2fe78bSCy Schubert static krb5_error_code
ctx_allfiles(krb5_db2_context * dbc,char ** dbname_out,char ** lockname_out,char ** polname_out,char ** plockname_out)307*7f2fe78bSCy Schubert ctx_allfiles(krb5_db2_context *dbc, char **dbname_out, char **lockname_out,
308*7f2fe78bSCy Schubert char **polname_out, char **plockname_out)
309*7f2fe78bSCy Schubert {
310*7f2fe78bSCy Schubert char *a = NULL, *b = NULL, *c = NULL, *d = NULL;
311*7f2fe78bSCy Schubert
312*7f2fe78bSCy Schubert *dbname_out = *lockname_out = *polname_out = *plockname_out = NULL;
313*7f2fe78bSCy Schubert if (ctx_dbsuffix(dbc, SUFFIX_DB, &a))
314*7f2fe78bSCy Schubert goto error;
315*7f2fe78bSCy Schubert if (ctx_dbsuffix(dbc, SUFFIX_LOCK, &b))
316*7f2fe78bSCy Schubert goto error;
317*7f2fe78bSCy Schubert if (ctx_dbsuffix(dbc, SUFFIX_POLICY, &c))
318*7f2fe78bSCy Schubert goto error;
319*7f2fe78bSCy Schubert if (ctx_dbsuffix(dbc, SUFFIX_POLICY_LOCK, &d))
320*7f2fe78bSCy Schubert goto error;
321*7f2fe78bSCy Schubert *dbname_out = a;
322*7f2fe78bSCy Schubert *lockname_out = b;
323*7f2fe78bSCy Schubert *polname_out = c;
324*7f2fe78bSCy Schubert *plockname_out = d;
325*7f2fe78bSCy Schubert return 0;
326*7f2fe78bSCy Schubert error:
327*7f2fe78bSCy Schubert free(a);
328*7f2fe78bSCy Schubert free(b);
329*7f2fe78bSCy Schubert free(c);
330*7f2fe78bSCy Schubert free(d);
331*7f2fe78bSCy Schubert return ENOMEM;
332*7f2fe78bSCy Schubert }
333*7f2fe78bSCy Schubert
334*7f2fe78bSCy Schubert /*
335*7f2fe78bSCy Schubert * Open the DB2 database described by dbc, using the specified flags and mode,
336*7f2fe78bSCy Schubert * and return the resulting handle. Try both hash and btree database types;
337*7f2fe78bSCy Schubert * dbc->hashfirst determines which is attempted first. If dbc->hashfirst
338*7f2fe78bSCy Schubert * indicated the wrong type, update it to indicate the correct type.
339*7f2fe78bSCy Schubert */
340*7f2fe78bSCy Schubert static krb5_error_code
open_db(krb5_context context,krb5_db2_context * dbc,int flags,int mode,DB ** db_out)341*7f2fe78bSCy Schubert open_db(krb5_context context, krb5_db2_context *dbc, int flags, int mode,
342*7f2fe78bSCy Schubert DB **db_out)
343*7f2fe78bSCy Schubert {
344*7f2fe78bSCy Schubert char *fname = NULL;
345*7f2fe78bSCy Schubert DB *db;
346*7f2fe78bSCy Schubert BTREEINFO bti;
347*7f2fe78bSCy Schubert HASHINFO hashi;
348*7f2fe78bSCy Schubert bti.flags = 0;
349*7f2fe78bSCy Schubert bti.cachesize = 0;
350*7f2fe78bSCy Schubert bti.psize = 4096;
351*7f2fe78bSCy Schubert bti.lorder = 0;
352*7f2fe78bSCy Schubert bti.minkeypage = 0;
353*7f2fe78bSCy Schubert bti.compare = NULL;
354*7f2fe78bSCy Schubert bti.prefix = NULL;
355*7f2fe78bSCy Schubert
356*7f2fe78bSCy Schubert *db_out = NULL;
357*7f2fe78bSCy Schubert
358*7f2fe78bSCy Schubert if (ctx_dbsuffix(dbc, SUFFIX_DB, &fname) != 0)
359*7f2fe78bSCy Schubert return ENOMEM;
360*7f2fe78bSCy Schubert
361*7f2fe78bSCy Schubert hashi.bsize = 4096;
362*7f2fe78bSCy Schubert hashi.cachesize = 0;
363*7f2fe78bSCy Schubert hashi.ffactor = 40;
364*7f2fe78bSCy Schubert hashi.hash = NULL;
365*7f2fe78bSCy Schubert hashi.lorder = 0;
366*7f2fe78bSCy Schubert hashi.nelem = 1;
367*7f2fe78bSCy Schubert
368*7f2fe78bSCy Schubert /* Try our best guess at the database type. */
369*7f2fe78bSCy Schubert db = dbopen(fname, flags, mode,
370*7f2fe78bSCy Schubert dbc->hashfirst ? DB_HASH : DB_BTREE,
371*7f2fe78bSCy Schubert dbc->hashfirst ? (void *) &hashi : (void *) &bti);
372*7f2fe78bSCy Schubert
373*7f2fe78bSCy Schubert if (db == NULL && IS_EFTYPE(errno)) {
374*7f2fe78bSCy Schubert db = dbopen(fname, flags, mode,
375*7f2fe78bSCy Schubert dbc->hashfirst ? DB_BTREE : DB_HASH,
376*7f2fe78bSCy Schubert dbc->hashfirst ? (void *) &bti : (void *) &hashi);
377*7f2fe78bSCy Schubert /* If that worked, update our guess for next time. */
378*7f2fe78bSCy Schubert if (db != NULL)
379*7f2fe78bSCy Schubert dbc->hashfirst = !dbc->hashfirst;
380*7f2fe78bSCy Schubert }
381*7f2fe78bSCy Schubert
382*7f2fe78bSCy Schubert /* Don't try unlocked iteration with a hash database. */
383*7f2fe78bSCy Schubert if (db != NULL && dbc->hashfirst)
384*7f2fe78bSCy Schubert dbc->unlockiter = FALSE;
385*7f2fe78bSCy Schubert
386*7f2fe78bSCy Schubert if (db == NULL) {
387*7f2fe78bSCy Schubert k5_prependmsg(context, errno, _("Cannot open DB2 database '%s'"),
388*7f2fe78bSCy Schubert fname);
389*7f2fe78bSCy Schubert }
390*7f2fe78bSCy Schubert
391*7f2fe78bSCy Schubert *db_out = db;
392*7f2fe78bSCy Schubert free(fname);
393*7f2fe78bSCy Schubert return (db == NULL) ? errno : 0;
394*7f2fe78bSCy Schubert }
395*7f2fe78bSCy Schubert
396*7f2fe78bSCy Schubert static krb5_error_code
ctx_unlock(krb5_context context,krb5_db2_context * dbc)397*7f2fe78bSCy Schubert ctx_unlock(krb5_context context, krb5_db2_context *dbc)
398*7f2fe78bSCy Schubert {
399*7f2fe78bSCy Schubert krb5_error_code retval, retval2;
400*7f2fe78bSCy Schubert DB *db;
401*7f2fe78bSCy Schubert
402*7f2fe78bSCy Schubert retval = osa_adb_release_lock(dbc->policy_db);
403*7f2fe78bSCy Schubert
404*7f2fe78bSCy Schubert if (!dbc->db_locks_held) /* lock already unlocked */
405*7f2fe78bSCy Schubert return KRB5_KDB_NOTLOCKED;
406*7f2fe78bSCy Schubert
407*7f2fe78bSCy Schubert db = dbc->db;
408*7f2fe78bSCy Schubert if (--(dbc->db_locks_held) == 0) {
409*7f2fe78bSCy Schubert db->close(db);
410*7f2fe78bSCy Schubert dbc->db = NULL;
411*7f2fe78bSCy Schubert dbc->db_lock_mode = 0;
412*7f2fe78bSCy Schubert
413*7f2fe78bSCy Schubert retval2 = krb5_lock_file(context, dbc->db_lf_file,
414*7f2fe78bSCy Schubert KRB5_LOCKMODE_UNLOCK);
415*7f2fe78bSCy Schubert if (retval2)
416*7f2fe78bSCy Schubert return retval2;
417*7f2fe78bSCy Schubert }
418*7f2fe78bSCy Schubert
419*7f2fe78bSCy Schubert /* We may be unlocking because osa_adb_get_lock() failed. */
420*7f2fe78bSCy Schubert if (retval == OSA_ADB_NOTLOCKED)
421*7f2fe78bSCy Schubert return 0;
422*7f2fe78bSCy Schubert return retval;
423*7f2fe78bSCy Schubert }
424*7f2fe78bSCy Schubert
425*7f2fe78bSCy Schubert static krb5_error_code
ctx_lock(krb5_context context,krb5_db2_context * dbc,int lockmode)426*7f2fe78bSCy Schubert ctx_lock(krb5_context context, krb5_db2_context *dbc, int lockmode)
427*7f2fe78bSCy Schubert {
428*7f2fe78bSCy Schubert krb5_error_code retval;
429*7f2fe78bSCy Schubert int kmode;
430*7f2fe78bSCy Schubert
431*7f2fe78bSCy Schubert if (lockmode == KRB5_DB_LOCKMODE_PERMANENT ||
432*7f2fe78bSCy Schubert lockmode == KRB5_DB_LOCKMODE_EXCLUSIVE)
433*7f2fe78bSCy Schubert kmode = KRB5_LOCKMODE_EXCLUSIVE;
434*7f2fe78bSCy Schubert else if (lockmode == KRB5_DB_LOCKMODE_SHARED)
435*7f2fe78bSCy Schubert kmode = KRB5_LOCKMODE_SHARED;
436*7f2fe78bSCy Schubert else
437*7f2fe78bSCy Schubert return EINVAL;
438*7f2fe78bSCy Schubert
439*7f2fe78bSCy Schubert if (dbc->db_locks_held == 0 || dbc->db_lock_mode < kmode) {
440*7f2fe78bSCy Schubert /* Acquire or upgrade the lock. */
441*7f2fe78bSCy Schubert retval = krb5_lock_file(context, dbc->db_lf_file, kmode);
442*7f2fe78bSCy Schubert /* Check if we tried to lock something not open for write. */
443*7f2fe78bSCy Schubert if (retval == EBADF && kmode == KRB5_LOCKMODE_EXCLUSIVE)
444*7f2fe78bSCy Schubert return KRB5_KDB_CANTLOCK_DB;
445*7f2fe78bSCy Schubert else if (retval == EACCES || retval == EAGAIN || retval == EWOULDBLOCK)
446*7f2fe78bSCy Schubert return KRB5_KDB_CANTLOCK_DB;
447*7f2fe78bSCy Schubert else if (retval)
448*7f2fe78bSCy Schubert return retval;
449*7f2fe78bSCy Schubert
450*7f2fe78bSCy Schubert /* Open the DB (or re-open it for read/write). */
451*7f2fe78bSCy Schubert if (dbc->db != NULL)
452*7f2fe78bSCy Schubert dbc->db->close(dbc->db);
453*7f2fe78bSCy Schubert retval = open_db(context, dbc,
454*7f2fe78bSCy Schubert kmode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR,
455*7f2fe78bSCy Schubert 0600, &dbc->db);
456*7f2fe78bSCy Schubert if (retval) {
457*7f2fe78bSCy Schubert dbc->db_locks_held = 0;
458*7f2fe78bSCy Schubert dbc->db_lock_mode = 0;
459*7f2fe78bSCy Schubert (void) osa_adb_release_lock(dbc->policy_db);
460*7f2fe78bSCy Schubert (void) krb5_lock_file(context, dbc->db_lf_file,
461*7f2fe78bSCy Schubert KRB5_LOCKMODE_UNLOCK);
462*7f2fe78bSCy Schubert return retval;
463*7f2fe78bSCy Schubert }
464*7f2fe78bSCy Schubert
465*7f2fe78bSCy Schubert dbc->db_lock_mode = kmode;
466*7f2fe78bSCy Schubert }
467*7f2fe78bSCy Schubert dbc->db_locks_held++;
468*7f2fe78bSCy Schubert
469*7f2fe78bSCy Schubert /* Acquire or upgrade the policy lock. */
470*7f2fe78bSCy Schubert retval = osa_adb_get_lock(dbc->policy_db, lockmode);
471*7f2fe78bSCy Schubert if (retval) {
472*7f2fe78bSCy Schubert (void) ctx_unlock(context, dbc);
473*7f2fe78bSCy Schubert if (retval == OSA_ADB_NOEXCL_PERM || retval == OSA_ADB_CANTLOCK_DB ||
474*7f2fe78bSCy Schubert retval == OSA_ADB_NOLOCKFILE)
475*7f2fe78bSCy Schubert retval = KRB5_KDB_CANTLOCK_DB;
476*7f2fe78bSCy Schubert }
477*7f2fe78bSCy Schubert return retval;
478*7f2fe78bSCy Schubert }
479*7f2fe78bSCy Schubert
480*7f2fe78bSCy Schubert /* Initialize the lock file and policy database fields of dbc. The db_name and
481*7f2fe78bSCy Schubert * tempdb fields must already be set. */
482*7f2fe78bSCy Schubert static krb5_error_code
ctx_init(krb5_db2_context * dbc)483*7f2fe78bSCy Schubert ctx_init(krb5_db2_context *dbc)
484*7f2fe78bSCy Schubert {
485*7f2fe78bSCy Schubert krb5_error_code retval;
486*7f2fe78bSCy Schubert char *polname = NULL, *plockname = NULL;
487*7f2fe78bSCy Schubert
488*7f2fe78bSCy Schubert retval = ctx_dbsuffix(dbc, SUFFIX_LOCK, &dbc->db_lf_name);
489*7f2fe78bSCy Schubert if (retval)
490*7f2fe78bSCy Schubert return retval;
491*7f2fe78bSCy Schubert
492*7f2fe78bSCy Schubert /*
493*7f2fe78bSCy Schubert * should be opened read/write so that write locking can work with
494*7f2fe78bSCy Schubert * POSIX systems
495*7f2fe78bSCy Schubert */
496*7f2fe78bSCy Schubert if ((dbc->db_lf_file = open(dbc->db_lf_name, O_RDWR, 0666)) < 0) {
497*7f2fe78bSCy Schubert if ((dbc->db_lf_file = open(dbc->db_lf_name, O_RDONLY, 0666)) < 0) {
498*7f2fe78bSCy Schubert retval = errno;
499*7f2fe78bSCy Schubert goto cleanup;
500*7f2fe78bSCy Schubert }
501*7f2fe78bSCy Schubert }
502*7f2fe78bSCy Schubert set_cloexec_fd(dbc->db_lf_file);
503*7f2fe78bSCy Schubert dbc->db_inited++;
504*7f2fe78bSCy Schubert
505*7f2fe78bSCy Schubert retval = ctx_dbsuffix(dbc, SUFFIX_POLICY, &polname);
506*7f2fe78bSCy Schubert if (retval)
507*7f2fe78bSCy Schubert goto cleanup;
508*7f2fe78bSCy Schubert retval = ctx_dbsuffix(dbc, SUFFIX_POLICY_LOCK, &plockname);
509*7f2fe78bSCy Schubert if (retval)
510*7f2fe78bSCy Schubert goto cleanup;
511*7f2fe78bSCy Schubert retval = osa_adb_init_db(&dbc->policy_db, polname, plockname,
512*7f2fe78bSCy Schubert OSA_ADB_POLICY_DB_MAGIC);
513*7f2fe78bSCy Schubert
514*7f2fe78bSCy Schubert cleanup:
515*7f2fe78bSCy Schubert free(polname);
516*7f2fe78bSCy Schubert free(plockname);
517*7f2fe78bSCy Schubert if (retval)
518*7f2fe78bSCy Schubert ctx_clear(dbc);
519*7f2fe78bSCy Schubert return retval;
520*7f2fe78bSCy Schubert }
521*7f2fe78bSCy Schubert
522*7f2fe78bSCy Schubert static void
ctx_fini(krb5_db2_context * dbc)523*7f2fe78bSCy Schubert ctx_fini(krb5_db2_context *dbc)
524*7f2fe78bSCy Schubert {
525*7f2fe78bSCy Schubert if (dbc->db_lf_file != -1)
526*7f2fe78bSCy Schubert (void) close(dbc->db_lf_file);
527*7f2fe78bSCy Schubert if (dbc->policy_db)
528*7f2fe78bSCy Schubert (void) osa_adb_fini_db(dbc->policy_db, OSA_ADB_POLICY_DB_MAGIC);
529*7f2fe78bSCy Schubert ctx_clear(dbc);
530*7f2fe78bSCy Schubert free(dbc);
531*7f2fe78bSCy Schubert }
532*7f2fe78bSCy Schubert
533*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_fini(krb5_context context)534*7f2fe78bSCy Schubert krb5_db2_fini(krb5_context context)
535*7f2fe78bSCy Schubert {
536*7f2fe78bSCy Schubert if (context->dal_handle->db_context != NULL) {
537*7f2fe78bSCy Schubert ctx_fini(context->dal_handle->db_context);
538*7f2fe78bSCy Schubert context->dal_handle->db_context = NULL;
539*7f2fe78bSCy Schubert }
540*7f2fe78bSCy Schubert return 0;
541*7f2fe78bSCy Schubert }
542*7f2fe78bSCy Schubert
543*7f2fe78bSCy Schubert /* Return successfully if the db2 name set in context can be opened. */
544*7f2fe78bSCy Schubert static krb5_error_code
check_openable(krb5_context context)545*7f2fe78bSCy Schubert check_openable(krb5_context context)
546*7f2fe78bSCy Schubert {
547*7f2fe78bSCy Schubert krb5_error_code retval;
548*7f2fe78bSCy Schubert DB *db;
549*7f2fe78bSCy Schubert krb5_db2_context *dbc;
550*7f2fe78bSCy Schubert
551*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
552*7f2fe78bSCy Schubert retval = open_db(context, dbc, O_RDONLY, 0, &db);
553*7f2fe78bSCy Schubert if (retval)
554*7f2fe78bSCy Schubert return retval;
555*7f2fe78bSCy Schubert db->close(db);
556*7f2fe78bSCy Schubert return 0;
557*7f2fe78bSCy Schubert }
558*7f2fe78bSCy Schubert
559*7f2fe78bSCy Schubert /*
560*7f2fe78bSCy Schubert * Return the last modification time of the database.
561*7f2fe78bSCy Schubert *
562*7f2fe78bSCy Schubert * Think about using fstat.
563*7f2fe78bSCy Schubert */
564*7f2fe78bSCy Schubert
565*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_get_age(krb5_context context,char * db_name,time_t * age)566*7f2fe78bSCy Schubert krb5_db2_get_age(krb5_context context, char *db_name, time_t *age)
567*7f2fe78bSCy Schubert {
568*7f2fe78bSCy Schubert krb5_db2_context *dbc;
569*7f2fe78bSCy Schubert struct stat st;
570*7f2fe78bSCy Schubert
571*7f2fe78bSCy Schubert if (!inited(context))
572*7f2fe78bSCy Schubert return (KRB5_KDB_DBNOTINITED);
573*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
574*7f2fe78bSCy Schubert
575*7f2fe78bSCy Schubert if (fstat(dbc->db_lf_file, &st) < 0)
576*7f2fe78bSCy Schubert *age = -1;
577*7f2fe78bSCy Schubert else
578*7f2fe78bSCy Schubert *age = st.st_mtime;
579*7f2fe78bSCy Schubert return 0;
580*7f2fe78bSCy Schubert }
581*7f2fe78bSCy Schubert
582*7f2fe78bSCy Schubert /* Try to update the timestamp on dbc's lockfile. */
583*7f2fe78bSCy Schubert static void
ctx_update_age(krb5_db2_context * dbc)584*7f2fe78bSCy Schubert ctx_update_age(krb5_db2_context *dbc)
585*7f2fe78bSCy Schubert {
586*7f2fe78bSCy Schubert struct stat st;
587*7f2fe78bSCy Schubert time_t now;
588*7f2fe78bSCy Schubert struct utimbuf utbuf;
589*7f2fe78bSCy Schubert
590*7f2fe78bSCy Schubert now = time((time_t *) NULL);
591*7f2fe78bSCy Schubert if (fstat(dbc->db_lf_file, &st) != 0)
592*7f2fe78bSCy Schubert return;
593*7f2fe78bSCy Schubert if (st.st_mtime >= now) {
594*7f2fe78bSCy Schubert utbuf.actime = st.st_mtime + 1;
595*7f2fe78bSCy Schubert utbuf.modtime = st.st_mtime + 1;
596*7f2fe78bSCy Schubert (void) utime(dbc->db_lf_name, &utbuf);
597*7f2fe78bSCy Schubert } else
598*7f2fe78bSCy Schubert (void) utime(dbc->db_lf_name, (struct utimbuf *) NULL);
599*7f2fe78bSCy Schubert }
600*7f2fe78bSCy Schubert
601*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_lock(krb5_context context,int lockmode)602*7f2fe78bSCy Schubert krb5_db2_lock(krb5_context context, int lockmode)
603*7f2fe78bSCy Schubert {
604*7f2fe78bSCy Schubert if (!inited(context))
605*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
606*7f2fe78bSCy Schubert return ctx_lock(context, context->dal_handle->db_context, lockmode);
607*7f2fe78bSCy Schubert }
608*7f2fe78bSCy Schubert
609*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_unlock(krb5_context context)610*7f2fe78bSCy Schubert krb5_db2_unlock(krb5_context context)
611*7f2fe78bSCy Schubert {
612*7f2fe78bSCy Schubert if (!inited(context))
613*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
614*7f2fe78bSCy Schubert return ctx_unlock(context, context->dal_handle->db_context);
615*7f2fe78bSCy Schubert }
616*7f2fe78bSCy Schubert
617*7f2fe78bSCy Schubert /* Zero out and unlink filename. */
618*7f2fe78bSCy Schubert static krb5_error_code
destroy_file(char * filename)619*7f2fe78bSCy Schubert destroy_file(char *filename)
620*7f2fe78bSCy Schubert {
621*7f2fe78bSCy Schubert struct stat statb;
622*7f2fe78bSCy Schubert int dowrite, j, nb, fd, retval;
623*7f2fe78bSCy Schubert off_t pos;
624*7f2fe78bSCy Schubert char buf[BUFSIZ], zbuf[BUFSIZ];
625*7f2fe78bSCy Schubert
626*7f2fe78bSCy Schubert fd = open(filename, O_RDWR, 0);
627*7f2fe78bSCy Schubert if (fd < 0)
628*7f2fe78bSCy Schubert return errno;
629*7f2fe78bSCy Schubert set_cloexec_fd(fd);
630*7f2fe78bSCy Schubert /* fstat() will probably not fail unless using a remote filesystem
631*7f2fe78bSCy Schubert * (which is inappropriate for the kerberos database) so this check
632*7f2fe78bSCy Schubert * is mostly paranoia. */
633*7f2fe78bSCy Schubert if (fstat(fd, &statb) == -1)
634*7f2fe78bSCy Schubert goto error;
635*7f2fe78bSCy Schubert /*
636*7f2fe78bSCy Schubert * Stroll through the file, reading in BUFSIZ chunks. If everything
637*7f2fe78bSCy Schubert * is zero, then we're done for that block, otherwise, zero the block.
638*7f2fe78bSCy Schubert * We would like to just blast through everything, but some DB
639*7f2fe78bSCy Schubert * implementations make holey files and writing data to the holes
640*7f2fe78bSCy Schubert * causes actual blocks to be allocated which is no good, since
641*7f2fe78bSCy Schubert * we're just about to unlink it anyways.
642*7f2fe78bSCy Schubert */
643*7f2fe78bSCy Schubert memset(zbuf, 0, BUFSIZ);
644*7f2fe78bSCy Schubert pos = 0;
645*7f2fe78bSCy Schubert while (pos < statb.st_size) {
646*7f2fe78bSCy Schubert dowrite = 0;
647*7f2fe78bSCy Schubert nb = read(fd, buf, BUFSIZ);
648*7f2fe78bSCy Schubert if (nb < 0)
649*7f2fe78bSCy Schubert goto error;
650*7f2fe78bSCy Schubert for (j = 0; j < nb; j++) {
651*7f2fe78bSCy Schubert if (buf[j] != '\0') {
652*7f2fe78bSCy Schubert dowrite = 1;
653*7f2fe78bSCy Schubert break;
654*7f2fe78bSCy Schubert }
655*7f2fe78bSCy Schubert }
656*7f2fe78bSCy Schubert /* For signedness */
657*7f2fe78bSCy Schubert j = nb;
658*7f2fe78bSCy Schubert if (dowrite) {
659*7f2fe78bSCy Schubert lseek(fd, pos, SEEK_SET);
660*7f2fe78bSCy Schubert nb = write(fd, zbuf, j);
661*7f2fe78bSCy Schubert if (nb < 0)
662*7f2fe78bSCy Schubert goto error;
663*7f2fe78bSCy Schubert }
664*7f2fe78bSCy Schubert pos += nb;
665*7f2fe78bSCy Schubert }
666*7f2fe78bSCy Schubert /* ??? Is fsync really needed? I don't know of any non-networked
667*7f2fe78bSCy Schubert * filesystem which will discard queued writes to disk if a file
668*7f2fe78bSCy Schubert * is deleted after it is closed. --jfc */
669*7f2fe78bSCy Schubert #ifndef NOFSYNC
670*7f2fe78bSCy Schubert fsync(fd);
671*7f2fe78bSCy Schubert #endif
672*7f2fe78bSCy Schubert close(fd);
673*7f2fe78bSCy Schubert
674*7f2fe78bSCy Schubert if (unlink(filename))
675*7f2fe78bSCy Schubert return errno;
676*7f2fe78bSCy Schubert return 0;
677*7f2fe78bSCy Schubert
678*7f2fe78bSCy Schubert error:
679*7f2fe78bSCy Schubert retval = errno;
680*7f2fe78bSCy Schubert close(fd);
681*7f2fe78bSCy Schubert return retval;
682*7f2fe78bSCy Schubert }
683*7f2fe78bSCy Schubert
684*7f2fe78bSCy Schubert /* Initialize dbc by locking and creating the DB. If the DB already exists,
685*7f2fe78bSCy Schubert * clear it out if dbc->tempdb is set; otherwise return EEXIST. */
686*7f2fe78bSCy Schubert static krb5_error_code
ctx_create_db(krb5_context context,krb5_db2_context * dbc)687*7f2fe78bSCy Schubert ctx_create_db(krb5_context context, krb5_db2_context *dbc)
688*7f2fe78bSCy Schubert {
689*7f2fe78bSCy Schubert krb5_error_code retval = 0;
690*7f2fe78bSCy Schubert char *dbname = NULL, *polname = NULL, *plockname = NULL;
691*7f2fe78bSCy Schubert
692*7f2fe78bSCy Schubert retval = ctx_allfiles(dbc, &dbname, &dbc->db_lf_name, &polname,
693*7f2fe78bSCy Schubert &plockname);
694*7f2fe78bSCy Schubert if (retval)
695*7f2fe78bSCy Schubert return retval;
696*7f2fe78bSCy Schubert
697*7f2fe78bSCy Schubert dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC,
698*7f2fe78bSCy Schubert 0600);
699*7f2fe78bSCy Schubert if (dbc->db_lf_file < 0) {
700*7f2fe78bSCy Schubert retval = errno;
701*7f2fe78bSCy Schubert goto cleanup;
702*7f2fe78bSCy Schubert }
703*7f2fe78bSCy Schubert retval = krb5_lock_file(context, dbc->db_lf_file, KRB5_LOCKMODE_EXCLUSIVE);
704*7f2fe78bSCy Schubert if (retval != 0)
705*7f2fe78bSCy Schubert goto cleanup;
706*7f2fe78bSCy Schubert set_cloexec_fd(dbc->db_lf_file);
707*7f2fe78bSCy Schubert dbc->db_lock_mode = KRB5_LOCKMODE_EXCLUSIVE;
708*7f2fe78bSCy Schubert dbc->db_locks_held = 1;
709*7f2fe78bSCy Schubert
710*7f2fe78bSCy Schubert if (dbc->tempdb) {
711*7f2fe78bSCy Schubert /* Temporary DBs are locked for their whole lifetime. Since we have
712*7f2fe78bSCy Schubert * the lock, any remnant files can be safely destroyed. */
713*7f2fe78bSCy Schubert (void) destroy_file(dbname);
714*7f2fe78bSCy Schubert (void) unlink(polname);
715*7f2fe78bSCy Schubert (void) unlink(plockname);
716*7f2fe78bSCy Schubert }
717*7f2fe78bSCy Schubert
718*7f2fe78bSCy Schubert retval = open_db(context, dbc, O_RDWR | O_CREAT | O_EXCL, 0600, &dbc->db);
719*7f2fe78bSCy Schubert if (retval)
720*7f2fe78bSCy Schubert goto cleanup;
721*7f2fe78bSCy Schubert
722*7f2fe78bSCy Schubert /* Create the policy database, initialize a handle to it, and lock it. */
723*7f2fe78bSCy Schubert retval = osa_adb_create_db(polname, plockname, OSA_ADB_POLICY_DB_MAGIC);
724*7f2fe78bSCy Schubert if (retval)
725*7f2fe78bSCy Schubert goto cleanup;
726*7f2fe78bSCy Schubert retval = osa_adb_init_db(&dbc->policy_db, polname, plockname,
727*7f2fe78bSCy Schubert OSA_ADB_POLICY_DB_MAGIC);
728*7f2fe78bSCy Schubert if (retval)
729*7f2fe78bSCy Schubert goto cleanup;
730*7f2fe78bSCy Schubert retval = osa_adb_get_lock(dbc->policy_db, KRB5_DB_LOCKMODE_EXCLUSIVE);
731*7f2fe78bSCy Schubert if (retval)
732*7f2fe78bSCy Schubert goto cleanup;
733*7f2fe78bSCy Schubert
734*7f2fe78bSCy Schubert dbc->db_inited = 1;
735*7f2fe78bSCy Schubert
736*7f2fe78bSCy Schubert cleanup:
737*7f2fe78bSCy Schubert if (retval) {
738*7f2fe78bSCy Schubert if (dbc->db != NULL)
739*7f2fe78bSCy Schubert dbc->db->close(dbc->db);
740*7f2fe78bSCy Schubert if (dbc->db_locks_held > 0) {
741*7f2fe78bSCy Schubert (void) krb5_lock_file(context, dbc->db_lf_file,
742*7f2fe78bSCy Schubert KRB5_LOCKMODE_UNLOCK);
743*7f2fe78bSCy Schubert }
744*7f2fe78bSCy Schubert if (dbc->db_lf_file >= 0)
745*7f2fe78bSCy Schubert close(dbc->db_lf_file);
746*7f2fe78bSCy Schubert ctx_clear(dbc);
747*7f2fe78bSCy Schubert }
748*7f2fe78bSCy Schubert free(dbname);
749*7f2fe78bSCy Schubert free(polname);
750*7f2fe78bSCy Schubert free(plockname);
751*7f2fe78bSCy Schubert return retval;
752*7f2fe78bSCy Schubert }
753*7f2fe78bSCy Schubert
754*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_get_principal(krb5_context context,krb5_const_principal searchfor,unsigned int flags,krb5_db_entry ** entry)755*7f2fe78bSCy Schubert krb5_db2_get_principal(krb5_context context, krb5_const_principal searchfor,
756*7f2fe78bSCy Schubert unsigned int flags, krb5_db_entry **entry)
757*7f2fe78bSCy Schubert {
758*7f2fe78bSCy Schubert krb5_db2_context *dbc;
759*7f2fe78bSCy Schubert krb5_error_code retval;
760*7f2fe78bSCy Schubert DB *db;
761*7f2fe78bSCy Schubert DBT key, contents;
762*7f2fe78bSCy Schubert krb5_data keydata, contdata;
763*7f2fe78bSCy Schubert int dbret;
764*7f2fe78bSCy Schubert
765*7f2fe78bSCy Schubert *entry = NULL;
766*7f2fe78bSCy Schubert if (!inited(context))
767*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
768*7f2fe78bSCy Schubert
769*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
770*7f2fe78bSCy Schubert
771*7f2fe78bSCy Schubert retval = ctx_lock(context, dbc, KRB5_LOCKMODE_SHARED);
772*7f2fe78bSCy Schubert if (retval)
773*7f2fe78bSCy Schubert return retval;
774*7f2fe78bSCy Schubert
775*7f2fe78bSCy Schubert /* XXX deal with wildcard lookups */
776*7f2fe78bSCy Schubert retval = krb5_encode_princ_dbkey(context, &keydata, searchfor);
777*7f2fe78bSCy Schubert if (retval)
778*7f2fe78bSCy Schubert goto cleanup;
779*7f2fe78bSCy Schubert key.data = keydata.data;
780*7f2fe78bSCy Schubert key.size = keydata.length;
781*7f2fe78bSCy Schubert
782*7f2fe78bSCy Schubert db = dbc->db;
783*7f2fe78bSCy Schubert dbret = (*db->get)(db, &key, &contents, 0);
784*7f2fe78bSCy Schubert retval = errno;
785*7f2fe78bSCy Schubert krb5_free_data_contents(context, &keydata);
786*7f2fe78bSCy Schubert switch (dbret) {
787*7f2fe78bSCy Schubert case 1:
788*7f2fe78bSCy Schubert retval = KRB5_KDB_NOENTRY;
789*7f2fe78bSCy Schubert /* Fall through. */
790*7f2fe78bSCy Schubert case -1:
791*7f2fe78bSCy Schubert default:
792*7f2fe78bSCy Schubert goto cleanup;
793*7f2fe78bSCy Schubert case 0:
794*7f2fe78bSCy Schubert contdata.data = contents.data;
795*7f2fe78bSCy Schubert contdata.length = contents.size;
796*7f2fe78bSCy Schubert retval = krb5_decode_princ_entry(context, &contdata, entry);
797*7f2fe78bSCy Schubert break;
798*7f2fe78bSCy Schubert }
799*7f2fe78bSCy Schubert
800*7f2fe78bSCy Schubert cleanup:
801*7f2fe78bSCy Schubert (void) krb5_db2_unlock(context); /* unlock read lock */
802*7f2fe78bSCy Schubert return retval;
803*7f2fe78bSCy Schubert }
804*7f2fe78bSCy Schubert
805*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_put_principal(krb5_context context,krb5_db_entry * entry,char ** db_args)806*7f2fe78bSCy Schubert krb5_db2_put_principal(krb5_context context, krb5_db_entry *entry,
807*7f2fe78bSCy Schubert char **db_args)
808*7f2fe78bSCy Schubert {
809*7f2fe78bSCy Schubert int dbret;
810*7f2fe78bSCy Schubert DB *db;
811*7f2fe78bSCy Schubert DBT key, contents;
812*7f2fe78bSCy Schubert krb5_data contdata, keydata;
813*7f2fe78bSCy Schubert krb5_error_code retval;
814*7f2fe78bSCy Schubert krb5_db2_context *dbc;
815*7f2fe78bSCy Schubert
816*7f2fe78bSCy Schubert krb5_clear_error_message (context);
817*7f2fe78bSCy Schubert if (db_args) {
818*7f2fe78bSCy Schubert /* DB2 does not support db_args DB arguments for principal */
819*7f2fe78bSCy Schubert k5_setmsg(context, EINVAL, _("Unsupported argument \"%s\" for db2"),
820*7f2fe78bSCy Schubert db_args[0]);
821*7f2fe78bSCy Schubert return EINVAL;
822*7f2fe78bSCy Schubert }
823*7f2fe78bSCy Schubert
824*7f2fe78bSCy Schubert if (!inited(context))
825*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
826*7f2fe78bSCy Schubert
827*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
828*7f2fe78bSCy Schubert if ((retval = ctx_lock(context, dbc, KRB5_LOCKMODE_EXCLUSIVE)))
829*7f2fe78bSCy Schubert return retval;
830*7f2fe78bSCy Schubert
831*7f2fe78bSCy Schubert db = dbc->db;
832*7f2fe78bSCy Schubert
833*7f2fe78bSCy Schubert retval = krb5_encode_princ_entry(context, &contdata, entry);
834*7f2fe78bSCy Schubert if (retval)
835*7f2fe78bSCy Schubert goto cleanup;
836*7f2fe78bSCy Schubert contents.data = contdata.data;
837*7f2fe78bSCy Schubert contents.size = contdata.length;
838*7f2fe78bSCy Schubert retval = krb5_encode_princ_dbkey(context, &keydata, entry->princ);
839*7f2fe78bSCy Schubert if (retval) {
840*7f2fe78bSCy Schubert krb5_free_data_contents(context, &contdata);
841*7f2fe78bSCy Schubert goto cleanup;
842*7f2fe78bSCy Schubert }
843*7f2fe78bSCy Schubert
844*7f2fe78bSCy Schubert key.data = keydata.data;
845*7f2fe78bSCy Schubert key.size = keydata.length;
846*7f2fe78bSCy Schubert dbret = (*db->put)(db, &key, &contents, 0);
847*7f2fe78bSCy Schubert retval = dbret ? errno : 0;
848*7f2fe78bSCy Schubert krb5_free_data_contents(context, &keydata);
849*7f2fe78bSCy Schubert krb5_free_data_contents(context, &contdata);
850*7f2fe78bSCy Schubert
851*7f2fe78bSCy Schubert cleanup:
852*7f2fe78bSCy Schubert ctx_update_age(dbc);
853*7f2fe78bSCy Schubert (void) krb5_db2_unlock(context); /* unlock database */
854*7f2fe78bSCy Schubert return (retval);
855*7f2fe78bSCy Schubert }
856*7f2fe78bSCy Schubert
857*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_delete_principal(krb5_context context,krb5_const_principal searchfor)858*7f2fe78bSCy Schubert krb5_db2_delete_principal(krb5_context context, krb5_const_principal searchfor)
859*7f2fe78bSCy Schubert {
860*7f2fe78bSCy Schubert krb5_error_code retval;
861*7f2fe78bSCy Schubert krb5_db_entry *entry;
862*7f2fe78bSCy Schubert krb5_db2_context *dbc;
863*7f2fe78bSCy Schubert DB *db;
864*7f2fe78bSCy Schubert DBT key, contents;
865*7f2fe78bSCy Schubert krb5_data keydata, contdata;
866*7f2fe78bSCy Schubert int i, dbret;
867*7f2fe78bSCy Schubert
868*7f2fe78bSCy Schubert if (!inited(context))
869*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
870*7f2fe78bSCy Schubert
871*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
872*7f2fe78bSCy Schubert if ((retval = ctx_lock(context, dbc, KRB5_LOCKMODE_EXCLUSIVE)))
873*7f2fe78bSCy Schubert return (retval);
874*7f2fe78bSCy Schubert
875*7f2fe78bSCy Schubert if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor)))
876*7f2fe78bSCy Schubert goto cleanup;
877*7f2fe78bSCy Schubert key.data = keydata.data;
878*7f2fe78bSCy Schubert key.size = keydata.length;
879*7f2fe78bSCy Schubert
880*7f2fe78bSCy Schubert db = dbc->db;
881*7f2fe78bSCy Schubert dbret = (*db->get) (db, &key, &contents, 0);
882*7f2fe78bSCy Schubert retval = errno;
883*7f2fe78bSCy Schubert switch (dbret) {
884*7f2fe78bSCy Schubert case 1:
885*7f2fe78bSCy Schubert retval = KRB5_KDB_NOENTRY;
886*7f2fe78bSCy Schubert /* Fall through. */
887*7f2fe78bSCy Schubert case -1:
888*7f2fe78bSCy Schubert default:
889*7f2fe78bSCy Schubert goto cleankey;
890*7f2fe78bSCy Schubert case 0:
891*7f2fe78bSCy Schubert ;
892*7f2fe78bSCy Schubert }
893*7f2fe78bSCy Schubert contdata.data = contents.data;
894*7f2fe78bSCy Schubert contdata.length = contents.size;
895*7f2fe78bSCy Schubert retval = krb5_decode_princ_entry(context, &contdata, &entry);
896*7f2fe78bSCy Schubert if (retval)
897*7f2fe78bSCy Schubert goto cleankey;
898*7f2fe78bSCy Schubert
899*7f2fe78bSCy Schubert /* Clear encrypted key contents */
900*7f2fe78bSCy Schubert for (i = 0; i < entry->n_key_data; i++) {
901*7f2fe78bSCy Schubert if (entry->key_data[i].key_data_length[0]) {
902*7f2fe78bSCy Schubert memset(entry->key_data[i].key_data_contents[0], 0,
903*7f2fe78bSCy Schubert (unsigned) entry->key_data[i].key_data_length[0]);
904*7f2fe78bSCy Schubert }
905*7f2fe78bSCy Schubert }
906*7f2fe78bSCy Schubert
907*7f2fe78bSCy Schubert retval = krb5_encode_princ_entry(context, &contdata, entry);
908*7f2fe78bSCy Schubert krb5_db_free_principal(context, entry);
909*7f2fe78bSCy Schubert if (retval)
910*7f2fe78bSCy Schubert goto cleankey;
911*7f2fe78bSCy Schubert
912*7f2fe78bSCy Schubert contents.data = contdata.data;
913*7f2fe78bSCy Schubert contents.size = contdata.length;
914*7f2fe78bSCy Schubert dbret = (*db->put) (db, &key, &contents, 0);
915*7f2fe78bSCy Schubert retval = dbret ? errno : 0;
916*7f2fe78bSCy Schubert krb5_free_data_contents(context, &contdata);
917*7f2fe78bSCy Schubert if (retval)
918*7f2fe78bSCy Schubert goto cleankey;
919*7f2fe78bSCy Schubert dbret = (*db->del) (db, &key, 0);
920*7f2fe78bSCy Schubert retval = dbret ? errno : 0;
921*7f2fe78bSCy Schubert cleankey:
922*7f2fe78bSCy Schubert krb5_free_data_contents(context, &keydata);
923*7f2fe78bSCy Schubert
924*7f2fe78bSCy Schubert cleanup:
925*7f2fe78bSCy Schubert ctx_update_age(dbc);
926*7f2fe78bSCy Schubert (void) krb5_db2_unlock(context); /* unlock write lock */
927*7f2fe78bSCy Schubert return retval;
928*7f2fe78bSCy Schubert }
929*7f2fe78bSCy Schubert
930*7f2fe78bSCy Schubert typedef krb5_error_code (*ctx_iterate_cb)(krb5_pointer, krb5_db_entry *);
931*7f2fe78bSCy Schubert
932*7f2fe78bSCy Schubert /* Cursor structure for ctx_iterate() */
933*7f2fe78bSCy Schubert typedef struct iter_curs {
934*7f2fe78bSCy Schubert DBT key;
935*7f2fe78bSCy Schubert DBT data;
936*7f2fe78bSCy Schubert DBT keycopy;
937*7f2fe78bSCy Schubert unsigned int startflag;
938*7f2fe78bSCy Schubert unsigned int stepflag;
939*7f2fe78bSCy Schubert krb5_context ctx;
940*7f2fe78bSCy Schubert krb5_db2_context *dbc;
941*7f2fe78bSCy Schubert int lockmode;
942*7f2fe78bSCy Schubert krb5_boolean islocked;
943*7f2fe78bSCy Schubert } iter_curs;
944*7f2fe78bSCy Schubert
945*7f2fe78bSCy Schubert /* Lock DB handle of curs, updating curs->islocked. */
946*7f2fe78bSCy Schubert static krb5_error_code
curs_lock(iter_curs * curs)947*7f2fe78bSCy Schubert curs_lock(iter_curs *curs)
948*7f2fe78bSCy Schubert {
949*7f2fe78bSCy Schubert krb5_error_code retval;
950*7f2fe78bSCy Schubert
951*7f2fe78bSCy Schubert retval = ctx_lock(curs->ctx, curs->dbc, curs->lockmode);
952*7f2fe78bSCy Schubert if (retval)
953*7f2fe78bSCy Schubert return retval;
954*7f2fe78bSCy Schubert curs->islocked = TRUE;
955*7f2fe78bSCy Schubert return 0;
956*7f2fe78bSCy Schubert }
957*7f2fe78bSCy Schubert
958*7f2fe78bSCy Schubert /* Unlock DB handle of curs, updating curs->islocked. */
959*7f2fe78bSCy Schubert static void
curs_unlock(iter_curs * curs)960*7f2fe78bSCy Schubert curs_unlock(iter_curs *curs)
961*7f2fe78bSCy Schubert {
962*7f2fe78bSCy Schubert ctx_unlock(curs->ctx, curs->dbc);
963*7f2fe78bSCy Schubert curs->islocked = FALSE;
964*7f2fe78bSCy Schubert }
965*7f2fe78bSCy Schubert
966*7f2fe78bSCy Schubert /* Set up curs and lock DB. */
967*7f2fe78bSCy Schubert static krb5_error_code
curs_init(iter_curs * curs,krb5_context ctx,krb5_db2_context * dbc,krb5_flags iterflags)968*7f2fe78bSCy Schubert curs_init(iter_curs *curs, krb5_context ctx, krb5_db2_context *dbc,
969*7f2fe78bSCy Schubert krb5_flags iterflags)
970*7f2fe78bSCy Schubert {
971*7f2fe78bSCy Schubert int isrecurse = iterflags & KRB5_DB_ITER_RECURSE;
972*7f2fe78bSCy Schubert unsigned int prevflag = R_PREV;
973*7f2fe78bSCy Schubert unsigned int nextflag = R_NEXT;
974*7f2fe78bSCy Schubert
975*7f2fe78bSCy Schubert curs->keycopy.size = 0;
976*7f2fe78bSCy Schubert curs->keycopy.data = NULL;
977*7f2fe78bSCy Schubert curs->islocked = FALSE;
978*7f2fe78bSCy Schubert curs->ctx = ctx;
979*7f2fe78bSCy Schubert curs->dbc = dbc;
980*7f2fe78bSCy Schubert
981*7f2fe78bSCy Schubert if (iterflags & KRB5_DB_ITER_WRITE)
982*7f2fe78bSCy Schubert curs->lockmode = KRB5_LOCKMODE_EXCLUSIVE;
983*7f2fe78bSCy Schubert else
984*7f2fe78bSCy Schubert curs->lockmode = KRB5_LOCKMODE_SHARED;
985*7f2fe78bSCy Schubert
986*7f2fe78bSCy Schubert if (isrecurse) {
987*7f2fe78bSCy Schubert #ifdef R_RNEXT
988*7f2fe78bSCy Schubert if (dbc->hashfirst) {
989*7f2fe78bSCy Schubert k5_setmsg(ctx, EINVAL, _("Recursive iteration is not supported "
990*7f2fe78bSCy Schubert "for hash databases"));
991*7f2fe78bSCy Schubert return EINVAL;
992*7f2fe78bSCy Schubert }
993*7f2fe78bSCy Schubert prevflag = R_RPREV;
994*7f2fe78bSCy Schubert nextflag = R_RNEXT;
995*7f2fe78bSCy Schubert #else
996*7f2fe78bSCy Schubert k5_setmsg(ctx, EINVAL, _("Recursive iteration not supported "
997*7f2fe78bSCy Schubert "in this version of libdb"));
998*7f2fe78bSCy Schubert return EINVAL;
999*7f2fe78bSCy Schubert #endif
1000*7f2fe78bSCy Schubert }
1001*7f2fe78bSCy Schubert if (iterflags & KRB5_DB_ITER_REV) {
1002*7f2fe78bSCy Schubert curs->startflag = R_LAST;
1003*7f2fe78bSCy Schubert curs->stepflag = prevflag;
1004*7f2fe78bSCy Schubert } else {
1005*7f2fe78bSCy Schubert curs->startflag = R_FIRST;
1006*7f2fe78bSCy Schubert curs->stepflag = nextflag;
1007*7f2fe78bSCy Schubert }
1008*7f2fe78bSCy Schubert return curs_lock(curs);
1009*7f2fe78bSCy Schubert }
1010*7f2fe78bSCy Schubert
1011*7f2fe78bSCy Schubert /* Get initial entry. */
1012*7f2fe78bSCy Schubert static int
curs_start(iter_curs * curs)1013*7f2fe78bSCy Schubert curs_start(iter_curs *curs)
1014*7f2fe78bSCy Schubert {
1015*7f2fe78bSCy Schubert DB *db = curs->dbc->db;
1016*7f2fe78bSCy Schubert
1017*7f2fe78bSCy Schubert return db->seq(db, &curs->key, &curs->data, curs->startflag);
1018*7f2fe78bSCy Schubert }
1019*7f2fe78bSCy Schubert
1020*7f2fe78bSCy Schubert /* Save iteration state so DB can be unlocked/closed. */
1021*7f2fe78bSCy Schubert static krb5_error_code
curs_save(iter_curs * curs)1022*7f2fe78bSCy Schubert curs_save(iter_curs *curs)
1023*7f2fe78bSCy Schubert {
1024*7f2fe78bSCy Schubert if (!curs->dbc->unlockiter)
1025*7f2fe78bSCy Schubert return 0;
1026*7f2fe78bSCy Schubert
1027*7f2fe78bSCy Schubert curs->keycopy.data = malloc(curs->key.size);
1028*7f2fe78bSCy Schubert if (curs->keycopy.data == NULL)
1029*7f2fe78bSCy Schubert return ENOMEM;
1030*7f2fe78bSCy Schubert
1031*7f2fe78bSCy Schubert curs->keycopy.size = curs->key.size;
1032*7f2fe78bSCy Schubert memcpy(curs->keycopy.data, curs->key.data, curs->key.size);
1033*7f2fe78bSCy Schubert return 0;
1034*7f2fe78bSCy Schubert }
1035*7f2fe78bSCy Schubert
1036*7f2fe78bSCy Schubert /* Free allocated cursor resources */
1037*7f2fe78bSCy Schubert static void
curs_free(iter_curs * curs)1038*7f2fe78bSCy Schubert curs_free(iter_curs *curs)
1039*7f2fe78bSCy Schubert {
1040*7f2fe78bSCy Schubert free(curs->keycopy.data);
1041*7f2fe78bSCy Schubert curs->keycopy.size = 0;
1042*7f2fe78bSCy Schubert curs->keycopy.data = NULL;
1043*7f2fe78bSCy Schubert }
1044*7f2fe78bSCy Schubert
1045*7f2fe78bSCy Schubert /* Move one step of iteration (forwards or backwards as requested). Free
1046*7f2fe78bSCy Schubert * curs->keycopy as a side effect, if needed. */
1047*7f2fe78bSCy Schubert static int
curs_step(iter_curs * curs)1048*7f2fe78bSCy Schubert curs_step(iter_curs *curs)
1049*7f2fe78bSCy Schubert {
1050*7f2fe78bSCy Schubert int dbret;
1051*7f2fe78bSCy Schubert krb5_db2_context *dbc = curs->dbc;
1052*7f2fe78bSCy Schubert
1053*7f2fe78bSCy Schubert if (dbc->unlockiter) {
1054*7f2fe78bSCy Schubert /* Reacquire libdb cursor using saved copy of key. */
1055*7f2fe78bSCy Schubert curs->key = curs->keycopy;
1056*7f2fe78bSCy Schubert dbret = dbc->db->seq(dbc->db, &curs->key, &curs->data, R_CURSOR);
1057*7f2fe78bSCy Schubert curs_free(curs);
1058*7f2fe78bSCy Schubert if (dbret)
1059*7f2fe78bSCy Schubert return dbret;
1060*7f2fe78bSCy Schubert }
1061*7f2fe78bSCy Schubert return dbc->db->seq(dbc->db, &curs->key, &curs->data, curs->stepflag);
1062*7f2fe78bSCy Schubert }
1063*7f2fe78bSCy Schubert
1064*7f2fe78bSCy Schubert /* Run one invocation of the callback, unlocking the mutex and possibly the DB
1065*7f2fe78bSCy Schubert * around the invocation. */
1066*7f2fe78bSCy Schubert static krb5_error_code
curs_run_cb(iter_curs * curs,ctx_iterate_cb func,krb5_pointer func_arg)1067*7f2fe78bSCy Schubert curs_run_cb(iter_curs *curs, ctx_iterate_cb func, krb5_pointer func_arg)
1068*7f2fe78bSCy Schubert {
1069*7f2fe78bSCy Schubert krb5_db2_context *dbc = curs->dbc;
1070*7f2fe78bSCy Schubert krb5_error_code retval, lockerr;
1071*7f2fe78bSCy Schubert krb5_db_entry *entry;
1072*7f2fe78bSCy Schubert krb5_context ctx = curs->ctx;
1073*7f2fe78bSCy Schubert krb5_data contdata;
1074*7f2fe78bSCy Schubert
1075*7f2fe78bSCy Schubert contdata = make_data(curs->data.data, curs->data.size);
1076*7f2fe78bSCy Schubert retval = krb5_decode_princ_entry(ctx, &contdata, &entry);
1077*7f2fe78bSCy Schubert if (retval)
1078*7f2fe78bSCy Schubert return retval;
1079*7f2fe78bSCy Schubert /* Save libdb key across possible DB closure. */
1080*7f2fe78bSCy Schubert retval = curs_save(curs);
1081*7f2fe78bSCy Schubert if (retval)
1082*7f2fe78bSCy Schubert return retval;
1083*7f2fe78bSCy Schubert
1084*7f2fe78bSCy Schubert if (dbc->unlockiter)
1085*7f2fe78bSCy Schubert curs_unlock(curs);
1086*7f2fe78bSCy Schubert
1087*7f2fe78bSCy Schubert k5_mutex_unlock(krb5_db2_mutex);
1088*7f2fe78bSCy Schubert retval = (*func)(func_arg, entry);
1089*7f2fe78bSCy Schubert krb5_db_free_principal(ctx, entry);
1090*7f2fe78bSCy Schubert k5_mutex_lock(krb5_db2_mutex);
1091*7f2fe78bSCy Schubert if (dbc->unlockiter) {
1092*7f2fe78bSCy Schubert lockerr = curs_lock(curs);
1093*7f2fe78bSCy Schubert if (lockerr)
1094*7f2fe78bSCy Schubert return lockerr;
1095*7f2fe78bSCy Schubert }
1096*7f2fe78bSCy Schubert return retval;
1097*7f2fe78bSCy Schubert }
1098*7f2fe78bSCy Schubert
1099*7f2fe78bSCy Schubert /* Free cursor resources and unlock the DB if needed. */
1100*7f2fe78bSCy Schubert static void
curs_fini(iter_curs * curs)1101*7f2fe78bSCy Schubert curs_fini(iter_curs *curs)
1102*7f2fe78bSCy Schubert {
1103*7f2fe78bSCy Schubert curs_free(curs);
1104*7f2fe78bSCy Schubert if (curs->islocked)
1105*7f2fe78bSCy Schubert curs_unlock(curs);
1106*7f2fe78bSCy Schubert }
1107*7f2fe78bSCy Schubert
1108*7f2fe78bSCy Schubert static krb5_error_code
ctx_iterate(krb5_context context,krb5_db2_context * dbc,ctx_iterate_cb func,krb5_pointer func_arg,krb5_flags iterflags)1109*7f2fe78bSCy Schubert ctx_iterate(krb5_context context, krb5_db2_context *dbc,
1110*7f2fe78bSCy Schubert ctx_iterate_cb func, krb5_pointer func_arg, krb5_flags iterflags)
1111*7f2fe78bSCy Schubert {
1112*7f2fe78bSCy Schubert krb5_error_code retval;
1113*7f2fe78bSCy Schubert int dbret;
1114*7f2fe78bSCy Schubert iter_curs curs;
1115*7f2fe78bSCy Schubert
1116*7f2fe78bSCy Schubert retval = curs_init(&curs, context, dbc, iterflags);
1117*7f2fe78bSCy Schubert if (retval)
1118*7f2fe78bSCy Schubert return retval;
1119*7f2fe78bSCy Schubert dbret = curs_start(&curs);
1120*7f2fe78bSCy Schubert while (dbret == 0) {
1121*7f2fe78bSCy Schubert retval = curs_run_cb(&curs, func, func_arg);
1122*7f2fe78bSCy Schubert if (retval)
1123*7f2fe78bSCy Schubert goto cleanup;
1124*7f2fe78bSCy Schubert dbret = curs_step(&curs);
1125*7f2fe78bSCy Schubert }
1126*7f2fe78bSCy Schubert switch (dbret) {
1127*7f2fe78bSCy Schubert case 1:
1128*7f2fe78bSCy Schubert case 0:
1129*7f2fe78bSCy Schubert break;
1130*7f2fe78bSCy Schubert case -1:
1131*7f2fe78bSCy Schubert default:
1132*7f2fe78bSCy Schubert retval = errno;
1133*7f2fe78bSCy Schubert }
1134*7f2fe78bSCy Schubert cleanup:
1135*7f2fe78bSCy Schubert curs_fini(&curs);
1136*7f2fe78bSCy Schubert return retval;
1137*7f2fe78bSCy Schubert }
1138*7f2fe78bSCy Schubert
1139*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_iterate(krb5_context context,char * match_expr,ctx_iterate_cb func,krb5_pointer func_arg,krb5_flags iterflags)1140*7f2fe78bSCy Schubert krb5_db2_iterate(krb5_context context, char *match_expr, ctx_iterate_cb func,
1141*7f2fe78bSCy Schubert krb5_pointer func_arg, krb5_flags iterflags)
1142*7f2fe78bSCy Schubert {
1143*7f2fe78bSCy Schubert if (!inited(context))
1144*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
1145*7f2fe78bSCy Schubert return ctx_iterate(context, context->dal_handle->db_context, func,
1146*7f2fe78bSCy Schubert func_arg, iterflags);
1147*7f2fe78bSCy Schubert }
1148*7f2fe78bSCy Schubert
1149*7f2fe78bSCy Schubert krb5_boolean
krb5_db2_set_lockmode(krb5_context context,krb5_boolean mode)1150*7f2fe78bSCy Schubert krb5_db2_set_lockmode(krb5_context context, krb5_boolean mode)
1151*7f2fe78bSCy Schubert {
1152*7f2fe78bSCy Schubert krb5_boolean old;
1153*7f2fe78bSCy Schubert krb5_db2_context *dbc;
1154*7f2fe78bSCy Schubert
1155*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
1156*7f2fe78bSCy Schubert old = mode;
1157*7f2fe78bSCy Schubert if (dbc) {
1158*7f2fe78bSCy Schubert old = dbc->db_nb_locks;
1159*7f2fe78bSCy Schubert dbc->db_nb_locks = mode;
1160*7f2fe78bSCy Schubert }
1161*7f2fe78bSCy Schubert return old;
1162*7f2fe78bSCy Schubert }
1163*7f2fe78bSCy Schubert
1164*7f2fe78bSCy Schubert /*
1165*7f2fe78bSCy Schubert * DAL API functions
1166*7f2fe78bSCy Schubert */
1167*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_lib_init()1168*7f2fe78bSCy Schubert krb5_db2_lib_init()
1169*7f2fe78bSCy Schubert {
1170*7f2fe78bSCy Schubert return 0;
1171*7f2fe78bSCy Schubert }
1172*7f2fe78bSCy Schubert
1173*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_lib_cleanup()1174*7f2fe78bSCy Schubert krb5_db2_lib_cleanup()
1175*7f2fe78bSCy Schubert {
1176*7f2fe78bSCy Schubert /* right now, no cleanup required */
1177*7f2fe78bSCy Schubert return 0;
1178*7f2fe78bSCy Schubert }
1179*7f2fe78bSCy Schubert
1180*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_open(krb5_context context,char * conf_section,char ** db_args,int mode)1181*7f2fe78bSCy Schubert krb5_db2_open(krb5_context context, char *conf_section, char **db_args,
1182*7f2fe78bSCy Schubert int mode)
1183*7f2fe78bSCy Schubert {
1184*7f2fe78bSCy Schubert krb5_error_code status = 0;
1185*7f2fe78bSCy Schubert
1186*7f2fe78bSCy Schubert krb5_clear_error_message(context);
1187*7f2fe78bSCy Schubert if (inited(context))
1188*7f2fe78bSCy Schubert return 0;
1189*7f2fe78bSCy Schubert
1190*7f2fe78bSCy Schubert status = configure_context(context, conf_section, db_args);
1191*7f2fe78bSCy Schubert if (status != 0)
1192*7f2fe78bSCy Schubert return status;
1193*7f2fe78bSCy Schubert
1194*7f2fe78bSCy Schubert status = check_openable(context);
1195*7f2fe78bSCy Schubert if (status != 0)
1196*7f2fe78bSCy Schubert return status;
1197*7f2fe78bSCy Schubert
1198*7f2fe78bSCy Schubert return ctx_init(context->dal_handle->db_context);
1199*7f2fe78bSCy Schubert }
1200*7f2fe78bSCy Schubert
1201*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_create(krb5_context context,char * conf_section,char ** db_args)1202*7f2fe78bSCy Schubert krb5_db2_create(krb5_context context, char *conf_section, char **db_args)
1203*7f2fe78bSCy Schubert {
1204*7f2fe78bSCy Schubert krb5_error_code status = 0;
1205*7f2fe78bSCy Schubert krb5_db2_context *dbc;
1206*7f2fe78bSCy Schubert
1207*7f2fe78bSCy Schubert krb5_clear_error_message(context);
1208*7f2fe78bSCy Schubert if (inited(context))
1209*7f2fe78bSCy Schubert return 0;
1210*7f2fe78bSCy Schubert
1211*7f2fe78bSCy Schubert status = configure_context(context, conf_section, db_args);
1212*7f2fe78bSCy Schubert if (status != 0)
1213*7f2fe78bSCy Schubert return status;
1214*7f2fe78bSCy Schubert
1215*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
1216*7f2fe78bSCy Schubert status = ctx_create_db(context, dbc);
1217*7f2fe78bSCy Schubert if (status != 0)
1218*7f2fe78bSCy Schubert return status;
1219*7f2fe78bSCy Schubert
1220*7f2fe78bSCy Schubert if (!dbc->tempdb)
1221*7f2fe78bSCy Schubert krb5_db2_unlock(context);
1222*7f2fe78bSCy Schubert
1223*7f2fe78bSCy Schubert return 0;
1224*7f2fe78bSCy Schubert }
1225*7f2fe78bSCy Schubert
1226*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_destroy(krb5_context context,char * conf_section,char ** db_args)1227*7f2fe78bSCy Schubert krb5_db2_destroy(krb5_context context, char *conf_section, char **db_args)
1228*7f2fe78bSCy Schubert {
1229*7f2fe78bSCy Schubert krb5_error_code status;
1230*7f2fe78bSCy Schubert krb5_db2_context *dbc;
1231*7f2fe78bSCy Schubert char *dbname = NULL, *lockname = NULL, *polname = NULL, *plockname = NULL;
1232*7f2fe78bSCy Schubert
1233*7f2fe78bSCy Schubert if (inited(context)) {
1234*7f2fe78bSCy Schubert status = krb5_db2_fini(context);
1235*7f2fe78bSCy Schubert if (status != 0)
1236*7f2fe78bSCy Schubert return status;
1237*7f2fe78bSCy Schubert }
1238*7f2fe78bSCy Schubert
1239*7f2fe78bSCy Schubert krb5_clear_error_message(context);
1240*7f2fe78bSCy Schubert status = configure_context(context, conf_section, db_args);
1241*7f2fe78bSCy Schubert if (status != 0)
1242*7f2fe78bSCy Schubert return status;
1243*7f2fe78bSCy Schubert
1244*7f2fe78bSCy Schubert status = check_openable(context);
1245*7f2fe78bSCy Schubert if (status != 0)
1246*7f2fe78bSCy Schubert return status;
1247*7f2fe78bSCy Schubert
1248*7f2fe78bSCy Schubert dbc = context->dal_handle->db_context;
1249*7f2fe78bSCy Schubert
1250*7f2fe78bSCy Schubert status = ctx_allfiles(dbc, &dbname, &lockname, &polname, &plockname);
1251*7f2fe78bSCy Schubert if (status)
1252*7f2fe78bSCy Schubert goto cleanup;
1253*7f2fe78bSCy Schubert status = destroy_file(dbname);
1254*7f2fe78bSCy Schubert if (status)
1255*7f2fe78bSCy Schubert goto cleanup;
1256*7f2fe78bSCy Schubert status = unlink(lockname);
1257*7f2fe78bSCy Schubert if (status)
1258*7f2fe78bSCy Schubert goto cleanup;
1259*7f2fe78bSCy Schubert status = osa_adb_destroy_db(polname, plockname, OSA_ADB_POLICY_DB_MAGIC);
1260*7f2fe78bSCy Schubert if (status)
1261*7f2fe78bSCy Schubert goto cleanup;
1262*7f2fe78bSCy Schubert
1263*7f2fe78bSCy Schubert status = krb5_db2_fini(context);
1264*7f2fe78bSCy Schubert
1265*7f2fe78bSCy Schubert cleanup:
1266*7f2fe78bSCy Schubert free(dbname);
1267*7f2fe78bSCy Schubert free(lockname);
1268*7f2fe78bSCy Schubert free(polname);
1269*7f2fe78bSCy Schubert free(plockname);
1270*7f2fe78bSCy Schubert return status;
1271*7f2fe78bSCy Schubert }
1272*7f2fe78bSCy Schubert
1273*7f2fe78bSCy Schubert /* policy functions */
1274*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_create_policy(krb5_context context,osa_policy_ent_t policy)1275*7f2fe78bSCy Schubert krb5_db2_create_policy(krb5_context context, osa_policy_ent_t policy)
1276*7f2fe78bSCy Schubert {
1277*7f2fe78bSCy Schubert krb5_db2_context *dbc = context->dal_handle->db_context;
1278*7f2fe78bSCy Schubert
1279*7f2fe78bSCy Schubert return osa_adb_create_policy(dbc->policy_db, policy);
1280*7f2fe78bSCy Schubert }
1281*7f2fe78bSCy Schubert
1282*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_get_policy(krb5_context context,char * name,osa_policy_ent_t * policy)1283*7f2fe78bSCy Schubert krb5_db2_get_policy(krb5_context context,
1284*7f2fe78bSCy Schubert char *name, osa_policy_ent_t *policy)
1285*7f2fe78bSCy Schubert {
1286*7f2fe78bSCy Schubert krb5_db2_context *dbc = context->dal_handle->db_context;
1287*7f2fe78bSCy Schubert
1288*7f2fe78bSCy Schubert return osa_adb_get_policy(dbc->policy_db, name, policy);
1289*7f2fe78bSCy Schubert }
1290*7f2fe78bSCy Schubert
1291*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_put_policy(krb5_context context,osa_policy_ent_t policy)1292*7f2fe78bSCy Schubert krb5_db2_put_policy(krb5_context context, osa_policy_ent_t policy)
1293*7f2fe78bSCy Schubert {
1294*7f2fe78bSCy Schubert krb5_db2_context *dbc = context->dal_handle->db_context;
1295*7f2fe78bSCy Schubert
1296*7f2fe78bSCy Schubert return osa_adb_put_policy(dbc->policy_db, policy);
1297*7f2fe78bSCy Schubert }
1298*7f2fe78bSCy Schubert
1299*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_iter_policy(krb5_context context,char * match_entry,osa_adb_iter_policy_func func,void * data)1300*7f2fe78bSCy Schubert krb5_db2_iter_policy(krb5_context context,
1301*7f2fe78bSCy Schubert char *match_entry,
1302*7f2fe78bSCy Schubert osa_adb_iter_policy_func func, void *data)
1303*7f2fe78bSCy Schubert {
1304*7f2fe78bSCy Schubert krb5_db2_context *dbc = context->dal_handle->db_context;
1305*7f2fe78bSCy Schubert
1306*7f2fe78bSCy Schubert return osa_adb_iter_policy(dbc->policy_db, func, data);
1307*7f2fe78bSCy Schubert }
1308*7f2fe78bSCy Schubert
1309*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_delete_policy(krb5_context context,char * policy)1310*7f2fe78bSCy Schubert krb5_db2_delete_policy(krb5_context context, char *policy)
1311*7f2fe78bSCy Schubert {
1312*7f2fe78bSCy Schubert krb5_db2_context *dbc = context->dal_handle->db_context;
1313*7f2fe78bSCy Schubert
1314*7f2fe78bSCy Schubert return osa_adb_destroy_policy(dbc->policy_db, policy);
1315*7f2fe78bSCy Schubert }
1316*7f2fe78bSCy Schubert
1317*7f2fe78bSCy Schubert /*
1318*7f2fe78bSCy Schubert * Merge non-replicated attributes from src into dst, setting
1319*7f2fe78bSCy Schubert * changed to non-zero if dst was changed.
1320*7f2fe78bSCy Schubert *
1321*7f2fe78bSCy Schubert * Non-replicated attributes are: last_success, last_failed,
1322*7f2fe78bSCy Schubert * fail_auth_count, and any negative TL data values.
1323*7f2fe78bSCy Schubert */
1324*7f2fe78bSCy Schubert static krb5_error_code
krb5_db2_merge_principal(krb5_context context,krb5_db_entry * src,krb5_db_entry * dst,int * changed)1325*7f2fe78bSCy Schubert krb5_db2_merge_principal(krb5_context context,
1326*7f2fe78bSCy Schubert krb5_db_entry *src,
1327*7f2fe78bSCy Schubert krb5_db_entry *dst,
1328*7f2fe78bSCy Schubert int *changed)
1329*7f2fe78bSCy Schubert {
1330*7f2fe78bSCy Schubert *changed = 0;
1331*7f2fe78bSCy Schubert
1332*7f2fe78bSCy Schubert if (dst->last_success != src->last_success) {
1333*7f2fe78bSCy Schubert dst->last_success = src->last_success;
1334*7f2fe78bSCy Schubert (*changed)++;
1335*7f2fe78bSCy Schubert }
1336*7f2fe78bSCy Schubert
1337*7f2fe78bSCy Schubert if (dst->last_failed != src->last_failed) {
1338*7f2fe78bSCy Schubert dst->last_failed = src->last_failed;
1339*7f2fe78bSCy Schubert (*changed)++;
1340*7f2fe78bSCy Schubert }
1341*7f2fe78bSCy Schubert
1342*7f2fe78bSCy Schubert if (dst->fail_auth_count != src->fail_auth_count) {
1343*7f2fe78bSCy Schubert dst->fail_auth_count = src->fail_auth_count;
1344*7f2fe78bSCy Schubert (*changed)++;
1345*7f2fe78bSCy Schubert }
1346*7f2fe78bSCy Schubert
1347*7f2fe78bSCy Schubert return 0;
1348*7f2fe78bSCy Schubert }
1349*7f2fe78bSCy Schubert
1350*7f2fe78bSCy Schubert struct nra_context {
1351*7f2fe78bSCy Schubert krb5_context kcontext;
1352*7f2fe78bSCy Schubert krb5_db2_context *db_context;
1353*7f2fe78bSCy Schubert };
1354*7f2fe78bSCy Schubert
1355*7f2fe78bSCy Schubert /*
1356*7f2fe78bSCy Schubert * Iteration callback merges non-replicated attributes from
1357*7f2fe78bSCy Schubert * old database.
1358*7f2fe78bSCy Schubert */
1359*7f2fe78bSCy Schubert static krb5_error_code
krb5_db2_merge_nra_iterator(krb5_pointer ptr,krb5_db_entry * entry)1360*7f2fe78bSCy Schubert krb5_db2_merge_nra_iterator(krb5_pointer ptr, krb5_db_entry *entry)
1361*7f2fe78bSCy Schubert {
1362*7f2fe78bSCy Schubert struct nra_context *nra = (struct nra_context *)ptr;
1363*7f2fe78bSCy Schubert kdb5_dal_handle *dal_handle = nra->kcontext->dal_handle;
1364*7f2fe78bSCy Schubert krb5_error_code retval;
1365*7f2fe78bSCy Schubert int changed;
1366*7f2fe78bSCy Schubert krb5_db_entry *s_entry;
1367*7f2fe78bSCy Schubert krb5_db2_context *dst_db;
1368*7f2fe78bSCy Schubert
1369*7f2fe78bSCy Schubert memset(&s_entry, 0, sizeof(s_entry));
1370*7f2fe78bSCy Schubert
1371*7f2fe78bSCy Schubert dst_db = dal_handle->db_context;
1372*7f2fe78bSCy Schubert dal_handle->db_context = nra->db_context;
1373*7f2fe78bSCy Schubert
1374*7f2fe78bSCy Schubert /* look up the new principal in the old DB */
1375*7f2fe78bSCy Schubert retval = krb5_db2_get_principal(nra->kcontext, entry->princ, 0, &s_entry);
1376*7f2fe78bSCy Schubert if (retval != 0) {
1377*7f2fe78bSCy Schubert /* principal may be newly created, so ignore */
1378*7f2fe78bSCy Schubert dal_handle->db_context = dst_db;
1379*7f2fe78bSCy Schubert return 0;
1380*7f2fe78bSCy Schubert }
1381*7f2fe78bSCy Schubert
1382*7f2fe78bSCy Schubert /* merge non-replicated attributes from the old entry in */
1383*7f2fe78bSCy Schubert krb5_db2_merge_principal(nra->kcontext, s_entry, entry, &changed);
1384*7f2fe78bSCy Schubert
1385*7f2fe78bSCy Schubert dal_handle->db_context = dst_db;
1386*7f2fe78bSCy Schubert
1387*7f2fe78bSCy Schubert /* if necessary, commit the modified new entry to the new DB */
1388*7f2fe78bSCy Schubert if (changed) {
1389*7f2fe78bSCy Schubert retval = krb5_db2_put_principal(nra->kcontext, entry, NULL);
1390*7f2fe78bSCy Schubert } else {
1391*7f2fe78bSCy Schubert retval = 0;
1392*7f2fe78bSCy Schubert }
1393*7f2fe78bSCy Schubert
1394*7f2fe78bSCy Schubert krb5_db_free_principal(nra->kcontext, s_entry);
1395*7f2fe78bSCy Schubert return retval;
1396*7f2fe78bSCy Schubert }
1397*7f2fe78bSCy Schubert
1398*7f2fe78bSCy Schubert /*
1399*7f2fe78bSCy Schubert * Merge non-replicated attributes (that is, lockout-related
1400*7f2fe78bSCy Schubert * attributes and negative TL data types) from the real database
1401*7f2fe78bSCy Schubert * into the temporary one.
1402*7f2fe78bSCy Schubert */
1403*7f2fe78bSCy Schubert static krb5_error_code
ctx_merge_nra(krb5_context context,krb5_db2_context * dbc_temp,krb5_db2_context * dbc_real)1404*7f2fe78bSCy Schubert ctx_merge_nra(krb5_context context, krb5_db2_context *dbc_temp,
1405*7f2fe78bSCy Schubert krb5_db2_context *dbc_real)
1406*7f2fe78bSCy Schubert {
1407*7f2fe78bSCy Schubert struct nra_context nra;
1408*7f2fe78bSCy Schubert
1409*7f2fe78bSCy Schubert nra.kcontext = context;
1410*7f2fe78bSCy Schubert nra.db_context = dbc_real;
1411*7f2fe78bSCy Schubert return ctx_iterate(context, dbc_temp, krb5_db2_merge_nra_iterator, &nra, 0);
1412*7f2fe78bSCy Schubert }
1413*7f2fe78bSCy Schubert
1414*7f2fe78bSCy Schubert /*
1415*7f2fe78bSCy Schubert * In the filesystem, promote the temporary database described by dbc_temp to
1416*7f2fe78bSCy Schubert * the real database described by dbc_real. Both must be exclusively locked.
1417*7f2fe78bSCy Schubert */
1418*7f2fe78bSCy Schubert static krb5_error_code
ctx_promote(krb5_context context,krb5_db2_context * dbc_temp,krb5_db2_context * dbc_real)1419*7f2fe78bSCy Schubert ctx_promote(krb5_context context, krb5_db2_context *dbc_temp,
1420*7f2fe78bSCy Schubert krb5_db2_context *dbc_real)
1421*7f2fe78bSCy Schubert {
1422*7f2fe78bSCy Schubert krb5_error_code retval;
1423*7f2fe78bSCy Schubert char *tdb = NULL, *tlock = NULL, *tpol = NULL, *tplock = NULL;
1424*7f2fe78bSCy Schubert char *rdb = NULL, *rlock = NULL, *rpol = NULL, *rplock = NULL;
1425*7f2fe78bSCy Schubert
1426*7f2fe78bSCy Schubert /* Generate all filenames of interest (including a few we don't need). */
1427*7f2fe78bSCy Schubert retval = ctx_allfiles(dbc_temp, &tdb, &tlock, &tpol, &tplock);
1428*7f2fe78bSCy Schubert if (retval)
1429*7f2fe78bSCy Schubert return retval;
1430*7f2fe78bSCy Schubert retval = ctx_allfiles(dbc_real, &rdb, &rlock, &rpol, &rplock);
1431*7f2fe78bSCy Schubert if (retval)
1432*7f2fe78bSCy Schubert goto cleanup;
1433*7f2fe78bSCy Schubert
1434*7f2fe78bSCy Schubert /* Rename the principal and policy databases into place. */
1435*7f2fe78bSCy Schubert if (rename(tdb, rdb)) {
1436*7f2fe78bSCy Schubert retval = errno;
1437*7f2fe78bSCy Schubert goto cleanup;
1438*7f2fe78bSCy Schubert }
1439*7f2fe78bSCy Schubert if (rename(tpol, rpol)) {
1440*7f2fe78bSCy Schubert retval = errno;
1441*7f2fe78bSCy Schubert goto cleanup;
1442*7f2fe78bSCy Schubert }
1443*7f2fe78bSCy Schubert
1444*7f2fe78bSCy Schubert ctx_update_age(dbc_real);
1445*7f2fe78bSCy Schubert
1446*7f2fe78bSCy Schubert /* Release and remove the temporary DB lockfiles. */
1447*7f2fe78bSCy Schubert (void) unlink(tlock);
1448*7f2fe78bSCy Schubert (void) unlink(tplock);
1449*7f2fe78bSCy Schubert
1450*7f2fe78bSCy Schubert cleanup:
1451*7f2fe78bSCy Schubert free(tdb);
1452*7f2fe78bSCy Schubert free(tlock);
1453*7f2fe78bSCy Schubert free(tpol);
1454*7f2fe78bSCy Schubert free(tplock);
1455*7f2fe78bSCy Schubert free(rdb);
1456*7f2fe78bSCy Schubert free(rlock);
1457*7f2fe78bSCy Schubert free(rpol);
1458*7f2fe78bSCy Schubert free(rplock);
1459*7f2fe78bSCy Schubert return retval;
1460*7f2fe78bSCy Schubert }
1461*7f2fe78bSCy Schubert
1462*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_promote_db(krb5_context context,char * conf_section,char ** db_args)1463*7f2fe78bSCy Schubert krb5_db2_promote_db(krb5_context context, char *conf_section, char **db_args)
1464*7f2fe78bSCy Schubert {
1465*7f2fe78bSCy Schubert krb5_error_code retval;
1466*7f2fe78bSCy Schubert krb5_boolean merge_nra = FALSE, real_locked = FALSE;
1467*7f2fe78bSCy Schubert krb5_db2_context *dbc_temp, *dbc_real = NULL;
1468*7f2fe78bSCy Schubert char **db_argp;
1469*7f2fe78bSCy Schubert
1470*7f2fe78bSCy Schubert /* context must be initialized with an exclusively locked temp DB. */
1471*7f2fe78bSCy Schubert if (!inited(context))
1472*7f2fe78bSCy Schubert return KRB5_KDB_DBNOTINITED;
1473*7f2fe78bSCy Schubert dbc_temp = context->dal_handle->db_context;
1474*7f2fe78bSCy Schubert if (dbc_temp->db_lock_mode != KRB5_LOCKMODE_EXCLUSIVE)
1475*7f2fe78bSCy Schubert return KRB5_KDB_NOTLOCKED;
1476*7f2fe78bSCy Schubert if (!dbc_temp->tempdb)
1477*7f2fe78bSCy Schubert return EINVAL;
1478*7f2fe78bSCy Schubert
1479*7f2fe78bSCy Schubert /* Check db_args for whether we should merge non-replicated attributes. */
1480*7f2fe78bSCy Schubert for (db_argp = db_args; *db_argp; db_argp++) {
1481*7f2fe78bSCy Schubert if (!strcmp(*db_argp, "merge_nra")) {
1482*7f2fe78bSCy Schubert merge_nra = TRUE;
1483*7f2fe78bSCy Schubert break;
1484*7f2fe78bSCy Schubert }
1485*7f2fe78bSCy Schubert }
1486*7f2fe78bSCy Schubert
1487*7f2fe78bSCy Schubert /* Make a db2 context for the real DB. */
1488*7f2fe78bSCy Schubert dbc_real = k5alloc(sizeof(*dbc_real), &retval);
1489*7f2fe78bSCy Schubert if (dbc_real == NULL)
1490*7f2fe78bSCy Schubert return retval;
1491*7f2fe78bSCy Schubert ctx_clear(dbc_real);
1492*7f2fe78bSCy Schubert
1493*7f2fe78bSCy Schubert /* Try creating the real DB. */
1494*7f2fe78bSCy Schubert dbc_real->db_name = strdup(dbc_temp->db_name);
1495*7f2fe78bSCy Schubert if (dbc_real->db_name == NULL)
1496*7f2fe78bSCy Schubert goto cleanup;
1497*7f2fe78bSCy Schubert dbc_real->tempdb = FALSE;
1498*7f2fe78bSCy Schubert retval = ctx_create_db(context, dbc_real);
1499*7f2fe78bSCy Schubert if (retval == EEXIST) {
1500*7f2fe78bSCy Schubert /* The real database already exists, so open and lock it. */
1501*7f2fe78bSCy Schubert dbc_real->db_name = strdup(dbc_temp->db_name);
1502*7f2fe78bSCy Schubert if (dbc_real->db_name == NULL)
1503*7f2fe78bSCy Schubert goto cleanup;
1504*7f2fe78bSCy Schubert dbc_real->tempdb = FALSE;
1505*7f2fe78bSCy Schubert retval = ctx_init(dbc_real);
1506*7f2fe78bSCy Schubert if (retval)
1507*7f2fe78bSCy Schubert goto cleanup;
1508*7f2fe78bSCy Schubert retval = ctx_lock(context, dbc_real, KRB5_DB_LOCKMODE_EXCLUSIVE);
1509*7f2fe78bSCy Schubert if (retval)
1510*7f2fe78bSCy Schubert goto cleanup;
1511*7f2fe78bSCy Schubert } else if (retval)
1512*7f2fe78bSCy Schubert goto cleanup;
1513*7f2fe78bSCy Schubert real_locked = TRUE;
1514*7f2fe78bSCy Schubert
1515*7f2fe78bSCy Schubert if (merge_nra) {
1516*7f2fe78bSCy Schubert retval = ctx_merge_nra(context, dbc_temp, dbc_real);
1517*7f2fe78bSCy Schubert if (retval)
1518*7f2fe78bSCy Schubert goto cleanup;
1519*7f2fe78bSCy Schubert }
1520*7f2fe78bSCy Schubert
1521*7f2fe78bSCy Schubert /* Perform filesystem manipulations for the promotion. */
1522*7f2fe78bSCy Schubert retval = ctx_promote(context, dbc_temp, dbc_real);
1523*7f2fe78bSCy Schubert if (retval)
1524*7f2fe78bSCy Schubert goto cleanup;
1525*7f2fe78bSCy Schubert
1526*7f2fe78bSCy Schubert /* Unlock and finalize context since the temp DB is gone. */
1527*7f2fe78bSCy Schubert (void) krb5_db2_unlock(context);
1528*7f2fe78bSCy Schubert krb5_db2_fini(context);
1529*7f2fe78bSCy Schubert
1530*7f2fe78bSCy Schubert cleanup:
1531*7f2fe78bSCy Schubert if (real_locked)
1532*7f2fe78bSCy Schubert (void) ctx_unlock(context, dbc_real);
1533*7f2fe78bSCy Schubert if (dbc_real)
1534*7f2fe78bSCy Schubert ctx_fini(dbc_real);
1535*7f2fe78bSCy Schubert return retval;
1536*7f2fe78bSCy Schubert }
1537*7f2fe78bSCy Schubert
1538*7f2fe78bSCy Schubert krb5_error_code
krb5_db2_check_policy_as(krb5_context kcontext,krb5_kdc_req * request,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp kdc_time,const char ** status,krb5_pa_data *** e_data)1539*7f2fe78bSCy Schubert krb5_db2_check_policy_as(krb5_context kcontext, krb5_kdc_req *request,
1540*7f2fe78bSCy Schubert krb5_db_entry *client, krb5_db_entry *server,
1541*7f2fe78bSCy Schubert krb5_timestamp kdc_time, const char **status,
1542*7f2fe78bSCy Schubert krb5_pa_data ***e_data)
1543*7f2fe78bSCy Schubert {
1544*7f2fe78bSCy Schubert krb5_error_code retval;
1545*7f2fe78bSCy Schubert
1546*7f2fe78bSCy Schubert retval = krb5_db2_lockout_check_policy(kcontext, client, kdc_time);
1547*7f2fe78bSCy Schubert if (retval == KRB5KDC_ERR_CLIENT_REVOKED)
1548*7f2fe78bSCy Schubert *status = "LOCKED_OUT";
1549*7f2fe78bSCy Schubert return retval;
1550*7f2fe78bSCy Schubert }
1551*7f2fe78bSCy Schubert
1552*7f2fe78bSCy Schubert void
krb5_db2_audit_as_req(krb5_context kcontext,krb5_kdc_req * request,const krb5_address * local_addr,const krb5_address * remote_addr,krb5_db_entry * client,krb5_db_entry * server,krb5_timestamp authtime,krb5_error_code error_code)1553*7f2fe78bSCy Schubert krb5_db2_audit_as_req(krb5_context kcontext, krb5_kdc_req *request,
1554*7f2fe78bSCy Schubert const krb5_address *local_addr,
1555*7f2fe78bSCy Schubert const krb5_address *remote_addr, krb5_db_entry *client,
1556*7f2fe78bSCy Schubert krb5_db_entry *server, krb5_timestamp authtime,
1557*7f2fe78bSCy Schubert krb5_error_code error_code)
1558*7f2fe78bSCy Schubert {
1559*7f2fe78bSCy Schubert (void) krb5_db2_lockout_audit(kcontext, client, authtime, error_code);
1560*7f2fe78bSCy Schubert }
1561