This allows callers to fail properly if the format string is invalid.
auth_request_expand_cache_key(const struct auth_request *request,
const char *key)
{
+ static bool error_logged = FALSE;
+ const char *value, *error;
+
/* Uniquely identify the request's passdb/userdb with the P/U prefix
and by "%!", which expands to the passdb/userdb ID number. */
key = t_strconcat(request->userdb_lookup ? "U" : "P", "%!",
request->master_user == NULL ? "" : "+%{master_user}",
"\t", key, NULL);
- return t_auth_request_var_expand(key, request, auth_cache_escape);
+ if (t_auth_request_var_expand(key, request, auth_cache_escape,
+ &value, &error) <= 0 && !error_logged) {
+ error_logged = TRUE;
+ i_error("Failed to expand auth cache key %s: %s", key, error);
+ }
+ return value;
}
const char *
const char *hashed_password = binary_to_hex(str_data(buffer), str_len(buffer));
str_append_c(context->json, '{');
var_table = policy_get_var_expand_table(context->request, hashed_password);
- auth_request_var_expand_with_table(context->json, auth_policy_json_template,
- context->request, var_table,
- auth_policy_escape_function);
+ const char *error;
+ if (auth_request_var_expand_with_table(context->json, auth_policy_json_template,
+ context->request, var_table,
+ auth_policy_escape_function, &error) <= 0) {
+ auth_request_log_error(context->request, "policy",
+ "Failed to expand auth policy template: %s", error);
+ }
if (include_success) {
str_append(context->json, ",\"success\":");
if (!context->request->failed && context->request->successful &&
{ NULL, NULL }
};
-void auth_request_var_expand(string_t *dest, const char *str,
- const struct auth_request *auth_request,
- auth_request_escape_func_t *escape_func)
+int auth_request_var_expand(string_t *dest, const char *str,
+ const struct auth_request *auth_request,
+ auth_request_escape_func_t *escape_func,
+ const char **error_r)
{
- auth_request_var_expand_with_table(dest, str, auth_request,
+ return auth_request_var_expand_with_table(dest, str, auth_request,
auth_request_get_var_expand_table(auth_request, escape_func),
- escape_func);
+ escape_func, error_r);
}
-void auth_request_var_expand_with_table(string_t *dest, const char *str,
- const struct auth_request *auth_request,
- const struct var_expand_table *table,
- auth_request_escape_func_t *escape_func)
+int auth_request_var_expand_with_table(string_t *dest, const char *str,
+ const struct auth_request *auth_request,
+ const struct var_expand_table *table,
+ auth_request_escape_func_t *escape_func,
+ const char **error_r)
{
struct auth_request_var_expand_ctx ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.auth_request = auth_request;
ctx.escape_func = escape_func == NULL ? escape_none : escape_func;
- var_expand_with_funcs(dest, str, table,
- auth_request_var_funcs_table, &ctx);
+ return var_expand_with_funcs(dest, str, table,
+ auth_request_var_funcs_table, &ctx, error_r);
}
-const char *
-t_auth_request_var_expand(const char *str,
- const struct auth_request *auth_request,
- auth_request_escape_func_t *escape_func)
+int t_auth_request_var_expand(const char *str,
+ const struct auth_request *auth_request ATTR_UNUSED,
+ auth_request_escape_func_t *escape_func ATTR_UNUSED,
+ const char **value_r, const char **error_r)
{
string_t *dest = t_str_new(128);
- auth_request_var_expand(dest, str, auth_request, escape_func);
- return str_c(dest);
+ int ret = auth_request_var_expand(dest, str, auth_request,
+ escape_func, error_r);
+ *value_r = str_c(dest);
+ return ret;
}
auth_request_escape_func_t *escape_func,
unsigned int *count) ATTR_NULL(2);
-void auth_request_var_expand(string_t *dest, const char *str,
- const struct auth_request *auth_request,
- auth_request_escape_func_t *escape_func);
-void auth_request_var_expand_with_table(string_t *dest, const char *str,
- const struct auth_request *auth_request,
- const struct var_expand_table *table,
- auth_request_escape_func_t *escape_func);
-const char *
-t_auth_request_var_expand(const char *str,
- const struct auth_request *auth_request,
- auth_request_escape_func_t *escape_func);
+int auth_request_var_expand(string_t *dest, const char *str,
+ const struct auth_request *auth_request,
+ auth_request_escape_func_t *escape_func,
+ const char **error_r);
+int auth_request_var_expand_with_table(string_t *dest, const char *str,
+ const struct auth_request *auth_request,
+ const struct var_expand_table *table,
+ auth_request_escape_func_t *escape_func,
+ const char **error_r);
+int t_auth_request_var_expand(const char *str,
+ const struct auth_request *auth_request,
+ auth_request_escape_func_t *escape_func,
+ const char **value_r, const char **error_r);
const char *auth_request_str_escape(const char *string,
const struct auth_request *request);
auth_request_verify_plain_callback_finish(enum passdb_result result,
struct auth_request *request)
{
- passdb_template_export(request->passdb->override_fields_tmpl, request);
+ const char *error;
+
+ if (passdb_template_export(request->passdb->override_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand override_fields: %s", error);
+ result = PASSDB_RESULT_INTERNAL_FAILURE;
+ }
if (!auth_request_handle_passdb_callback(&result, request)) {
/* try next passdb */
auth_request_verify_plain(request, request->mech_password,
struct auth_passdb *passdb;
enum passdb_result result;
- const char *cache_key;
+ const char *cache_key, *error;
const char *password = request->mech_password;
i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
PASSDB_RESULT_INTERNAL_FAILURE, request);
} else if (passdb->passdb->blocking) {
passdb_blocking_verify_plain(request);
+ } else if (passdb_template_export(passdb->default_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand default_fields: %s", error);
+ auth_request_verify_plain_callback(
+ PASSDB_RESULT_INTERNAL_FAILURE, request);
} else {
- passdb_template_export(passdb->default_fields_tmpl, request);
passdb->passdb->iface.verify_plain(request, password,
auth_request_verify_plain_callback);
}
size_t size,
struct auth_request *request)
{
- passdb_template_export(request->passdb->override_fields_tmpl, request);
+ const char *error;
+
+ if (passdb_template_export(request->passdb->override_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand override_fields: %s", error);
+ result = PASSDB_RESULT_INTERNAL_FAILURE;
+ }
if (!auth_request_handle_passdb_callback(&result, request)) {
/* try next passdb */
if (request->skip_password_check &&
lookup_credentials_callback_t *callback)
{
struct auth_passdb *passdb;
- const char *cache_key, *cache_cred, *cache_scheme;
+ const char *cache_key, *cache_cred, *cache_scheme, *error;
enum passdb_result result;
i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
uchar_empty_ptr, 0, request);
} else if (passdb->passdb->blocking) {
passdb_blocking_lookup_credentials(request);
+ } else if (passdb_template_export(passdb->default_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand default_fields: %s", error);
+ auth_request_lookup_credentials_callback(
+ PASSDB_RESULT_INTERNAL_FAILURE,
+ uchar_empty_ptr, 0, request);
} else {
- passdb_template_export(passdb->default_fields_tmpl, request);
passdb->passdb->iface.lookup_credentials(request,
auth_request_lookup_credentials_callback);
}
struct auth_userdb *userdb = request->userdb;
struct auth_userdb *next_userdb;
enum auth_db_rule result_rule;
+ const char *error;
bool userdb_continue = FALSE;
switch (result) {
if (result == USERDB_RESULT_OK) {
/* this userdb lookup succeeded, preserve its extra
fields */
- userdb_template_export(userdb->override_fields_tmpl, request);
+ if (userdb_template_export(userdb->override_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand override_fields: %s", error);
+ request->private_callback.userdb(
+ USERDB_RESULT_INTERNAL_FAILURE, request);
+ return;
+ }
auth_fields_snapshot(request->userdb_reply);
} else {
/* this userdb lookup failed, remove any extra fields
}
if (request->userdb_success) {
- result = USERDB_RESULT_OK;
- userdb_template_export(userdb->override_fields_tmpl, request);
+ if (userdb_template_export(userdb->override_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand override_fields: %s", error);
+ result = USERDB_RESULT_INTERNAL_FAILURE;
+ } else {
+ result = USERDB_RESULT_OK;
+ }
} else if (request->userdbs_seen_internal_failure ||
result == USERDB_RESULT_INTERNAL_FAILURE) {
/* one of the userdb lookups failed. the user might have been
userdb_callback_t *callback)
{
struct auth_userdb *userdb = request->userdb;
- const char *cache_key;
+ const char *cache_key, *error;
request->private_callback.userdb = callback;
request->userdb_lookup = TRUE;
/* we still want to set default_fields. these override any
existing fields set by previous userdbs (because if that is
unwanted, ":protected" can be used). */
- userdb_template_export(userdb->default_fields_tmpl, request);
+ if (userdb_template_export(userdb->default_fields_tmpl,
+ request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand default_fields: %s", error);
+ auth_request_userdb_callback(
+ USERDB_RESULT_INTERNAL_FAILURE, request);
+ return;
+ }
}
/* (for now) auth_cache is shared between passdb and userdb */
/* username format given, put it through variable expansion.
we'll have to temporarily replace request->user to get
%u to be the wanted username */
+ const char *error;
char *old_username;
string_t *dest;
request->user = user;
dest = t_str_new(256);
- auth_request_var_expand(dest, set->username_format, request, NULL);
+ if (auth_request_var_expand(dest, set->username_format,
+ request, NULL, &error) <= 0) {
+ *error_r = t_strdup_printf(
+ "Failed to expand username_format=%s: %s",
+ set->username_format, error);
+ }
user = p_strdup(request->pool, str_c(dest));
request->user = old_username;
void auth_request_init_userdb_reply(struct auth_request *request)
{
+ const char *error;
+
request->userdb_reply = auth_fields_init(request->pool);
- userdb_template_export(request->userdb->default_fields_tmpl, request);
+ if (userdb_template_export(request->userdb->default_fields_tmpl,
+ request, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand default_fields: %s", error);
+ }
}
static void auth_request_set_uidgid_file(struct auth_request *request,
{
string_t *path;
struct stat st;
+ const char *error;
path = t_str_new(256);
- auth_request_var_expand(path, path_template, request, NULL);
- if (stat(str_c(path), &st) < 0) {
+ if (auth_request_var_expand(path, path_template, request,
+ NULL, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand uidgid_file=%s: %s", path_template, error);
+ request->userdb_lookup_tempfailed = TRUE;
+ } else if (stat(str_c(path), &st) < 0) {
auth_request_log_error(request, AUTH_SUBSYS_DB,
"stat(%s) failed: %m", str_c(path));
request->userdb_lookup_tempfailed = TRUE;
const char *checkpassword_reply_path)
{
string_t *str;
+ const char *error;
str = t_str_new(256);
- auth_request_var_expand(str, args, request, NULL);
+ if (auth_request_var_expand(str, args, request, NULL, &error) <= 0) {
+ i_error("Failed to expand checkpassword_path=%s: %s",
+ args, error);
+ }
+
return t_strconcat(str_c(str), " ", checkpassword_reply_path, NULL);
}
continue;
str_truncate(path, strlen(DICT_PATH_SHARED));
- var_expand(path, key->key->key, iter->var_expand_table);
+ ret = var_expand(path, key->key->key, iter->var_expand_table, &error);
+ if (ret <= 0) {
+ auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand key %s: %s", key->key->key, error);
+ return -1;
+ }
ret = dict_lookup(iter->conn->dict, iter->pool,
str_c(path), &key->value, &error);
if (ret > 0) {
struct db_dict_key *new_key = p_new(iter->pool, struct db_dict_key, 1);
memcpy(new_key, key, sizeof(struct db_dict_key));
string_t *expanded_key = str_new(iter->pool, strlen(key->key));
- auth_request_var_expand_with_table(expanded_key, key->key, auth_request,
- iter->var_expand_table,
- NULL);
+ const char *error;
+ if (auth_request_var_expand_with_table(expanded_key, key->key, auth_request,
+ iter->var_expand_table,
+ NULL, &error) <= 0) {
+ auth_request_log_error(iter->auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand key %s: %s", key->key, error);
+ pool_unref(&pool);
+ return -1;
+ }
new_key->key = str_c(expanded_key);
iterkey->key = new_key;
}
{ NULL, NULL }
};
const struct db_dict_field *field;
+ const char *error;
if (iter->field_idx == array_count(iter->fields))
return db_dict_value_iter_object_next(iter, key_r, value_r);
field = array_idx(iter->fields, iter->field_idx++);
str_truncate(iter->tmpstr, 0);
- var_expand_with_funcs(iter->tmpstr, field->value,
- iter->var_expand_table, var_funcs_table, iter);
+ if (var_expand_with_funcs(iter->tmpstr, field->value,
+ iter->var_expand_table, var_funcs_table,
+ iter, &error) <= 0) {
+ iter->error = p_strdup_printf(iter->pool,
+ "Failed to expand %s=%s: %s",
+ field->name, field->value, error);
+ return FALSE;
+ }
*key_r = field->name;
*value_r = str_c(iter->tmpstr);
return TRUE;
{ NULL, NULL }
};
const struct ldap_field *field;
- const char *p;
+ const char *p, *error;
char *name;
struct ldap_field_find_subquery_context ctx;
string_t *tmp_str = t_str_new(64);
array_foreach(request->attr_map, field) {
if (field->ldap_attr_name[0] == '\0') {
str_truncate(tmp_str, 0);
- var_expand_with_funcs(tmp_str, field->value, NULL,
- var_funcs_table, &ctx);
+ if (var_expand_with_funcs(tmp_str, field->value, NULL,
+ var_funcs_table, &ctx, &error) <= 0) {
+ auth_request_log_error(request->request.auth_request,
+ AUTH_SUBSYS_DB,
+ "Failed to expand subquery %s: %s",
+ field->value, error);
+ return -1;
+ }
} else {
p = strchr(field->ldap_attr_name, '@');
if (p != NULL &&
struct ldap_field_find_context ctx;
struct ldap_field *field;
string_t *tmp_str;
- const char *const *attr, *attr_data, *p;
+ const char *const *attr, *attr_data, *p, *error;
char *ldap_attr, *name, *templ;
unsigned int i;
} else {
*templ++ = '\0';
str_truncate(tmp_str, 0);
- var_expand_with_funcs(tmp_str, templ, NULL,
- var_funcs_table, &ctx);
+ if (var_expand_with_funcs(tmp_str, templ, NULL,
+ var_funcs_table, &ctx, &error) <= 0) {
+ i_error("LDAP %s: Failed to expand attr_names=%s: %s",
+ conn->config_path, name, error);
+ }
if (strchr(templ, '%') == NULL) {
/* backwards compatibility:
attr=name=prefix means same as
struct db_ldap_value *ldap_value)
{
const struct var_expand_table *var_table;
- const char *const *values;
+ const char *const *values, *error;
if (ldap_value != NULL)
values = ldap_value->values;
(and less importantly the same for other variables) */
var_table = db_ldap_value_get_var_expand_table(ctx->auth_request,
values[0]);
- var_expand_with_funcs(ctx->var, field->value, var_table,
- ldap_var_funcs_table, ctx);
+ if (var_expand_with_funcs(ctx->var, field->value, var_table,
+ ldap_var_funcs_table, ctx, &error) <= 0) {
+ auth_request_log_warning(ctx->auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand template %s: %s",
+ field->value, error);
+ }
ctx->val_1_arr[0] = str_c(ctx->var);
values = ctx->val_1_arr;
}
const char **name_r,
const char *const **values_r)
{
+ const struct var_expand_table *tab;
const struct ldap_field *field;
struct db_ldap_value *ldap_value;
unsigned int pos;
+ const char *error;
do {
if (ctx->attr_idx == array_count(ctx->attr_map))
str_append_c(ctx->var, '\0');
pos = str_len(ctx->var);
- var_expand_with_funcs(ctx->var, field->name,
- auth_request_get_var_expand_table(ctx->auth_request, NULL),
- ldap_var_funcs_table, ctx);
+ tab = auth_request_get_var_expand_table(ctx->auth_request, NULL);
+ if (var_expand_with_funcs(ctx->var, field->name, tab,
+ ldap_var_funcs_table, ctx, &error) <= 0) {
+ auth_request_log_warning(ctx->auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand %s: %s", field->name, error);
+ }
*name_r = str_c(ctx->var) + pos;
}
/* just extra escaped % chars. remove them. */
struct var_expand_table empty_table[1];
string_t *dest;
+ const char *error;
empty_table[0].key = '\0';
dest = t_str_new(256);
- var_expand(dest, path, empty_table);
+ if (var_expand(dest, path, empty_table, &error) <= 0)
+ i_unreached();
path = str_c(dest);
}
{
struct passwd_file *pw;
string_t *username, *dest;
+ const char *error;
if (!db->vars)
pw = db->default_file;
else {
dest = t_str_new(256);
- auth_request_var_expand(dest, db->path, request, path_fix);
+ if (auth_request_var_expand(dest, db->path, request, path_fix,
+ &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand passwd-file path %s: %s",
+ db->path, error);
+ return -1;
+ }
pw = hash_table_lookup(db->files, str_c(dest));
if (pw == NULL) {
}
username = t_str_new(256);
- auth_request_var_expand(username, username_format, request,
- auth_request_str_escape);
+ if (auth_request_var_expand(username, username_format, request,
+ auth_request_str_escape, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand username_format=%s: %s",
+ username_format, error);
+ return -1;
+ }
auth_request_log_debug(request, AUTH_SUBSYS_DB,
"lookup: user=%s file=%s",
(struct imap_passdb_module *)_module;
struct imap_auth_request *request;
struct imapc_client_settings set;
+ const char *error;
string_t *str;
set = module->set;
if (module->set_have_vars) {
str = t_str_new(128);
- auth_request_var_expand(str, set.username, auth_request, NULL);
+ if (auth_request_var_expand(str, set.username, auth_request,
+ NULL, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand username=%s: %s",
+ set.username, error);
+ callback(PASSDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
set.username = t_strdup(str_c(str));
str_truncate(str, 0);
- auth_request_var_expand(str, set.host, auth_request, NULL);
+ if (auth_request_var_expand(str, set.host, auth_request,
+ NULL, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand host=%s: %s",
+ set.host, error);
+ callback(PASSDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
set.host = t_strdup(str_c(str));
}
auth_request_log_debug(auth_request, AUTH_SUBSYS_DB,
db_ldap_request(conn, &brequest->request);
}
+static void passdb_ldap_request_fail(struct passdb_ldap_request *request,
+ enum passdb_result passdb_result)
+{
+ struct auth_request *auth_request = request->request.ldap.auth_request;
+
+ if (auth_request->credentials_scheme != NULL) {
+ request->callback.lookup_credentials(passdb_result, NULL, 0,
+ auth_request);
+ } else {
+ request->callback.verify_plain(passdb_result, auth_request);
+ }
+ auth_request_unref(&auth_request);
+}
+
static void
ldap_bind_lookup_dn_fail(struct auth_request *auth_request,
struct passdb_ldap_request *request,
passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
}
- if (auth_request->credentials_scheme != NULL) {
- request->callback.lookup_credentials(passdb_result, NULL, 0,
- auth_request);
- } else {
- request->callback.verify_plain(passdb_result, auth_request);
- }
- auth_request_unref(&auth_request);
+ passdb_ldap_request_fail(request, passdb_result);
}
static void ldap_bind_lookup_dn_callback(struct ldap_connection *conn,
struct ldap_connection *conn = module->conn;
struct ldap_request_search *srequest = &request->request.search;
const char **attr_names = (const char **)conn->pass_attr_names;
+ const char *error;
string_t *str;
request->require_password = require_password;
srequest->request.type = LDAP_REQUEST_TYPE_SEARCH;
str = t_str_new(512);
- auth_request_var_expand(str, conn->set.base, auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.base, auth_request,
+ ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand base=%s: %s", conn->set.base, error);
+ passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE);
+ return;
+ }
srequest->base = p_strdup(auth_request->pool, str_c(str));
str_truncate(str, 0);
- auth_request_var_expand(str, conn->set.pass_filter,
- auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.pass_filter,
+ auth_request, ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand pass_filter=%s: %s",
+ conn->set.pass_filter, error);
+ passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE);
+ return;
+ }
srequest->filter = p_strdup(auth_request->pool, str_c(str));
srequest->attr_map = &conn->pass_attr_map;
srequest->attributes = conn->pass_attr_names;
(struct ldap_passdb_module *)_module;
struct ldap_connection *conn = module->conn;
struct ldap_request_search *srequest = &request->request.search;
+ const char *error;
string_t *str;
srequest->request.type = LDAP_REQUEST_TYPE_SEARCH;
str = t_str_new(512);
- auth_request_var_expand(str, conn->set.base, auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.base, auth_request,
+ ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand base=%s: %s", conn->set.base, error);
+ passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE);
+ return;
+ }
srequest->base = p_strdup(auth_request->pool, str_c(str));
str_truncate(str, 0);
- auth_request_var_expand(str, conn->set.pass_filter,
- auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.pass_filter,
+ auth_request, ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand pass_filter=%s: %s",
+ conn->set.pass_filter, error);
+ passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE);
+ return;
+ }
srequest->filter = p_strdup(auth_request->pool, str_c(str));
/* we don't need the attributes to perform authentication, but they
struct ldap_connection *conn = module->conn;
struct ldap_request_bind *brequest = &request->request.bind;
string_t *dn;
+ const char *error;
brequest->request.type = LDAP_REQUEST_TYPE_BIND;
dn = t_str_new(512);
- auth_request_var_expand(dn, conn->set.auth_bind_userdn, auth_request, ldap_escape);
+ if (auth_request_var_expand(dn, conn->set.auth_bind_userdn,
+ auth_request, ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand auth_bind_userdn=%s: %s",
+ conn->set.auth_bind_userdn, error);
+ passdb_ldap_request_fail(request, PASSDB_RESULT_INTERNAL_FAILURE);
+ return;
+ }
brequest->dn = p_strdup(auth_request->pool, str_c(dn));
ldap_auth_bind(conn, brequest);
struct passdb_module *_module = request->passdb->passdb;
struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
enum passdb_result result;
- const char *service;
+ const char *service, *error;
if (module->requests_left > 0) {
if (--module->requests_left == 0)
worker_restart_request = TRUE;
}
- service = t_auth_request_var_expand(module->service_name, request, NULL);
+ if (t_auth_request_var_expand(module->service_name, request, NULL,
+ &service, &error) <= 0) {
+ auth_request_log_debug(request, AUTH_SUBSYS_DB,
+ "Failed to expand service %s: %s",
+ module->service_name, error);
+ callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
+ return;
+ }
auth_request_log_debug(request, AUTH_SUBSYS_DB,
"lookup service=%s", service);
const char *username_format;
};
-static void
+static int
passwd_file_add_extra_fields(struct auth_request *request, char *const *fields)
{
string_t *str = t_str_new(512);
const struct var_expand_table *table;
- const char *key, *value;
+ const char *key, *value, *error;
unsigned int i;
table = auth_request_get_var_expand_table(request, NULL);
if (value != NULL) {
key = t_strdup_until(fields[i], value);
str_truncate(str, 0);
- auth_request_var_expand_with_table(str, value + 1,
- request, table, NULL);
+ if (auth_request_var_expand_with_table(str, value + 1,
+ request, table, NULL, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand extra field %s: %s",
+ fields[i], error);
+ return -1;
+ }
value = str_c(str);
} else {
key = fields[i];
}
auth_request_set_field(request, key, value, NULL);
}
+ return 0;
}
-static void passwd_file_save_results(struct auth_request *request,
- const struct passwd_user *pu,
- const char **crypted_pass_r,
- const char **scheme_r)
+static int passwd_file_save_results(struct auth_request *request,
+ const struct passwd_user *pu,
+ const char **crypted_pass_r,
+ const char **scheme_r)
{
*crypted_pass_r = pu->password != NULL ? pu->password : "";
*scheme_r = password_get_scheme(crypted_pass_r);
auth_request_set_field(request, "password",
*crypted_pass_r, *scheme_r);
- if (pu->extra_fields != NULL)
- passwd_file_add_extra_fields(request, pu->extra_fields);
+ if (pu->extra_fields != NULL) {
+ if (passwd_file_add_extra_fields(request, pu->extra_fields) < 0)
+ return -1;
+ }
+ return 0;
}
static void
return;
}
- passwd_file_save_results(request, pu, &crypted_pass, &scheme);
+ if (passwd_file_save_results(request, pu, &crypted_pass, &scheme) < 0) {
+ callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
+ return;
+ }
ret = auth_request_password_verify(request, password, crypted_pass,
scheme, AUTH_SUBSYS_DB);
return;
}
- passwd_file_save_results(request, pu, &crypted_pass, &scheme);
+ if (passwd_file_save_results(request, pu, &crypted_pass, &scheme) < 0) {
+ callback(PASSDB_RESULT_INTERNAL_FAILURE, NULL, 0, request);
+ return;
+ }
passdb_handle_credentials(PASSDB_RESULT_OK, crypted_pass, scheme,
callback, request);
struct passdb_module *_module =
sql_request->auth_request->passdb->passdb;
struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
- const char *query;
-
- query = t_auth_request_var_expand(module->conn->set.password_query,
- sql_request->auth_request,
- passdb_sql_escape);
+ const char *query, *error;
+
+ if (t_auth_request_var_expand(module->conn->set.password_query,
+ sql_request->auth_request,
+ passdb_sql_escape, &query, &error) <= 0) {
+ auth_request_log_debug(sql_request->auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand password_query=%s: %s",
+ module->conn->set.password_query, error);
+ sql_request->callback.verify_plain(PASSDB_RESULT_INTERNAL_FAILURE,
+ sql_request->auth_request);
+ return;
+ }
auth_request_log_debug(sql_request->auth_request, AUTH_SUBSYS_DB,
"query: %s", query);
(struct sql_passdb_module *) request->passdb->passdb;
struct sql_transaction_context *transaction;
struct passdb_sql_request *sql_request;
- const char *query;
+ const char *query, *error;
request->mech_password = p_strdup(request->pool, new_credentials);
- query = t_auth_request_var_expand(module->conn->set.update_query,
- request, passdb_sql_escape);
+ if (t_auth_request_var_expand(module->conn->set.update_query,
+ request, passdb_sql_escape,
+ &query, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand update_query=%s: %s",
+ module->conn->set.update_query, error);
+ callback(FALSE, request);
+ return;
+ }
sql_request = i_new(struct passdb_sql_request, 1);
sql_request->auth_request = request;
};
static enum passdb_result
-static_save_fields(struct auth_request *request, const char **password_r, const char **scheme_r)
+static_save_fields(struct auth_request *request, const char **password_r,
+ const char **scheme_r)
{
struct static_passdb_module *module =
(struct static_passdb_module *)request->passdb->passdb;
+ const char *error;
auth_request_log_debug(request, AUTH_SUBSYS_DB, "lookup");
- passdb_template_export(module->tmpl, request);
+ if (passdb_template_export(module->tmpl, request, &error) < 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand template: %s", error);
+ return PASSDB_RESULT_INTERNAL_FAILURE;
+ }
if (module->static_password_tmpl != NULL) {
- *password_r = t_auth_request_var_expand(
- module->static_password_tmpl, request, NULL);
+ if (t_auth_request_var_expand(module->static_password_tmpl,
+ request, NULL, password_r, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand password=%s: %s",
+ module->static_password_tmpl, error);
+ return PASSDB_RESULT_INTERNAL_FAILURE;
+ }
} else if (auth_fields_exists(request->extra_fields, "nopassword")) {
*password_r = "";
} else {
return tmpl;
}
-void passdb_template_export(struct passdb_template *tmpl,
- struct auth_request *auth_request)
+int passdb_template_export(struct passdb_template *tmpl,
+ struct auth_request *auth_request,
+ const char **error_r)
{
const struct var_expand_table *table;
string_t *str;
unsigned int i, count;
if (passdb_template_is_empty(tmpl))
- return;
+ return 0;
str = t_str_new(256);
table = auth_request_get_var_expand_table(auth_request, NULL);
value = "";
else {
str_truncate(str, 0);
- auth_request_var_expand_with_table(str, args[i+1],
- auth_request, table, NULL);
+ if (auth_request_var_expand_with_table(str, args[i+1],
+ auth_request, table, NULL, error_r) <= 0)
+ return -1;
value = str_c(str);
}
auth_request_set_field(auth_request, args[i], value,
STATIC_PASS_SCHEME);
}
+ return 0;
}
bool passdb_template_remove(struct passdb_template *tmpl,
#define STATIC_PASS_SCHEME "PLAIN"
struct passdb_template *passdb_template_build(pool_t pool, const char *args);
-void passdb_template_export(struct passdb_template *tmpl,
- struct auth_request *auth_request);
+int passdb_template_export(struct passdb_template *tmpl,
+ struct auth_request *auth_request,
+ const char **error_r);
bool passdb_template_remove(struct passdb_template *tmpl,
const char *key, const char **value_r);
bool passdb_template_is_empty(struct passdb_template *tmpl);
{ '\0', NULL, NULL }
};
-const char *
-t_auth_request_var_expand(const char *str,
- const struct auth_request *auth_request ATTR_UNUSED,
- auth_request_escape_func_t *escape_func ATTR_UNUSED)
+int t_auth_request_var_expand(const char *str,
+ const struct auth_request *auth_request ATTR_UNUSED,
+ auth_request_escape_func_t *escape_func ATTR_UNUSED,
+ const char **value_r, const char **error_r)
{
string_t *dest = t_str_new(128);
- var_expand(dest, str, auth_request_var_expand_static_tab);
- return str_c(dest);
+ int ret = var_expand(dest, str, auth_request_var_expand_static_tab, error_r);
+ *value_r = str_c(dest);
+ return ret;
}
static void test_auth_cache_parse_key(void)
static bool test_empty_request(string_t *str, const char *input)
{
+ const struct var_expand_table *tab =
+ auth_request_get_var_expand_table(&empty_test_request, NULL);
+ const char *error;
+
str_truncate(str, 0);
- var_expand(str, input,
- auth_request_get_var_expand_table(&empty_test_request, NULL));
+ test_assert(var_expand(str, input, tab, &error) == 1);
return strspn(str_c(str), "\n0") == str_len(str);
}
"+user@+domain1@+domain2\n+user\n+domain1@+domain2\n+service\n\n"
"7.91.205.21\n73.150.2.210\n54321\n+password\n+mech\nsecured\n"
"21\n210\nvalid\n";
+ const struct var_expand_table *tab;
string_t *str = t_str_new(256);
+ const char *error;
test_begin("auth request var expand short and long");
- var_expand(str, test_input_short,
- auth_request_get_var_expand_table(&test_request, test_escape));
+ tab = auth_request_get_var_expand_table(&test_request, test_escape);
+ test_assert(var_expand(str, test_input_short, tab, &error) == 1);
test_assert(strcmp(str_c(str), test_output) == 0);
str_truncate(str, 0);
- var_expand(str, test_input_long,
- auth_request_get_var_expand_table(&test_request, test_escape));
+ test_assert(var_expand(str, test_input_long, tab, &error) == 1);
test_assert(strcmp(str_c(str), test_output) == 0);
/* test with empty input that it won't crash */
{
static const char *test_input = "%!\n%{secured}\n%{cert}\n";
string_t *str = t_str_new(10);
+ const char *error;
test_begin("auth request var expand flags");
test_request.userdb_lookup = FALSE;
test_request.secured = FALSE;
test_request.valid_client_cert = FALSE;
- var_expand(str, test_input,
- auth_request_get_var_expand_table(&test_request, test_escape));
+ test_assert(var_expand(str, test_input,
+ auth_request_get_var_expand_table(&test_request, test_escape),
+ &error) == 1);
test_assert(strcmp(str_c(str), "40\n\n\n") == 0);
test_request.userdb_lookup = TRUE;
test_request.valid_client_cert = TRUE;
str_truncate(str, 0);
- var_expand(str, test_input,
- auth_request_get_var_expand_table(&test_request, test_escape));
+ test_assert(var_expand(str, test_input,
+ auth_request_get_var_expand_table(&test_request, test_escape),
+ &error) == 1);
test_assert(strcmp(str_c(str), "41\nsecured\nvalid\n") == 0);
test_assert(test_empty_request(str, test_input));
"+masteruser@+masterdomain1@+masterdomain2\n5000\n"
"+origuser@+origdomain1@+origdomain2\n+origuser\n+origdomain1@+origdomain2\n";
string_t *str = t_str_new(256);
+ const char *error;
test_begin("auth request var expand long-only");
- var_expand(str, test_input,
- auth_request_get_var_expand_table(&test_request, test_escape));
+ test_assert(var_expand(str, test_input,
+ auth_request_get_var_expand_table(&test_request, test_escape),
+ &error) == 1);
test_assert(strcmp(str_c(str), test_output) == 0);
test_assert(test_empty_request(str, test_input));
static const char *test_input =
"%{username}\n%{domain}\n%{domain_first}\n%{domain_last}\n%{user}";
string_t *str = t_str_new(64);
+ const char *error;
unsigned int i;
test_begin("auth request var expand usernames");
for (i = 0; i < N_ELEMENTS(tests); i++) {
test_request.user = t_strdup_noconst(tests[i].username);
str_truncate(str, 0);
- var_expand(str, test_input,
- auth_request_get_var_expand_table(&test_request, test_escape));
+ test_assert(var_expand(str, test_input,
+ auth_request_get_var_expand_table(&test_request, test_escape),
+ &error) == 1);
test_assert_idx(strcmp(str_c(str), tests[i].output) == 0, i);
}
test_request.user = default_test_request.user;
static void test_auth_request_var_expand_funcs(void)
{
pool_t pool;
- const char *value;
+ const char *value, *error;
test_begin("auth request var expand funcs");
auth_fields_add(test_request.userdb_reply, "ukey1", "-uval1", 0);
auth_fields_add(test_request.userdb_reply, "ukey2", "", 0);
- value = t_auth_request_var_expand(
+ test_assert(t_auth_request_var_expand(
"%{passdb:pkey1}\n%{passdb:pkey1:default1}\n"
"%{passdb:pkey2}\n%{passdb:pkey2:default2}\n"
"%{passdb:pkey3}\n%{passdb:pkey3:default3}\n"
"%{passdb:ukey1}\n%{passdb:ukey1:default4}\n",
- &test_request, test_escape);
+ &test_request, test_escape, &value, &error) == 0);
test_assert(strcmp(value, "+pval1\n+pval1\n\n\n\ndefault3\n\ndefault4\n") == 0);
- value = t_auth_request_var_expand(
+ test_assert(t_auth_request_var_expand(
"%{userdb:ukey1}\n%{userdb:ukey1:default1}\n"
"%{userdb:ukey2}\n%{userdb:ukey2:default2}\n"
"%{userdb:ukey3}\n%{userdb:ukey3:default3}\n"
"%{userdb:pkey1}\n%{userdb:pkey1:default4}\n",
- &test_request, test_escape);
+ &test_request, test_escape, &value, &error) == 0);
test_assert(strcmp(value, "+uval1\n+uval1\n\n\n\ndefault3\n\ndefault4\n") == 0);
pool_unref(&pool);
(struct dict_userdb_module *)_module;
struct dict_userdb_iterate_context *ctx;
string_t *path;
+ const char *error;
ctx = i_new(struct dict_userdb_iterate_context, 1);
ctx->ctx.auth_request = auth_request;
path = t_str_new(128);
str_append(path, DICT_PATH_SHARED);
- auth_request_var_expand(path, module->conn->set.iterate_prefix,
- auth_request, NULL);
+ if (auth_request_var_expand(path, module->conn->set.iterate_prefix,
+ auth_request, NULL, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand iterate_prefix=%s: %s",
+ module->conn->set.iterate_prefix, error);
+ ctx->ctx.failed = TRUE;
+ return &ctx->ctx;
+ }
ctx->key_prefix = p_strdup(auth_request->pool, str_c(path));
ctx->key_prefix_len = strlen(ctx->key_prefix);
struct ldap_connection *conn = module->conn;
const char **attr_names = (const char **)conn->user_attr_names;
struct userdb_ldap_request *request;
+ const char *error;
string_t *str;
auth_request_ref(auth_request);
request->userdb_callback = callback;
str = t_str_new(512);
- auth_request_var_expand(str, conn->set.base, auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.base, auth_request,
+ ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand base=%s: %s", conn->set.base, error);
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
request->request.base = p_strdup(auth_request->pool, str_c(str));
str_truncate(str, 0);
- auth_request_var_expand(str, conn->set.user_filter, auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.user_filter, auth_request,
+ ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand user_filter=%s: %s",
+ conn->set.user_filter, error);
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
request->request.filter = p_strdup(auth_request->pool, str_c(str));
request->request.attr_map = &conn->user_attr_map;
struct ldap_userdb_iterate_context *ctx;
struct userdb_iter_ldap_request *request;
const char **attr_names = (const char **)conn->iterate_attr_names;
+ const char *error;
string_t *str;
ctx = i_new(struct ldap_userdb_iterate_context, 1);
request->request.request.auth_request = auth_request;
str = t_str_new(512);
- auth_request_var_expand(str, conn->set.base, auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.base, auth_request,
+ ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand base=%s: %s", conn->set.base, error);
+ ctx->ctx.failed = TRUE;
+ }
request->request.base = p_strdup(auth_request->pool, str_c(str));
str_truncate(str, 0);
- auth_request_var_expand(str, conn->set.iterate_filter,
- auth_request, ldap_escape);
+ if (auth_request_var_expand(str, conn->set.iterate_filter,
+ auth_request, ldap_escape, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand iterate_filter=%s: %s",
+ conn->set.iterate_filter, error);
+ ctx->ctx.failed = TRUE;
+ }
request->request.filter = p_strdup(auth_request->pool, str_c(str));
request->request.attr_map = &conn->iterate_attr_map;
request->request.attributes = conn->iterate_attr_names;
const char *username_format;
};
-static void
+static int
passwd_file_add_extra_fields(struct auth_request *request, char *const *fields)
{
string_t *str = t_str_new(512);
const struct var_expand_table *table;
- const char *key, *value;
+ const char *key, *value, *error;
unsigned int i;
table = auth_request_get_var_expand_table(request, NULL);
if (value != NULL) {
key = t_strdup_until(key, value);
str_truncate(str, 0);
- auth_request_var_expand_with_table(str, value + 1,
- request, table, NULL);
+ if (auth_request_var_expand_with_table(str, value + 1,
+ request, table, NULL, &error) <= 0) {
+ auth_request_log_error(request, AUTH_SUBSYS_DB,
+ "Failed to expand extra field %s: %s",
+ fields[i], error);
+ return -1;
+ }
value = str_c(str);
} else {
value = "";
}
auth_request_set_userdb_field(request, key, value);
}
+ return 0;
}
static void passwd_file_lookup(struct auth_request *auth_request,
ret = db_passwd_file_lookup(module->pwf, auth_request,
module->username_format, &pu);
if (ret <= 0 || pu->uid == 0) {
- callback(USERDB_RESULT_USER_UNKNOWN, auth_request);
+ callback(ret < 0 ? USERDB_RESULT_INTERNAL_FAILURE :
+ USERDB_RESULT_USER_UNKNOWN, auth_request);
return;
}
if (pu->home != NULL)
auth_request_set_userdb_field(auth_request, "home", pu->home);
- if (pu->extra_fields != NULL)
- passwd_file_add_extra_fields(auth_request, pu->extra_fields);
+ if (pu->extra_fields != NULL &&
+ passwd_file_add_extra_fields(auth_request, pu->extra_fields) < 0) {
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
callback(USERDB_RESULT_OK, auth_request);
}
(struct passwd_userdb_module *)_module;
struct passwd pw;
struct timeval start_tv;
+ const char *error;
int ret;
auth_request_log_debug(auth_request, AUTH_SUBSYS_DB, "lookup");
auth_request_set_userdb_field(auth_request, "gid", dec2str(pw.pw_gid));
auth_request_set_userdb_field(auth_request, "home", pw.pw_dir);
- userdb_template_export(module->tmpl, auth_request);
+ if (userdb_template_export(module->tmpl, auth_request, &error) < 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand template: %s", error);
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ }
callback(USERDB_RESULT_OK, auth_request);
}
struct sql_userdb_module *module =
(struct sql_userdb_module *)_module;
struct userdb_sql_request *sql_request;
- const char *query;
-
- query = t_auth_request_var_expand(module->conn->set.user_query,
- auth_request, userdb_sql_escape);
+ const char *query, *error;
+
+ if (t_auth_request_var_expand(module->conn->set.user_query,
+ auth_request, userdb_sql_escape,
+ &query, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand user_query=%s: %s",
+ module->conn->set.user_query, error);
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ return;
+ }
auth_request_ref(auth_request);
sql_request = i_new(struct userdb_sql_request, 1);
struct sql_userdb_module *module =
(struct sql_userdb_module *)_module;
struct sql_userdb_iterate_context *ctx;
- const char *query;
-
- query = t_auth_request_var_expand(module->conn->set.iterate_query,
- auth_request, userdb_sql_escape);
+ const char *query, *error;
+
+ if (t_auth_request_var_expand(module->conn->set.iterate_query,
+ auth_request, userdb_sql_escape,
+ &query, &error) <= 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand iterate_query=%s: %s",
+ module->conn->set.iterate_query, error);
+ }
ctx = i_new(struct sql_userdb_iterate_context, 1);
ctx->ctx.auth_request = auth_request;
struct userdb_module *_module = auth_request->userdb->userdb;
struct static_userdb_module *module =
(struct static_userdb_module *)_module;
+ const char *error;
- userdb_template_export(module->tmpl, auth_request);
+ if (userdb_template_export(module->tmpl, auth_request, &error) < 0) {
+ auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
+ "Failed to expand template: %s", error);
+ callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request);
+ }
callback(USERDB_RESULT_OK, auth_request);
}
return tmpl;
}
-void userdb_template_export(struct userdb_template *tmpl,
- struct auth_request *auth_request)
+int userdb_template_export(struct userdb_template *tmpl,
+ struct auth_request *auth_request,
+ const char **error_r)
{
const struct var_expand_table *table;
string_t *str;
unsigned int i, count;
if (userdb_template_is_empty(tmpl))
- return;
+ return 0;
str = t_str_new(256);
table = auth_request_get_var_expand_table(auth_request, NULL);
value = "";
else {
str_truncate(str, 0);
- auth_request_var_expand_with_table(str, args[i+1],
- auth_request, table, NULL);
+ if (auth_request_var_expand_with_table(str, args[i+1],
+ auth_request, table, NULL, error_r) <= 0)
+ return -1;
value = str_c(str);
}
auth_request_set_userdb_field(auth_request, args[i], value);
}
+ return 0;
}
bool userdb_template_remove(struct userdb_template *tmpl,
struct userdb_template *
userdb_template_build(pool_t pool, const char *userdb_name, const char *args);
-void userdb_template_export(struct userdb_template *tmpl,
- struct auth_request *auth_request);
+int userdb_template_export(struct userdb_template *tmpl,
+ struct auth_request *auth_request,
+ const char **error_r);
bool userdb_template_remove(struct userdb_template *tmpl,
const char *key, const char **value_r);
bool userdb_template_is_empty(struct userdb_template *tmpl);
director_request_callback *callback, void *context)
{
struct director_request *request;
- unsigned int username_hash =
- user_directory_get_username_hash(dir->users, username);
+ unsigned int username_hash;
+
+ if (!user_directory_get_username_hash(dir->users, username,
+ &username_hash)) {
+ callback(NULL, NULL, "Failed to expand director_username_hash", context);
+ return;
+ }
dir->num_requests++;
{ 'h', user->host->hostname, "host" },
{ '\0', NULL, NULL }
};
+ const char *error;
/* Execute flush script, if set. Only the director that started the
user moving will call the flush script. Having each director do it
ctx->host_ip = user->host->ip;
string_t *s_sock = str_new(default_pool, 32);
- var_expand(s_sock, dir->set->director_flush_socket, tab);
+ if (var_expand(s_sock, dir->set->director_flush_socket, tab, &error) <= 0) {
+ i_error("Failed to expand director_flush_socket=%s: %s",
+ dir->set->director_flush_socket, error);
+ director_user_kill_finish_delayed(dir, user, FALSE);
+ return;
+ }
ctx->socket_path = str_free_without_data(&s_sock);
- const char *error;
struct program_client_settings set = {
.client_connect_timeout_msecs = 10000,
.dns_client_socket_path = DIRECTOR_DNS_SOCKET_PATH,
username = args[0];
tag = args[1] != NULL ? args[1] : "";
}
- if (str_to_uint(username, &username_hash) < 0)
- username_hash = user_directory_get_username_hash(conn->dir->users, username);
+ if (str_to_uint(username, &username_hash) < 0) {
+ if (!user_directory_get_username_hash(conn->dir->users,
+ args[0], &username_hash)) {
+ o_stream_nsend_str(conn->output, "TRYAGAIN\n");
+ return 1;
+ }
+ }
/* get user's current host */
user = user_directory_lookup(conn->dir->users, username_hash);
return 1;
}
- if (str_to_uint(args[0], &username_hash) < 0)
- username_hash = user_directory_get_username_hash(conn->dir->users, args[0]);
+ if (str_to_uint(args[0], &username_hash) < 0) {
+ if (!user_directory_get_username_hash(conn->dir->users,
+ args[0], &username_hash)) {
+ o_stream_nsend_str(conn->output, "TRYAGAIN\n");
+ return 1;
+ }
+ }
user = user_directory_lookup(conn->dir->users, username_hash);
if (user != NULL && USER_IS_BEING_KILLED(user)) {
o_stream_nsend_str(conn->output, "TRYAGAIN\n");
int diff;
while ((line = i_stream_read_next_line(conn->input)) != NULL) {
- hash = user_directory_get_username_hash(conn->dir->users, line);
+ if (!user_directory_get_username_hash(conn->dir->users, line, &hash))
+ continue;
+
user = user_directory_lookup(conn->dir->users, hash);
if (user != NULL) {
diff = ioloop_time - user->timestamp;
#define USER_DIR_TIMEOUT 1000000
-unsigned int mail_user_hash(const char *username ATTR_UNUSED,
- const char *format ATTR_UNUSED) { return 0; }
+bool mail_user_hash(const char *username ATTR_UNUSED,
+ const char *format ATTR_UNUSED,
+ unsigned int *hash_r, const char **error_r ATTR_UNUSED)
+{
+ *hash_r = 0;
+ return TRUE;
+}
static void
verify_user_directory(struct user_directory *dir, unsigned int user_count)
array_free(&users);
}
-unsigned int user_directory_get_username_hash(struct user_directory *dir,
- const char *username)
+bool user_directory_get_username_hash(struct user_directory *dir,
+ const char *username,
+ unsigned int *hash_r)
{
- return mail_user_hash(username, dir->username_hash_fmt);
+ const char *error;
+
+ if (mail_user_hash(username, dir->username_hash_fmt, hash_r, &error))
+ return TRUE;
+ i_error("Failed to expand director_user_expire=%s: %s",
+ dir->username_hash_fmt, error);
+ return FALSE;
}
bool user_directory_user_is_recently_updated(struct user_directory *dir,
timestamps based on remote director's user list after handshake. */
void user_directory_sort(struct user_directory *dir);
-unsigned int user_directory_get_username_hash(struct user_directory *dir,
- const char *username);
+bool user_directory_get_username_hash(struct user_directory *dir,
+ const char *username,
+ unsigned int *hash_r);
bool user_directory_user_is_recently_updated(struct user_directory *dir,
struct user *user);
cmd_user_mail_print_fields(input, user, userdb_fields, show_field);
else {
string_t *str = t_str_new(128);
- var_expand_with_funcs(str, expand_field,
- mail_user_var_expand_table(user),
- mail_user_var_expand_func_table, user);
- string_t *value = t_str_new(128);
- json_append_escaped(value, expand_field);
- o_stream_nsend_str(doveadm_print_ostream, "\"");
- o_stream_nsend_str(doveadm_print_ostream, str_c(value));
- o_stream_nsend_str(doveadm_print_ostream, "\":\"");
- str_truncate(value, 0);
- json_append_escaped(value, str_c(str));
- o_stream_nsend_str(doveadm_print_ostream, str_c(value));
- o_stream_nsend_str(doveadm_print_ostream, "\"");
+ if (var_expand_with_funcs(str, expand_field,
+ mail_user_var_expand_table(user),
+ mail_user_var_expand_func_table, user,
+ &error) <= 0) {
+ string_t *str = t_str_new(128);
+ str_printfa(str, "\"error\":\"Failed to expand field: ");
+ json_append_escaped(str, error);
+ str_append_c(str, '"');
+ o_stream_nsend(doveadm_print_ostream, str_data(str), str_len(str));
+ } else {
+ string_t *value = t_str_new(128);
+ json_append_escaped(value, expand_field);
+ o_stream_nsend_str(doveadm_print_ostream, "\"");
+ o_stream_nsend_str(doveadm_print_ostream, str_c(value));
+ o_stream_nsend_str(doveadm_print_ostream, "\":\"");
+ str_truncate(value, 0);
+ json_append_escaped(value, str_c(str));
+ o_stream_nsend_str(doveadm_print_ostream, str_c(value));
+ o_stream_nsend_str(doveadm_print_ostream, "\"");
+ }
}
cmd_user_mail_print_fields(input, user, userdb_fields, show_field);
else {
string_t *str = t_str_new(128);
- var_expand_with_funcs(str, expand_field,
- mail_user_var_expand_table(user),
- mail_user_var_expand_func_table, user);
- printf("%s\n", str_c(str));
+ if (var_expand_with_funcs(str, expand_field,
+ mail_user_var_expand_table(user),
+ mail_user_var_expand_func_table, user,
+ &error) <= 0) {
+ i_error("Failed to expand %s: %s", expand_field, error);
+ } else {
+ printf("%s\n", str_c(str));
+ }
}
mail_user_unref(&user);
director_disconnect(ctx);
}
+static bool user_hash_expand(const char *username, unsigned int *hash_r)
+{
+ const char *error;
+
+ if (!mail_user_hash(username, doveadm_settings->director_username_hash,
+ hash_r, &error)) {
+ i_error("Failed to expand director_username_hash=%s: %s",
+ doveadm_settings->director_username_hash, error);
+ return FALSE;
+ }
+ return TRUE;
+}
+
static void
user_list_add(const char *username, pool_t pool,
HASH_TABLE_TYPE(user_list) users)
struct user_list *user, *old_user;
unsigned int user_hash;
+ if (!user_hash_expand(username, &user_hash))
+ return;
+
user = p_new(pool, struct user_list, 1);
user->name = p_strdup(pool, username);
- user_hash = mail_user_hash(username, doveadm_settings->director_username_hash);
old_user = hash_table_lookup(users, POINTER_CAST(user_hash));
if (old_user != NULL)
if (ctx->user_map) {
/* user -> hash mapping */
- user_hash = mail_user_hash(ctx->host, doveadm_settings->director_username_hash);
- doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
- doveadm_print_header("hash", "hash", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
- doveadm_print(t_strdup_printf("%u", user_hash));
+ if (user_hash_expand(ctx->host, &user_hash)) {
+ doveadm_print_init(DOVEADM_PRINT_TYPE_TABLE);
+ doveadm_print_header("hash", "hash", DOVEADM_PRINT_HEADER_FLAG_HIDE_TITLE);
+ doveadm_print(t_strdup_printf("%u", user_hash));
+ }
director_disconnect(ctx);
return;
}
return;
}
- user_hash = mail_user_hash(ctx->user, doveadm_settings->director_username_hash);
-
- if (director_get_host(ctx->host, &ips, &ips_count) != 0) {
+ if (!user_hash_expand(ctx->user, &user_hash) ||
+ director_get_host(ctx->host, &ips, &ips_count) != 0) {
director_disconnect(ctx);
return;
}
struct var_expand_table *tab;
ARRAY_TYPE(const_string) cmd_args;
string_t *str, *str2;
- const char *value, *const *args;
+ const char *value, *const *args, *error;
tab = t_malloc_no0(sizeof(static_tab));
memcpy(tab, static_tab, sizeof(static_tab));
text in the parameter, skip it. */
str_truncate(str, 0);
str_truncate(str2, 0);
- var_expand(str, *args, tab);
- var_expand(str2, *args, static_tab);
+ if (var_expand(str, *args, tab, &error) <= 0 ||
+ var_expand(str2, *args, static_tab, &error) <= 0) {
+ i_error("Failed to expand dsync_remote_cmd=%s: %s",
+ *args, error);
+ }
if (strcmp(str_c(str), str_c(str2)) == 0 &&
str_len(str) > 0)
continue;
if (ctx.format == NULL) {
i_fatal("formatted formatter cannot be used without a format.");
}
+ const char *error;
struct var_expand_table *entry = array_idx_modifiable(&ctx.headers, ctx.idx++);
entry->value = value;
if (ctx.idx >= array_count(&ctx.headers)) {
- var_expand(ctx.buf, ctx.format, array_idx(&ctx.headers,0));
+ if (var_expand(ctx.buf, ctx.format, array_idx(&ctx.headers,0), &error) <= 0) {
+ i_error("Failed to expand print format '%s': %s",
+ ctx.format, error);
+ }
doveadm_print_formatted_flush();
ctx.idx = 0;
}
struct imap_client *client;
pool_t pool = pool_alloconly_create("imap client", 256);
void *statebuf;
- const char *ident;
+ const char *ident, *error;
i_assert(state->username != NULL);
i_assert(state->mail_log_prefix != NULL);
string_t *str;
str = t_str_new(256);
- var_expand(str, state->mail_log_prefix,
- imap_client_get_var_expand_table(client));
+ if (var_expand(str, state->mail_log_prefix,
+ imap_client_get_var_expand_table(client),
+ &error) <= 0) {
+ i_error("Failed to expand mail_log_prefix=%s: %s",
+ state->mail_log_prefix, error);
+ }
client->log_prefix = p_strdup(pool, str_c(str));
} T_END;
restrict_access_allow_coredumps(TRUE);
set = mail_storage_service_user_get_set(user)[1];
- settings_var_expand(&imap_urlauth_worker_setting_parser_info, set,
- mail_user->pool,
- mail_user_var_expand_table(mail_user));
+ if (settings_var_expand(&imap_urlauth_worker_setting_parser_info, set,
+ mail_user->pool,
+ mail_user_var_expand_table(mail_user),
+ &error) <= 0) {
+ client_send_line(client, "NO");
+ client_abort(client, t_strdup_printf(
+ "Session aborted: Failed to expand settings: %s", error));
+ return 0;
+ }
if (set->verbose_proctitle) {
verbose_proctitle = TRUE;
{ '\0', NULL, NULL }
};
string_t *str;
+ const char *error;
str = t_str_new(128);
- var_expand(str, client->set->imap_logout_format, tab);
+ if (var_expand(str, client->set->imap_logout_format, tab, &error) <= 0) {
+ i_error("Failed to expand imap_logout_format=%s: %s",
+ client->set->imap_logout_format, error);
+ }
return str_c(str);
}
verbose_proctitle = TRUE;
lda_set = mail_storage_service_user_get_set(user)[2];
- settings_var_expand(&imap_setting_parser_info, imap_set,
- mail_user->pool, mail_user_var_expand_table(mail_user));
- settings_var_expand(&lda_setting_parser_info, lda_set,
- mail_user->pool, mail_user_var_expand_table(mail_user));
+ if (settings_var_expand(&imap_setting_parser_info, imap_set,
+ mail_user->pool, mail_user_var_expand_table(mail_user),
+ &errstr) <= 0 ||
+ settings_var_expand(&lda_setting_parser_info, lda_set,
+ mail_user->pool, mail_user_var_expand_table(mail_user),
+ &errstr) <= 0) {
+ *error_r = t_strdup_printf("Failed to expand settings: %s", errstr);
+ mail_user_unref(&mail_user);
+ mail_storage_service_user_free(&user);
+ return -1;
+ }
client = client_create(fd_in, fd_out, input->session_id,
mail_user, user, imap_set, lda_set);
lib_signals_ignore(SIGXFSZ, TRUE);
#endif
lda_set = mail_storage_service_user_get_set(service_user)[1];
- settings_var_expand(&lda_setting_parser_info, lda_set,
- ctx.dest_user->pool,
- mail_user_var_expand_table(ctx.dest_user));
+ if (settings_var_expand(&lda_setting_parser_info, lda_set,
+ ctx.dest_user->pool,
+ mail_user_var_expand_table(ctx.dest_user),
+ &errstr) <= 0)
+ i_fatal("Failed to expand settings: %s", errstr);
ctx.set = lda_set;
if (ctx.dest_user->mail_debug && *user_source != '\0') {
{
va_list args;
string_t *str;
- const char *msg;
+ const char *msg, *error;
if (*ctx->set->deliver_log_format == '\0')
return;
/* update %$ */
ctx->var_expand_table[0].value = msg;
mail_deliver_log_var_expand_table_update_times(ctx, ctx->var_expand_table);
- var_expand(str, ctx->set->deliver_log_format, ctx->var_expand_table);
+ if (var_expand(str, ctx->set->deliver_log_format,
+ ctx->var_expand_table, &error) <= 0) {
+ i_error("Failed to expand deliver_log_format=%s: %s",
+ ctx->set->deliver_log_format, error);
+ }
ctx->var_expand_table[0].value = "";
ctx->var_expand_table[VAR_EXPAND_DELIVERY_TIME_IDX].value = "";
ctx->dsn ? "delivery-status" : "disposition-notification",
boundary);
str_append(str, "Subject: ");
- var_expand(str, ctx->set->rejection_subject,
- get_var_expand_table(mail, reason, recipient));
+ if (var_expand(str, ctx->set->rejection_subject,
+ get_var_expand_table(mail, reason, recipient), &error) <= 0) {
+ i_error("Failed to expand rejection_subject=%s: %s",
+ ctx->set->rejection_subject, error);
+ }
str_append(str, "\r\n");
str_append(str, "Auto-Submitted: auto-replied (rejected)\r\n");
str_append(str, "Content-Disposition: inline\r\n");
str_append(str, "Content-Transfer-Encoding: 8bit\r\n\r\n");
- var_expand(str, ctx->set->rejection_reason,
- get_var_expand_table(mail, reason, recipient));
+ if (var_expand(str, ctx->set->rejection_reason,
+ get_var_expand_table(mail, reason, recipient), &error) <= 0) {
+ i_error("Failed to expand rejection_reason=%s: %s",
+ ctx->set->rejection_reason, error);
+ }
str_append(str, "\r\n");
if (ctx->dsn) {
#include "var-expand.h"
#include "mail-user-hash.h"
-unsigned int mail_user_hash(const char *username, const char *format)
+bool mail_user_hash(const char *username, const char *format,
+ unsigned int *hash_r, const char **error_r)
{
unsigned char md5[MD5_RESULTLEN];
unsigned int i, hash = 0;
+ char *error_dup = NULL;
+ int ret = 1;
if (strcmp(format, "%u") == 0) {
/* fast path */
{ '\0', NULL, NULL }
};
string_t *str = t_str_new(128);
+ const char *error;
- var_expand(str, format, tab);
+ ret = var_expand(str, format, tab, &error);
+ i_assert(ret >= 0);
+ if (ret == 0)
+ error_dup = i_strdup(error);
md5_get_digest(str_data(str), str_len(str), md5);
} T_END;
for (i = 0; i < sizeof(hash); i++)
hash = (hash << CHAR_BIT) | md5[i];
- return hash;
+ *hash_r = hash;
+ *error_r = t_strdup(error_dup);
+ i_free(error_dup);
+ return ret > 0;
}
-
#ifndef MAIL_USER_HASH
#define MAIL_USER_HASH
-/* Return a hash for username, based on given format. The format can use
- %n, %d and %u variables. */
-unsigned int mail_user_hash(const char *username, const char *format);
+/* Get a hash for username, based on given format. The format can use
+ %n, %d and %u variables. Returns TRUE if ok, FALSE if format is invalid. */
+bool mail_user_hash(const char *username, const char *format,
+ unsigned int *hash_r, const char **error_r);
#endif
settings_parse_set_key_expandeded(ctx, pool, *keys);
}
-static void ATTR_NULL(3, 4, 5)
+static int ATTR_NULL(3, 4, 5)
settings_var_expand_info(const struct setting_parser_info *info, void *set,
pool_t pool,
const struct var_expand_table *table,
const struct var_expand_func_table *func_table,
- void *func_context, string_t *str)
+ void *func_context, string_t *str,
+ const char **error_r)
{
const struct setting_define *def;
void *value, *const *children;
+ const char *error;
unsigned int i, count;
+ int ret, final_ret = 1;
for (def = info->defines; def->key != NULL; def++) {
value = PTR_OFFSET(set, def->offset);
*val += 1;
} else if (**val == SETTING_STRVAR_UNEXPANDED[0]) {
str_truncate(str, 0);
- var_expand_with_funcs(str, *val + 1, table,
- func_table, func_context);
+ ret = var_expand_with_funcs(str, *val + 1, table,
+ func_table, func_context,
+ &error);
+ if (final_ret > ret) {
+ final_ret = ret;
+ *error_r = t_strdup_printf(
+ "%s: %s", def->key, error);
+ }
*val = p_strdup(pool, str_c(str));
} else {
i_assert(**val == SETTING_STRVAR_EXPANDED[0]);
children = array_get(val, &count);
for (i = 0; i < count; i++) {
- settings_var_expand_info(def->list_info,
+ ret = settings_var_expand_info(def->list_info,
children[i], pool, table, func_table,
- func_context, str);
+ func_context, str, &error);
+ if (final_ret > ret) {
+ final_ret = ret;
+ *error_r = error;
+ }
}
break;
}
}
}
+ return final_ret;
}
-void settings_var_expand(const struct setting_parser_info *info,
- void *set, pool_t pool,
- const struct var_expand_table *table)
+int settings_var_expand(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table,
+ const char **error_r)
{
- settings_var_expand_with_funcs(info, set, pool, table, NULL, NULL);
+ return settings_var_expand_with_funcs(info, set, pool, table,
+ NULL, NULL, error_r);
}
-void settings_var_expand_with_funcs(const struct setting_parser_info *info,
- void *set, pool_t pool,
- const struct var_expand_table *table,
- const struct var_expand_func_table *func_table,
- void *func_context)
+int settings_var_expand_with_funcs(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table,
+ const struct var_expand_func_table *func_table,
+ void *func_context, const char **error_r)
{
- string_t *str;
+ char *error_dup = NULL;
+ int ret;
T_BEGIN {
- str = t_str_new(256);
- settings_var_expand_info(info, set, pool, table,
- func_table, func_context, str);
+ const char *error;
+ string_t *str = t_str_new(256);
+
+ ret = settings_var_expand_info(info, set, pool, table,
+ func_table, func_context, str,
+ &error);
+ if (ret <= 0)
+ error_dup = i_strdup(error);
} T_END;
+ *error_r = t_strdup(error_dup);
+ i_free(error_dup);
+ return ret;
}
void settings_parse_var_skip(struct setting_parser_context *ctx)
{
unsigned int i;
+ const char *error;
for (i = 0; i < ctx->root_count; i++) {
- settings_var_expand_info(ctx->roots[i].info,
- ctx->roots[i].set_struct,
- NULL, NULL, NULL, NULL, NULL);
+ (void)settings_var_expand_info(ctx->roots[i].info,
+ ctx->roots[i].set_struct,
+ NULL, NULL, NULL, NULL, NULL,
+ &error);
}
}
actually knowing what the variables are. */
void settings_parse_var_skip(struct setting_parser_context *ctx);
/* Expand all unexpanded variables using the given table. Update the string
- pointers so that they can be used without skipping over the '1'. */
-void settings_var_expand(const struct setting_parser_info *info,
- void *set, pool_t pool,
- const struct var_expand_table *table);
-void settings_var_expand_with_funcs(const struct setting_parser_info *info,
- void *set, pool_t pool,
- const struct var_expand_table *table,
- const struct var_expand_func_table *func_table,
- void *func_context);
+ pointers so that they can be used without skipping over the '1'.
+ Returns the same as var_expand(). */
+int settings_var_expand(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table,
+ const char **error_r);
+int settings_var_expand_with_funcs(const struct setting_parser_info *info,
+ void *set, pool_t pool,
+ const struct var_expand_table *table,
+ const struct var_expand_func_table *func_table,
+ void *func_context, const char **error_r);
/* Go through all the settings and return the first one that has an unexpanded
setting containing the given %key. */
bool settings_vars_have_key(const struct setting_parser_info *info, void *set,
};
string_t *path = t_str_new(64);
string_t *data;
+ const char *error;
int fd;
- var_expand(path, db->metrics_path, tab);
+ if (var_expand(path, db->metrics_path, tab, &error) <= 0) {
+ i_error("cassandra: Failed to expand metrics_path=%s: %s",
+ db->metrics_path, error);
+ return;
+ }
fd = open(str_c(path), O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, 0600);
if (fd == -1) {
prefix = t_str_new(128);
str_append(prefix, ns->prefix);
- var_expand(prefix, storage->ns_prefix_pattern, tab);
+ if (var_expand(prefix, storage->ns_prefix_pattern, tab, &error) <= 0) {
+ mailbox_list_set_critical(list,
+ "Failed to expand namespace prefix '%s': %s",
+ storage->ns_prefix_pattern, error);
+ return -1;
+ }
*_ns = mail_namespace_find_prefix(user->namespaces, str_c(prefix));
if (*_ns != NULL) {
}
}
+ location = t_str_new(256);
+ if (ret > 0 &&
+ var_expand(location, storage->location, tab, &error) <= 0) {
+ mailbox_list_set_critical(list,
+ "Failed to expand namespace location '%s': %s",
+ storage->location, error);
+ return -1;
+ }
+
/* create the new namespace */
new_ns = i_new(struct mail_namespace, 1);
new_ns->refcount = 1;
new_ns->mail_set = _storage->set;
i_array_init(&new_ns->all_storages, 2);
- location = t_str_new(256);
- if (ret > 0)
- var_expand(location, storage->location, tab);
- else {
+ if (ret <= 0) {
get_nonexistent_user_location(storage, userdomain, location);
new_ns->flags |= NAMESPACE_FLAG_UNUSABLE;
if (ns->user->mail_debug) {
struct module *mail_storage_service_modules = NULL;
-static void
+static int
mail_storage_service_var_expand(struct mail_storage_service_ctx *ctx,
string_t *str, const char *format,
struct mail_storage_service_user *user,
const struct mail_storage_service_input *input,
- const struct mail_storage_service_privileges *priv);
+ const struct mail_storage_service_privileges *priv,
+ const char **error_r);
static bool
mail_user_set_get_mail_debug(const struct setting_parser_info *user_info,
return get_var_expand_table(ctx->service, NULL, input, &priv);
}
-static const char *
+static bool
user_expand_varstr(struct mail_storage_service_ctx *ctx,
struct mail_storage_service_user *user,
struct mail_storage_service_privileges *priv,
- const char *str)
+ const char *str, const char **value_r, const char **error_r)
{
- string_t *ret;
+ string_t *value;
+ int ret;
- if (*str == SETTING_STRVAR_EXPANDED[0])
- return str + 1;
+ if (*str == SETTING_STRVAR_EXPANDED[0]) {
+ *value_r = str + 1;
+ return 1;
+ }
i_assert(*str == SETTING_STRVAR_UNEXPANDED[0]);
- ret = t_str_new(256);
- mail_storage_service_var_expand(ctx, ret, str + 1, user, &user->input, priv);
- return str_c(ret);
+ value = t_str_new(256);
+ ret = mail_storage_service_var_expand(ctx, value, str + 1, user,
+ &user->input, priv, error_r);
+ *value_r = str_c(value);
+ return ret > 0;
}
static int
const struct mail_user_settings *set = user->user_set;
uid_t uid = (uid_t)-1;
gid_t gid = (gid_t)-1;
+ const char *error;
memset(priv_r, 0, sizeof(*priv_r));
if (*set->mail_uid != '\0') {
/* variable strings are expanded in mail_user_init(),
but we need the home and chroot sooner so do them separately here. */
- priv_r->home = user_expand_varstr(ctx, user, priv_r,
- user->user_set->mail_home);
- priv_r->chroot = user_expand_varstr(ctx, user, priv_r,
- user->user_set->mail_chroot);
+ if (!user_expand_varstr(ctx, user, priv_r, user->user_set->mail_home,
+ &priv_r->home, &error) <= 0) {
+ *error_r = t_strdup_printf(
+ "Failed to expand mail_home '%s': %s",
+ user->user_set->mail_home, error);
+ return -1;
+ }
+ if (!user_expand_varstr(ctx, user, priv_r, user->user_set->mail_chroot,
+ &priv_r->chroot, &error)) {
+ *error_r = t_strdup_printf(
+ "Failed to expand mail_chroot '%s': %s",
+ user->user_set->mail_chroot, error);
+ return -1;
+ }
return 0;
}
user == NULL ? NULL : user->input.userdb_fields);
}
-static void
+static int
mail_storage_service_var_expand(struct mail_storage_service_ctx *ctx,
string_t *str, const char *format,
struct mail_storage_service_user *user,
const struct mail_storage_service_input *input,
- const struct mail_storage_service_privileges *priv)
+ const struct mail_storage_service_privileges *priv,
+ const char **error_r)
{
static const struct var_expand_func_table func_table[] = {
{ "userdb", mail_storage_service_input_var_userdb },
{ NULL, NULL }
};
- var_expand_with_funcs(str, format,
+ return var_expand_with_funcs(str, format,
get_var_expand_table(ctx->service, user, input, priv),
- func_table, user);
+ func_table, user, error_r);
}
static void
struct mail_storage_service_user *user,
struct mail_storage_service_privileges *priv)
{
+ const char *error;
+
ctx->log_initialized = TRUE;
T_BEGIN {
string_t *str;
str = t_str_new(256);
- mail_storage_service_var_expand(ctx, str,
+ (void)mail_storage_service_var_expand(ctx, str,
user->user_set->mail_log_prefix,
- user, &user->input, priv);
+ user, &user->input, priv, &error);
user->log_prefix = p_strdup(user->pool, str_c(str));
} T_END;
const struct mail_storage_service_privileges *priv)
{
string_t *str;
+ const char *error;
str = t_str_new(256);
- mail_storage_service_var_expand(ctx, str, user_set->mail_log_prefix,
- user, input, priv);
+ (void)mail_storage_service_var_expand(ctx, str, user_set->mail_log_prefix,
+ user, input, priv, &error);
i_set_failure_prefix("%s", str_c(str));
}
static void
mail_user_expand_plugins_envs(struct mail_user *user)
{
- const char **envs, *home;
+ const char **envs, *home, *error;
string_t *str;
unsigned int i, count;
return;
}
str_truncate(str, 0);
- var_expand_with_funcs(str, envs[i+1],
- mail_user_var_expand_table(user),
- mail_user_var_expand_func_table, user);
+ if (var_expand_with_funcs(str, envs[i+1],
+ mail_user_var_expand_table(user),
+ mail_user_var_expand_func_table, user,
+ &error) <= 0) {
+ user->error = p_strdup_printf(user->pool,
+ "Failed to expand plugin setting %s = '%s': %s",
+ envs[i], envs[i+1], error);
+ return;
+ }
envs[i+1] = p_strdup(user->pool, str_c(str));
}
}
int mail_user_init(struct mail_user *user, const char **error_r)
{
const struct mail_storage_settings *mail_set;
- const char *home, *key, *value;
+ const char *home, *key, *value, *error;
bool need_home_dir;
need_home_dir = user->_home == NULL &&
}
/* expand settings after we can expand %h */
- settings_var_expand_with_funcs(user->set_info, user->set,
- user->pool, mail_user_var_expand_table(user),
- mail_user_var_expand_func_table, user);
+ if (settings_var_expand_with_funcs(user->set_info, user->set,
+ user->pool, mail_user_var_expand_table(user),
+ mail_user_var_expand_func_table, user,
+ &error) <= 0) {
+ user->error = p_strdup_printf(user->pool,
+ "Failed to expand settings: %s", error);
+ }
user->settings_expanded = TRUE;
mail_user_expand_plugins_envs(user);
return ret;
}
-static void mail_user_get_mail_home(struct mail_user *user)
+static bool mail_user_get_mail_home(struct mail_user *user)
{
- const char *home = user->set->mail_home;
+ const char *error, *home = user->set->mail_home;
string_t *str;
if (user->settings_expanded) {
user->_home = home[0] != '\0' ? home : NULL;
- return;
+ return TRUE;
}
/* we're still initializing user. need to do the expansion ourself. */
i_assert(home[0] == SETTING_STRVAR_UNEXPANDED[0]);
home++;
if (home[0] == '\0')
- return;
+ return TRUE;
str = t_str_new(128);
- var_expand_with_funcs(str, home,
- mail_user_var_expand_table(user),
- mail_user_var_expand_func_table, user);
+ if (var_expand_with_funcs(str, home,
+ mail_user_var_expand_table(user),
+ mail_user_var_expand_func_table, user,
+ &error) <= 0) {
+ i_error("Failed to expand mail_home=%s: %s", home, error);
+ return FALSE;
+ }
user->_home = p_strdup(user->pool, str_c(str));
+ return TRUE;
}
int mail_user_get_home(struct mail_user *user, const char **home_r)
if (mail_user_auth_master_conn == NULL) {
/* no userdb connection. we can only use mail_home setting. */
- mail_user_get_mail_home(user);
+ if (!mail_user_get_mail_home(user))
+ return -1;
} else if ((ret = mail_user_userdb_lookup_home(user)) < 0) {
/* userdb lookup failed */
return -1;
} else if (user->_home == NULL) {
/* no home returned by userdb lookup, fallback to
mail_home setting. */
- mail_user_get_mail_home(user);
+ if (!mail_user_get_mail_home(user))
+ return -1;
}
user->home_looked_up = TRUE;
struct var_expand_test {
const char *in;
const char *out;
+ int ret;
};
struct var_get_key_range_test {
static void test_var_expand_ranges(void)
{
static struct var_expand_test tests[] = {
- { "%v", "value1234" },
- { "%3v", "val" },
- { "%3.2v", "ue" },
- { "%3.-2v", "ue12" },
- { "%-3.2v", "23" },
- { "%0.-1v", "value123" },
- { "%-4.-1v", "123" }
+ { "%v", "value1234", 1 },
+ { "%3v", "val", 1 },
+ { "%3.2v", "ue", 1 },
+ { "%3.-2v", "ue12", 1 },
+ { "%-3.2v", "23", 1 },
+ { "%0.-1v", "value123", 1 },
+ { "%-4.-1v", "123", 1 }
};
static struct var_expand_table table[] = {
{ 'v', "value1234", NULL },
{ '\0', NULL, NULL }
};
string_t *str = t_str_new(128);
+ const char *error;
unsigned int i;
test_begin("var_expand - ranges");
for (i = 0; i < N_ELEMENTS(tests); i++) {
str_truncate(str, 0);
- var_expand(str, tests[i].in, table);
+ test_assert(var_expand(str, tests[i].in, table, &error) == tests[i].ret);
test_assert(strcmp(tests[i].out, str_c(str)) == 0);
}
test_end();
static void test_var_expand_builtin(void)
{
static struct var_expand_test tests[] = {
- { "%{hostname}", NULL },
- { "%{pid}", NULL },
- { "a%{env:FOO}b", "abaRb" },
- { "%50Hv", "1f" },
- { "%50Hw", "2e" },
- { "%50Nv", "25" },
- { "%50Nw", "e" },
-
- { "%{nonexistent}", "UNSUPPORTED_VARIABLE_nonexistent" },
- { "%{nonexistent:default}", "UNSUPPORTED_VARIABLE_nonexistent" },
+ { "%{hostname}", NULL, 1 },
+ { "%{pid}", NULL, 1 },
+ { "a%{env:FOO}b", "abaRb", 1 },
+ { "%50Hv", "1f", 1 },
+ { "%50Hw", "2e", 1 },
+ { "%50Nv", "25", 1 },
+ { "%50Nw", "e", 1 },
+
+ { "%{nonexistent}", "UNSUPPORTED_VARIABLE_nonexistent", 0 },
+ { "%{nonexistent:default}", "UNSUPPORTED_VARIABLE_nonexistent", 0 },
};
static struct var_expand_table table[] = {
{ 'v', "value", NULL },
{ '\0', NULL, NULL }
};
string_t *str = t_str_new(128);
+ const char *error;
unsigned int i;
tests[0].out = my_hostname;
test_begin("var_expand - builtin");
for (i = 0; i < N_ELEMENTS(tests); i++) {
str_truncate(str, 0);
- var_expand(str, tests[i].in, table);
+ test_assert_idx(var_expand(str, tests[i].in, table, &error) == tests[i].ret, i);
test_assert_idx(strcmp(tests[i].out, str_c(str)) == 0, i);
}
test_end();
static void test_var_expand_with_funcs(void)
{
static struct var_expand_test tests[] = {
- { "%{func1}", "<>" },
- { "%{func1:foo}", "<foo>" },
- { "%{func2}", "" },
- { "%{func3}", "" }
+ { "%{func1}", "<>", 1 },
+ { "%{func1:foo}", "<foo>", 1 },
+ { "%{func2}", "", 1 },
+ { "%{func3}", "", 1 }
};
static struct var_expand_table table[] = {
{ '\0', NULL, NULL }
{ NULL, NULL }
};
string_t *str = t_str_new(128);
+ const char *error;
unsigned int i;
int ctx = 0xabcdef;
test_begin("var_expand_with_funcs");
for (i = 0; i < N_ELEMENTS(tests); i++) {
str_truncate(str, 0);
- var_expand_with_funcs(str, tests[i].in, table, func_table, &ctx);
+ test_assert_idx(var_expand_with_funcs(str, tests[i].in, table, func_table, &ctx, &error) == tests[i].ret, i);
test_assert_idx(strcmp(tests[i].out, str_c(str)) == 0, i);
}
test_end();
{ '\0', NULL }
};
-static const char *
-var_expand_short(const struct var_expand_table *table, char key)
+static int
+var_expand_short(const struct var_expand_table *table, char key,
+ const char **var_r, const char **error_r)
{
const struct var_expand_table *t;
if (table != NULL) {
for (t = table; !TABLE_LAST(t); t++) {
- if (t->key == key)
- return t->value != NULL ? t->value : "";
+ if (t->key == key) {
+ *var_r = t->value != NULL ? t->value : "";
+ return 1;
+ }
}
}
/* not found */
- if (key == '%')
- return "%";
- return NULL;
+ if (key == '%') {
+ *var_r = "%";
+ return 1;
+ }
+ if (*error_r == NULL)
+ *error_r = t_strdup_printf("Unknown variable '%%%c'", key);
+ return 0;
}
-static const char *
+static int
var_expand_func(const struct var_expand_func_table *func_table,
- const char *key, const char *data, void *context)
+ const char *key, const char *data, void *context,
+ const char **var_r, const char **error_r)
{
const char *value;
if (strcmp(key, "env") == 0) {
value = getenv(data);
- return value != NULL ? value : "";
+ *var_r = value != NULL ? value : "";
+ return 1;
}
- if (func_table == NULL)
- return NULL;
-
- for (; func_table->key != NULL; func_table++) {
- if (strcmp(func_table->key, key) == 0) {
- value = func_table->func(data, context);
- return value != NULL ? value : "";
+ if (func_table != NULL) {
+ for (; func_table->key != NULL; func_table++) {
+ if (strcmp(func_table->key, key) == 0) {
+ value = func_table->func(data, context);
+ *var_r = value != NULL ? value : "";
+ return 1;
+ }
}
}
- return NULL;
+ if (*error_r == NULL)
+ *error_r = t_strdup_printf("Unknown variable '%%%s'", key);
+ *var_r = t_strdup_printf("UNSUPPORTED_VARIABLE_%s", key);
+ return 0;
}
-static const char *
+static int
var_expand_long(const struct var_expand_table *table,
const struct var_expand_func_table *func_table,
- const void *key_start, unsigned int key_len, void *context)
+ const void *key_start, unsigned int key_len, void *context,
+ const char **var_r, const char **error_r)
{
const struct var_expand_table *t;
const char *key, *value = NULL;
+ int ret = 1;
if (table != NULL) {
for (t = table; !TABLE_LAST(t); t++) {
if (t->long_key != NULL &&
strncmp(t->long_key, key_start, key_len) == 0 &&
t->long_key[key_len] == '\0') {
- return t->value != NULL ? t->value : "";
+ *var_r = t->value != NULL ? t->value : "";
+ return 1;
}
}
}
key = t_strdup_until(key, data++);
else
data = "";
- value = var_expand_func(func_table, key, data, context);
+ ret = var_expand_func(func_table, key, data, context, &value, error_r);
}
- if (value == NULL)
- return t_strdup_printf("UNSUPPORTED_VARIABLE_%s", key);
- return value;
+ *var_r = value;
+ return ret;
}
-void var_expand_with_funcs(string_t *dest, const char *str,
- const struct var_expand_table *table,
- const struct var_expand_func_table *func_table,
- void *context)
+int var_expand_with_funcs(string_t *dest, const char *str,
+ const struct var_expand_table *table,
+ const struct var_expand_func_table *func_table,
+ void *context, const char **error_r)
{
const struct var_expand_modifier *m;
const char *var;
(const char *, struct var_expand_context *);
const char *end;
unsigned int i, len, modifier_count;
+ int ret, final_ret = 1;
+
+ *error_r = NULL;
memset(&ctx, 0, sizeof(ctx));
for (; *str != '\0'; str++) {
if (*str == '{' && (end = strchr(str, '}')) != NULL) {
/* %{long_key} */
len = end - (str + 1);
- var = var_expand_long(table, func_table,
- str+1, len, context);
+ ret = var_expand_long(table, func_table,
+ str+1, len, context,
+ &var, error_r);
i_assert(var != NULL);
str = end;
} else {
- var = var_expand_short(table, *str);
+ ret = var_expand_short(table, *str, &var, error_r);
}
+ if (final_ret > ret)
+ final_ret = ret;
if (var != NULL) {
for (i = 0; i < modifier_count; i++)
}
}
}
+ return final_ret;
}
-void var_expand(string_t *dest, const char *str,
- const struct var_expand_table *table)
+int var_expand(string_t *dest, const char *str,
+ const struct var_expand_table *table, const char **error_r)
{
- var_expand_with_funcs(dest, str, table, NULL, NULL);
+ return var_expand_with_funcs(dest, str, table, NULL, NULL, error_r);
}
static bool
};
/* Expand % variables in src and append the string in dest.
- table must end with key = 0. */
-void var_expand(string_t *dest, const char *str,
- const struct var_expand_table *table);
+ table must end with key = 0. Returns 1 on success, 0 if the format string
+ contained invalid/unknown %variables. Even in case of errors the dest string
+ is still written as fully as possible. */
+int var_expand(string_t *dest, const char *str,
+ const struct var_expand_table *table,
+ const char **error_r);
/* Like var_expand(), but support also callback functions for
variable expansion. */
-void var_expand_with_funcs(string_t *dest, const char *str,
- const struct var_expand_table *table,
- const struct var_expand_func_table *func_table,
- void *func_context) ATTR_NULL(3, 4, 5);
+int var_expand_with_funcs(string_t *dest, const char *str,
+ const struct var_expand_table *table,
+ const struct var_expand_func_table *func_table,
+ void *func_context, const char **error_r) ATTR_NULL(3, 4, 5);
/* Returns the actual key character for given string, ie. skip any modifiers
that are before it. The string should be the data after the '%' character.
i_fatal("%s", error);
lmtp_settings_dup(set_parser, client->pool, &lmtp_set, &lda_set);
- settings_var_expand(&lmtp_setting_parser_info, lmtp_set, client->pool,
- mail_storage_service_get_var_expand_table(storage_service, &input));
+ const struct var_expand_table *tab =
+ mail_storage_service_get_var_expand_table(storage_service, &input);
+ if (settings_var_expand(&lmtp_setting_parser_info, lmtp_set,
+ client->pool, tab, &error) <= 0)
+ i_fatal("Failed to expand settings: %s", error);
client->service_set = master_service_settings_get(master_service);
client->lmtp_set = lmtp_set;
client->unexpanded_lda_set = lda_set;
rcpt->address);
return -1;
}
- str = t_str_new(256);
- var_expand_with_funcs(str, client->state.dest_user->set->mail_log_prefix,
- mail_user_var_expand_table(client->state.dest_user),
- mail_user_var_expand_func_table,
- client->state.dest_user);
- i_set_failure_prefix("%s", str_c(str));
sets = mail_storage_service_user_get_set(rcpt->service_user);
lda_set = sets[1];
- settings_var_expand(&lda_setting_parser_info, lda_set, client->pool,
- mail_user_var_expand_table(client->state.dest_user));
+ if (settings_var_expand(&lda_setting_parser_info, lda_set, client->pool,
+ mail_user_var_expand_table(client->state.dest_user), &error) <= 0) {
+ i_error("Failed to expand settings: %s", error);
+ client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
+ rcpt->address);
+ return -1;
+ }
+
+ str = t_str_new(256);
+ if (var_expand_with_funcs(str, client->state.dest_user->set->mail_log_prefix,
+ mail_user_var_expand_table(client->state.dest_user),
+ mail_user_var_expand_func_table,
+ client->state.dest_user, &error) <= 0) {
+ i_error("Failed to expand mail_log_prefix=%s: %s",
+ client->state.dest_user->set->mail_log_prefix, error);
+ client_send_line(client, ERRSTR_TEMP_MAILBOX_FAIL,
+ rcpt->address);
+ return -1;
+ }
+ i_set_failure_prefix("%s", str_c(str));
memset(&dctx, 0, sizeof(dctx));
dctx.session = session;
{ "passdb", client_var_expand_func_passdb },
{ NULL, NULL }
};
+ static bool expand_error_logged = FALSE;
const struct var_expand_table *var_expand_table;
char *const *e;
+ const char *error;
string_t *str, *str2;
unsigned int pos;
str2 = t_str_new(128);
for (e = client->set->log_format_elements_split; *e != NULL; e++) {
pos = str_len(str);
- var_expand_with_funcs(str, *e, var_expand_table,
- func_table, client);
+ if (var_expand_with_funcs(str, *e, var_expand_table,
+ func_table, client, &error) <= 0 &&
+ !expand_error_logged) {
+ i_error("Failed to expand log_format_elements=%s: %s",
+ *e, error);
+ expand_error_logged = TRUE;
+ }
if (have_username_key(*e)) {
/* username is added even if it's empty */
} else {
str_truncate(str2, 0);
- var_expand(str2, *e, login_var_expand_empty_tab);
+ if (var_expand(str2, *e, login_var_expand_empty_tab,
+ &error) <= 0) {
+ /* we just logged this error above. no need
+ to do it again. */
+ }
if (strcmp(str_c(str)+pos, str_c(str2)) == 0) {
/* empty %variables, don't add */
str_truncate(str, pos);
};
str_truncate(str, 0);
- var_expand(str, client->set->login_log_format, tab);
+ if (var_expand(str, client->set->login_log_format, tab, &error) <= 0) {
+ i_error("Failed to expand login_log_format=%s: %s",
+ client->set->login_log_format, error);
+ expand_error_logged = TRUE;
+ }
return str_c(str);
}
login_proxy_cmd_kick_full(cmd, args+1, want_kick_alt_username, i);
}
-static unsigned int director_username_hash(struct client *client)
+static bool director_username_hash(struct client *client, unsigned int *hash_r)
{
- return mail_user_hash(client->virtual_user,
- client->set->director_username_hash);
+ const char *error;
+
+ if (!mail_user_hash(client->virtual_user,
+ client->set->director_username_hash,
+ hash_r, &error)) {
+ i_error("Failed to expand director_username_hash=%s: %s",
+ client->set->director_username_hash, error);
+ return FALSE;
+ }
+ return TRUE;
}
static void
{
struct login_proxy *proxy, *next;
struct ip_addr except_ip;
- unsigned int hash, count = 0;
+ unsigned int hash, proxy_hash, count = 0;
if (args[0] == NULL || str_to_uint(args[0], &hash) < 0) {
ipc_cmd_fail(&cmd, "Invalid parameters");
for (proxy = login_proxies; proxy != NULL; proxy = next) {
next = proxy->next;
- if (director_username_hash(proxy->client) == hash &&
+ if (director_username_hash(proxy->client, &proxy_hash) &&
+ proxy_hash == hash &&
!net_ip_compare(&proxy->ip, &except_ip)) {
login_proxy_free_delayed(&proxy, KILLED_BY_DIRECTOR_REASON);
count++;
for (proxy = login_proxies_pending; proxy != NULL; proxy = next) {
next = proxy->next;
- if (director_username_hash(proxy->client) == hash &&
+ if (director_username_hash(proxy->client, &proxy_hash) &&
+ proxy_hash == hash &&
!net_ip_compare(&proxy->ip, &except_ip)) {
client_destroy(proxy->client, "Connection kicked");
count++;
for (i = 0; i < count; i++)
sets[i] = login_setting_dup(pool, input.roots[i], cache_sets[i]);
- settings_var_expand(&login_setting_parser_info, sets[0], pool,
- login_set_var_expand_table(&input));
+ if (settings_var_expand(&login_setting_parser_info, sets[0], pool,
+ login_set_var_expand_table(&input), &error) <= 0)
+ i_fatal("Failed to expand settings: %s", error);
*ssl_set_r =
login_setting_dup(pool, &master_service_ssl_setting_parser_info,
struct mail_namespace *new_ns = ns;
struct mailbox_list_iterate_context *iter;
const struct mailbox_info *info;
- const char *mailbox;
+ const char *mailbox, *error;
string_t *str;
if (strcmp(ns->user->username, userdomain) == 0) {
};
str = t_str_new(128);
- var_expand(str, sstorage->ns_prefix_pattern, tab);
+ if (var_expand(str, sstorage->ns_prefix_pattern, tab, &error) <= 0) {
+ i_error("Failed to expand namespace prefix %s: %s",
+ sstorage->ns_prefix_pattern, error);
+ return;
+ }
mailbox = str_c(str);
if (shared_storage_get_namespace(&new_ns, &mailbox) < 0)
return;
return ldap_client_init(&set, &dict->client, error_r);
}
-static void
+static bool
ldap_dict_build_query(struct ldap_dict *dict, const struct dict_ldap_map *map,
ARRAY_TYPE(const_string) *values, bool priv,
- string_t *query_r)
+ string_t *query_r, const char **error_r)
{
- const char *template;
+ const char *template, *error;
ARRAY(struct var_expand_table) exp;
struct var_expand_table entry;
array_append_zero(&exp);
- var_expand(query_r, template, array_idx(&exp, 0));
+ if (var_expand(query_r, template, array_idx(&exp, 0), &error) <= 0) {
+ *error_r = t_strdup_printf("Failed to expand %s: %s", template, error);
+ return FALSE;
+ }
+ return TRUE;
}
static
struct ldap_search_input input;
struct ldap_dict *ctx = (struct ldap_dict*)dict;
struct dict_ldap_op *op;
+ const char *error;
+
pool_t oppool = pool_alloconly_create("ldap dict lookup", 64);
string_t *query = str_new(oppool, 64);
op = p_new(oppool, struct dict_ldap_op, 1);
memset(&input, 0, sizeof(input));
input.base_dn = map->base_dn;
input.scope = map->scope_val;
- ldap_dict_build_query(ctx, map, &values, strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE))==0, query);
+ if (!ldap_dict_build_query(ctx, map, &values, strncmp(key, DICT_PATH_PRIVATE, strlen(DICT_PATH_PRIVATE))==0, query, &error)) {
+ op->res.error = error;
+ callback(&(op->res), context);
+ pool_unref(&oppool);
+ }
input.filter = str_c(query);
input.attributes = attributes;
input.timeout_secs = ctx->set->timeout;
{ '\0', NULL, NULL }
};
string_t *str;
+ const char *error;
str = t_str_new(128);
- var_expand(str, client->set->pop3_logout_format, tab);
+ if (var_expand(str, client->set->pop3_logout_format, tab, &error) <= 0) {
+ i_error("Failed to expand pop3_logout_format=%s: %s",
+ client->set->pop3_logout_format, error);
+ }
return str_c(str);
}
{ 'g', guid, "guid" },
{ '\0', NULL, NULL }
};
- var_expand(str, client->mail_set->pop3_uidl_format, tab);
+ const char *error;
+
+ if (var_expand(str, client->mail_set->pop3_uidl_format,
+ tab, &error) <= 0) {
+ i_error("UIDL: Failed to expand pop3_uidl_format=%s: %s",
+ client->mail_set->pop3_uidl_format, error);
+ return -1;
+ }
return 0;
}