static void
auth_request_handler_reply_success_finish(struct auth_request *request)
{
        struct auth_request_handler *handler = request->handler;
	string_t *str = t_str_new(128);

	if (request->last_penalty != 0 && auth_penalty != NULL) {
		/* reset penalty */
		auth_penalty_update(auth_penalty, request, 0);
	}

	/* sanitize these fields, since the login code currently assumes they
	   are exactly in this format. */
	auth_fields_booleanize(request->extra_fields, "nologin");
	auth_fields_booleanize(request->extra_fields, "proxy");

	str_printfa(str, "OK\t%u\tuser="******"nologin") ||
	    auth_fields_exists(request->extra_fields, "proxy")) {
		/* this request doesn't have to wait for master
		   process to pick it up. delete it */
		auth_request_handler_remove(handler, request);
	}
	handler->callback(str_c(str), handler->context);
}
static void
auth_str_append_extra_fields(struct auth_request *request, string_t *dest)
{
	if (!auth_fields_is_empty(request->extra_fields)) {
		str_append_c(dest, '\t');
		auth_fields_append(request->extra_fields, dest,
				   AUTH_FIELD_FLAG_HIDDEN, 0);
	}

	if (request->original_username != NULL &&
	    null_strcmp(request->original_username, request->user) != 0) {
		auth_str_add_keyvalue(dest, "original_user",
				      request->original_username);
	}
	if (request->master_user != NULL)
		auth_str_add_keyvalue(dest, "auth_user", request->master_user);

	if (!request->auth_only &&
	    auth_fields_exists(request->extra_fields, "proxy")) {
		/* we're proxying */
		if (!auth_fields_exists(request->extra_fields, "pass") &&
		    request->mech_password != NULL) {
			/* send back the password that was sent by user
			   (not the password in passdb). */
			auth_str_add_keyvalue(dest, "pass",
					      request->mech_password);
		}
		if (request->master_user != NULL &&
		    !auth_fields_exists(request->extra_fields, "master")) {
			/* the master username needs to be forwarded */
			auth_str_add_keyvalue(dest, "master",
					      request->master_user);
		}
	}
}
Beispiel #3
0
static enum passdb_result
passdb_dict_lookup_key(struct auth_request *auth_request,
                       struct dict_passdb_module *module)
{
    struct db_dict_value_iter *iter;
    int ret;

    ret = db_dict_value_iter_init(module->conn, auth_request,
    &module->conn->set.passdb_fields,
    &module->conn->set.parsed_passdb_objects,
    &iter);
    if (ret < 0)
        return PASSDB_RESULT_INTERNAL_FAILURE;
    else if (ret == 0) {
        auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB);
        return PASSDB_RESULT_USER_UNKNOWN;
    } else {
        if (dict_query_save_results(auth_request, module->conn, iter) < 0)
            return PASSDB_RESULT_INTERNAL_FAILURE;

        if (auth_request->passdb_password == NULL &&
        !auth_fields_exists(auth_request->extra_fields, "nopassword")) {
            auth_request_log_info(auth_request, AUTH_SUBSYS_DB,
            "No password returned (and no nopassword)");
            return PASSDB_RESULT_PASSWORD_MISMATCH;
        } else {
            return PASSDB_RESULT_OK;
        }
    }
}
Beispiel #4
0
static enum passdb_result
passdb_dict_lookup_key(struct auth_request *auth_request,
		       struct dict_passdb_module *module, const char *key)
{
	const char *value;
	int ret;

