auth-request.c revision bd0720cca74a9f7603675b01c17bbea7945c1bc4
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterunsigned int auth_request_state_count[AUTH_REQUEST_STATE_MAX];
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic void get_log_prefix(string_t *str, struct auth_request *auth_request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *subsystem);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_state_count[AUTH_REQUEST_STATE_NEW]++;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->mech_name = mech == NULL ? NULL : mech->mech_name;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstruct auth_request *auth_request_new_dummy(void)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter pool = pool_alloconly_create("auth_request", 1024);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_state_count[AUTH_REQUEST_STATE_NEW]++;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_set_state(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(auth_request_state_count[request->state] > 0);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_init(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstruct auth *auth_request_get_auth(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_success(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* password was valid, but some other check failed. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_handler_reply(request, AUTH_CLIENT_RESULT_SUCCESS,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_fail(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_set_state(request, AUTH_REQUEST_STATE_FINISHED);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_handler_reply(request, AUTH_CLIENT_RESULT_FAILURE,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_internal_failure(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_ref(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_unref(struct auth_request **_request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_export(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "user", request->user);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "service", request->service);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "original_username",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "requested_login_user",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "skip_password_check", "1");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "valid-client-cert", "1");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "no-penalty", "1");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "successful", "1");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(reply, "mech", request->mech_name);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterbool auth_request_import(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->master_user = p_strdup(request->pool, value);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->original_username = p_strdup(request->pool, value);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter else if (strcmp(key, "requested_login_user") == 0)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->requested_login_user = p_strdup(request->pool, value);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* get username from SSL certificate. it overrides
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter the username given by the auth mechanism. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->service = p_strdup(request->pool, value);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter else if (strcmp(key, "skip_password_check") == 0) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->mech_name = p_strdup(request->pool, value);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_initial(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->state == AUTH_REQUEST_STATE_NEW);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_set_state(request, AUTH_REQUEST_STATE_MECH_CONTINUE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->mech->auth_initial(request, request->initial_response,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_continue(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->mech->auth_continue(request, data, data_size);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic void auth_request_save_cache(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter struct passdb_module *passdb = request->passdb->passdb;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter /* can be cached */
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter /* FIXME: we can't cache this now, or cache lookup would
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter return success. */
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter extra_fields = request->extra_fields == NULL ? NULL :
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter auth_stream_reply_export(request->extra_fields);
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter if (passdb_cache == NULL || passdb->cache_key == NULL ||
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter /* lookup failed. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!request->no_password && request->passdb_password == NULL) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* passdb didn't provide the correct password */
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter /* we can still cache valid password lookups though.
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter strdup() it so that mech_password doesn't get
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter cleared too early. */
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter if (!password_generate_encoded(request->mech_password,
c2cc119de8eac712c040b3993f41c967ff2278deStef Walter p_strconcat(request->pool, "{"CACHED_PASSWORD_SCHEME"}",
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter /* save all except the currently given password in cache */
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter /* cached passwords must have a known scheme */
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter if (strchr(request->passdb_password, '\t') != NULL)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter i_panic("%s: Password contains TAB", request->user);
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter if (strchr(request->passdb_password, '\n') != NULL)
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter i_panic("%s: Password contains LF", request->user);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (extra_fields != NULL && *extra_fields != '\0') {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_export(request->extra_cache_fields);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_cache_insert(passdb_cache, request, passdb->cache_key, str_c(str),
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic void auth_request_userdb_reply_update_user(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter const char *str, *p;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter str = t_strdup(auth_stream_reply_export(request->userdb_reply));
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* reset the reply and add the new username */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(request->userdb_reply, NULL, request->user);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* add the rest */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_import(request->userdb_reply, p + 1);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic bool auth_request_master_lookup_finish(struct auth_request *request)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* master login successful. update user and master_user variables. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_log_info(request, "passdb", "Master user logging in as %s",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* skip the passdb lookup, we're authenticated now. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* the authentication continues with passdb lookup for the
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter requested_login_user. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->passdb = auth_request_get_auth(request)->passdbs;
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter for (passdb = request->passdb; passdb != NULL; passdb = passdb->next) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (passdb->passdb->iface.lookup_credentials != NULL)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "No passdbs support skipping password verification - "
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "pass=yes can't be used in master passdb");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterauth_request_handle_passdb_callback(enum passdb_result *result,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* deny passdb. we can get through this step only if the
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter lookup returned that user doesn't exist in it. internal
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter errors are fatal here. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (*result != PASSDB_RESULT_INTERNAL_FAILURE) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "User found from deny passdb");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* success */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* this was a master user lookup. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!auth_request_master_lookup_finish(request))
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* this wasn't the final passdb lookup,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter continue to next passdb */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter } else if (*result == PASSDB_RESULT_PASS_EXPIRED) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_stream_reply_add(request->extra_fields, "reason",
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "Password expired");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* try next passdb. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* remember that we did at least one successful
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter passdb lookup */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter } else if (*result == PASSDB_RESULT_INTERNAL_FAILURE) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* remember that we have had an internal failure. at
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter the end return internal failure if we couldn't
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter successfully login. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* last passdb lookup returned internal failure. it may have
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter had the correct password, so return internal failure
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter instead of plain failure. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterauth_request_verify_plain_callback_finish(enum passdb_result result,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter if (!auth_request_handle_passdb_callback(&result, request)) {
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* try next passdb */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_verify_plain(request, request->mech_password,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request->private_callback.verify_plain(result, request);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_verify_plain_callback(enum passdb_result result,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->state == AUTH_REQUEST_STATE_PASSDB);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_set_state(request, AUTH_REQUEST_STATE_MECH_CONTINUE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* lookup failed. if we're looking here only because the
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter request was expired in cache, fallback to using cached
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter expired record. */
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter const char *cache_key = request->passdb->passdb->cache_key;
fcd8093c58638dc7c4f9cddfc97f273b94ce2eadStef Walter if (passdb_cache_verify_plain(request, cache_key,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter "Fallbacking to expired data from cache");
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter auth_request_verify_plain_callback_finish(result, request);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walterstatic bool password_has_illegal_chars(const char *password)
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter case '\001':
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* these characters have a special meaning in internal
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter protocols, make sure the password doesn't
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter accidentally get there unescaped. */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Waltervoid auth_request_verify_plain(struct auth_request *request,
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE);
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter /* no masterdbs, master logins not supported */
b699c4d7f85a5404be1d1ee9450331aea869b886Stef Walter i_assert(request->requested_login_user != NULL);
const unsigned char *credentials,
const unsigned char *credentials,
request);
request);
const char *scheme,
request);
callback);
const char *str;
const char *key,
bool use_expired)
const char *value;
return FALSE;
return FALSE;
return TRUE;
return TRUE;
const char *cache_key;
request);
const char **error_r)
char *user;
return NULL;
char *old_username;
return user;
if (p != NULL) {
return FALSE;
return FALSE;
return FALSE;
error_r))
return FALSE;
return TRUE;
const char *username,
const char **error_r)
return TRUE;
return FALSE;
return TRUE;
const char *networks)
const char *const *net;
unsigned int bits;
if (!found) {
return value;
return value;
if (p == NULL) {
return NULL;
const char *new_value;
return FALSE;
return TRUE;
const char *default_scheme)
const char *const *fields,
const char *default_scheme)
value++;
const char *path_template)
const char *name,
const char *const *values)
return FALSE;
return FALSE;
return FALSE;
if (!success) {
const char *plain_password,
const char *crypted_password,
const char *subsystem)
const char *working_scheme;
if (!scheme_ok) {
const char *subsystem)
i_unreached();
const char *plain_password,
const char *crypted_password,
const unsigned char *raw_password;
int ret;
if (ret <= 0) {
if (ret < 0) {
scheme);
if (ret == 0) {
} T_END;
return ret;
return string;
const struct var_expand_table *
return tab;
const char *subsystem)
const char *ip;
const char *subsystem,
const char *format, ...)
T_BEGIN {
} T_END;
const char *subsystem,
const char *format, ...)
T_BEGIN {
} T_END;
const char *subsystem,
const char *format, ...)
T_BEGIN {
} T_END;
const char *subsystem,
const char *format, ...)
T_BEGIN {
} T_END;