/* Run one invocation of the callback, unlocking the mutex and possibly the DB * around the invocation. */ static krb5_error_code curs_run_cb(iter_curs *curs, ctx_iterate_cb func, krb5_pointer func_arg) { krb5_db2_context *dbc = curs->dbc; krb5_error_code retval, lockerr; krb5_db_entry *entry; krb5_context ctx = curs->ctx; krb5_data contdata; contdata = make_data(curs->data.data, curs->data.size); retval = krb5_decode_princ_entry(ctx, &contdata, &entry); if (retval) return retval; /* Save libdb key across possible DB closure. */ retval = curs_save(curs); if (retval) return retval; if (dbc->unlockiter) curs_unlock(curs); k5_mutex_unlock(krb5_db2_mutex); retval = (*func)(func_arg, entry); krb5_db2_free(ctx, entry); k5_mutex_lock(krb5_db2_mutex); if (dbc->unlockiter) { lockerr = curs_lock(curs); if (lockerr) return lockerr; } return retval; }
krb5_error_code krb5_db2_get_principal(krb5_context context, krb5_const_principal searchfor, unsigned int flags, krb5_db_entry **entry) { krb5_db2_context *db_ctx; krb5_error_code retval; DB *db; DBT key, contents; krb5_data keydata, contdata; int trynum, dbret; *entry = NULL; if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; db_ctx = context->dal_handle->db_context; for (trynum = 0; trynum < KRB5_DB2_MAX_RETRY; trynum++) { if ((retval = krb5_db2_lock(context, KRB5_LOCKMODE_SHARED))) { if (db_ctx->db_nb_locks) return (retval); sleep(1); continue; } break; } if (trynum == KRB5_DB2_MAX_RETRY) return KRB5_KDB_DB_INUSE; /* XXX deal with wildcard lookups */ retval = krb5_encode_princ_dbkey(context, &keydata, searchfor); if (retval) goto cleanup; key.data = keydata.data; key.size = keydata.length; db = db_ctx->db; dbret = (*db->get)(db, &key, &contents, 0); retval = errno; krb5_free_data_contents(context, &keydata); switch (dbret) { case 1: retval = KRB5_KDB_NOENTRY; /* Fall through. */ case -1: default: goto cleanup; case 0: contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, entry); break; } cleanup: (void) krb5_db2_unlock(context); /* unlock read lock */ 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; }
krb5_error_code krb5_db2_get_principal(krb5_context context, krb5_const_principal searchfor, unsigned int flags, krb5_db_entry **entry) { krb5_db2_context *dbc; krb5_error_code retval; DB *db; DBT key, contents; krb5_data keydata, contdata; int dbret; *entry = NULL; if (!inited(context)) return KRB5_KDB_DBNOTINITED; dbc = context->dal_handle->db_context; retval = ctx_lock(context, dbc, KRB5_LOCKMODE_SHARED); if (retval) return retval; /* XXX deal with wildcard lookups */ retval = krb5_encode_princ_dbkey(context, &keydata, searchfor); if (retval) goto cleanup; key.data = keydata.data; key.size = keydata.length; db = dbc->db; dbret = (*db->get)(db, &key, &contents, 0); retval = errno; krb5_free_data_contents(context, &keydata); switch (dbret) { case 1: retval = KRB5_KDB_NOENTRY; /* Fall through. */ case -1: default: goto cleanup; case 0: contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, entry); break; } cleanup: (void) krb5_db2_unlock(context); /* unlock read lock */ return retval; }
krb5_error_code krb5_db2_delete_principal(krb5_context context, krb5_const_principal searchfor) { krb5_error_code retval; krb5_db_entry *entry; krb5_db2_context *db_ctx; DB *db; DBT key, contents; krb5_data keydata, contdata; int i, dbret; if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; db_ctx = context->dal_handle->db_context; if ((retval = krb5_db2_lock(context, KRB5_LOCKMODE_EXCLUSIVE))) return (retval); if ((retval = krb5_db2_start_update(context))) { (void) krb5_db2_unlock(context); /* unlock write lock */ return (retval); } if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor))) goto cleanup; key.data = keydata.data; key.size = keydata.length; db = db_ctx->db; dbret = (*db->get) (db, &key, &contents, 0); retval = errno; switch (dbret) { case 1: retval = KRB5_KDB_NOENTRY; /* Fall through. */ case -1: default: goto cleankey; case 0: ; } contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, &entry); if (retval) goto cleankey; /* Clear encrypted key contents */ for (i = 0; i < entry->n_key_data; i++) { if (entry->key_data[i].key_data_length[0]) { memset(entry->key_data[i].key_data_contents[0], 0, (unsigned) entry->key_data[i].key_data_length[0]); } } retval = krb5_encode_princ_entry(context, &contdata, entry); krb5_dbe_free(context, entry); if (retval) goto cleankey; contents.data = contdata.data; contents.size = contdata.length; dbret = (*db->put) (db, &key, &contents, 0); retval = dbret ? errno : 0; krb5_free_data_contents(context, &contdata); if (retval) goto cleankey; dbret = (*db->del) (db, &key, 0); retval = dbret ? errno : 0; cleankey: krb5_free_data_contents(context, &keydata); cleanup: (void) krb5_db2_end_update(context); (void) krb5_db2_unlock(context); /* unlock write lock */ return retval; }
krb5_error_code krb5_db2_iterate_ext(krb5_context context, krb5_error_code(*func) (krb5_pointer, krb5_db_entry *), krb5_pointer func_arg, int backwards, int recursive) { krb5_db2_context *db_ctx; DB *db; DBT key, contents; krb5_data contdata; krb5_db_entry *entry; krb5_error_code retval; int dbret; void *cookie; cookie = NULL; if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; db_ctx = context->dal_handle->db_context; retval = krb5_db2_lock(context, KRB5_LOCKMODE_SHARED); if (retval) return retval; db = db_ctx->db; if (recursive && db->type != DB_BTREE) { (void) krb5_db2_unlock(context); return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */ } if (!recursive) { dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST); } else { #ifdef HAVE_BT_RSEQ dbret = bt_rseq(db, &key, &contents, &cookie, backwards ? R_LAST : R_FIRST); #else (void) krb5_db2_unlock(context); return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */ #endif } while (dbret == 0) { krb5_error_code retval2; 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; } if (!recursive) { dbret = (*db->seq) (db, &key, &contents, backwards ? R_PREV : R_NEXT); } else { #ifdef HAVE_BT_RSEQ dbret = bt_rseq(db, &key, &contents, &cookie, backwards ? R_PREV : R_NEXT); #else (void) krb5_db2_unlock(context); return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */ #endif } } switch (dbret) { case 1: case 0: break; case -1: default: retval = errno; } (void) krb5_db2_unlock(context); return retval; }