	auth_request_log_debug(auth_request, "dict", "lookup %s", key);
	ret = dict_lookup(module->conn->dict, pool_datastack_create(),
			  key, &value);
	if (ret < 0) {
		auth_request_log_error(auth_request, "dict", "Lookup failed");
		return PASSDB_RESULT_INTERNAL_FAILURE;
	} else if (ret == 0) {
		auth_request_log_unknown_user(auth_request, "dict");
		return PASSDB_RESULT_USER_UNKNOWN;
	} else {
		auth_request_log_debug(auth_request, "dict",
				       "result: %s", value);
		if (dict_query_save_results(auth_request, module->conn, value) < 0)
			return PASSDB_RESULT_INTERNAL_FAILURE;

		if (auth_request->passdb_password == NULL &&
		    !auth_fields_exists(auth_request->extra_fields, "nopassword")) {
			auth_request_log_info(auth_request, "dict",
				"No password returned (and no nopassword)");
			return PASSDB_RESULT_PASSWORD_MISMATCH;
		} else {
			return PASSDB_RESULT_OK;
		}
	}
}
Beispiel #5
0
static enum passdb_result
static_save_fields(struct auth_request *request, const char **password_r)
{
	struct static_passdb_module *module =
		(struct static_passdb_module *)request->passdb->passdb;
        const struct var_expand_table *table;
	string_t *str = t_str_new(128);

	auth_request_log_debug(request, AUTH_SUBSYS_DB, "lookup");
	passdb_template_export(module->tmpl, request);

	if (module->static_password_tmpl != NULL) {
		table = auth_request_get_var_expand_table(request, NULL);
		var_expand(str, module->static_password_tmpl, table);
		*password_r = str_c(str);
	} else if (auth_fields_exists(request->extra_fields, "nopassword")) {
		*password_r = "";
	} else {
		auth_request_log_info(request, AUTH_SUBSYS_DB,
			"No password returned (and no nopassword)");
		*password_r = NULL;
		return PASSDB_RESULT_PASSWORD_MISMATCH;
	}
	return PASSDB_RESULT_OK;
}
Beispiel #6
0
static void verify_plain_callback(enum passdb_result result,
				  struct auth_request *request)
{
	struct auth_worker_client *client = request->context;
	string_t *str;

	if (request->failed && result == PASSDB_RESULT_OK)
		result = PASSDB_RESULT_PASSWORD_MISMATCH;

	str = t_str_new(128);
	str_printfa(str, "%u\t", request->id);

	if (result == PASSDB_RESULT_OK)
		if (auth_fields_exists(request->extra_fields, "noauthenticate"))
			str_append(str, "NEXT");
		else
			str_append(str, "OK");
	else
		str_printfa(str, "FAIL\t%d", result);
	if (result != PASSDB_RESULT_INTERNAL_FAILURE) {
		str_append_c(str, '\t');
		str_append_tabescaped(str, request->user);
		str_append_c(str, '\t');
		if (request->passdb_password != NULL)
			str_append_tabescaped(str, request->passdb_password);
		reply_append_extra_fields(str, request);
	}
	str_append_c(str, '\n');
	auth_worker_send_reply(client, request, str);

