auth-request.c revision d481a0f92e3673a345a6c3d61a1f74924f80bd44
/* Copyright (C) 2002-2005 Timo Sirainen */
#include "common.h"
#include "ioloop.h"
#include "buffer.h"
#include "hash.h"
#include "str.h"
#include "safe-memset.h"
#include "str-sanitize.h"
#include "strescape.h"
#include "var-expand.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
}
{
}
}
}
}
{
/* 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 != NULL) {
}
if (request->no_failure_delay) {
}
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");
}
}
}
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;
}
else
return;
}
else {
}
}
static void
const char *password,
struct auth_request *request)
{
/* try next passdb */
} else {
result == PASSDB_RESULT_OK) {
"Credentials: %s", password);
}
}
}
const char *password,
struct auth_request *request)
{
const char *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");
scheme);
}
}
request);
}
{
enum passdb_result result;
scheme);
return;
}
}
} else {
/* this passdb doesn't support credentials */
}
}
const char *data,
{
const char *cache_key, *new_credentials;
callback);
} else {
/* this passdb doesn't support credentials update */
}
}
struct auth_request *request)
{
/* try next userdb. */
return;
}
/* this was actual login attempt */
"user not found from userdb");
}
}
{
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;
t_push();
t_pop();
}
return user;
}
{
const char *p, *login_username = NULL;
/* 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;
}
/* check if the username contains a master user */
if (p != NULL) {
/* it does, set it. */
/* username is the master user */
username = p + 1;
}
}
if (*username == '\0') {
/* Some PAM plugins go nuts with empty usernames */
*error_r = "Empty username";
return FALSE;
}
return FALSE;
}
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 *p;
if (p == NULL) {
/* full IP address must match */
} else {
/* get the network mask */
}
return -1;
/* one is IPv6 and one is IPv4 */
return 0;
}
/* check first the full 32bit ints */
return 0;
}
/* check the last full bytes */
return 0;
}
/* check the last bits, they're reversed in bytes */
return 0;
}
return 1;
}
const char *networks)
{
const char *const *net;
/* IP not known */
"allow_nets check failed: Remote IP not known");
return;
}
t_push();
"allow_nets: Matching for network %s", *net);
case 1:
break;
case -1:
"allow_nets: Invalid network '%s'", *net);
break;
default:
break;
}
}
t_pop();
if (!found) {
"allow_nets check failed: IP not in allowed networks");
}
}
const char *default_scheme)
{
"Multiple password values not supported");
return;
}
if (*value == '{') {
} else {
}
return;
}
/* update username to be exactly as it's in database */
"username changed %s -> %s",
}
return;
}
/* don't delay replying to client of the failure */
return;
}
/* NULL password - anything goes */
return;
}
return;
}
/* 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. */
}
}
const char *plain_password,
const char *crypted_password,
{
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 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) {
"Unknown password scheme %s", scheme);
} else 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 },
{ '\0', NULL }
};
struct var_expand_table *tab;
if (escape_func == NULL)
/* tab[4] = we have no home dir */
}
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_push();
t_pop();
}
const char *subsystem,
const char *format, ...)
{
return;
t_push();
t_pop();
}
const char *subsystem,
const char *format, ...)
{
t_push();
t_pop();
}