static apr_status_t htdbm_list(htdbm_t *htdbm)
{
    apr_status_t rv;
    apr_datum_t key, val;
    char *cmnt;
    int i = 0;

    rv = apr_dbm_firstkey(htdbm->dbm, &key);
    if (rv != APR_SUCCESS) {
        fprintf(stderr, "Empty database -- %s\n", htdbm->filename);
        return APR_ENOENT;
    }
    fprintf(stderr, "Dumping records from database -- %s\n", htdbm->filename);
    fprintf(stderr, "    %-32s Comment\n", "Username");
    while (key.dptr != NULL) {
        rv = apr_dbm_fetch(htdbm->dbm, key, &val);
        if (rv != APR_SUCCESS) {
            fprintf(stderr, "Failed getting data from %s\n", htdbm->filename);
            return APR_EGENERAL;
        }
        /* Note: we don't store \0-terminators on our dbm data */
        fprintf(stderr, "    %-32.*s", (int)key.dsize, key.dptr);
        cmnt = memchr(val.dptr, ':', val.dsize);
        if (cmnt)
            fprintf(stderr, " %.*s", (int)(val.dptr+val.dsize - (cmnt+1)), cmnt + 1);
        fprintf(stderr, "\n");
        rv = apr_dbm_nextkey(htdbm->dbm, &key);
        if (rv != APR_SUCCESS)
            fprintf(stderr, "Failed getting NextKey\n");
        ++i;
    }

    fprintf(stderr, "Total #records : %d\n", i);
    return APR_SUCCESS;
}
Beispiel #2
0
static char *get_dbm_pw(request_rec *r, 
                        char *user, 
                        char *auth_dbmpwfile, 
                        char *dbtype)
{
    apr_dbm_t *f;
    apr_datum_t d, q;
    char *pw = NULL;
    apr_status_t retval;
    q.dptr = user;
#ifndef NETSCAPE_DBM_COMPAT
    q.dsize = strlen(q.dptr);
#else
    q.dsize = strlen(q.dptr) + 1;
#endif

    retval = apr_dbm_open_ex(&f, dbtype, auth_dbmpwfile, APR_DBM_READONLY, 
                             APR_OS_DEFAULT, r->pool);
    if (retval != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, retval, r,
                      "could not open dbm (type %s) auth file: %s", dbtype, 
                      auth_dbmpwfile);
        return NULL;
    }
    if (apr_dbm_fetch(f, q, &d) == APR_SUCCESS && d.dptr) {
        pw = apr_palloc(r->pool, d.dsize + 1);
        strncpy(pw, d.dptr, d.dsize);
        pw[d.dsize] = '\0'; /* Terminate the string */
    }

    apr_dbm_close(f);
    return pw;
}
Beispiel #3
0
static apr_status_t fetch_dbm_value(const char *dbmtype, const char *dbmfile,
                                    const char *user, char **value,
                                    apr_pool_t *pool)
{
    apr_dbm_t *f;
    apr_datum_t key, val;
    apr_status_t rv;

    rv = apr_dbm_open_ex(&f, dbmtype, dbmfile, APR_DBM_READONLY,
                         APR_OS_DEFAULT, pool);

    if (rv != APR_SUCCESS) {
        return rv;
    }

    key.dptr = (char*)user;
#ifndef NETSCAPE_DBM_COMPAT
    key.dsize = strlen(key.dptr);
#else
    key.dsize = strlen(key.dptr) + 1;
#endif

    *value = NULL;

    if (apr_dbm_fetch(f, key, &val) == APR_SUCCESS && val.dptr) {
        *value = apr_pstrmemdup(pool, val.dptr, val.dsize);
    }

    apr_dbm_close(f);

    return rv;
}
Beispiel #4
0
int main(int argc,char **argv) {
    apr_initialize();
    apr_pool_t *pool;
    apr_pool_create(&pool,NULL);


    apr_status_t st;
    apr_dbm_t *dbm;
    st=apr_dbm_open(&dbm,"friends",APR_DBM_RWCREATE,APR_OS_DEFAULT ,pool);

    apr_datum_t key,value;
    key.dptr="laomeng";
    key.dsize=strlen(key.dptr);
    
    value.dptr="*****@*****.**";
    value.dsize=strlen(value.dptr);
   
    st=apr_dbm_store(dbm,key,value);

    apr_datum_t pvalue;
    st=apr_dbm_fetch(dbm,key,&pvalue);

    char *pstr=apr_pstrndup(pool,pvalue.dptr,pvalue.dsize);
    printf("value => %s\n",pstr);
    
    apr_dbm_close(dbm);

    apr_pool_destroy(pool);
    apr_terminate();
    return 0;
}
Beispiel #5
0
static ftpd_chroot_status_t ftpd_dbm_map_chroot(const request_rec *r,
										const char **chroot,
										const char **initroot)
{
	apr_status_t res;
	apr_dbm_t *file;
	ftpd_chroot_status_t ret = FTPD_CHROOT_USER_NOT_FOUND;
	apr_datum_t key,val = { 0 };
	char *value, *tok, *tok_ses;
	ftpd_user_rec *ur  __attribute__ ((unused))= ftpd_get_user_rec(r);
	ftpd_dbm_server_conf *pConfig = ap_get_module_config(r->server->module_config,
										&ftpd_dbm_module);

	if ((res = apr_dbm_open_ex(&file, pConfig->dbtype, pConfig->chrootdb_path,
								APR_DBM_READONLY, APR_OS_DEFAULT, r->pool))
								!= APR_SUCCESS) {
		ap_log_rerror(APLOG_MARK, APLOG_ERR, res, r,
			"Error opening DBM file: %s",pConfig->chrootdb_path);
		ret = FTPD_CHROOT_FAIL;
	} else {
		if (file != NULL) {
			/* search the DB */
			key.dptr = r->user;
			key.dsize = strlen(key.dptr);

			if (apr_dbm_exists(file, key)) {
				if (apr_dbm_fetch(file, key, &val) == APR_SUCCESS) {
					value = apr_pstrndup(r->pool, val.dptr, val.dsize);
					tok = apr_strtok(value, ":", &tok_ses);
					if (tok != NULL) {
						*chroot = apr_pstrdup(r->pool, tok);
						tok = apr_strtok(NULL, ":", &tok_ses);
						if (tok != NULL) {
							*initroot = apr_pstrdup(r->pool, tok);
						}
						ret = FTPD_CHROOT_USER_FOUND;
					} else {
						ret = FTPD_CHROOT_FAIL;
					}
				}
			}

			apr_dbm_close(file);
		} else {
			ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
				"File open failed: %s",pConfig->chrootdb_path);
			ret = FTPD_CHROOT_FAIL;
		}
	}
	return ret;
}
Beispiel #6
0
dav_error * dav_dbm_fetch(dav_db *db, apr_datum_t key, apr_datum_t *pvalue)
{
    apr_status_t status;

    if (!key.dptr) {
        /* no key could be created (namespace not known) => no value */
        memset(pvalue, 0, sizeof(*pvalue));
        status = APR_SUCCESS;
    } else {
        status = apr_dbm_fetch(db->file, key, pvalue);
    }

    return dav_fs_dbm_error(db, NULL, status);
}
Beispiel #7
0
/* This should go into APR; perhaps with some nice
 * caching/locking/flocking of the open dbm file.
 */