	auth_request_unref(&request);
	auth_worker_client_check_throttle(client);
	auth_worker_client_unref(&client);
}
Beispiel #7
0
static void
ldap_lookup_finish(struct auth_request *auth_request,
		   struct passdb_ldap_request *ldap_request,
		   LDAPMessage *res)
{
	enum passdb_result passdb_result;
	const char *password = NULL, *scheme;
	int ret;

	if (res == NULL) {
		passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
	} else if (ldap_request->entries == 0) {
		passdb_result = PASSDB_RESULT_USER_UNKNOWN;
		auth_request_log_info(auth_request, "ldap",
				      "unknown user");
	} else if (ldap_request->entries > 1) {
		auth_request_log_error(auth_request, "ldap",
			"pass_filter matched multiple objects, aborting");
		passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
	} else if (auth_request->passdb_password == NULL &&
		   !auth_fields_exists(auth_request->extra_fields, "nopassword")) {
		auth_request_log_info(auth_request, "ldap",
			"No password returned (and no nopassword)");
		passdb_result = PASSDB_RESULT_PASSWORD_MISMATCH;
	} else {
		/* passdb_password may change on the way,
		   so we'll need to strdup. */
		password = t_strdup(auth_request->passdb_password);
		passdb_result = PASSDB_RESULT_OK;
	}

	scheme = password_get_scheme(&password);
	/* auth_request_set_field() sets scheme */
	i_assert(password == NULL || scheme != NULL);

	if (auth_request->credentials_scheme != NULL) {
		passdb_handle_credentials(passdb_result, password, scheme,
			ldap_request->callback.lookup_credentials,
			auth_request);
	} else {
		if (password != NULL) {
			ret = auth_request_password_verify(auth_request,
					auth_request->mech_password,
					password, scheme, "ldap");
			passdb_result = ret > 0 ? PASSDB_RESULT_OK :
				PASSDB_RESULT_PASSWORD_MISMATCH;
		}

		ldap_request->callback.verify_plain(passdb_result,
						    auth_request);
	}
}
Beispiel #8
0
static enum passdb_result
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;

	*password_r = NULL;
	*scheme_r = NULL;

	auth_request_log_debug(request, AUTH_SUBSYS_DB, "lookup");
	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) {
		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 {
		auth_request_log_info(request, AUTH_SUBSYS_DB,
			"No password returned (and no nopassword)");
		return PASSDB_RESULT_PASSWORD_MISMATCH;
	}

	*scheme_r = password_get_scheme(password_r);

	if (*scheme_r == NULL)
		*scheme_r = STATIC_PASS_SCHEME;

	auth_request_set_field(request, "password",
			       *password_r, *scheme_r);

	return PASSDB_RESULT_OK;
}
static void
auth_request_handler_reply_failure_finish(struct auth_request *request)
{
	string_t *str = t_str_new(128);

	str_printfa(str, "FAIL\t%u", request->id);
	if (request->user != NULL)
		auth_str_add_keyvalue(str, "user", request->user);
	else if (request->original_username != NULL) {
		auth_str_add_keyvalue(str, "user", 
				      request->original_username);
	}

	if (request->internal_failure)
		str_append(str, "\ttemp");
	else if (request->master_user != NULL) {
		/* authentication succeeded, but we can't log in
		   as the wanted user */
		str_append(str, "\tauthz");
	}
	if (auth_fields_exists(request->extra_fields, "nodelay")) {
		/* this is normally a hidden field, need to add it explicitly */
		str_append(str, "\tnodelay");
	}
	auth_str_append_extra_fields(request, str);

	switch (request->passdb_result) {
	case PASSDB_RESULT_INTERNAL_FAILURE:
	case PASSDB_RESULT_SCHEME_NOT_AVAILABLE:
	case PASSDB_RESULT_USER_UNKNOWN:
	case PASSDB_RESULT_PASSWORD_MISMATCH:
	case PASSDB_RESULT_OK:
		break;
	case PASSDB_RESULT_USER_DISABLED:
		str_append(str, "\tuser_disabled");
		break;
	case PASSDB_RESULT_PASS_EXPIRED:
		str_append(str, "\tpass_expired");
		break;
	}

	auth_request_handle_failure(request, str_c(str));
}
static void
auth_request_handle_failure(struct auth_request *request, const char *reply)
{
        struct auth_request_handler *handler = request->handler;

	if (request->in_delayed_failure_queue) {
		/* we came here from flush_failures() */
		handler->callback(reply, handler->context);
		return;
	}

	/* remove the request from requests-list */
	auth_request_ref(request);
	auth_request_handler_remove(handler, request);

	if (auth_fields_exists(request->extra_fields, "nodelay")) {
		/* passdb specifically requested not to delay the reply. */
		handler->callback(reply, handler->context);
		auth_request_unref(&request);
		return;
	}

	/* failure. don't announce it immediately to avoid
	   a) timing attacks, b) flooding */
	request->in_delayed_failure_queue = TRUE;
	handler->refcount++;

	if (auth_penalty != NULL) {
		auth_penalty_update(auth_penalty, request,
				    request->last_penalty + 1);
	}

	auth_request_refresh_last_access(request);
	aqueue_append(auth_failures, &request);
	if (to_auth_failures == NULL) {
		to_auth_failures =
			timeout_add_short(AUTH_FAILURE_DELAY_CHECK_MSECS,
					  auth_failure_timeout, (void *)NULL);
	}
}
Beispiel #11
0
static bool user_callback(const char *reply, void *context)
{
	struct auth_request *request = context;
	enum userdb_result result;
	const char *username, *args;

	if (str_begins(reply, "FAIL\t")) {
		result = USERDB_RESULT_INTERNAL_FAILURE;
		args = reply + 5;
	} else if (str_begins(reply, "NOTFOUND\t")) {
		result = USERDB_RESULT_USER_UNKNOWN;
		args = reply + 9;
	} else if (str_begins(reply, "OK\t")) {
		result = USERDB_RESULT_OK;
		username = reply + 3;
		args = strchr(username, '\t');
		if (args == NULL)
			args = "";
		else
			username = t_strdup_until(username, args++);
		if (username[0] != '\0' && strcmp(request->user, username) != 0)
			request->user = p_strdup(request->pool, username);
	} else {
		result = USERDB_RESULT_INTERNAL_FAILURE;
		i_error("BUG: auth-worker sent invalid user reply");
		args = "";
	}

	if (*args != '\0') {
		auth_fields_import(request->userdb_reply, args, 0);
		if (auth_fields_exists(request->userdb_reply, "tempfail"))
			request->userdb_lookup_tempfailed = TRUE;
	}

        auth_request_userdb_callback(result, request);
	auth_request_unref(&request);
	return TRUE;
}
static void auth_str_append_userdb_extra_fields(struct auth_request *request,
						string_t *dest)
{
	str_append_c(dest, '\t');
	auth_fields_append(request->userdb_reply, dest,
			   AUTH_FIELD_FLAG_HIDDEN, 0);

	if (request->master_user != NULL &&
	    !auth_fields_exists(request->userdb_reply, "master_user")) {
		auth_str_add_keyvalue(dest, "master_user",
				      request->master_user);
	}
	if (*request->set->anonymous_username != '\0' &&
	    strcmp(request->user, request->set->anonymous_username) == 0) {
		/* this is an anonymous login, either via ANONYMOUS
		   SASL mechanism or simply logging in as the anonymous
		   user via another mechanism */
		str_append(dest, "\tanonymous");
	}
	/* generate auth_token when master service provided session_pid */
	if (request->request_auth_token &&
	    request->session_pid != (pid_t)-1) {
		const char *auth_token =
			auth_token_get(request->service,
				       dec2str(request->session_pid),
				       request->user,
				       request->session_id);
		auth_str_add_keyvalue(dest, "auth_token", auth_token);
	}
	if (request->master_user != NULL) {
		auth_str_add_keyvalue(dest, "auth_user", request->master_user);
	} else if (request->original_username != NULL &&
		   strcmp(request->original_username, request->user) != 0) {
		auth_str_add_keyvalue(dest, "auth_user",
				      request->original_username);
	}
}
Beispiel #13
0
static void sql_query_callback(struct sql_result *result,
			       struct passdb_sql_request *sql_request)
{
	struct auth_request *auth_request = sql_request->auth_request;
	struct passdb_module *_module = auth_request->passdb->passdb;
	struct sql_passdb_module *module = (struct sql_passdb_module *)_module;
	enum passdb_result passdb_result;
	const char *password, *scheme;
	int ret;

