Mercurial > dovecot > original-hg > dovecot-1.2
changeset 4078:265655f270df HEAD
Added "allow_nets" extra field. If set, the user can log in only from
within the given networks (hope the code is correct...)
author | Timo Sirainen <timo.sirainen@movial.fi> |
---|---|
date | Mon, 27 Feb 2006 20:46:29 +0200 |
parents | 73573b9ecb00 |
children | b033db13c2e0 |
files | src/auth/auth-request.c src/auth/auth-request.h |
diffstat | 2 files changed, 105 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- a/src/auth/auth-request.c Mon Feb 27 18:30:39 2006 +0200 +++ b/src/auth/auth-request.c Mon Feb 27 20:46:29 2006 +0200 @@ -17,6 +17,8 @@ #include "passdb-cache.h" #include "password-scheme.h" +#include <stdlib.h> + struct auth_request * auth_request_new(struct auth *auth, struct mech_module *mech, mech_callback_t *callback, void *context) @@ -63,6 +65,12 @@ { i_assert(request->state == AUTH_REQUEST_STATE_MECH_CONTINUE); + if (request->passdb_failure) { + /* password was valid, but some other check failed. */ + auth_request_fail(request); + return; + } + request->state = AUTH_REQUEST_STATE_FINISHED; request->successful = TRUE; request->callback(request, AUTH_CLIENT_RESULT_SUCCESS, @@ -582,6 +590,97 @@ return request->requested_login_user != NULL; } +static int is_ip_in_network(const char *network, const struct ip_addr *ip) +{ + const uint32_t *ip1, *ip2; + struct ip_addr net_ip; + const char *p; + unsigned int max_bits, bits, pos, i; + uint32_t mask; + + max_bits = IPADDR_IS_V4(ip) ? 32 : 128; + p = strchr(network, '/'); + if (p == NULL) { + /* full IP address must match */ + bits = max_bits; + } else { + /* get the network mask */ + network = t_strdup_until(network, p); + bits = strtoul(p+1, NULL, 10); + if (bits > max_bits) + bits = max_bits; + } + + if (net_addr2ip(network, &net_ip) < 0) + return -1; + + if (IPADDR_IS_V4(ip) && !IPADDR_IS_V4(&net_ip)) { + /* one is IPv6 and one is IPv4 */ + return 0; + } + i_assert(IPADDR_IS_V6(ip) == IPADDR_IS_V6(&net_ip)); + + ip1 = (const uint32_t *)&ip->ip; + ip2 = (const uint32_t *)&net_ip.ip; + + /* check first the full 32bit ints */ + for (pos = 0, i = 0; pos + 32 <= bits; pos += 32, i++) { + if (ip1[i] != ip2[i]) + return 0; + } + + /* check the last full bytes */ + for (mask = 0xff; pos + 8 <= bits; pos += 8, mask <<= 8) { + if ((ip1[i] & mask) != (ip2[i] & mask)) + return 0; + } + + /* check the last bits, they're reversed in bytes */ + bits -= pos; + for (mask = 0x80 << (pos % 32); bits > 0; bits--, mask >>= 1) { + if ((ip1[i] & mask) != (ip2[i] & mask)) + return 0; + } + return 1; +} + +static void auth_request_validate_networks(struct auth_request *request, + const char *networks) +{ + const char *const *net; + bool found = FALSE; + + if (request->remote_ip.family == 0) { + /* IP not known */ + auth_request_log_info(request, "passdb", + "allow_nets check failed: Remote IP not known"); + request->passdb_failure = TRUE; + return; + } + + t_push(); + for (net = t_strsplit_spaces(networks, ", "); *net != NULL; net++) { + switch (is_ip_in_network(*net, &request->remote_ip)) { + case 1: + found = TRUE; + break; + case -1: + auth_request_log_info(request, "passdb", + "allow_nets: Invalid network '%s'", *net); + break; + default: + break; + } + } + t_pop(); + + if (!found) { + auth_request_log_info(request, "passdb", + "allow_nets check failed: IP not in allowed networks"); + } + request->passdb_failure = !found; +} + void auth_request_set_field(struct auth_request *request, const char *name, const char *value, const char *default_scheme) @@ -633,6 +732,11 @@ return; } + if (strcmp(name, "allow_nets") == 0) { + auth_request_validate_networks(request, value); + return; + } + if (strcmp(name, "nologin") == 0) { /* user can't actually login - don't keep this reply for master */
--- a/src/auth/auth-request.h Mon Feb 27 18:30:39 2006 +0200 +++ b/src/auth/auth-request.h Mon Feb 27 20:46:29 2006 +0200 @@ -64,6 +64,7 @@ struct auth_master_connection *master; unsigned int successful:1; + unsigned int passdb_failure:1; unsigned int internal_failure:1; unsigned int passdb_internal_failure:1; unsigned int delayed_failure:1;