static char *get_dbm_entry_as_str(apr_pool_t *pool, apr_dbm_t *f, char *key)
{
    apr_datum_t d, q;
    q.dptr = key;

#ifndef NETSCAPE_DBM_COMPAT
    q.dsize = strlen(q.dptr);
#else
    q.dsize = strlen(q.dptr) + 1;
#endif

    if (apr_dbm_fetch(f, q, &d) == APR_SUCCESS && d.dptr) {
        return apr_pstrmemdup(pool, d.dptr, d.dsize);
    }

    return NULL;
}
Beispiel #8
0
    mbox_cache_get_count(mbox_cache_info *mli, int *count, char *path)
{
    apr_status_t rv = APR_SUCCESS;
    apr_datum_t key;
    apr_datum_t nv;

    key.dptr = path;
    key.dsize = strlen(path) + 1;

    rv = apr_dbm_fetch(mli->db, key, &nv);

    if (rv == APR_SUCCESS && nv.dsize == sizeof(int)) {
        memcpy(count, nv.dptr, sizeof(int));
    }
    else {
        *count = 0;
    }
    return rv;
}
static apr_status_t htdbm_verify(htdbm_t *htdbm)
{
    apr_datum_t key, val;
    char *pwd;
    char *rec, *cmnt;

    key.dptr = htdbm->username;
    key.dsize = strlen(htdbm->username);
    if (!apr_dbm_exists(htdbm->dbm, key))
        return APR_ENOENT;
    if (apr_dbm_fetch(htdbm->dbm, key, &val) != APR_SUCCESS)
        return APR_ENOENT;
    rec = apr_pstrndup(htdbm->ctx.pool, val.dptr, val.dsize);
    cmnt = strchr(rec, ':');
    if (cmnt)
        pwd = apr_pstrndup(htdbm->ctx.pool, rec, cmnt - rec);
    else
        pwd = apr_pstrdup(htdbm->ctx.pool, rec);
    return apr_password_validate(htdbm->ctx.passwd, pwd);
}
Beispiel #10
0
    mbox_cache_update(mbox_cache_info ** mlix,
                  const char *path, apr_pool_t *pool,
                  char *list, char *domain)
{
    apr_status_t rv;
    char *temp;
    apr_datum_t key;
    apr_datum_t nv;
    mbox_cache_info *mli;
    int update_only = 0;
    int tver;

    OPEN_DBM(pool, mli, APR_DBM_READWRITE, path, temp, rv);

    if (rv != APR_SUCCESS) {
        OPEN_DBM(pool, mli, APR_DBM_RWCREATE, path, temp, rv);

        mli->mtime = 0;
        if (rv != APR_SUCCESS) {
            return rv;
        }
    }
    else {
        update_only = 1;
    }

    mli->pool = pool;
    apr_pool_cleanup_register(pool, (void *) mli, mli_cleanup,
                              apr_pool_cleanup_null);

    key.dptr = str_cache_version;
    key.dsize = strlen(str_cache_version) + 1;
    tver = MBOX_CACHE_VERSION;

    temp = apr_palloc(pool, sizeof(tver));
    memcpy(temp, &tver, sizeof(tver));

    nv.dptr = temp;
    nv.dsize = sizeof(tver);
    rv = apr_dbm_store(mli->db, key, nv);

    if (rv != APR_SUCCESS) {
        return rv;
    }

    if (update_only == 1) {
        key.dptr = str_cache_mtime;
        key.dsize = strlen(str_cache_mtime) + 1;
        rv = apr_dbm_fetch(mli->db, key, &nv);

        if (rv != APR_SUCCESS) {
            apr_dbm_close(mli->db);
            return rv;
        }
        if (nv.dptr && nv.dsize == sizeof(mli->mtime)) {
            memcpy(&mli->mtime, nv.dptr, sizeof(mli->mtime));
        }
        else {
            mli->mtime = 0;
        }
    }
    else {
        mli->mtime = 0;
    }

    key.dptr = str_cache_list;
    key.dsize = strlen(str_cache_list) + 1;
    nv.dptr = list;
    nv.dsize = strlen(list) + 1;
    rv = apr_dbm_store(mli->db, key, nv);
    if (rv != APR_SUCCESS) {
        return rv;
    }
    mli->domain = apr_pstrdup(pool, list);

    key.dptr = str_cache_domain;
    key.dsize = strlen(str_cache_domain) + 1;
    nv.dptr = domain;
    nv.dsize = strlen(domain) + 1;
    rv = apr_dbm_store(mli->db, key, nv);

    if (rv != APR_SUCCESS) {
        return rv;
    }
    mli->domain = apr_pstrdup(pool, domain);

    *mlix = mli;

    return rv;
}
Beispiel #11
0
    mbox_cache_get(mbox_cache_info ** mlix, const char *path, apr_pool_t *p)
{
    apr_status_t rv;
    char *temp;
    apr_datum_t key;
    apr_datum_t nv;
    int tver;
    mbox_cache_info *mli;

    OPEN_DBM(p, mli, APR_DBM_READONLY, path, temp, rv);

    if (rv != APR_SUCCESS) {
        return rv;
    }

    mli->pool = p;

    apr_pool_cleanup_register(p, (void *) mli, mli_cleanup,
                              apr_pool_cleanup_null);

    key.dptr = str_cache_version;
    key.dsize = strlen(str_cache_version) + 1;

    rv = apr_dbm_fetch(mli->db, key, &nv);

    if (rv != APR_SUCCESS) {
        apr_dbm_close(mli->db);
        return rv;
    }

    memcpy(&tver, nv.dptr, sizeof(tver));

    if (tver != MBOX_CACHE_VERSION) {
        apr_dbm_close(mli->db);
        return 1;
    }
    mli->version = tver;

    key.dptr = str_cache_mtime;
    key.dsize = strlen(str_cache_mtime) + 1;

    rv = apr_dbm_fetch(mli->db, key, &nv);

    if (rv != APR_SUCCESS) {
        apr_dbm_close(mli->db);
        return rv;
    }
    memcpy(&mli->mtime, nv.dptr, sizeof(mli->mtime));

    key.dptr = str_cache_list;
    key.dsize = strlen(str_cache_list) + 1;
    rv = apr_dbm_fetch(mli->db, key, &nv);
    if (rv != APR_SUCCESS) {
        apr_dbm_close(mli->db);
        return rv;
    }
    mli->list = apr_pstrdup(p, nv.dptr);

    key.dptr = str_cache_domain;
    key.dsize = strlen(str_cache_domain) + 1;
    rv = apr_dbm_fetch(mli->db, key, &nv);
    if (rv != APR_SUCCESS) {
        apr_dbm_close(mli->db);
        return rv;
    }
    mli->domain = apr_pstrdup(p, nv.dptr);

    *mlix = mli;

    return rv;
}
static authn_status authn_check_otp(request_rec *r, const char *user,
                                    const char *password)
{
    apr_status_t rv;
    apr_dbm_t *userDbm = NULL;
    yubiauth_dir_cfg *cfg = ap_get_module_config(r->per_dir_config, &authn_yubikey_module);

    apr_datum_t key,dbUserRecord;
    key.dptr = NULL;
    dbUserRecord.dptr = NULL;

    char *lookedUpToken = NULL;
    char *lookedUpPassword = NULL; //This is the OTP token
    char *dbUserKey = (char *) malloc(sizeof(user));
    apr_size_t passwordLength = 0;
    apr_time_t lookedUpDate = 0;



    /* No username and no password is set */
    if (!*user || !*password)
        return AUTH_DENIED;

    /* Since the password field contains possibly a password and the OTP token, we 
     * have to break that up here
     */
    passwordLength = (apr_size_t) strlen(password) - YUBIKEY_TOKEN_LENGTH;

    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
                  LOG_PREFIX "Username is: %s and password is: %s", user, &password[passwordLength]);

    /* Now open the User DB and see if the user really is one of us.
     * for that we save the 12char token:username combo.
     * Ideally we can fill that with the htpasswd utility
     * NOTE: enter full password here
     */
    if (!isUserValid(user, password, cfg, r)) {
      return AUTH_DENIED;
    }

    openDb(&userDbm, cfg->tmpAuthDbFilename, r);

    dbUserKey = strcpy(dbUserKey, user);
    dbUserKey = getDbKey(dbUserKey, cfg, r);
    key = string2datum(dbUserKey, r);
    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r, LOG_PREFIX "Fetching token (pw:time) for user %s from db ...", user);
    rv = apr_dbm_fetch(userDbm, key, &dbUserRecord);
    if (rv != APR_SUCCESS) {
        ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, LOG_PREFIX "unable to fetch the user (%s) from the"
                      "Database, better abort here.", user);
        closeDb(userDbm, r);
        return HTTP_INTERNAL_SERVER_ERROR;
    }
    if (dbUserRecord.dptr != NULL) {

        /* it's separated pw:time here */
        const char *sep = ":";
        char *time;

        lookedUpToken = apr_pstrmemdup(r->pool, dbUserRecord.dptr, dbUserRecord.dsize);
        /* Break down the token into it's pw:time components */
        lookedUpPassword = apr_strtok(lookedUpToken, sep, &time);
        lookedUpDate = (apr_time_t) apr_atoi64(time);


        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
                      LOG_PREFIX "We could extrace these values from the token:");
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
                      LOG_PREFIX "The looked up token for the user: %s",
                      user);
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
                      LOG_PREFIX "The looked up password: %s",
                      lookedUpPassword);
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
                      LOG_PREFIX "The looked up time: %" APR_TIME_T_FMT,
                      lookedUpDate);
        ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
                      LOG_PREFIX "The looked up token: %s",
                      lookedUpToken);
    }
    ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r, LOG_PREFIX "Fetched token (%s) ...", lookedUpToken);

    /* password has to be set, if the pw content is NULL or empty, we have 
     * catched that earlier ...
     */
    if (lookedUpPassword != NULL && !strcmp(lookedUpPassword, &password[passwordLength])) {
        /* The date expired */
        if (passwordExpired(user, lookedUpDate, cfg->timeoutSeconds, r)) {
            /* Delete user record */
            ap_log_rerror(APLOG_MARK, APLOG_ERR|APLOG_DEBUG, 0, r,
			LOG_PREFIX "Remove expired entry for user : %s",
			user);
            deleteKeyFromDb(userDbm, user, cfg, r);
            closeDb(userDbm, r);
            return AUTH_DENIED;
        }
        else {
            closeDb(userDbm, r);
            return AUTH_GRANTED;
        }
    }
    else {
        int authenticationSuccessful = 0;
        int ret = YUBIKEY_CLIENT_BAD_OTP;
        /* We could not lookup the password, verify the sent password */
        ret = yubikey_client_simple_request(&password[passwordLength], 1, 0, NULL, r);
            if (ret == YUBIKEY_CLIENT_OK) {
                authenticationSuccessful = 1;
            } else {
                ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
                              LOG_PREFIX "Authentication failed, reason: %s",
                              yubikey_client_strerror(ret));
                return AUTH_DENIED;
            }

        /* We could successfully authenticate the user */
        if (authenticationSuccessful) {
            /* Try to write the user into the db */
            if (setUserInDb(userDbm, user, &password[passwordLength], cfg, r)
		!= APR_SUCCESS) {
                /* Abort, we could not write the user into the db after
                 * authenticating him ...
                 */
                closeDb(userDbm, r);
                return HTTP_INTERNAL_SERVER_ERROR;
            }

            /* User could be written to the db*/
            closeDb(userDbm, r);
            return AUTH_GRANTED;
        }

        /* Could not authenticate successful */
        closeDb(userDbm, r);
        return AUTH_DENIED;
    }

    /* Something went wrong or we did not think about it, better deny */
    closeDb(userDbm, r);
    return AUTH_DENIED;
}
Beispiel #13
0
static int xlate_name(request_rec *r)
{
    int i;
    const char *name;
    char *backend;
    apr_dbm_t *db;
    apr_status_t rv;
    apr_datum_t key, val;
    struct proxy_alias *ralias;
    proxy_dir_conf *dconf;
    express_server_conf *sconf;

    sconf = ap_get_module_config(r->server->module_config, &proxy_express_module);
    dconf = ap_get_module_config(r->per_dir_config, &proxy_module);

    if (!sconf->enabled) {
        return DECLINED;
    }

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01001) "proxy_express: Enabled");
    if (!sconf->dbmfile || (r->filename && strncmp(r->filename, "proxy:", 6) == 0)) {
        /* it should be go on as an internal proxy request */
        return DECLINED;
    }

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01002)
                  "proxy_express: Opening DBM file: %s (%s)",
                  sconf->dbmfile, sconf->dbmtype);
    rv = apr_dbm_open_ex(&db, sconf->dbmtype, sconf->dbmfile, APR_DBM_READONLY,
                         APR_OS_DEFAULT, r->pool);
    if (rv != APR_SUCCESS) {
        return DECLINED;
    }

    name = ap_get_server_name(r);
    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01003)
                  "proxy_express: looking for %s", name);
    key.dptr = (char *)name;
    key.dsize = strlen(key.dptr);

    rv = apr_dbm_fetch(db, key, &val);
    apr_dbm_close(db);
    if (rv != APR_SUCCESS) {
        return DECLINED;
    }

    backend = apr_pstrmemdup(r->pool, val.dptr, val.dsize);
    if (!backend) {
        return DECLINED;
    }

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01004)
                  "proxy_express: found %s -> %s", name, backend);
    r->filename = apr_pstrcat(r->pool, "proxy:", backend, r->uri, NULL);
    r->handler = "proxy-server";
    r->proxyreq = PROXYREQ_REVERSE;

    ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01005)
                  "proxy_express: rewritten as: %s", r->filename);

    ralias = (struct proxy_alias *)dconf->raliases->elts;
    /*
     * See if we have already added a ProxyPassReverse entry
     * for this host... If so, don't do it again.
     */
    /*
     * NOTE: dconf is process specific so this wil only
     *       work as long as we maintain that this process
     *       or thread is handling the backend
     */
    for (i = 0; i < dconf->raliases->nelts; i++, ralias++) {
        if (strcasecmp(backend, ralias->real) == 0) {
            ralias = NULL;
            break;
        }
    }

    /* Didn't find one... add it */
    if (!ralias) {
        ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, APLOGNO(01006)
                      "proxy_express: adding PPR entry");
        ralias = apr_array_push(dconf->raliases);
        ralias->fake = "/";
        ralias->real = apr_pstrdup(dconf->raliases->pool, backend);
        ralias->flags = 0;
    }
    return OK;
}
Beispiel #14
0
dav_error * dav_dbm_fetch(dav_db *db, apr_datum_t key, apr_datum_t *pvalue)
{
    apr_status_t status = apr_dbm_fetch(db->file, key, pvalue);

    return dav_fs_dbm_error(db, NULL, status);
}
Beispiel #15
0
/*
 * dav_load_lock_record:  Reads lock information about key from lock db;
 *    creates linked lists of the direct and indirect locks.
 *
 *    If add_method = DAV_APPEND_LIST, the result will be appended to the
 *    head of the direct and indirect lists supplied.
 *
 *    Passive lock removal:  If lock has timed out, it will not be returned.
 *    ### How much "logging" does RFC 2518 require?
 */