	passdb_result = PASSDB_RESULT_INTERNAL_FAILURE;
	password = NULL;

	ret = sql_result_next_row(result);
	if (ret >= 0)
		db_sql_success(module->conn);
	if (ret < 0) {
		if (!module->conn->default_password_query) {
			auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
					       "Password query failed: %s",
					       sql_result_get_error(result));
		} else {
			auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
				"Password query failed: %s "
				"(using built-in default password_query: %s)",
				sql_result_get_error(result),
				module->conn->set.password_query);
		}
	} else if (ret == 0) {
		auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB);
		passdb_result = PASSDB_RESULT_USER_UNKNOWN;
	} else {
		sql_query_save_results(result, sql_request);

		/* Note that we really want to check if the password field is
		   found. Just checking if password is set isn't enough,
		   because with proxies we might want to return NULL as
		   password. */
		if (sql_result_find_field(result, "password") < 0 &&
		    sql_result_find_field(result, "password_noscheme") < 0) {
			auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
				"Password query must return a field named "
				"'password'");
		} else if (sql_result_next_row(result) > 0) {
			auth_request_log_error(auth_request, AUTH_SUBSYS_DB,
				"Password query returned multiple matches");
		} else if (auth_request->passdb_password == NULL &&
			   !auth_fields_exists(auth_request->extra_fields, "nopassword") &&
			   !auth_fields_exists(auth_request->extra_fields, "noauthenticate")) {
			auth_request_log_info(auth_request, AUTH_SUBSYS_DB,
				"Empty password returned without nopassword");
			passdb_result = PASSDB_RESULT_PASSWORD_MISMATCH;
		} else {
			/* passdb_password may change on the way,
			   so we'll need to strdup. */
			password = t_strdup(auth_request->passdb_password);
			passdb_result = PASSDB_RESULT_OK;
		}
	}

	scheme = password_get_scheme(&password);
	/* auth_request_set_field() sets scheme */
	i_assert(password == NULL || scheme != NULL);

	if (auth_request->credentials_scheme != NULL) {
		passdb_handle_credentials(passdb_result, password, scheme,
			sql_request->callback.lookup_credentials,
			auth_request);
		auth_request_unref(&auth_request);
		return;
	}

	/* verify plain */
	if (password == NULL) {
		sql_request->callback.verify_plain(passdb_result, auth_request);
		auth_request_unref(&auth_request);
		return;
	}

	ret = auth_request_password_verify(auth_request,
					   auth_request->mech_password,
					   password, scheme, AUTH_SUBSYS_DB);

	sql_request->callback.verify_plain(ret > 0 ? PASSDB_RESULT_OK :
					   PASSDB_RESULT_PASSWORD_MISMATCH,
					   auth_request);
	auth_request_unref(&auth_request);
}