155
* Restore the default context.
153
/* Restore dbctx to the uninitialized state. */
158
k5db2_clear_context(krb5_db2_context *dbctx)
155
ctx_clear(krb5_db2_context *dbc)
161
158
* Free any dynamically allocated memory. File descriptors and locks
162
159
* are the caller's problem.
164
free(dbctx->db_lf_name);
165
free(dbctx->db_name);
161
free(dbc->db_lf_name);
167
164
* Clear the structure and reset the defaults.
169
memset(dbctx, 0, sizeof(krb5_db2_context));
170
dbctx->db_name = NULL;
171
dbctx->db_nb_locks = FALSE;
172
dbctx->tempdb = FALSE;
166
memset(dbc, 0, sizeof(krb5_db2_context));
168
dbc->db_lf_name = NULL;
169
dbc->db_lf_file = -1;
171
dbc->db_nb_locks = FALSE;
175
/* Set *dbc_out to the db2 database context for context. If one does not
176
* exist, create one in the uninitialized state. */
175
177
static krb5_error_code
176
k5db2_init_context(krb5_context context)
178
ctx_get(krb5_context context, krb5_db2_context **dbc_out)
178
krb5_db2_context *db_ctx;
180
krb5_db2_context *dbc;
179
181
kdb5_dal_handle *dal_handle;
181
183
dal_handle = context->dal_handle;
183
185
if (dal_handle->db_context == NULL) {
184
db_ctx = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
186
dbc = (krb5_db2_context *) malloc(sizeof(krb5_db2_context));
188
memset(db_ctx, 0, sizeof(krb5_db2_context));
189
k5db2_clear_context((krb5_db2_context *) db_ctx);
190
dal_handle->db_context = (void *) db_ctx;
190
memset(dbc, 0, sizeof(krb5_db2_context));
192
dal_handle->db_context = dbc;
195
*dbc_out = dal_handle->db_context;
196
199
/* Using db_args and the profile, initialize the configurable parameters of the
199
202
configure_context(krb5_context context, char *conf_section, char **db_args)
201
204
krb5_error_code status;
202
krb5_db2_context *db_ctx;
205
krb5_db2_context *dbc;
203
206
char **t_ptr, *opt = NULL, *val = NULL, *pval = NULL;
204
207
profile_t profile = KRB5_DB_GET_PROFILE(context);
207
status = k5db2_init_context(context);
210
status = ctx_get(context, &dbc);
210
db_ctx = context->dal_handle->db_context;
212
214
for (t_ptr = db_args; t_ptr && *t_ptr; t_ptr++) {
215
status = krb5_db2_get_db_opt(*t_ptr, &opt, &val);
217
status = get_db_opt(*t_ptr, &opt, &val);
216
218
if (opt && !strcmp(opt, "dbname")) {
217
db_ctx->db_name = strdup(val);
218
if (db_ctx->db_name == NULL) {
219
dbc->db_name = strdup(val);
220
if (dbc->db_name == NULL) {
223
225
else if (!opt && !strcmp(val, "temporary")) {
225
227
} else if (!opt && !strcmp(val, "merge_nra")) {
227
229
} else if (opt && !strcmp(opt, "hash")) {
228
db_ctx->hashfirst = TRUE;
230
dbc->hashfirst = TRUE;
231
233
krb5_set_error_message(context, status,
232
"Unsupported argument \"%s\" for db2",
234
_("Unsupported argument \"%s\" for db2"),
233
235
opt ? opt : val);
238
if (db_ctx->db_name == NULL) {
240
if (dbc->db_name == NULL) {
239
241
/* Check for database_name in the db_module section. */
240
242
status = profile_get_string(profile, KDB_MODULE_SECTION, conf_section,
241
243
KDB_DB2_DATABASE_NAME, NULL, &pval);
274
* Utility routine: generate name of database file.
278
gen_dbsuffix(char *db_name, char *sfx)
283
return ((char *) NULL);
285
if (asprintf(&dbsuffix, "%s%s", db_name, sfx) < 0)
276
* Set *out to one of the filenames used for the DB described by dbc. sfx
277
* should be one of SUFFIX_DB, SUFFIX_LOCK, SUFFIX_POLICY, or
278
* SUFFIX_POLICY_LOCK.
280
static krb5_error_code
281
ctx_dbsuffix(krb5_db2_context *dbc, const char *sfx, char **out)
287
tilde = dbc->tempdb ? "~" : "";
288
if (asprintf(&result, "%s%s%s", dbc->db_name, tilde, sfx) < 0)
294
/* Generate all four files corresponding to dbc. */
295
static krb5_error_code
296
ctx_allfiles(krb5_db2_context *dbc, char **dbname_out, char **lockname_out,
297
char **polname_out, char **plockname_out)
299
char *a = NULL, *b = NULL, *c = NULL, *d = NULL;
301
*dbname_out = *lockname_out = *polname_out = *plockname_out = NULL;
302
if (ctx_dbsuffix(dbc, SUFFIX_DB, &a))
304
if (ctx_dbsuffix(dbc, SUFFIX_LOCK, &b))
306
if (ctx_dbsuffix(dbc, SUFFIX_POLICY, &c))
308
if (ctx_dbsuffix(dbc, SUFFIX_POLICY_LOCK, &d))
324
* Open the DB2 database described by dbc, using the specified flags and mode,
325
* and return the resulting handle. Try both hash and btree database types;
326
* dbc->hashfirst determines which is attempted first. If dbc->hashfirst
327
* indicated the wrong type, update it to indicate the correct type.
291
k5db2_dbopen(krb5_db2_context *dbc, char *fname, int flags, int mode, int tempdb)
330
open_db(krb5_db2_context *dbc, int flags, int mode)
335
369
db = dbopen(fname, flags, mode,
336
370
dbc->hashfirst ? DB_BTREE : DB_HASH,
337
371
dbc->hashfirst ? (void *) &bti : (void *) &hashi);
372
/* If that worked, update our guess for next time. */
339
374
dbc->hashfirst = !dbc->hashfirst;
347
* initialization for data base routines.
351
krb5_db2_init(krb5_context context)
353
char *filename = NULL;
354
krb5_db2_context *db_ctx;
355
krb5_error_code retval;
356
char policy_db_name[1024], policy_lock_name[1024];
358
if (k5db2_inited(context))
361
/* Check for presence of our context, if not present, allocate one. */
362
if ((retval = k5db2_init_context(context)))
365
db_ctx = context->dal_handle->db_context;
368
if (!(filename = gen_dbsuffix(db_ctx->db_name, db_ctx->tempdb
369
?KDB2_TEMP_LOCK_EXT:KDB2_LOCK_EXT)))
371
db_ctx->db_lf_name = filename; /* so it gets freed by clear_context */
383
static krb5_error_code
384
ctx_unlock(krb5_context context, krb5_db2_context *dbc)
386
krb5_error_code retval;
389
retval = osa_adb_release_lock(dbc->policy_db);
393
if (!dbc->db_locks_held) /* lock already unlocked */
394
return KRB5_KDB_NOTLOCKED;
397
if (--(dbc->db_locks_held) == 0) {
400
dbc->db_lock_mode = 0;
402
retval = krb5_lock_file(context, dbc->db_lf_file,
403
KRB5_LOCKMODE_UNLOCK);
408
#define MAX_LOCK_TRIES 5
410
static krb5_error_code
411
ctx_lock(krb5_context context, krb5_db2_context *dbc, int lockmode)
413
krb5_error_code retval;
416
if (lockmode == KRB5_DB_LOCKMODE_PERMANENT ||
417
lockmode == KRB5_DB_LOCKMODE_EXCLUSIVE)
418
kmode = KRB5_LOCKMODE_EXCLUSIVE;
419
else if (lockmode == KRB5_DB_LOCKMODE_SHARED)
420
kmode = KRB5_LOCKMODE_SHARED;
424
if (dbc->db_locks_held == 0 || dbc->db_lock_mode < kmode) {
425
/* Acquire or upgrade the lock. */
426
for (tries = 0; tries < MAX_LOCK_TRIES; tries++) {
427
retval = krb5_lock_file(context, dbc->db_lf_file,
428
kmode | KRB5_LOCKMODE_DONTBLOCK);
431
if (retval == EBADF && kmode == KRB5_LOCKMODE_EXCLUSIVE)
432
/* Tried to lock something we don't have write access to. */
433
return KRB5_KDB_CANTLOCK_DB;
436
if (retval == EACCES)
437
return KRB5_KDB_CANTLOCK_DB;
438
else if (retval == EAGAIN || retval == EWOULDBLOCK)
439
return OSA_ADB_CANTLOCK_DB;
443
/* Open the DB (or re-open it for read/write). */
445
dbc->db->close(dbc->db);
446
dbc->db = open_db(dbc,
447
kmode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR,
449
if (dbc->db == NULL) {
451
dbc->db_locks_held = 0;
452
dbc->db_lock_mode = 0;
453
(void) osa_adb_release_lock(dbc->policy_db);
454
(void) krb5_lock_file(context, dbc->db_lf_file,
455
KRB5_LOCKMODE_UNLOCK);
459
dbc->db_lock_mode = kmode;
461
dbc->db_locks_held++;
463
/* Acquire or upgrade the policy lock. */
464
retval = osa_adb_get_lock(dbc->policy_db, lockmode);
466
(void) ctx_unlock(context, dbc);
470
/* Initialize the lock file and policy database fields of dbc. The db_name and
471
* tempdb fields must already be set. */
472
static krb5_error_code
473
ctx_init(krb5_db2_context *dbc)
475
krb5_error_code retval;
476
char *polname = NULL, *plockname = NULL;
478
retval = ctx_dbsuffix(dbc, SUFFIX_LOCK, &dbc->db_lf_name);
374
483
* should be opened read/write so that write locking can work with
377
if ((db_ctx->db_lf_file = open(filename, O_RDWR, 0666)) < 0) {
378
if ((db_ctx->db_lf_file = open(filename, O_RDONLY, 0666)) < 0) {
486
if ((dbc->db_lf_file = open(dbc->db_lf_name, O_RDWR, 0666)) < 0) {
487
if ((dbc->db_lf_file = open(dbc->db_lf_name, O_RDONLY, 0666)) < 0) {
383
set_cloexec_fd(db_ctx->db_lf_file);
386
if ((retval = krb5_db2_get_age(context, NULL, &db_ctx->db_lf_time)))
389
snprintf(policy_db_name, sizeof(policy_db_name), "%s%s.kadm5",
390
db_ctx->db_name, db_ctx->tempdb ? "~" : "");
391
snprintf(policy_lock_name, sizeof(policy_lock_name),
392
"%s.lock", policy_db_name);
394
if ((retval = osa_adb_init_db(&db_ctx->policy_db, policy_db_name,
395
policy_lock_name, OSA_ADB_POLICY_DB_MAGIC)))
403
k5db2_clear_context(db_ctx);
408
* gracefully shut down database--must be called by ANY program that does
492
set_cloexec_fd(dbc->db_lf_file);
495
retval = ctx_dbsuffix(dbc, SUFFIX_POLICY, &polname);
498
retval = ctx_dbsuffix(dbc, SUFFIX_POLICY_LOCK, &plockname);
501
retval = osa_adb_init_db(&dbc->policy_db, polname, plockname,
502
OSA_ADB_POLICY_DB_MAGIC);
513
ctx_fini(krb5_db2_context *dbc)
515
if (dbc->db_lf_file != -1)
516
(void) close(dbc->db_lf_file);
518
(void) osa_adb_fini_db(dbc->policy_db, OSA_ADB_POLICY_DB_MAGIC);
412
524
krb5_db2_fini(krb5_context context)
414
krb5_error_code retval = 0;
415
krb5_db2_context *db_ctx;
417
db_ctx = context->dal_handle->db_context;
418
if (k5db2_inited(context)) {
419
if (close(db_ctx->db_lf_file))
425
if (db_ctx->policy_db) {
427
osa_adb_fini_db(db_ctx->policy_db, OSA_ADB_POLICY_DB_MAGIC);
432
k5db2_clear_context(db_ctx);
433
free(context->dal_handle->db_context);
526
if (context->dal_handle->db_context != NULL) {
527
ctx_fini(context->dal_handle->db_context);
434
528
context->dal_handle->db_context = NULL;
441
533
/* Return successfully if the db2 name set in context can be opened. */
442
534
static krb5_error_code
443
535
check_openable(krb5_context context)
446
krb5_db2_context *db_ctx;
538
krb5_db2_context *dbc;
448
db_ctx = context->dal_handle->db_context;
449
db = k5db2_dbopen(db_ctx, db_ctx->db_name, O_RDONLY, 0, db_ctx->tempdb);
540
dbc = context->dal_handle->db_context;
541
db = open_db(dbc, O_RDONLY, 0);
463
555
krb5_db2_get_age(krb5_context context, char *db_name, time_t *age)
465
krb5_db2_context *db_ctx;
557
krb5_db2_context *dbc;
468
if (!k5db2_inited(context))
560
if (!inited(context))
469
561
return (KRB5_KDB_DBNOTINITED);
470
db_ctx = context->dal_handle->db_context;
562
dbc = context->dal_handle->db_context;
472
if (fstat(db_ctx->db_lf_file, &st) < 0)
564
if (fstat(dbc->db_lf_file, &st) < 0)
475
567
*age = st.st_mtime;
480
* Remove the semaphore file; indicates that database is currently
483
* This is only for use when moving the database out from underneath
484
* the server (for example, during slave updates).
487
static krb5_error_code
488
krb5_db2_start_update(krb5_context context)
493
static krb5_error_code
494
krb5_db2_end_update(krb5_context context)
496
krb5_error_code retval;
497
krb5_db2_context *db_ctx;
571
/* Try to update the timestamp on dbc's lockfile. */
573
ctx_update_age(krb5_db2_context *dbc)
500
577
struct utimbuf utbuf;
502
if (!k5db2_inited(context))
503
return (KRB5_KDB_DBNOTINITED);
506
db_ctx = context->dal_handle->db_context;
507
579
now = time((time_t *) NULL);
508
if (fstat(db_ctx->db_lf_file, &st) == 0) {
509
if (st.st_mtime >= now) {
510
utbuf.actime = st.st_mtime + 1;
511
utbuf.modtime = st.st_mtime + 1;
512
if (utime(db_ctx->db_lf_name, &utbuf))
515
if (utime(db_ctx->db_lf_name, (struct utimbuf *) NULL))
580
if (fstat(dbc->db_lf_file, &st) != 0)
582
if (st.st_mtime >= now) {
583
utbuf.actime = st.st_mtime + 1;
584
utbuf.modtime = st.st_mtime + 1;
585
(void) utime(dbc->db_lf_name, &utbuf);
521
if (fstat(db_ctx->db_lf_file, &st) == 0)
522
db_ctx->db_lf_time = st.st_mtime;
587
(void) utime(dbc->db_lf_name, (struct utimbuf *) NULL);
529
#define MAX_LOCK_TRIES 5
532
krb5_db2_lock(krb5_context context, int in_mode)
591
krb5_db2_lock(krb5_context context, int lockmode)
534
krb5_db2_context *db_ctx;
537
krb5_error_code retval;
539
int mode, gotlock, tries;
542
case KRB5_DB_LOCKMODE_PERMANENT:
543
mode = KRB5_DB_LOCKMODE_EXCLUSIVE;
545
case KRB5_DB_LOCKMODE_EXCLUSIVE:
546
mode = KRB5_LOCKMODE_EXCLUSIVE;
549
case KRB5_DB_LOCKMODE_SHARED:
550
mode = KRB5_LOCKMODE_SHARED;
556
if (!k5db2_inited(context))
593
if (!inited(context))
557
594
return KRB5_KDB_DBNOTINITED;
559
db_ctx = context->dal_handle->db_context;
560
if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) {
561
/* No need to upgrade lock, just return */
562
db_ctx->db_locks_held++;
566
if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE))
567
return KRB5_KDB_BADLOCKMODE;
569
krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK;
570
for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) {
571
retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode);
575
} else if (retval == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE)
576
/* tried to exclusive-lock something we don't have */
577
/* write access to */
578
return KRB5_KDB_CANTLOCK_DB;
581
if (retval == EACCES)
582
return KRB5_KDB_CANTLOCK_DB;
583
else if (retval == EAGAIN || retval == EWOULDBLOCK)
584
return OSA_ADB_CANTLOCK_DB;
585
else if (retval != 0)
588
if ((retval = krb5_db2_get_age(context, NULL, &mod_time)))
591
db = k5db2_dbopen(db_ctx, db_ctx->db_name,
592
mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600, db_ctx->tempdb);
594
db_ctx->db_lf_time = mod_time;
602
db_ctx->db_lock_mode = mode;
603
db_ctx->db_locks_held++;
606
if ((retval = osa_adb_get_lock(db_ctx->policy_db, in_mode))) {
607
krb5_db2_unlock(context);
612
db_ctx->db_lock_mode = 0;
613
db_ctx->db_locks_held = 0;
614
krb5_db2_unlock(context);
595
return ctx_lock(context, context->dal_handle->db_context, lockmode);
619
599
krb5_db2_unlock(krb5_context context)
621
krb5_db2_context *db_ctx;
623
krb5_error_code retval;
625
if (!k5db2_inited(context))
601
if (!inited(context))
626
602
return KRB5_KDB_DBNOTINITED;
628
db_ctx = context->dal_handle->db_context;
630
if ((retval = osa_adb_release_lock(db_ctx->policy_db))) {
634
if (!db_ctx->db_locks_held) /* lock already unlocked */
635
return KRB5_KDB_NOTLOCKED;
637
if (--(db_ctx->db_locks_held) == 0) {
641
retval = krb5_lock_file(context, db_ctx->db_lf_file,
642
KRB5_LOCKMODE_UNLOCK);
643
db_ctx->db_lock_mode = 0;
649
/* Create the database, assuming it's not there. */
650
static krb5_error_code
651
create_db(krb5_context context, char *db_name)
653
krb5_error_code retval = 0;
655
char *db_name2 = NULL;
657
krb5_db2_context *db_ctx;
659
char policy_db_name[1024], policy_lock_name[1024];
661
retval = k5db2_init_context(context);
665
db_ctx = context->dal_handle->db_context;
666
db = k5db2_dbopen(db_ctx, db_name, O_RDWR | O_CREAT | O_EXCL, 0600,
672
db_name2 = db_ctx->tempdb ? gen_dbsuffix(db_name, "~") : strdup(db_name);
673
if (db_name2 == NULL)
675
okname = gen_dbsuffix(db_name2, KDB2_LOCK_EXT);
679
fd = open(okname, O_CREAT | O_RDWR | O_TRUNC, 0600);
684
free_dbsuffix(okname);
687
snprintf(policy_db_name, sizeof(policy_db_name), "%s.kadm5", db_name2);
688
snprintf(policy_lock_name, sizeof(policy_lock_name),
689
"%s.lock", policy_db_name);
691
retval = osa_adb_create_db(policy_db_name,
692
policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
698
* Destroy the database. Zero's out all of the files, just to be sure.
700
static krb5_error_code
701
destroy_file_suffix(char *dbname, char *suffix)
603
return ctx_unlock(context, context->dal_handle->db_context);
606
/* Zero out and unlink filename. */
607
static krb5_error_code
608
destroy_file(char *filename)
704
610
struct stat statb;
611
int dowrite, j, nb, fd, retval;
613
char buf[BUFSIZ], zbuf[BUFSIZ];
712
filename = gen_dbsuffix(dbname, suffix);
715
if ((fd = open(filename, O_RDWR, 0)) < 0) {
615
fd = open(filename, O_RDWR, 0);
719
618
set_cloexec_fd(fd);
720
619
/* fstat() will probably not fail unless using a remote filesystem
721
620
* (which is inappropriate for the kerberos database) so this check
722
621
* is mostly paranoia. */
723
if (fstat(fd, &statb) == -1) {
622
if (fstat(fd, &statb) == -1)
729
625
* Stroll through the file, reading in BUFSIZ chunks. If everything
730
626
* is zero, then we're done for that block, otherwise, zero the block.
773
if (unlink(filename)) {
663
if (unlink(filename))
782
* Since the destroy operation happens outside the init/fini bracket, we
783
* have some tomfoolery to undergo here. If we're operating under no
784
* database context, then we initialize with the default. If the caller
785
* wishes a different context (e.g. different dispatch table), it's their
786
* responsibility to call kdb5_db_set_dbops() before this call. That will
787
* set up the right dispatch table values (e.g. name extensions).
789
* Not quite valid due to ripping out of dbops...
673
/* Initialize dbc by locking and creating the DB. If the DB already exists,
674
* clear it out if dbc->tempdb is set; otherwise return EEXIST. */
791
675
static krb5_error_code
792
destroy_db(krb5_context context, char *dbname)
676
ctx_create_db(krb5_context context, krb5_db2_context *dbc)
794
krb5_error_code retval1, retval2;
795
krb5_boolean tmpcontext;
796
char policy_db_name[1024], policy_lock_name[1024];
799
if (!context->dal_handle->db_context) {
801
if ((retval1 = k5db2_init_context(context)))
805
retval1 = retval2 = 0;
806
retval1 = destroy_file_suffix(dbname, "");
807
retval2 = destroy_file_suffix(dbname, KDB2_LOCK_EXT);
810
k5db2_clear_context(context->dal_handle->db_context);
811
free(context->dal_handle->db_context);
812
context->dal_handle->db_context = NULL;
815
if (retval1 || retval2)
816
return (retval1 ? retval1 : retval2);
818
snprintf(policy_db_name, sizeof(policy_db_name), "%s.kadm5", dbname);
819
snprintf(policy_lock_name, sizeof(policy_lock_name),
820
"%s.lock", policy_db_name);
822
retval1 = osa_adb_destroy_db(policy_db_name,
823
policy_lock_name, OSA_ADB_POLICY_DB_MAGIC);
678
krb5_error_code retval = 0;
679
char *dbname = NULL, *polname = NULL, *plockname = NULL;
681
retval = ctx_allfiles(dbc, &dbname, &dbc->db_lf_name, &polname,
686
dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC,
688
if (dbc->db_lf_file < 0) {
692
retval = krb5_lock_file(context, dbc->db_lf_file,
693
KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK);
696
set_cloexec_fd(dbc->db_lf_file);
697
dbc->db_lock_mode = KRB5_LOCKMODE_EXCLUSIVE;
698
dbc->db_locks_held = 1;
701
/* Temporary DBs are locked for their whole lifetime. Since we have
702
* the lock, any remnant files can be safely destroyed. */
703
(void) destroy_file(dbname);
704
(void) unlink(polname);
705
(void) unlink(plockname);
708
dbc->db = open_db(dbc, O_RDWR | O_CREAT | O_EXCL, 0600);
709
if (dbc->db == NULL) {
714
/* Create the policy database, initialize a handle to it, and lock it. */
715
retval = osa_adb_create_db(polname, plockname, OSA_ADB_POLICY_DB_MAGIC);
718
retval = osa_adb_init_db(&dbc->policy_db, polname, plockname,
719
OSA_ADB_POLICY_DB_MAGIC);
722
retval = osa_adb_get_lock(dbc->policy_db, KRB5_DB_LOCKMODE_EXCLUSIVE);
731
dbc->db->close(dbc->db);
732
if (dbc->db_locks_held > 0) {
733
(void) krb5_lock_file(context, dbc->db_lf_file,
734
KRB5_LOCKMODE_UNLOCK);
736
if (dbc->db_lf_file >= 0)
737
close(dbc->db_lf_file);
829
747
krb5_db2_get_principal(krb5_context context, krb5_const_principal searchfor,
830
748
unsigned int flags, krb5_db_entry **entry)
832
krb5_db2_context *db_ctx;
750
krb5_db2_context *dbc;
833
751
krb5_error_code retval;
835
753
DBT key, contents;
1021
930
krb5_free_data_contents(context, &keydata);
1024
(void) krb5_db2_end_update(context);
1025
934
(void) krb5_db2_unlock(context); /* unlock write lock */
1030
krb5_db2_iterate_ext(krb5_context context,
1031
krb5_error_code(*func) (krb5_pointer, krb5_db_entry *),
1032
krb5_pointer func_arg, int backwards, int recursive)
938
static krb5_error_code
939
ctx_iterate(krb5_context context, krb5_db2_context *dbc,
940
krb5_error_code (*func)(krb5_pointer, krb5_db_entry *),
941
krb5_pointer func_arg)
1034
krb5_db2_context *db_ctx;
1037
945
krb5_data contdata;
1038
946
krb5_db_entry *entry;
1039
krb5_error_code retval;
1044
if (!k5db2_inited(context))
1045
return KRB5_KDB_DBNOTINITED;
1047
db_ctx = context->dal_handle->db_context;
1048
retval = krb5_db2_lock(context, KRB5_LOCKMODE_SHARED);
947
krb5_error_code retval, retval2;
950
retval = ctx_lock(context, dbc, KRB5_LOCKMODE_SHARED);
1054
if (recursive && db->type != DB_BTREE) {
1055
(void) krb5_db2_unlock(context);
1056
return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
1060
dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST);
1063
dbret = bt_rseq(db, &key, &contents, &cookie,
1064
backwards ? R_LAST : R_FIRST);
1066
(void) krb5_db2_unlock(context);
1067
return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */
955
dbret = db->seq(db, &key, &contents, R_FIRST);
1070
956
while (dbret == 0) {
1071
krb5_error_code retval2;
1073
957
contdata.data = contents.data;
1074
958
contdata.length = contents.size;
1075
959
retval = krb5_decode_princ_entry(context, &contdata, &entry);
1422
1270
* Merge non-replicated attributes (that is, lockout-related
1423
* attributes and negative TL data types) from the old database
1426
* Note: src_db is locked on success.
1271
* attributes and negative TL data types) from the real database
1272
* into the temporary one.
1428
1274
static krb5_error_code
1429
krb5_db2_begin_nra_merge(krb5_context context,
1430
krb5_db2_context *src_db,
1431
krb5_db2_context *dst_db)
1275
ctx_merge_nra(krb5_context context, krb5_db2_context *dbc_temp,
1276
krb5_db2_context *dbc_real)
1433
krb5_error_code retval;
1434
kdb5_dal_handle *dal_handle = context->dal_handle;
1435
1278
struct nra_context nra;
1437
1280
nra.kcontext = context;
1438
nra.db_context = dst_db;
1440
assert(dal_handle->db_context == dst_db);
1441
dal_handle->db_context = src_db;
1443
retval = krb5_db2_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
1445
dal_handle->db_context = dst_db;
1449
retval = krb5_db2_iterate_ext(context, krb5_db2_merge_nra_iterator,
1452
(void) krb5_db2_unlock(context);
1454
dal_handle->db_context = dst_db;
1281
nra.db_context = dbc_real;
1282
return ctx_iterate(context, dbc_temp, krb5_db2_merge_nra_iterator, &nra);
1460
* Finish merge of non-replicated attributes by unlocking
1286
* In the filesystem, promote the temporary database described by dbc_temp to
1287
* the real database described by dbc_real. Both must be exclusively locked.
1463
1289
static krb5_error_code
1464
krb5_db2_end_nra_merge(krb5_context context,
1465
krb5_db2_context *src_db,
1466
krb5_db2_context *dst_db)
1290
ctx_promote(krb5_context context, krb5_db2_context *dbc_temp,
1291
krb5_db2_context *dbc_real)
1468
1293
krb5_error_code retval;
1469
kdb5_dal_handle *dal_handle = context->dal_handle;
1471
dal_handle->db_context = src_db;
1472
retval = krb5_db2_unlock(context);
1473
dal_handle->db_context = dst_db;
1294
char *tdb = NULL, *tlock = NULL, *tpol = NULL, *tplock = NULL;
1295
char *rdb = NULL, *rlock = NULL, *rpol = NULL, *rplock = NULL;
1297
/* Generate all filenames of interest (including a few we don't need). */
1298
retval = ctx_allfiles(dbc_temp, &tdb, &tlock, &tpol, &tplock);
1301
retval = ctx_allfiles(dbc_real, &rdb, &rlock, &rpol, &rplock);
1305
/* Rename the principal and policy databases into place. */
1306
if (rename(tdb, rdb)) {
1310
if (rename(tpol, rpol)) {
1315
ctx_update_age(dbc_real);
1317
/* Release and remove the temporary DB lockfiles. */
1318
(void) unlink(tlock);
1319
(void) unlink(tplock);
1478
/* Retrieved from pre-DAL code base. */
1480
* "Atomically" rename the database in a way that locks out read
1481
* access in the middle of the rename.
1483
* Not perfect; if we crash in the middle of an update, we don't
1484
* necessarily know to complete the transaction the rename, but...
1486
* Since the rename operation happens outside the init/fini bracket, we
1487
* have to go through the same stuff that we went through up in db_destroy.
1489
1333
krb5_error_code
1490
krb5_db2_rename(krb5_context context, char *from, char *to, int merge_nra)
1334
krb5_db2_promote_db(krb5_context context, char *conf_section, char **db_args)
1493
1336
krb5_error_code retval;
1494
krb5_db2_context *s_context, *db_ctx;
1495
kdb5_dal_handle *dal_handle = context->dal_handle;
1497
s_context = dal_handle->db_context;
1498
dal_handle->db_context = NULL;
1499
if ((retval = k5db2_init_context(context)))
1337
krb5_boolean merge_nra = FALSE, real_locked = FALSE;
1338
krb5_db2_context *dbc_temp, *dbc_real = NULL;
1341
/* context must be initialized with an exclusively locked temp DB. */
1342
if (!inited(context))
1343
return KRB5_KDB_DBNOTINITED;
1344
dbc_temp = context->dal_handle->db_context;
1345
if (dbc_temp->db_lock_mode != KRB5_LOCKMODE_EXCLUSIVE)
1346
return KRB5_KDB_NOTLOCKED;
1347
if (!dbc_temp->tempdb)
1350
/* Check db_args for whether we should merge non-replicated attributes. */
1351
for (db_argp = db_args; *db_argp; db_argp++) {
1352
if (!strcmp(*db_argp, "merge_nra")) {
1358
/* Make a db2 context for the real DB. */
1359
dbc_real = k5alloc(sizeof(*dbc_real), &retval);
1360
if (dbc_real == NULL)
1501
db_ctx = (krb5_db2_context *) dal_handle->db_context;
1504
* Create the database if it does not already exist; the
1505
* files must exist because krb5_db2_lock, called below,
1506
* will fail otherwise.
1508
retval = create_db(context, to);
1509
if (retval != 0 && retval != EEXIST)
1513
* Set the database to the target, so that other processes sharing
1514
* the target will stop their activity, and notice the new database.
1516
db_ctx->db_name = strdup(to);
1517
if (db_ctx->db_name == NULL) {
1522
retval = check_openable(context);
1526
retval = krb5_db2_init(context);
1530
db_ctx->db_lf_name = gen_dbsuffix(db_ctx->db_name, KDB2_LOCK_EXT);
1531
if (db_ctx->db_lf_name == NULL) {
1535
db_ctx->db_lf_file = open(db_ctx->db_lf_name, O_RDWR|O_CREAT, 0600);
1536
if (db_ctx->db_lf_file < 0) {
1540
set_cloexec_fd(db_ctx->db_lf_file);
1542
db_ctx->db_inited = 1;
1544
retval = krb5_db2_get_age(context, NULL, &db_ctx->db_lf_time);
1548
fromok = gen_dbsuffix(from, KDB2_LOCK_EXT);
1549
if (fromok == NULL) {
1554
if ((retval = krb5_db2_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
1557
if ((retval = krb5_db2_start_update(context)))
1561
if ((retval = krb5_db2_begin_nra_merge(context, s_context, db_ctx)))
1565
if (rename(from, to)) {
1569
if (unlink(fromok)) {
1575
krb5_db2_end_nra_merge(context, s_context, db_ctx);
1578
retval = krb5_db2_end_update(context);
1583
/* XXX moved so that NRA merge works */
1584
/* Ugly brute force hack.
1586
Should be going through nice friendly helper routines for
1587
this, but it's a mess of jumbled so-called interfaces right
1589
char policy[2048], new_policy[2048];
1590
assert (strlen(db_ctx->db_name) < 2000);
1591
snprintf(policy, sizeof(policy), "%s.kadm5", db_ctx->db_name);
1592
snprintf(new_policy, sizeof(new_policy),
1593
"%s~.kadm5", db_ctx->db_name);
1594
if (0 != rename(new_policy, policy)) {
1598
strlcat(new_policy, ".lock",sizeof(new_policy));
1599
(void) unlink(new_policy);
1603
free_dbsuffix(fromok);
1605
if (dal_handle->db_context) {
1606
if (db_ctx->db_lf_file >= 0) {
1607
krb5_db2_unlock(context);
1608
close(db_ctx->db_lf_file);
1610
k5db2_clear_context((krb5_db2_context *) dal_handle->db_context);
1611
free(dal_handle->db_context);
1614
dal_handle->db_context = s_context;
1615
(void) krb5_db2_unlock(context); /* unlock saved context db */
1362
ctx_clear(dbc_real);
1364
/* Try creating the real DB. */
1365
dbc_real->db_name = strdup(dbc_temp->db_name);
1366
if (dbc_real->db_name == NULL)
1368
dbc_real->tempdb = FALSE;
1369
retval = ctx_create_db(context, dbc_real);
1370
if (retval == EEXIST) {
1371
/* The real database already exists, so open and lock it. */
1372
dbc_real->db_name = strdup(dbc_temp->db_name);
1373
if (dbc_real->db_name == NULL)
1375
dbc_real->tempdb = FALSE;
1376
retval = ctx_init(dbc_real);
1379
retval = ctx_lock(context, dbc_real, KRB5_DB_LOCKMODE_EXCLUSIVE);
1387
retval = ctx_merge_nra(context, dbc_temp, dbc_real);
1392
/* Perform filesystem manipulations for the promotion. */
1393
retval = ctx_promote(context, dbc_temp, dbc_real);
1397
/* Unlock and finalize context since the temp DB is gone. */
1398
(void) krb5_db2_unlock(context);
1399
krb5_db2_fini(context);
1403
(void) ctx_unlock(context, dbc_real);