static dav_error * dav_generic_load_lock_record(dav_lockdb *lockdb,
                                                apr_datum_t key,
                                                int add_method,
                                                dav_lock_discovery **direct,
                                                dav_lock_indirect **indirect)
{
    apr_pool_t *p = lockdb->info->pool;
    dav_error *err;
    apr_status_t status;
    apr_size_t offset = 0;
    int need_save = DAV_FALSE;
    apr_datum_t val = { 0 };
    dav_lock_discovery *dp;
    dav_lock_indirect *ip;

    if (add_method != DAV_APPEND_LIST) {
        *direct = NULL;
        *indirect = NULL;
    }

    if ((err = dav_generic_really_open_lockdb(lockdb)) != NULL) {
        /* ### add a higher-level error? */
        return err;
    }

    /*
     * If we opened readonly and the db wasn't there, then there are no
     * locks for this resource. Just exit.
     */
    if (lockdb->info->db == NULL) {
        return NULL;
    }

    if ((status = apr_dbm_fetch(lockdb->info->db, key, &val)) != APR_SUCCESS) {
        return dav_generic_dbm_new_error(lockdb->info->db, p, status);
    }

    if (!val.dsize) {
        return NULL;
    }

    while (offset < val.dsize) {
        switch (*(val.dptr + offset++)) {
        case DAV_LOCK_DIRECT:
            /* Create and fill a dav_lock_discovery structure */

            dp = apr_pcalloc(p, sizeof(*dp));

            /* Copy the dav_lock_discovery_fixed portion */
            memcpy(dp, val.dptr + offset, sizeof(dp->f));
            offset += sizeof(dp->f);

            /* Copy the lock token. */
            dp->locktoken = apr_pmemdup(p, val.dptr + offset, sizeof(*dp->locktoken));
            offset += sizeof(*dp->locktoken);

            /* Do we have an owner field? */
            if (*(val.dptr + offset) == '\0') {
                ++offset;
            }
            else {
                apr_size_t len = strlen(val.dptr + offset);
                dp->owner = apr_pstrmemdup(p, val.dptr + offset, len);
                offset += len + 1;
            }

            if (*(val.dptr + offset) == '\0') {
                ++offset;
            }
            else {
                apr_size_t len = strlen(val.dptr + offset);
                dp->auth_user = apr_pstrmemdup(p, val.dptr + offset, len);
                offset += len + 1;
            }

            if (!dav_generic_lock_expired(dp->f.timeout)) {
                dp->next = *direct;
                *direct = dp;
            }
            else {
                need_save = DAV_TRUE;
            }
            break;

        case DAV_LOCK_INDIRECT:
            /* Create and fill a dav_lock_indirect structure */

            ip = apr_pcalloc(p, sizeof(*ip));
            ip->locktoken = apr_pmemdup(p, val.dptr + offset, sizeof(*ip->locktoken));
            offset += sizeof(*ip->locktoken);
            memcpy(&ip->timeout, val.dptr + offset, sizeof(ip->timeout));
            offset += sizeof(ip->timeout);
            /* length of datum */
            ip->key.dsize = *((int *) (val.dptr + offset));
            offset += sizeof(ip->key.dsize);
            ip->key.dptr = apr_pmemdup(p, val.dptr + offset, ip->key.dsize);
            offset += ip->key.dsize;

            if (!dav_generic_lock_expired(ip->timeout)) {
                ip->next = *indirect;
                *indirect = ip;
            }
            else {
                need_save = DAV_TRUE;
            }

            break;

        default:
            apr_dbm_freedatum(lockdb->info->db, val);

            /* ### should use a computed_desc and insert corrupt token data */
            --offset;
            return dav_new_error(p,
                                 HTTP_INTERNAL_SERVER_ERROR,
                                 DAV_ERR_LOCK_CORRUPT_DB, 0,
                                 apr_psprintf(p,
                                             "The lock database was found to "
                                             "be corrupt. offset %"
                                             APR_SIZE_T_FMT ", c=%02x",
                                             offset, val.dptr[offset]));
        }
    }

    apr_dbm_freedatum(lockdb->info->db, val);

    /* Clean up this record if we found expired locks */
    /*
     * ### shouldn't do this if we've been opened READONLY. elide the
     * ### timed-out locks from the response, but don't save that info back
     */
    if (need_save == DAV_TRUE) {
        return dav_generic_save_lock_record(lockdb, key, *direct, *indirect);
    }

    return NULL;
}