Mercurial > dovecot > core-2.2
view src/auth/passdb-vpopmail.c @ 20419:0dc214cf2e30
auth-policy: Add policy implementation
author | Aki Tuomi <aki.tuomi@dovecot.fi> |
---|---|
date | Fri, 03 Jun 2016 20:21:42 +0300 |
parents | 2fb8d127acf4 |
children | 2e2563132d5f |
line wrap: on
line source
/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */ /* Thanks to Courier-IMAP for showing how the vpopmail API should be used */ #include "auth-common.h" #include "passdb.h" #ifdef PASSDB_VPOPMAIL #include "safe-memset.h" #include "password-scheme.h" #include "auth-cache.h" #include "userdb-vpopmail.h" #define VPOPMAIL_DEFAULT_PASS_SCHEME "CRYPT" /* pw_flags was added in vpopmail 5.4, olders use pw_gid field */ #ifndef VQPASSWD_HAS_PW_FLAGS # define pw_flags pw_gid #endif struct vpopmail_passdb_module { struct passdb_module module; struct ip_addr webmail_ip; }; static bool vpopmail_is_disabled(struct auth_request *request, const struct vqpasswd *vpw) { struct passdb_module *_module = request->passdb->passdb; struct vpopmail_passdb_module *module = (struct vpopmail_passdb_module *)_module; if (strcasecmp(request->service, "IMAP") == 0) { if ((vpw->pw_flags & NO_IMAP) != 0) { /* IMAP from webmail IP may still be allowed */ if (!net_ip_compare(&module->webmail_ip, &request->remote_ip)) return TRUE; } if ((vpw->pw_flags & NO_WEBMAIL) != 0) { if (net_ip_compare(&module->webmail_ip, &request->remote_ip)) return TRUE; } } if ((vpw->pw_flags & NO_POP) != 0 && strcasecmp(request->service, "POP3") == 0) return TRUE; return FALSE; } static char * vpopmail_password_lookup(struct auth_request *auth_request, bool *cleartext, enum passdb_result *result_r) { char vpop_user[VPOPMAIL_LIMIT], vpop_domain[VPOPMAIL_LIMIT]; struct vqpasswd *vpw; char *password; vpw = vpopmail_lookup_vqp(auth_request, vpop_user, vpop_domain); if (vpw == NULL) { *result_r = PASSDB_RESULT_USER_UNKNOWN; return NULL; } if (vpopmail_is_disabled(auth_request, vpw)) { auth_request_log_info(auth_request, AUTH_SUBSYS_DB, "%s disabled in vpopmail for this user", auth_request->service); password = NULL; *result_r = PASSDB_RESULT_USER_DISABLED; } else { if (vpw->pw_clear_passwd != NULL && *vpw->pw_clear_passwd != '\0') { password = t_strdup_noconst(vpw->pw_clear_passwd); *cleartext = TRUE; } else if (!*cleartext) password = t_strdup_noconst(vpw->pw_passwd); else password = NULL; *result_r = password != NULL ? PASSDB_RESULT_OK : PASSDB_RESULT_SCHEME_NOT_AVAILABLE; } safe_memset(vpw->pw_passwd, 0, strlen(vpw->pw_passwd)); if (vpw->pw_clear_passwd != NULL) { safe_memset(vpw->pw_clear_passwd, 0, strlen(vpw->pw_clear_passwd)); } return password; } static void vpopmail_lookup_credentials(struct auth_request *request, lookup_credentials_callback_t *callback) { enum passdb_result result; char *password; bool cleartext = TRUE; password = vpopmail_password_lookup(request, &cleartext, &result); if (password == NULL) { callback(result, NULL, 0, request); return; } passdb_handle_credentials(PASSDB_RESULT_OK, password, "CLEARTEXT", callback, request); safe_memset(password, 0, strlen(password)); } static void vpopmail_verify_plain(struct auth_request *request, const char *password, verify_plain_callback_t *callback) { enum passdb_result result; const char *scheme, *tmp_pass; char *crypted_pass; bool cleartext = FALSE; int ret; crypted_pass = vpopmail_password_lookup(request, &cleartext, &result); if (crypted_pass == NULL) { callback(result, request); return; } tmp_pass = crypted_pass; if (cleartext) scheme = "CLEARTEXT"; else { scheme = password_get_scheme(&tmp_pass); if (scheme == NULL) scheme = request->passdb->passdb->default_pass_scheme; } ret = auth_request_password_verify(request, password, tmp_pass, scheme, AUTH_SUBSYS_DB); safe_memset(crypted_pass, 0, strlen(crypted_pass)); if (ret <= 0) { callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); return; } #ifdef POP_AUTH_OPEN_RELAY if (strcasecmp(request->service, "POP3") == 0 || strcasecmp(request->service, "IMAP") == 0) { const char *host = net_ip2addr(&request->remote_ip); /* vpopmail 5.4 does not understand IPv6 */ if (host[0] != '\0' && IPADDR_IS_V4(&request->remote_ip)) { /* use putenv() directly rather than env_put() which would leak memory every time we got here. use a static buffer for putenv() as SUSv2 requirements would otherwise corrupt our environment later. */ static char ip_env[256]; i_snprintf(ip_env, sizeof(ip_env), "TCPREMOTEIP=%s", host); putenv(ip_env); open_smtp_relay(); } } #endif callback(PASSDB_RESULT_OK, request); } static struct passdb_module * vpopmail_preinit(pool_t pool, const char *args) { static bool vauth_load_initialized = FALSE; struct vpopmail_passdb_module *module; const char *const *tmp; module = p_new(pool, struct vpopmail_passdb_module, 1); module->module.default_pass_scheme = VPOPMAIL_DEFAULT_PASS_SCHEME; module->module.blocking = TRUE; tmp = t_strsplit_spaces(args, " "); for (; *tmp != NULL; tmp++) { if (strncmp(*tmp, "cache_key=", 10) == 0) { module->module.default_cache_key = auth_cache_parse_key(pool, *tmp + 10); } else if (strncmp(*tmp, "webmail=", 8) == 0) { if (net_addr2ip(*tmp + 8, &module->webmail_ip) < 0) i_fatal("vpopmail: Invalid webmail IP address"); } else if (strcmp(*tmp, "blocking=no") == 0) { module->module.blocking = FALSE; } else { i_fatal("passdb vpopmail: Unknown setting: %s", *tmp); } } if (!vauth_load_initialized) { vauth_load_initialized = TRUE; if (vauth_open(0) != 0) i_fatal("vpopmail: vauth_open() failed"); } return &module->module; } static void vpopmail_deinit(struct passdb_module *module ATTR_UNUSED) { vclose(); } struct passdb_module_interface passdb_vpopmail = { "vpopmail", vpopmail_preinit, NULL, vpopmail_deinit, vpopmail_verify_plain, vpopmail_lookup_credentials, NULL }; #else struct passdb_module_interface passdb_vpopmail = { .name = "vpopmail" }; #endif