Index: modules/aaa/mod_authn_dbd.c =================================================================== --- modules/aaa/mod_authn_dbd.c (revision 780893) +++ modules/aaa/mod_authn_dbd.c (working copy) @@ -30,13 +30,23 @@ typedef struct { const char *user; + const char *uparams; const char *realm; + const char *rparams; } authn_dbd_conf; typedef struct { const char *label; const char *query; } authn_dbd_rec; +/* replacement in query format */ +#define QUERY_FMT_USERNAME 'u' +#define QUERY_FMT_PASSWORD 'p' +#define QUERY_FMT_REALM 'r' +#define QUERY_FMT_REMOTE_ADDR 'a' +#define QUERY_FMT_USER_DEFAULT "p" +#define QUERY_FMT_REALM_DEFAULT "ur" + /* optional function - look it up once in post_config */ static ap_dbd_t *(*authn_dbd_acquire_fn)(request_rec*) = NULL; static void (*authn_dbd_prepare_fn)(server_rec*, const char*, const char*) = NULL; @@ -52,7 +62,9 @@ authn_dbd_conf *base = BASE; authn_dbd_conf *ret = apr_palloc(pool, sizeof(authn_dbd_conf)); ret->user = (add->user == NULL) ? base->user : add->user; + ret->uparams = (add->user == NULL) ? base->uparams : add->uparams; ret->realm = (add->realm == NULL) ? base->realm : add->realm; + ret->rparams = (add->realm == NULL) ? base->rparams : add->rparams; return ret; } static const char *authn_dbd_prepare(cmd_parms *cmd, void *cfg, const char *query) @@ -74,6 +86,75 @@ /* save the label here for our own use */ return ap_set_string_slot(cmd, cfg, label); } +static const char *setup_query_fmt(apr_pool_t *p, const char *query, + const char **result_params) +{ + char *copy, *pos, *params, *tmp; + int pnums = 0, plimit = 0; + + copy = apr_palloc(p, strlen(query) + 1); + params = apr_palloc(p, plimit + 1); + + for (pos = copy; *query != '\0'; query++) { + if (*query != '$') { + *pos++ = *query; + continue; + } + /* expand parameter buffer */ + if (pnums == plimit) { + plimit += 10; + tmp = apr_palloc(p, plimit + 1); + strcpy(tmp, params); + params = tmp; + } + /* replace format string to %s */ + if (strncmp(query, "$(username)", 11) == 0) { + query += 10; + pos += sprintf(pos, "%%s"); + params[pnums++] = QUERY_FMT_USERNAME; + } + else if (strncmp(query, "$(password)", 11) == 0) { + query += 10; + pos += sprintf(pos, "%%s"); + params[pnums++] = QUERY_FMT_PASSWORD; + } + else if (strncmp(query, "$(realm)", 8) == 0) { + query += 7; + pos += sprintf(pos, "%%s"); + params[pnums++] = QUERY_FMT_REALM; + } + else if (strncmp(query, "$(remote_addr)", 14) == 0) { + query += 13; + pos += sprintf(pos, "%%s"); + params[pnums++] = QUERY_FMT_REMOTE_ADDR; + } + else { + /* keep the unknown $... */ + *pos++ = *query; + } + } + *pos = '\0'; + params[pnums++] = '\0'; + + *result_params = params; + return copy; +} +static const char *set_user_query_fmt(cmd_parms *cmd, void *cfg, const char *query) +{ + authn_dbd_conf *conf = cfg; + const char *new_query + = setup_query_fmt(cmd->pool, query, &conf->uparams); + /* do the normal setups */ + return authn_dbd_prepare(cmd, cfg, new_query); +} +static const char *set_realm_query_fmt(cmd_parms *cmd, void *cfg, const char *query) +{ + authn_dbd_conf *conf = cfg; + const char *new_query + = setup_query_fmt(cmd->pool, query, &conf->rparams); + /* do the normal setups */ + return authn_dbd_prepare(cmd, cfg, new_query); +} static const command_rec authn_dbd_cmds[] = { AP_INIT_TAKE1("AuthDBDUserPWQuery", authn_dbd_prepare, @@ -82,8 +163,49 @@ AP_INIT_TAKE1("AuthDBDUserRealmQuery", authn_dbd_prepare, (void *)APR_OFFSETOF(authn_dbd_conf, realm), ACCESS_CONF, "Query used to fetch password for user+realm"), + AP_INIT_TAKE1("AuthDBDUserPWQueryFmt", set_user_query_fmt, + (void *)APR_OFFSETOF(authn_dbd_conf, user), ACCESS_CONF, + "Query used to fetch password for user"), + AP_INIT_TAKE1("AuthDBDUserRealmQueryFmt", set_realm_query_fmt, + (void *)APR_OFFSETOF(authn_dbd_conf, realm), ACCESS_CONF, + "Query used to fetch password for user+realm"), {NULL} }; +static void authn_dbd_setup_params(request_rec *r, const char *params, + const char ***args, int *nargs, + const char *username, + const char *password, + const char *realm) +{ + const char **ptable = NULL; + int c, index = 0; + + ptable = apr_palloc(r->pool, sizeof(const char *) * strlen(params)); + + while ((c = *params++) != '\0') { + switch (c) { + case QUERY_FMT_USERNAME: + ptable[index++] = username; + break; + case QUERY_FMT_PASSWORD: + ptable[index++] = password; + break; + case QUERY_FMT_REALM: + ptable[index++] = realm; + break; + case QUERY_FMT_REMOTE_ADDR: + ptable[index++] = r->connection->remote_ip; + break; + default: + ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, + "Bug? unexpected format: %c", c); + break; + } + } + + *args = ptable; + *nargs = index; +} static authn_status authn_dbd_password(request_rec *r, const char *user, const char *password) { @@ -92,6 +214,8 @@ apr_dbd_prepared_t *statement; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; + const char **args; + int nargs; authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config, &authn_dbd_module); @@ -116,8 +240,11 @@ "AuthDBDUserPWQuery with the key '%s'", conf->user); return AUTH_GENERAL_ERROR; } - if (apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement, - 0, user, NULL) != 0) { + + authn_dbd_setup_params(r, conf->uparams ? conf->uparams : QUERY_FMT_USER_DEFAULT, + &args, &nargs, user, password, NULL); + if (apr_dbd_pselect(dbd->driver, r->pool, dbd->handle, &res, + statement, 0, nargs, args) != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Query execution error looking up '%s' " "in database", user); @@ -184,6 +311,8 @@ apr_dbd_prepared_t *statement; apr_dbd_results_t *res = NULL; apr_dbd_row_t *row = NULL; + const char **args; + int nargs; authn_dbd_conf *conf = ap_get_module_config(r->per_dir_config, &authn_dbd_module); @@ -206,8 +335,11 @@ "AuthDBDUserRealmQuery with the key '%s'", conf->realm); return AUTH_GENERAL_ERROR; } - if (apr_dbd_pvselect(dbd->driver, r->pool, dbd->handle, &res, statement, - 0, user, realm, NULL) != 0) { + + authn_dbd_setup_params(r, conf->rparams ? conf->rparams : QUERY_FMT_REALM_DEFAULT, + &args, &nargs, user, NULL, realm); + if (apr_dbd_pselect(dbd->driver, r->pool, dbd->handle, &res, + statement, 0, nargs, args) != 0) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Query execution error looking up '%s:%s' " "in database", user, realm);