string_t *str;
const char *value;
- if (auth_request->userdb_lookup_failed)
+ if (auth_request->userdb_lookup_tempfailed)
result = USERDB_RESULT_INTERNAL_FAILURE;
if (result == USERDB_RESULT_OK) {
switch (result) {
case USERDB_RESULT_INTERNAL_FAILURE:
str_printfa(str, "FAIL\t%u", auth_request->id);
- if (auth_request->userdb_lookup_failed) {
+ if (auth_request->userdb_lookup_tempfailed) {
value = auth_fields_find(auth_request->userdb_reply,
"reason");
if (value != NULL)
string_t *str;
const char *value;
- if (auth_request->userdb_lookup_failed)
+ if (auth_request->userdb_lookup_tempfailed)
result = USERDB_RESULT_INTERNAL_FAILURE;
str = t_str_new(128);
switch (result) {
case USERDB_RESULT_INTERNAL_FAILURE:
- if (auth_request->userdb_lookup_failed)
+ if (auth_request->userdb_lookup_tempfailed)
value = auth_fields_find(auth_request->userdb_reply, "reason");
else
value = NULL;
auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
- if (request->userdb_lookup_failed)
+ if (request->userdb_lookup_tempfailed)
result = USERDB_RESULT_INTERNAL_FAILURE;
str = t_str_new(128);
switch (result) {
case USERDB_RESULT_INTERNAL_FAILURE:
str_printfa(str, "FAIL\t%u", request->id);
- if (request->userdb_lookup_failed) {
+ if (request->userdb_lookup_tempfailed) {
value = auth_fields_find(request->userdb_reply, "reason");
if (value != NULL)
auth_str_add_keyvalue(str, "reason", value);
i_unreached();
}
+static bool
+auth_request_want_skip_userdb(struct auth_request *request,
+ struct auth_userdb *userdb)
+{
+ switch (userdb->skip) {
+ case AUTH_USERDB_SKIP_NEVER:
+ return FALSE;
+ case AUTH_USERDB_SKIP_FOUND:
+ return request->userdb_success;
+ case AUTH_USERDB_SKIP_NOTFOUND:
+ return !request->userdb_success;
+ }
+ i_unreached();
+}
+
static bool
auth_request_handle_passdb_callback(enum passdb_result *result,
struct auth_request *request)
{
struct auth_passdb *next_passdb;
- enum auth_passdb_rule result_rule;
+ enum auth_db_rule result_rule;
bool passdb_continue = FALSE;
if (request->passdb_password != NULL) {
}
switch (result_rule) {
- case AUTH_PASSDB_RULE_RETURN:
+ case AUTH_DB_RULE_RETURN:
break;
- case AUTH_PASSDB_RULE_RETURN_OK:
+ case AUTH_DB_RULE_RETURN_OK:
request->passdb_success = TRUE;
break;
- case AUTH_PASSDB_RULE_RETURN_FAIL:
+ case AUTH_DB_RULE_RETURN_FAIL:
request->passdb_success = FALSE;
break;
- case AUTH_PASSDB_RULE_CONTINUE:
+ case AUTH_DB_RULE_CONTINUE:
passdb_continue = TRUE;
break;
- case AUTH_PASSDB_RULE_CONTINUE_OK:
+ case AUTH_DB_RULE_CONTINUE_OK:
passdb_continue = TRUE;
request->passdb_success = TRUE;
break;
- case AUTH_PASSDB_RULE_CONTINUE_FAIL:
+ case AUTH_DB_RULE_CONTINUE_FAIL:
passdb_continue = TRUE;
request->passdb_success = FALSE;
break;
struct auth_request *request)
{
struct userdb_module *userdb = request->userdb->userdb;
+ struct auth_userdb *next_userdb;
+ enum auth_db_rule result_rule;
+ bool userdb_continue = FALSE;
- if (result != USERDB_RESULT_OK && request->userdb->next != NULL) {
+ switch (result) {
+ case USERDB_RESULT_OK:
+ result_rule = request->userdb->result_success;
+ break;
+ case USERDB_RESULT_INTERNAL_FAILURE:
+ result_rule = request->userdb->result_internalfail;
+ break;
+ case USERDB_RESULT_USER_UNKNOWN:
+ default:
+ result_rule = request->userdb->result_failure;
+ break;
+ }
+
+ switch (result_rule) {
+ case AUTH_DB_RULE_RETURN:
+ break;
+ case AUTH_DB_RULE_RETURN_OK:
+ request->userdb_success = TRUE;
+ break;
+ case AUTH_DB_RULE_RETURN_FAIL:
+ request->userdb_success = FALSE;
+ break;
+ case AUTH_DB_RULE_CONTINUE:
+ userdb_continue = TRUE;
+ break;
+ case AUTH_DB_RULE_CONTINUE_OK:
+ userdb_continue = TRUE;
+ request->userdb_success = TRUE;
+ break;
+ case AUTH_DB_RULE_CONTINUE_FAIL:
+ userdb_continue = TRUE;
+ request->userdb_success = FALSE;
+ break;
+ }
+
+ next_userdb = request->userdb->next;
+ while (next_userdb != NULL &&
+ auth_request_want_skip_userdb(request, next_userdb))
+ next_userdb = next_userdb->next;
+
+ if (userdb_continue && next_userdb != NULL) {
/* try next userdb. */
if (result == USERDB_RESULT_INTERNAL_FAILURE)
request->userdbs_seen_internal_failure = TRUE;
- request->userdb = request->userdb->next;
+ if (result == USERDB_RESULT_OK) {
+ /* this userdb lookup succeeded, preserve its extra
+ fields */
+ auth_fields_snapshot(request->userdb_reply);
+ } else {
+ /* this userdb lookup failed, remove any extra fields
+ it set */
+ auth_fields_rollback(request->userdb_reply);
+ }
+
+ request->userdb = next_userdb;
auth_request_lookup_user(request,
request->private_callback.userdb);
return;
}
- if (result == USERDB_RESULT_OK)
+ if (request->userdb_success)
userdb_template_export(userdb->override_fields_tmpl, request);
- else if (request->userdbs_seen_internal_failure) {
+ else if (request->userdbs_seen_internal_failure ||
+ result == USERDB_RESULT_INTERNAL_FAILURE) {
/* one of the userdb lookups failed. the user might have been
in there, so this is an internal failure */
result = USERDB_RESULT_INTERNAL_FAILURE;
- } else if (result == USERDB_RESULT_USER_UNKNOWN &&
- request->client_pid != 0) {
+ } else if (request->client_pid != 0) {
/* this was an actual login attempt, the user should
have been found. */
if (auth_request_get_auth(request)->userdbs->next == NULL) {
}
}
- if (request->userdb_lookup_failed) {
+ if (request->userdb_lookup_tempfailed) {
/* no caching */
} else if (result != USERDB_RESULT_INTERNAL_FAILURE)
auth_request_userdb_save_cache(request, result);
request->private_callback.userdb = callback;
request->userdb_lookup = TRUE;
+ if (request->userdb_reply == NULL)
+ auth_request_init_userdb_reply(request);
/* (for now) auth_cache is shared between passdb and userdb */
cache_key = passdb_cache == NULL ? NULL : userdb->cache_key;
if (strcmp(name, "uid") == 0) {
uid = userdb_parse_uid(request, value);
if (uid == (uid_t)-1) {
- request->userdb_lookup_failed = TRUE;
+ request->userdb_lookup_tempfailed = TRUE;
return;
}
value = dec2str(uid);
} else if (strcmp(name, "gid") == 0) {
gid = userdb_parse_gid(request, value);
if (gid == (gid_t)-1) {
- request->userdb_lookup_failed = TRUE;
+ request->userdb_lookup_tempfailed = TRUE;
return;
}
value = dec2str(gid);
} else if (strcmp(name, "tempfail") == 0) {
- request->userdb_lookup_failed = TRUE;
+ request->userdb_lookup_tempfailed = TRUE;
return;
} else if (auth_request_try_update_username(request, name, value)) {
return;
for (; *values != NULL; values++) {
gid = userdb_parse_gid(request, *values);
if (gid == (gid_t)-1) {
- request->userdb_lookup_failed = TRUE;
+ request->userdb_lookup_tempfailed = TRUE;
return;
}
at the end. mechanisms that don't require passdb, but do a passdb
lookup anyway (e.g. GSSAPI) need to set this to TRUE by default. */
unsigned int passdb_success:1;
+ /* userdb equivalent of passdb_success */
+ unsigned int userdb_success:1;
/* the last userdb lookup failed either due to "tempfail" extra field
or because one of the returned uid/gid fields couldn't be translated
to a number */
- unsigned int userdb_lookup_failed:1;
+ unsigned int userdb_lookup_tempfailed:1;
/* ... mechanism specific data ... */
};
DEF(SET_STR, args),
DEF(SET_STR, default_fields),
DEF(SET_STR, override_fields),
+
DEF(SET_ENUM, skip),
DEF(SET_ENUM, result_success),
DEF(SET_ENUM, result_failure),
DEF(SET_ENUM, result_internalfail),
+
DEF(SET_BOOL, deny),
DEF(SET_BOOL, pass),
DEF(SET_BOOL, master),
.args = "",
.default_fields = "",
.override_fields = "",
+
.skip = "never:authenticated:unauthenticated",
.result_success = "return-ok:return:return-fail:continue:continue-ok:continue-fail",
.result_failure = "continue:return:return-ok:return-fail:continue-ok:continue-fail",
.result_internalfail = "continue:return:return-ok:return-fail:continue-ok:continue-fail",
+
.deny = FALSE,
.pass = FALSE,
.master = FALSE
DEF(SET_STR, default_fields),
DEF(SET_STR, override_fields),
+ DEF(SET_ENUM, skip),
+ DEF(SET_ENUM, result_success),
+ DEF(SET_ENUM, result_failure),
+ DEF(SET_ENUM, result_internalfail),
+
SETTING_DEFINE_LIST_END
};
.driver = "",
.args = "",
.default_fields = "",
- .override_fields = ""
+ .override_fields = "",
+
+ .skip = "never:found:notfound",
+ .result_success = "return-ok:return:return-fail:continue:continue-ok:continue-fail",
+ .result_failure = "continue:return:return-ok:return-fail:continue-ok:continue-fail",
+ .result_internalfail = "continue:return:return-ok:return-fail:continue-ok:continue-fail"
};
const struct setting_parser_info auth_userdb_setting_parser_info = {
const char *args;
const char *default_fields;
const char *override_fields;
+
const char *skip;
const char *result_success;
const char *result_failure;
const char *result_internalfail;
bool deny;
- bool pass;
+ bool pass; /* deprecated, use result_success=continue instead */
bool master;
};
const char *args;
const char *default_fields;
const char *override_fields;
+
+ const char *skip;
+ const char *result_success;
+ const char *result_failure;
+ const char *result_internalfail;
};
struct auth_settings {
case USERDB_RESULT_OK:
str_append(str, "OK\t");
auth_fields_append(auth_request->userdb_reply, str, 0, 0);
- if (auth_request->userdb_lookup_failed)
+ if (auth_request->userdb_lookup_tempfailed)
str_append(str, "\ttempfail");
break;
}
return FALSE;
}
+ auth_request_init_userdb_reply(auth_request);
auth_request->userdb->userdb->iface->
lookup(auth_request, lookup_user_callback);
return TRUE;
i_unreached();
}
-static enum auth_passdb_rule auth_passdb_rule_parse(const char *str)
+static enum auth_userdb_skip auth_userdb_skip_parse(const char *str)
+{
+ if (strcmp(str, "never") == 0)
+ return AUTH_USERDB_SKIP_NEVER;
+ if (strcmp(str, "found") == 0)
+ return AUTH_USERDB_SKIP_FOUND;
+ if (strcmp(str, "notfound") == 0)
+ return AUTH_USERDB_SKIP_NOTFOUND;
+ i_unreached();
+}
+
+static enum auth_db_rule auth_db_rule_parse(const char *str)
{
if (strcmp(str, "return") == 0)
- return AUTH_PASSDB_RULE_RETURN;
+ return AUTH_DB_RULE_RETURN;
if (strcmp(str, "return-ok") == 0)
- return AUTH_PASSDB_RULE_RETURN_OK;
+ return AUTH_DB_RULE_RETURN_OK;
if (strcmp(str, "return-fail") == 0)
- return AUTH_PASSDB_RULE_RETURN_FAIL;
+ return AUTH_DB_RULE_RETURN_FAIL;
if (strcmp(str, "continue") == 0)
- return AUTH_PASSDB_RULE_CONTINUE;
+ return AUTH_DB_RULE_CONTINUE;
if (strcmp(str, "continue-ok") == 0)
- return AUTH_PASSDB_RULE_CONTINUE_OK;
+ return AUTH_DB_RULE_CONTINUE_OK;
if (strcmp(str, "continue-fail") == 0)
- return AUTH_PASSDB_RULE_CONTINUE_FAIL;
+ return AUTH_DB_RULE_CONTINUE_FAIL;
i_unreached();
}
auth_passdb->set = set;
auth_passdb->skip = auth_passdb_skip_parse(set->skip);
auth_passdb->result_success =
- auth_passdb_rule_parse(set->result_success);
+ auth_db_rule_parse(set->result_success);
auth_passdb->result_failure =
- auth_passdb_rule_parse(set->result_failure);
+ auth_db_rule_parse(set->result_failure);
auth_passdb->result_internalfail =
- auth_passdb_rule_parse(set->result_internalfail);
+ auth_db_rule_parse(set->result_internalfail);
/* for backwards compatibility: */
if (set->pass)
- auth_passdb->result_success = AUTH_PASSDB_RULE_CONTINUE;
+ auth_passdb->result_success = AUTH_DB_RULE_CONTINUE;
for (dest = passdbs; *dest != NULL; dest = &(*dest)->next) ;
*dest = auth_passdb;
auth_userdb = p_new(auth->pool, struct auth_userdb, 1);
auth_userdb->set = set;
+ auth_userdb->skip = auth_userdb_skip_parse(set->skip);
+ auth_userdb->result_success =
+ auth_db_rule_parse(set->result_success);
+ auth_userdb->result_failure =
+ auth_db_rule_parse(set->result_failure);
+ auth_userdb->result_internalfail =
+ auth_db_rule_parse(set->result_internalfail);
for (dest = &auth->userdbs; *dest != NULL; dest = &(*dest)->next) ;
*dest = auth_userdb;
AUTH_PASSDB_SKIP_UNAUTHENTICATED
};
-enum auth_passdb_rule {
- AUTH_PASSDB_RULE_RETURN,
- AUTH_PASSDB_RULE_RETURN_OK,
- AUTH_PASSDB_RULE_RETURN_FAIL,
- AUTH_PASSDB_RULE_CONTINUE,
- AUTH_PASSDB_RULE_CONTINUE_OK,
- AUTH_PASSDB_RULE_CONTINUE_FAIL
+enum auth_userdb_skip {
+ AUTH_USERDB_SKIP_NEVER,
+ AUTH_USERDB_SKIP_FOUND,
+ AUTH_USERDB_SKIP_NOTFOUND
+};
+
+enum auth_db_rule {
+ AUTH_DB_RULE_RETURN,
+ AUTH_DB_RULE_RETURN_OK,
+ AUTH_DB_RULE_RETURN_FAIL,
+ AUTH_DB_RULE_CONTINUE,
+ AUTH_DB_RULE_CONTINUE_OK,
+ AUTH_DB_RULE_CONTINUE_FAIL
};
struct auth_passdb {
struct passdb_module *passdb;
enum auth_passdb_skip skip;
- enum auth_passdb_rule result_success;
- enum auth_passdb_rule result_failure;
- enum auth_passdb_rule result_internalfail;
+ enum auth_db_rule result_success;
+ enum auth_db_rule result_failure;
+ enum auth_db_rule result_internalfail;
};
struct auth_userdb {
const struct auth_userdb_settings *set;
struct userdb_module *userdb;
+
+ enum auth_userdb_skip skip;
+ enum auth_db_rule result_success;
+ enum auth_db_rule result_failure;
+ enum auth_db_rule result_internalfail;
};
struct auth {
if (*args != '\0') {
auth_fields_import(request->userdb_reply, args, 0);
if (auth_fields_exists(request->userdb_reply, "tempfail"))
- request->userdb_lookup_failed = TRUE;
+ request->userdb_lookup_tempfailed = TRUE;
}
auth_request_userdb_callback(result, request);
{
const char *key, *value, *error;
- auth_request_init_userdb_reply(auth_request);
-
while (db_dict_value_iter_next(iter, &key, &value)) {
if (value != NULL)
auth_request_set_userdb_field(auth_request, key, value);
struct db_ldap_result_iterate_context *ldap_iter;
const char *name, *const *values;
- auth_request_init_userdb_reply(auth_request);
-
ldap_iter = db_ldap_result_iterate_init(conn, ldap_request, res, TRUE);
while (db_ldap_result_iterate_next(ldap_iter, &name, &values)) {
auth_request_set_userdb_field_values(auth_request,
auth_request_set_field(auth_request, "user", pw.pw_name, NULL);
- auth_request_init_userdb_reply(auth_request);
auth_request_set_userdb_field(auth_request, "system_groups_user",
pw.pw_name);
auth_request_set_userdb_field(auth_request, "uid", dec2str(pw.pw_uid));
return;
}
- auth_request_init_userdb_reply(auth_request);
if (pu->uid != (uid_t)-1) {
auth_request_set_userdb_field(auth_request, "uid",
dec2str(pu->uid));
auth_request_set_field(auth_request, "user", pw.pw_name, NULL);
- auth_request_init_userdb_reply(auth_request);
auth_request_set_userdb_field(auth_request, "system_groups_user",
pw.pw_name);
auth_request_set_userdb_field(auth_request, "uid", dec2str(pw.pw_uid));
const char *name, *value;
unsigned int i, fields_count;
- auth_request_init_userdb_reply(auth_request);
-
fields_count = sql_result_get_fields_count(result);
for (i = 0; i < fields_count; i++) {
name = sql_result_get_field_name(result, i);
struct static_userdb_module *module =
(struct static_userdb_module *)_module;
- auth_request_init_userdb_reply(auth_request);
userdb_template_export(module->tmpl, auth_request);
callback(USERDB_RESULT_OK, auth_request);
}
}
}
- auth_request_init_userdb_reply(auth_request);
auth_request_set_userdb_field(auth_request, "uid", dec2str(uid));
auth_request_set_userdb_field(auth_request, "gid", dec2str(gid));
auth_request_set_userdb_field(auth_request, "home", vpw->pw_dir);