krb5_error_code krb5_db2_unlock(krb5_context context) { if (!inited(context)) return KRB5_KDB_DBNOTINITED; return ctx_unlock(context, context->dal_handle->db_context); }
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; }
static krb5_error_code ctx_iterate(krb5_context context, krb5_db2_context *dbc, krb5_error_code (*func)(krb5_pointer, krb5_db_entry *), krb5_pointer func_arg) { DB *db; DBT key, contents; krb5_data contdata; krb5_db_entry *entry; krb5_error_code retval, retval2; int dbret; retval = ctx_lock(context, dbc, KRB5_LOCKMODE_SHARED); if (retval) return retval; db = dbc->db; dbret = db->seq(db, &key, &contents, R_FIRST); while (dbret == 0) { contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, &entry); if (retval) break; retval = k5_mutex_unlock(krb5_db2_mutex); if (retval) break; retval = (*func)(func_arg, entry); krb5_dbe_free(context, entry); retval2 = k5_mutex_lock(krb5_db2_mutex); /* Note: If re-locking fails, the wrapper in db2_exp.c will still try to unlock it again. That would be a bug. Fix when integrating the locking better. */ if (retval) break; if (retval2) { retval = retval2; break; } dbret = db->seq(db, &key, &contents, R_NEXT); } switch (dbret) { case 1: case 0: break; case -1: default: retval = errno; } (void) ctx_unlock(context, dbc); return retval; }
/* Unlock DB handle of curs, updating curs->islocked. */ static void curs_unlock(iter_curs *curs) { ctx_unlock(curs->ctx, curs->dbc); curs->islocked = FALSE; }
krb5_error_code krb5_db2_promote_db(krb5_context context, char *conf_section, char **db_args) { krb5_error_code retval; krb5_boolean merge_nra = FALSE, real_locked = FALSE; krb5_db2_context *dbc_temp, *dbc_real = NULL; char **db_argp; /* context must be initialized with an exclusively locked temp DB. */ if (!inited(context)) return KRB5_KDB_DBNOTINITED; dbc_temp = context->dal_handle->db_context; if (dbc_temp->db_lock_mode != KRB5_LOCKMODE_EXCLUSIVE) return KRB5_KDB_NOTLOCKED; if (!dbc_temp->tempdb) return EINVAL; /* Check db_args for whether we should merge non-replicated attributes. */ for (db_argp = db_args; *db_argp; db_argp++) { if (!strcmp(*db_argp, "merge_nra")) { merge_nra = TRUE; break; } } /* Make a db2 context for the real DB. */ dbc_real = k5alloc(sizeof(*dbc_real), &retval); if (dbc_real == NULL) return retval; ctx_clear(dbc_real); /* Try creating the real DB. */ dbc_real->db_name = strdup(dbc_temp->db_name); if (dbc_real->db_name == NULL) goto cleanup; dbc_real->tempdb = FALSE; retval = ctx_create_db(context, dbc_real); if (retval == EEXIST) { /* The real database already exists, so open and lock it. */ dbc_real->db_name = strdup(dbc_temp->db_name); if (dbc_real->db_name == NULL) goto cleanup; dbc_real->tempdb = FALSE; retval = ctx_init(dbc_real); if (retval) goto cleanup; retval = ctx_lock(context, dbc_real, KRB5_DB_LOCKMODE_EXCLUSIVE); if (retval) goto cleanup; } else if (retval) goto cleanup; real_locked = TRUE; if (merge_nra) { retval = ctx_merge_nra(context, dbc_temp, dbc_real); if (retval) goto cleanup; } /* Perform filesystem manipulations for the promotion. */ retval = ctx_promote(context, dbc_temp, dbc_real); if (retval) goto cleanup; /* Unlock and finalize context since the temp DB is gone. */ (void) krb5_db2_unlock(context); krb5_db2_fini(context); cleanup: if (real_locked) (void) ctx_unlock(context, dbc_real); if (dbc_real) ctx_fini(dbc_real); return retval; }