diff --git a/lib/hdb/db.c b/lib/hdb/db.c index 02bf0e7f4..d8023cb5f 100644 --- a/lib/hdb/db.c +++ b/lib/hdb/db.c @@ -42,7 +42,7 @@ RCSID("$Id$"); #ifdef HAVE_DB_H -krb5_error_code +static krb5_error_code DB_close(krb5_context context, HDB *db) { DB *d = (DB*)db->db; @@ -51,45 +51,72 @@ DB_close(krb5_context context, HDB *db) return 0; } +static krb5_error_code +DB_lock(krb5_context context, HDB *db, int operation) +{ + DB *d = (DB*)db->db; + int fd = (*d->fd)(d); + if(fd < 0) + return HDB_ERR_CANT_LOCK_DB; + return hdb_lock(fd, operation); +} + +static krb5_error_code +DB_unlock(krb5_context context, HDB *db) +{ + DB *d = (DB*)db->db; + int fd = (*d->fd)(d); + if(fd < 0) + return HDB_ERR_CANT_LOCK_DB; + return hdb_unlock(fd); +} + + static krb5_error_code DB_op(krb5_context context, HDB *db, hdb_entry *entry, int op) { DB *d = (DB*)db->db; DBT key, value; krb5_data data; - int err; + int code; hdb_principal2key(context, entry->principal, &data); key.data = data.data; key.size = data.length; switch(op){ case 0: -#if 0 - krb5_free_principal (context, entry->principal); -#endif - err = d->get(d, &key, &value, 0); + code = db->lock(context, db, HDB_RLOCK); + if(code) + return code; + code = d->get(d, &key, &value, 0); + db->unlock(context, db); /* XXX check value */ break; case 1: hdb_entry2value(context, entry, &data); value.data = data.data; value.size = data.length; - err = d->put(d, &key, &value, 0); + code = db->lock(context, db, HDB_WLOCK); + if(code) + return code; + code = d->put(d, &key, &value, 0); + db->unlock(context, db); /* XXX check value */ krb5_data_free(&data); break; case 2: -#if 0 - krb5_free_principal (context, entry->principal); -#endif - err = d->del(d, &key, 0); + code = db->lock(context, db, HDB_WLOCK); + if(code) + return code; + code = d->del(d, &key, 0); + db->unlock(context, db); /* XXX check value */ break; } data.data = key.data; data.length = key.size; krb5_data_free(&data); - if(err < 0) + if(code < 0) return errno; - if(err == 1) - return KRB5_HDB_NOENTRY; + if(code == 1) + return HDB_ERR_NOENTRY; if(op == 0){ data.data = value.data; data.length = value.size; @@ -123,14 +150,18 @@ DB_seq(krb5_context context, HDB *db, hdb_entry *entry, int flag) DB *d = (DB*)db->db; DBT key, value; krb5_data key_data, data; - int err; + int code; krb5_principal principal; - err = d->seq(d, &key, &value, flag); - if(err == -1) + code = db->lock(context, db, HDB_RLOCK); + if(code == -1) + return HDB_ERR_DB_INUSE; + code = d->seq(d, &key, &value, flag); + db->unlock(context, db); /* XXX check value */ + if(code == -1) return errno; - if(err == 1) - return KRB5_HDB_NOENTRY; + if(code == 1) + return HDB_ERR_NOENTRY; key_data.data = key.data; key_data.length = key.size; @@ -139,7 +170,7 @@ DB_seq(krb5_context context, HDB *db, hdb_entry *entry, int flag) hdb_value2entry(context, &data, entry); if (entry->principal == NULL) { entry->principal = malloc(sizeof(*entry->principal)); - hdb_key2principal(context, &key_data, &entry->principal); + hdb_key2principal(context, &key_data, entry->principal); } return 0; } @@ -158,13 +189,38 @@ DB_nextkey(krb5_context context, HDB *db, hdb_entry *entry) return DB_seq(context, db, entry, R_NEXT); } +static krb5_error_code +DB__get(krb5_context context, HDB *db, krb5_data key, krb5_data *reply) +{ + DB *d = (DB*)db->db; + DBT k, v; + int code; + + k.data = key.data; + k.size = key.length; + code = db->lock(context, db, HDB_RLOCK); + if(code) + return code; + code = d->get(d, &k, &v, 0); + db->unlock(context, db); + if(code < 0) + return errno; + if(code == 1) + return HDB_ERR_NOENTRY; + + reply->length = v.size; + reply->data = malloc(reply->length); + memcpy(reply->data, v.data, reply->length); + return 0; +} + krb5_error_code hdb_db_open(krb5_context context, HDB **db, const char *filename, int flags, mode_t mode) { DB *d; - char *fn = malloc(strlen(filename) + 4); - sprintf(fn, "%s.db", filename); + char *fn; + asprintf(&fn, "%s.db", filename); d = dbopen(fn, flags, mode, DB_BTREE, NULL); free(fn); if(d == NULL) @@ -177,6 +233,8 @@ hdb_db_open(krb5_context context, HDB **db, (*db)->delete = DB_delete; (*db)->firstkey = DB_firstkey; (*db)->nextkey= DB_nextkey; + (*db)->lock = DB_lock; + (*db)->unlock = DB_unlock; return 0; }