struct vqpasswd *vpopmail_lookup_vqp(struct auth_request *request, char vpop_user[VPOPMAIL_LIMIT], char vpop_domain[VPOPMAIL_LIMIT]) { struct vqpasswd *vpw; /* vpop_user must be zero-filled or parse_email() leaves an extra character after the user name. we'll fill vpop_domain as well just to be sure... */ memset(vpop_user, '\0', VPOPMAIL_LIMIT); memset(vpop_domain, '\0', VPOPMAIL_LIMIT); if (parse_email(request->user, vpop_user, vpop_domain, VPOPMAIL_LIMIT-1) < 0) { auth_request_log_info(request, "vpopmail", "parse_email() failed"); return NULL; } auth_request_log_debug(request, "vpopmail", "lookup user=%s domain=%s", vpop_user, vpop_domain); vpw = vauth_getpw(vpop_user, vpop_domain); if (vpw == NULL) { auth_request_log_unknown_user(request, "vpopmail"); return NULL; } return vpw; }
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; } } }
static void ldap_bind_lookup_dn_fail(struct auth_request *auth_request, struct passdb_ldap_request *request, LDAPMessage *res) { enum passdb_result passdb_result; if (res == NULL) passdb_result = PASSDB_RESULT_INTERNAL_FAILURE; else if (request->entries == 0) { passdb_result = PASSDB_RESULT_USER_UNKNOWN; auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB); } else { i_assert(request->entries > 1); auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "pass_filter matched multiple objects, aborting"); passdb_result = PASSDB_RESULT_INTERNAL_FAILURE; } if (auth_request->credentials_scheme != NULL) { request->callback.lookup_credentials(passdb_result, NULL, 0, auth_request); } else { request->callback.verify_plain(passdb_result, auth_request); } auth_request_unref(&auth_request); }
static void userdb_dict_lookup(struct auth_request *auth_request, userdb_callback_t *callback) { struct userdb_module *_module = auth_request->userdb->userdb; struct dict_userdb_module *module = (struct dict_userdb_module *)_module; struct db_dict_value_iter *iter; enum userdb_result userdb_result; int ret; if (array_count(&module->conn->set.userdb_fields) == 0 && array_count(&module->conn->set.parsed_userdb_objects) == 0) { auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "No userdb_objects or userdb_fields specified"); callback(USERDB_RESULT_INTERNAL_FAILURE, auth_request); return; } ret = db_dict_value_iter_init(module->conn, auth_request, &module->conn->set.userdb_fields, &module->conn->set.parsed_userdb_objects, &iter); if (ret < 0) userdb_result = USERDB_RESULT_INTERNAL_FAILURE; else if (ret == 0) { auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB); userdb_result = USERDB_RESULT_USER_UNKNOWN; } else { if (dict_query_save_results(auth_request, iter) < 0) userdb_result = USERDB_RESULT_INTERNAL_FAILURE; else userdb_result = USERDB_RESULT_OK; } callback(userdb_result, auth_request); }
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; } } }
static enum passdb_result passwd_lookup(struct auth_request *request, struct passwd *pw_r) { auth_request_log_debug(request, AUTH_SUBSYS_DB, "lookup"); switch (i_getpwnam(request->user, pw_r)) { case -1: auth_request_log_error(request, AUTH_SUBSYS_DB, "getpwnam() failed: %m"); return PASSDB_RESULT_INTERNAL_FAILURE; case 0: auth_request_log_unknown_user(request, AUTH_SUBSYS_DB); return PASSDB_RESULT_USER_UNKNOWN; } if (!IS_VALID_PASSWD(pw_r->pw_passwd)) { auth_request_log_info(request, AUTH_SUBSYS_DB, "invalid password field '%s'", pw_r->pw_passwd); return PASSDB_RESULT_USER_DISABLED; } /* save the password so cache can use it */ auth_request_set_field(request, "password", pw_r->pw_passwd, PASSWD_PASS_SCHEME); return PASSDB_RESULT_OK; }
bool passdb_cache_verify_plain(struct auth_request *request, const char *key, const char *password, enum passdb_result *result_r, bool use_expired) { const char *value, *cached_pw, *scheme, *const *list; struct auth_cache_node *node; int ret; bool neg_expired; if (passdb_cache == NULL || key == NULL) return FALSE; if (!passdb_cache_lookup(request, key, use_expired, &node, &value, &neg_expired)) return FALSE; if (*value == '\0') { /* negative cache entry */ auth_request_log_unknown_user(request, AUTH_SUBSYS_DB); *result_r = PASSDB_RESULT_USER_UNKNOWN; return TRUE; } list = t_strsplit_tab(value); cached_pw = list[0]; if (*cached_pw == '\0') { /* NULL password */ auth_request_log_info(request, AUTH_SUBSYS_DB, "Cached NULL password access"); ret = 1; } else { scheme = password_get_scheme(&cached_pw); i_assert(scheme != NULL); ret = auth_request_password_verify(request, password, cached_pw, scheme, AUTH_SUBSYS_DB); if (ret == 0 && (node->last_success || neg_expired)) { /* a) the last authentication was successful. assume that the password was changed and cache is expired. b) negative TTL reached, use it for password mismatches too. */ node->last_success = FALSE; return FALSE; } } node->last_success = ret > 0; /* save the extra_fields only after we know we're using the cached data */ auth_request_set_fields(request, list + 1, NULL); *result_r = ret > 0 ? PASSDB_RESULT_OK : PASSDB_RESULT_PASSWORD_MISMATCH; return TRUE; }
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_unknown_user(auth_request, AUTH_SUBSYS_DB); } else if (ldap_request->entries > 1) { auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "pass_filter matched multiple objects, aborting"); passdb_result = PASSDB_RESULT_INTERNAL_FAILURE; } else if (auth_request->passdb_password == NULL && ldap_request->require_password && !auth_fields_exists(auth_request->extra_fields, "nopassword")) { auth_request_log_info(auth_request, AUTH_SUBSYS_DB, "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, AUTH_SUBSYS_DB); passdb_result = ret > 0 ? PASSDB_RESULT_OK : PASSDB_RESULT_PASSWORD_MISMATCH; } ldap_request->callback.verify_plain(passdb_result, auth_request); } }
static void userdb_nss_lookup(struct auth_request *auth_request, userdb_callback_t *callback) { struct userdb_module *_module = auth_request->userdb->userdb; struct nss_userdb_module *module = (struct nss_userdb_module *)_module; struct passwd pw; enum nss_status status; enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE; int err; auth_request_log_debug(auth_request, AUTH_SUBSYS_DB, "lookup"); status = module->getpwnam_r(auth_request->user, &pw, module->buf, module->bufsize, &err); switch (status) { case NSS_STATUS_TRYAGAIN: auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "returned tryagain (err=%d)", err); break; case NSS_STATUS_UNAVAIL: auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "unavailable (err=%d)", err); break; case NSS_STATUS_NOTFOUND: auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB); result = USERDB_RESULT_USER_UNKNOWN; break; case NSS_STATUS_SUCCESS: result = USERDB_RESULT_OK; break; default: auth_request_log_info(auth_request, AUTH_SUBSYS_DB, "returned %d (err=%d)", status, err); break; } if (result != USERDB_RESULT_OK) { callback(result, auth_request); return; } auth_request_set_field(auth_request, "user", pw.pw_name, NULL); auth_request_set_userdb_field(auth_request, "system_groups_user", pw.pw_name); auth_request_set_userdb_field(auth_request, "uid", dec2str(pw.pw_uid)); auth_request_set_userdb_field(auth_request, "gid", dec2str(pw.pw_gid)); auth_request_set_userdb_field(auth_request, "home", pw.pw_dir); callback(USERDB_RESULT_OK, auth_request); }
static void passwd_verify_plain(struct auth_request *request, const char *password, verify_plain_callback_t *callback) { struct passwd pw; int ret; auth_request_log_debug(request, "passwd", "lookup"); switch (i_getpwnam(request->user, &pw)) { case -1: auth_request_log_error(request, "passwd", "getpwnam() failed: %m"); callback(PASSDB_RESULT_INTERNAL_FAILURE, request); return; case 0: auth_request_log_unknown_user(request, "passwd"); callback(PASSDB_RESULT_USER_UNKNOWN, request); return; } if (!IS_VALID_PASSWD(pw.pw_passwd)) { auth_request_log_info(request, "passwd", "invalid password field '%s'", pw.pw_passwd); callback(PASSDB_RESULT_USER_DISABLED, request); return; } /* save the password so cache can use it */ auth_request_set_field(request, "password", pw.pw_passwd, PASSWD_PASS_SCHEME); /* check if the password is valid */ ret = auth_request_password_verify(request, password, pw.pw_passwd, PASSWD_PASS_SCHEME, "passwd"); /* clear the passwords from memory */ safe_memset(pw.pw_passwd, 0, strlen(pw.pw_passwd)); if (ret <= 0) { callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); return; } /* make sure we're using the username exactly as it's in the database */ auth_request_set_field(request, "user", pw.pw_name, NULL); callback(PASSDB_RESULT_OK, request); }
static void ldap_auth_bind_callback(struct ldap_connection *conn, struct ldap_request *ldap_request, LDAPMessage *res) { struct passdb_ldap_request *passdb_ldap_request = (struct passdb_ldap_request *)ldap_request; struct auth_request *auth_request = ldap_request->auth_request; enum passdb_result passdb_result; const char *str; int ret; passdb_result = PASSDB_RESULT_INTERNAL_FAILURE; if (res != NULL) { ret = ldap_result2error(conn->ld, res, 0); if (ret == LDAP_SUCCESS) passdb_result = PASSDB_RESULT_OK; else if (ret == LDAP_INVALID_CREDENTIALS) { str = "invalid credentials"; if (auth_request->set->debug_passwords) { str = t_strconcat(str, " (given password: "******")", NULL); } auth_request_log_info(auth_request, AUTH_SUBSYS_DB, "%s", str); passdb_result = PASSDB_RESULT_PASSWORD_MISMATCH; } else if (ret == LDAP_NO_SUCH_OBJECT) { passdb_result = PASSDB_RESULT_USER_UNKNOWN; auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB); } else { auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "ldap_bind() failed: %s", ldap_err2string(ret)); } } passdb_ldap_request->callback. verify_plain(passdb_result, auth_request); auth_request_unref(&auth_request); }
static void bsdauth_verify_plain(struct auth_request *request, const char *password, verify_plain_callback_t *callback) { struct passwd pw; const char *type; int result; auth_request_log_debug(request, "bsdauth", "lookup"); switch (i_getpwnam(request->user, &pw)) { case -1: auth_request_log_error(request, "bsdauth", "getpwnam() failed: %m"); callback(PASSDB_RESULT_INTERNAL_FAILURE, request); return; case 0: auth_request_log_unknown_user(request, "bsdauth"); callback(PASSDB_RESULT_USER_UNKNOWN, request); return; } /* check if the password is valid */ type = t_strdup_printf("auth-%s", request->service); result = auth_userokay(request->user, NULL, t_strdup_noconst(type), t_strdup_noconst(password)); /* clear the passwords from memory */ safe_memset(pw.pw_passwd, 0, strlen(pw.pw_passwd)); if (result == 0) { auth_request_log_password_mismatch(request, "bsdauth"); callback(PASSDB_RESULT_PASSWORD_MISMATCH, request); return; } /* make sure we're using the username exactly as it's in the database */ auth_request_set_field(request, "user", pw.pw_name, NULL); callback(PASSDB_RESULT_OK, request); }
static void userdb_ldap_lookup_finish(struct auth_request *auth_request, struct userdb_ldap_request *urequest, LDAPMessage *res) { enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE; if (res == NULL) { result = USERDB_RESULT_INTERNAL_FAILURE; } else if (urequest->entries == 0) { result = USERDB_RESULT_USER_UNKNOWN; auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB); } else if (urequest->entries > 1) { auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "user_filter matched multiple objects, aborting"); result = USERDB_RESULT_INTERNAL_FAILURE; } else { result = USERDB_RESULT_OK; } urequest->userdb_callback(result, auth_request); }
static void sql_query_callback(struct sql_result *sql_result, struct userdb_sql_request *sql_request) { struct auth_request *auth_request = sql_request->auth_request; struct userdb_module *_module = auth_request->userdb->userdb; struct sql_userdb_module *module = (struct sql_userdb_module *)_module; enum userdb_result result = USERDB_RESULT_INTERNAL_FAILURE; int ret; ret = sql_result_next_row(sql_result); if (ret >= 0) db_sql_success(module->conn); if (ret < 0) { if (!module->conn->default_user_query) { auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "User query failed: %s", sql_result_get_error(sql_result)); } else { auth_request_log_error(auth_request, AUTH_SUBSYS_DB, "User query failed: %s " "(using built-in default user_query: %s)", sql_result_get_error(sql_result), module->conn->set.user_query); } } else if (ret == 0) { result = USERDB_RESULT_USER_UNKNOWN; auth_request_log_unknown_user(auth_request, AUTH_SUBSYS_DB); } else { sql_query_get_result(sql_result, auth_request); result = USERDB_RESULT_OK; } sql_request->callback(result, auth_request); auth_request_unref(&auth_request); i_free(sql_request); }
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); }