auth-request.c revision 258ff7d4f03dd9d29eca3664e4acacdf7f528234
/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
#include "common.h"
#include "ioloop.h"
#include "buffer.h"
#include "hash.h"
#include "hex-binary.h"
#include "str.h"
#include "safe-memset.h"
#include "str-sanitize.h"
#include "strescape.h"
#include "var-expand.h"
#include "auth-cache.h"
#include "auth-request.h"
#include "auth-client-connection.h"
#include "auth-master-connection.h"
#include "passdb.h"
#include "passdb-blocking.h"
#include "userdb-blocking.h"
#include "passdb-cache.h"
#include "password-scheme.h"
#include <stdlib.h>
struct auth_request *
{
struct auth_request *request;
return request;
}
{
struct auth_request *auth_request;
return auth_request;
}
{
if (request->passdb_failure) {
/* password was valid, but some other check failed. */
return;
}
}
{
}
{
}
{
}
{
return;
else
}
struct auth_stream_reply *reply)
{
}
}
}
if (request->local_port != 0) {
}
if (request->remote_port != 0) {
}
if (request->skip_password_check)
if (request->valid_client_cert)
}
{
/* get username from SSL certificate. it overrides
the username given by the auth mechanism. */
}
else
return FALSE;
return TRUE;
}
{
}
{
}
enum passdb_result result)
{
const char *extra_fields;
switch (result) {
case PASSDB_RESULT_OK:
/* can be cached */
break;
/* FIXME: we can't cache this now, or cache lookup would
return success. */
return;
i_unreached();
}
if (passdb_cache == NULL)
return;
return;
if (result < 0) {
/* lookup failed. */
if (result == PASSDB_RESULT_USER_UNKNOWN) {
}
return;
}
/* passdb didn't provide the correct password */
if (result != PASSDB_RESULT_OK ||
return;
/* we can still cache valid password lookups though.
strdup() it so that mech_password doesn't get
cleared too early. */
}
/* save all except the currently given password in cache */
/* cached passwords must have a known scheme */
}
}
}
if (*extra_fields != '\0') {
}
}
result == PASSDB_RESULT_OK);
}
{
if (request->passdb_failure)
return TRUE;
/* master login successful. update user and master_user variables. */
/* skip the passdb lookup, we're authenticated now. */
return TRUE;
}
/* the authentication continues with passdb lookup for the
requested_login_user. */
return FALSE;
}
static bool
struct auth_request *request)
{
}
/* deny passdb. we can get through this step only if the
lookup returned that user doesn't exist in it. internal
errors are fatal here. */
if (*result != PASSDB_RESULT_INTERNAL_FAILURE) {
"User found from deny passdb");
}
} else if (*result == PASSDB_RESULT_OK) {
/* success */
/* this was a master user lookup. */
return FALSE;
} else {
/* this wasn't the final passdb lookup,
continue to next passdb */
return FALSE;
}
}
} else if (*result == PASSDB_RESULT_PASS_EXPIRED) {
}
"Password expired");
/* try next passdb. */
if (*result == PASSDB_RESULT_INTERNAL_FAILURE) {
/* remember that we have had an internal failure. at
the end return internal failure if we couldn't
successfully login. */
}
return FALSE;
} else if (request->passdb_internal_failure) {
/* last passdb lookup returned internal failure. it may have
had the correct password, so return internal failure
instead of plain failure. */
}
return TRUE;
}
static void
struct auth_request *request)
{
/* try next passdb */
} else {
}
}
struct auth_request *request)
{
if (result != PASSDB_RESULT_INTERNAL_FAILURE)
else {
/* lookup failed. if we're looking here only because the
request was expired in cache, fallback to using cached
expired record. */
"Fallbacking to expired data from cache");
}
}
}
static bool password_has_illegal_chars(const char *password)
{
switch (*password) {
case '\001':
case '\t':
case '\r':
case '\n':
/* these characters have a special meaning in internal
protocols, make sure the password doesn't
accidentally get there unescaped. */
return TRUE;
}
}
return FALSE;
}
const char *password,
{
struct passdb_module *passdb;
enum passdb_result result;
const char *cache_key;
/* no masterdbs, master logins not supported */
"Attempted master login with no master passdbs");
return;
}
if (password_has_illegal_chars(password)) {
"Attempted login with password having illegal chars");
return;
}
else
return;
}
else {
}
}
static void
const unsigned char *credentials,
struct auth_request *request)
{
/* try next passdb */
} else {
result == PASSDB_RESULT_OK) {
"Credentials: %s",
}
}
}
const unsigned char *credentials,
struct auth_request *request)
{
const char *cache_cred, *cache_scheme;
if (result != PASSDB_RESULT_INTERNAL_FAILURE)
else {
/* lookup failed. if we're looking here only because the
request was expired in cache, fallback to using cached
expired record. */
"Fallbacking to expired data from cache");
}
if (result == PASSDB_RESULT_OK) {
&credentials, &size))
}
}
request);
}
const char *scheme,
{
const unsigned char *credentials;
enum passdb_result result;
if (result == PASSDB_RESULT_OK &&
&credentials, &size))
return;
}
}
/* this passdb doesn't support credentials */
} else {
}
}
{
const char *cache_key, *new_credentials;
callback);
} else {
/* this passdb doesn't support credentials update */
}
}
enum userdb_result result)
{
const char *str;
return;
/* last_success has no meaning with userdb */
}
const char *key,
struct auth_stream_reply **reply_r,
enum userdb_result *result_r,
bool use_expired)
{
const char *value;
struct auth_cache_node *node;
bool expired;
&expired);
return FALSE;
if (*value == '\0') {
/* negative cache entry */
return TRUE;
}
return TRUE;
}
struct auth_request *request)
{
/* try next userdb. */
if (result == USERDB_RESULT_INTERNAL_FAILURE)
return;
}
/* one of the userdb lookups failed. the user might have been
in there, so this is an internal failure */
} else if (result == USERDB_RESULT_USER_UNKNOWN &&
request->client_pid != 0) {
/* this was an actual login attempt, the user should
have been found. */
"user not found from userdb");
}
if (result != USERDB_RESULT_INTERNAL_FAILURE)
/* lookup failed. if we're looking here only because the
request was expired in cache, fallback to using cached
expired record. */
struct auth_stream_reply *reply;
"Fallbacking to expired data from cache");
}
}
}
{
const char *cache_key;
/* (for now) auth_cache is shared between passdb and userdb */
struct auth_stream_reply *reply;
enum userdb_result result;
return;
}
}
else
}
static char *
const char **error_r)
{
unsigned char *p;
char *user;
} else {
}
for (p = (unsigned char *)user; *p != '\0'; p++) {
"Username contains disallowed character: "
"0x%02x", *p);
return NULL;
}
}
/* 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 struct var_expand_table *table;
char *old_username;
}
return user;
}
{
const char *p, *login_username = NULL;
!request->userdb_lookup) {
/* check if the username contains a master user */
if (p != NULL) {
/* it does, set it. */
/* username is the master user */
username = p + 1;
}
}
/* the username may change later, but we need to use this
username when verifying at least DIGEST-MD5 password. */
}
if (request->cert_username) {
/* cert_username overrides the username given by
authentication mechanism. */
return TRUE;
}
if (*username == '\0') {
/* Some PAM plugins go nuts with empty usernames */
*error_r = "Empty username";
return FALSE;
}
return FALSE;
}
/* similar to original_username, but after translations */
}
if (login_username != NULL) {
error_r))
return FALSE;
}
return TRUE;
}
const char *username,
const char **error_r)
{
/* The usernames are the same, we don't really wish to log
in as someone else */
return TRUE;
}
/* lookup request->user from masterdb first */
}
const char *networks)
{
const char *const *net;
unsigned int bits;
/* IP not known */
"allow_nets check failed: Remote IP not known");
return;
}
"allow_nets: Matching for network %s", *net);
"allow_nets: Invalid network '%s'", *net);
}
break;
}
}
if (!found) {
"allow_nets check failed: IP not in allowed networks");
}
}
static void
const char *default_scheme, bool noscheme)
{
"Multiple password values not supported");
return;
}
/* if the password starts with '{' it most likely contains
also '}'. check it anyway to make sure, because we
assert-crash later if it doesn't exist. this could happen
if plaintext passwords are used. */
else {
}
}
{
/* user can't actually login - don't keep this
reply for master */
/* we're proxying authentication for this user. send
password back if using plaintext authentication. */
/* like "proxy", but log in normally if we're proxying to
ourself */
}
}
const char *default_scheme)
{
const char *p;
return;
}
return;
}
/* update username */
/* preserve the current @domain */
if (p == NULL) {
/* add the domain */
} else {
/* replace the existing domain */
}
}
/* remember the original username for cache */
}
"username changed %s -> %s",
}
/* don't delay replying to client of the failure */
/* NULL password - anything goes */
(void)password_get_scheme(&password);
if (*password != '\0') {
"nopassword set but password is "
"non-empty");
return;
}
}
/* for prefetch userdb */
} else {
/* these fields are returned to client */
return;
}
if (passdb_cache != NULL &&
/* we'll need to get this field stored into cache */
}
}
}
const char *const *fields,
const char *default_scheme)
{
if (**fields == '\0')
continue;
value = "";
} else {
value++;
}
}
}
{
}
static void
{
const char *str;
/* replace the username in userdb_reply if it changed */
return;
/* reset the reply and add the new username */
/* add the rest */
}
const char *path_template)
{
} else {
}
}
{
return;
}
return;
}
return;
return;
return;
}
}
const char *name,
const char *const *values)
{
return;
/* there can be only one. use the first one. */
/* convert gids to comma separated list */
return;
}
}
} else {
/* add only one */
}
}
{
}
/* broken setup */
return FALSE;
}
return FALSE;
return FALSE;
}
{
return;
if (!success) {
/* drop all proxy fields */
} else if (!request->proxy_maybe) {
/* proxying */
return;
} else if (!auth_request_proxy_is_self(request)) {
/* proxy destination isn't ourself - proxy */
return;
} else {
/* proxying to ourself - log in without proxying by dropping
all the proxying fields. */
}
}
const char *plain_password,
const char *crypted_password,
{
const unsigned char *raw_password;
const char *user;
int ret;
if (request->skip_password_check) {
/* currently this can happen only with master logins */
return 1;
}
/* this is a deny database, we don't care about the password */
return 0;
}
if (request->no_password) {
return 1;
}
if (ret <= 0) {
if (ret < 0) {
"Invalid password format for scheme %s",
scheme);
} else {
"Unknown scheme %s", scheme);
}
return -1;
}
/* If original_username is set, use it. It may be important for some
password schemes (eg. digest-md5). Otherwise the username is used
only for logging purposes. */
if (ret == 0) {
"Password mismatch");
"%s(%s) != '%s'", scheme,
}
}
return ret;
}
static const char *
escape_none(const char *string,
{
return string;
}
const char *
auth_request_str_escape(const char *string,
{
return str_escape(string);
}
const struct var_expand_table *
{
static struct var_expand_table static_tab[] = {
{ 'u', NULL },
{ 'n', NULL },
{ 'd', NULL },
{ 's', NULL },
{ 'h', NULL },
{ 'l', NULL },
{ 'r', NULL },
{ 'p', NULL },
{ 'w', NULL },
{ '!', NULL },
{ 'm', NULL },
{ 'c', NULL },
{ 'a', NULL },
{ 'b', NULL },
{ 'k', NULL },
{ '\0', NULL }
};
struct var_expand_table *tab;
if (escape_func == NULL)
/* tab[4] = we have no home dir */
}
if (auth_request->userdb_lookup) {
} else {
}
return tab;
}
static const char * ATTR_FORMAT(3, 0)
{
#define MAX_LOG_USERNAME_LEN 64
const char *ip;
else {
}
}
}
const char *subsystem,
const char *format, ...)
{
return;
T_BEGIN {
} T_END;
}
const char *subsystem,
const char *format, ...)
{
return;
T_BEGIN {
} T_END;
}
const char *subsystem,
const char *format, ...)
{
T_BEGIN {
} T_END;
}