krb5_error_code osa_adb_open_and_lock(osa_adb_princ_t db, int locktype) { int ret; ret = osa_adb_get_lock(db, locktype); if (ret != OSA_ADB_OK) return ret; if (db->opencnt) goto open_ok; db->db = dbopen(db->filename, O_RDWR, 0600, DB_BTREE, &db->btinfo); if (db->db != NULL) goto open_ok; if (IS_EFTYPE(errno)) { db->db = dbopen(db->filename, O_RDWR, 0600, DB_HASH, &db->info); if (db->db != NULL) goto open_ok; } else { (void) osa_adb_release_lock(db); if (errno == EINVAL) return OSA_ADB_BAD_DB; return errno; } open_ok: db->opencnt++; return OSA_ADB_OK; }
krb5_error_code osa_adb_rename_db(char *filefrom, char *lockfrom, char *fileto, char *lockto, int magic) { osa_adb_db_t fromdb, todb; krb5_error_code ret; /* make sure todb exists */ if ((ret = osa_adb_create_db(fileto, lockto, magic)) && ret != EEXIST) return ret; if ((ret = osa_adb_init_db(&fromdb, filefrom, lockfrom, magic))) return ret; if ((ret = osa_adb_init_db(&todb, fileto, lockto, magic))) { (void) osa_adb_fini_db(fromdb, magic); return ret; } if ((ret = osa_adb_get_lock(fromdb, KRB5_DB_LOCKMODE_PERMANENT))) { (void) osa_adb_fini_db(fromdb, magic); (void) osa_adb_fini_db(todb, magic); return ret; } if ((ret = osa_adb_get_lock(todb, KRB5_DB_LOCKMODE_PERMANENT))) { (void) osa_adb_fini_db(fromdb, magic); (void) osa_adb_fini_db(todb, magic); return ret; } if ((rename(filefrom, fileto) < 0)) { (void) osa_adb_fini_db(fromdb, magic); (void) osa_adb_fini_db(todb, magic); return errno; } /* * Do not release the lock on fromdb because it is being renamed * out of existence; no one can ever use it again. */ if ((ret = osa_adb_release_lock(todb))) { (void) osa_adb_fini_db(fromdb, magic); (void) osa_adb_fini_db(todb, magic); return ret; } (void) osa_adb_fini_db(fromdb, magic); (void) osa_adb_fini_db(todb, magic); return 0; }
static krb5_error_code ctx_lock(krb5_context context, krb5_db2_context *dbc, int lockmode) { krb5_error_code retval; int kmode, tries; if (lockmode == KRB5_DB_LOCKMODE_PERMANENT || lockmode == KRB5_DB_LOCKMODE_EXCLUSIVE) kmode = KRB5_LOCKMODE_EXCLUSIVE; else if (lockmode == KRB5_DB_LOCKMODE_SHARED) kmode = KRB5_LOCKMODE_SHARED; else return EINVAL; if (dbc->db_locks_held == 0 || dbc->db_lock_mode < kmode) { /* Acquire or upgrade the lock. */ for (tries = 0; tries < MAX_LOCK_TRIES; tries++) { retval = krb5_lock_file(context, dbc->db_lf_file, kmode | KRB5_LOCKMODE_DONTBLOCK); if (retval == 0) break; if (retval == EBADF && kmode == KRB5_LOCKMODE_EXCLUSIVE) /* Tried to lock something we don't have write access to. */ return KRB5_KDB_CANTLOCK_DB; sleep(1); } if (retval == EACCES) return KRB5_KDB_CANTLOCK_DB; else if (retval == EAGAIN || retval == EWOULDBLOCK) return OSA_ADB_CANTLOCK_DB; else if (retval) return retval; /* Open the DB (or re-open it for read/write). */ if (dbc->db != NULL) dbc->db->close(dbc->db); dbc->db = open_db(dbc, kmode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600); if (dbc->db == NULL) { retval = errno; dbc->db_locks_held = 0; dbc->db_lock_mode = 0; (void) osa_adb_release_lock(dbc->policy_db); (void) krb5_lock_file(context, dbc->db_lf_file, KRB5_LOCKMODE_UNLOCK); return retval; } dbc->db_lock_mode = kmode; } dbc->db_locks_held++; /* Acquire or upgrade the policy lock. */ retval = osa_adb_get_lock(dbc->policy_db, lockmode); if (retval) (void) ctx_unlock(context, dbc); return retval; }
static krb5_error_code ctx_lock(krb5_context context, krb5_db2_context *dbc, int lockmode) { krb5_error_code retval; int kmode; if (lockmode == KRB5_DB_LOCKMODE_PERMANENT || lockmode == KRB5_DB_LOCKMODE_EXCLUSIVE) kmode = KRB5_LOCKMODE_EXCLUSIVE; else if (lockmode == KRB5_DB_LOCKMODE_SHARED) kmode = KRB5_LOCKMODE_SHARED; else return EINVAL; if (dbc->db_locks_held == 0 || dbc->db_lock_mode < kmode) { /* Acquire or upgrade the lock. */ retval = krb5_lock_file(context, dbc->db_lf_file, kmode); /* Check if we tried to lock something not open for write. */ if (retval == EBADF && kmode == KRB5_LOCKMODE_EXCLUSIVE) return KRB5_KDB_CANTLOCK_DB; else if (retval == EACCES || retval == EAGAIN || retval == EWOULDBLOCK) return KRB5_KDB_CANTLOCK_DB; else if (retval) return retval; /* Open the DB (or re-open it for read/write). */ if (dbc->db != NULL) dbc->db->close(dbc->db); dbc->db = open_db(dbc, kmode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600); if (dbc->db == NULL) { retval = errno; dbc->db_locks_held = 0; dbc->db_lock_mode = 0; (void) osa_adb_release_lock(dbc->policy_db); (void) krb5_lock_file(context, dbc->db_lf_file, KRB5_LOCKMODE_UNLOCK); return retval; } dbc->db_lock_mode = kmode; } dbc->db_locks_held++; /* Acquire or upgrade the policy lock. */ retval = osa_adb_get_lock(dbc->policy_db, lockmode); if (retval) { (void) ctx_unlock(context, dbc); if (retval == OSA_ADB_NOEXCL_PERM || retval == OSA_ADB_CANTLOCK_DB || retval == OSA_ADB_NOLOCKFILE) retval = KRB5_KDB_CANTLOCK_DB; } return retval; }
krb5_error_code krb5_db2_lock(krb5_context context, int in_mode) { krb5_db2_context *db_ctx; int krb5_lock_mode; DB *db; krb5_error_code retval; time_t mod_time; int mode, gotlock, tries; switch (in_mode) { case KRB5_DB_LOCKMODE_PERMANENT: mode = KRB5_DB_LOCKMODE_EXCLUSIVE; break; case KRB5_DB_LOCKMODE_EXCLUSIVE: mode = KRB5_LOCKMODE_EXCLUSIVE; break; case KRB5_DB_LOCKMODE_SHARED: mode = KRB5_LOCKMODE_SHARED; break; default: return EINVAL; } if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; db_ctx = context->dal_handle->db_context; if (db_ctx->db_locks_held && (db_ctx->db_lock_mode >= mode)) { /* No need to upgrade lock, just return */ db_ctx->db_locks_held++; goto policy_lock; } if ((mode != KRB5_LOCKMODE_SHARED) && (mode != KRB5_LOCKMODE_EXCLUSIVE)) return KRB5_KDB_BADLOCKMODE; krb5_lock_mode = mode | KRB5_LOCKMODE_DONTBLOCK; for (gotlock = tries = 0; tries < MAX_LOCK_TRIES; tries++) { retval = krb5_lock_file(context, db_ctx->db_lf_file, krb5_lock_mode); if (retval == 0) { gotlock++; break; } else if (retval == EBADF && mode == KRB5_DB_LOCKMODE_EXCLUSIVE) /* tried to exclusive-lock something we don't have */ /* write access to */ return KRB5_KDB_CANTLOCK_DB; sleep(1); } if (retval == EACCES) return KRB5_KDB_CANTLOCK_DB; else if (retval == EAGAIN || retval == EWOULDBLOCK) return OSA_ADB_CANTLOCK_DB; else if (retval != 0) return retval; if ((retval = krb5_db2_get_age(context, NULL, &mod_time))) goto lock_error; db = k5db2_dbopen(db_ctx, db_ctx->db_name, mode == KRB5_LOCKMODE_SHARED ? O_RDONLY : O_RDWR, 0600, db_ctx->tempdb); if (db) { db_ctx->db_lf_time = mod_time; db_ctx->db = db; } else { retval = errno; db_ctx->db = NULL; goto lock_error; } db_ctx->db_lock_mode = mode; db_ctx->db_locks_held++; policy_lock: if ((retval = osa_adb_get_lock(db_ctx->policy_db, in_mode))) { krb5_db2_unlock(context); } return retval; lock_error:; db_ctx->db_lock_mode = 0; db_ctx->db_locks_held = 0; krb5_db2_unlock(context); return retval; }
/* Initialize dbc by locking and creating the DB. If the DB already exists, * clear it out if dbc->tempdb is set; otherwise return EEXIST. */ static krb5_error_code ctx_create_db(krb5_context context, krb5_db2_context *dbc) { krb5_error_code retval = 0; char *dbname = NULL, *polname = NULL, *plockname = NULL; retval = ctx_allfiles(dbc, &dbname, &dbc->db_lf_name, &polname, &plockname); if (retval) return retval; dbc->db_lf_file = open(dbc->db_lf_name, O_CREAT | O_RDWR | O_TRUNC, 0600); if (dbc->db_lf_file < 0) { retval = errno; goto cleanup; } retval = krb5_lock_file(context, dbc->db_lf_file, KRB5_LOCKMODE_EXCLUSIVE | KRB5_LOCKMODE_DONTBLOCK); if (retval != 0) goto cleanup; set_cloexec_fd(dbc->db_lf_file); dbc->db_lock_mode = KRB5_LOCKMODE_EXCLUSIVE; dbc->db_locks_held = 1; if (dbc->tempdb) { /* Temporary DBs are locked for their whole lifetime. Since we have * the lock, any remnant files can be safely destroyed. */ (void) destroy_file(dbname); (void) unlink(polname); (void) unlink(plockname); } dbc->db = open_db(dbc, O_RDWR | O_CREAT | O_EXCL, 0600); if (dbc->db == NULL) { retval = errno; goto cleanup; } /* Create the policy database, initialize a handle to it, and lock it. */ retval = osa_adb_create_db(polname, plockname, OSA_ADB_POLICY_DB_MAGIC); if (retval) goto cleanup; retval = osa_adb_init_db(&dbc->policy_db, polname, plockname, OSA_ADB_POLICY_DB_MAGIC); if (retval) goto cleanup; retval = osa_adb_get_lock(dbc->policy_db, KRB5_DB_LOCKMODE_EXCLUSIVE); if (retval) goto cleanup; dbc->db_inited = 1; cleanup: if (retval) { if (dbc->db != NULL) dbc->db->close(dbc->db); if (dbc->db_locks_held > 0) { (void) krb5_lock_file(context, dbc->db_lf_file, KRB5_LOCKMODE_UNLOCK); } if (dbc->db_lf_file >= 0) close(dbc->db_lf_file); ctx_clear(dbc); } free(dbname); free(polname); free(plockname); return retval; }