passdb-pam.c revision dd93aba1901a457346990f49c54a738947dc7128
183bea41fa640dc8117f3eb45ff935cd81377a84Timo Sirainen/*
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen Based on auth_pam.c from popa3d by Solar Designer <solar@openwall.com>.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen You're allowed to do whatever you like with this software (including
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen re-distribution in source and/or binary form, with or without
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen modification), provided that credit is given where it is due and any
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen modified versions are marked as such. There's absolutely no warranty.
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen*/
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "common.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "passdb.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef PASSDB_PAM
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib-signals.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "str.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "var-expand.h"
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen#include "network.h"
e8fd7988ec183fb6c104aed19a61f1a096c51d34Timo Sirainen#include "safe-memset.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "auth-cache.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen#include <stdlib.h>
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen#include <sys/stat.h>
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen#ifdef HAVE_SECURITY_PAM_APPL_H
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen# include <security/pam_appl.h>
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen#elif defined(HAVE_PAM_PAM_APPL_H)
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen# include <pam/pam_appl.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#endif
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen#if !defined(_SECURITY_PAM_APPL_H) && !defined(LINUX_PAM) && !defined(_OPENPAM)
ad850190d946d34966a56838cfdb216e021b5b5fTimo Sirainen/* Sun's PAM doesn't use const. we use a bit dirty hack to check it.
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen Originally it was just __sun__ check, but HP/UX also uses Sun's PAM
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen so I thought this might work better. */
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen# define SUNPAM
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen#endif
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen#ifdef SUNPAM
d35fee8d1e5e31614dba5e64d45ed23c7d6bfa53Timo Sirainen# define linux_const
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen# define linux_const const
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen#endif
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainentypedef linux_const void *pam_item_t;
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainenstruct pam_passdb_module {
eddd9bf1a1369aea4a2715f6be1137da6d17d293Timo Sirainen struct passdb_module module;
19e8adccba16ff419f5675b1575358c2956dce83Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *service_name, *pam_cache_key;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int pam_setcred:1;
8aacc9e7c84f8376822823ec98c2f551d4919b2eTimo Sirainen unsigned int pam_session:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int failure_show_msg:1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct pam_conv_context {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct auth_request *request;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *pass;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen const char *failure_msg;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen};
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainenpam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct pam_response **resp_r, void *appdata_ptr)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
6e235046e1d8e9d89fc948f5c623676c20421a28Timo Sirainen /* @UNSAFE */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct pam_conv_context *ctx = appdata_ptr;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct passdb_module *_passdb = ctx->request->passdb->passdb;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct pam_passdb_module *passdb = (struct pam_passdb_module *)_passdb;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen struct pam_response *resp;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen char *string;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *resp_r = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen resp = calloc(num_msg, sizeof(struct pam_response));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (resp == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen for (i = 0; i < num_msg; i++) {
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen auth_request_log_debug(ctx->request, "pam",
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen "#%d/%d style=%d msg=%s", i+1, num_msg,
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen msg[i]->msg_style,
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen msg[i]->msg != NULL ? msg[i]->msg : "");
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen switch (msg[i]->msg_style) {
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen case PAM_PROMPT_ECHO_ON:
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen /* Assume we're asking for user. We might not ever
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen get here because PAM already knows the user. */
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen string = strdup(ctx->request->user);
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen if (string == NULL)
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen break;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen case PAM_PROMPT_ECHO_OFF:
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen /* Assume we're asking for password */
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen if (passdb->failure_show_msg)
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen ctx->failure_msg = t_strdup(msg[i]->msg);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen string = strdup(ctx->pass);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (string == NULL)
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen break;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen case PAM_ERROR_MSG:
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen case PAM_TEXT_INFO:
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen string = NULL;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen break;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen default:
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen while (--i >= 0) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (resp[i].resp != NULL) {
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen safe_memset(resp[i].resp, 0,
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen strlen(resp[i].resp));
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen free(resp[i].resp);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen free(resp);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen return PAM_CONV_ERR;
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen }
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen resp[i].resp_retcode = PAM_SUCCESS;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen resp[i].resp = string;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen }
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen *resp_r = resp;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen return PAM_SUCCESS;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen}
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenstatic const char *
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainenpam_get_missing_service_file_path(const char *service ATTR_UNUSED)
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen{
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen#ifdef SUNPAM
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* Uses /etc/pam.conf - we're not going to parse that */
66ecc94150cbce23aad3240135e0782e0a74d479Timo Sirainen return NULL;
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen#else
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen static bool service_checked = FALSE;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen const char *path;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen struct stat st;
85da8c055280cd45553b6b335e9fb226d6e2801eTimo Sirainen
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen if (service_checked) {
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen /* check and complain only once */
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen return NULL;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen }
2131ef7a3390f15ea6a958256ea54908f1096350Timo Sirainen service_checked = TRUE;
bc564f1d3d953cf724828322b11ae89e0f59ffc9Timo Sirainen
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen path = t_strdup_printf("/etc/pam.d/%s", service);
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen if (stat(path, &st) < 0 && errno == ENOENT) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen /* looks like it's missing. but before assuming that the system
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen even uses /etc/pam.d, make sure that it exists. */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (stat("/etc/pam.d", &st) == 0)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen return path;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen /* exists or is unknown */
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen return NULL;
69e03a846f6980144aa75bff0590c04852bffbbcTimo Sirainen#endif
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen}
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenstatic int try_pam_auth(struct auth_request *request, pam_handle_t *pamh,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen const char *service)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct passdb_module *_module = request->passdb->passdb;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen const char *path, *str;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen pam_item_t item;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen int status;
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen path = pam_get_missing_service_file_path(service);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen switch (status) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen case PAM_USER_UNKNOWN:
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen str = "unknown user";
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen break;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen default:
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen str = t_strconcat("pam_authenticate() failed: ",
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen pam_strerror(pamh, status), NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen }
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen if (path != NULL) {
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen /* log this as error, since it probably is */
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen str = t_strdup_printf("%s (%s missing?)", str, path);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen auth_request_log_error(request, "pam", "%s", str);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen } else {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (status == PAM_AUTH_ERR) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen str = t_strconcat(str, " (password mismatch?)",
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen NULL);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen auth_request_log_info(request, "pam", "%s", str);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return status;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen }
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen#ifdef HAVE_PAM_SETCRED
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if (module->pam_setcred) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) !=
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen PAM_SUCCESS) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_error(request, "pam",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "pam_setcred() failed: %s",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen pam_strerror(pamh, status));
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen return status;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen }
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen }
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen#endif
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen auth_request_log_error(request, "pam",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "pam_acct_mgmt() failed: %s",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen pam_strerror(pamh, status));
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen return status;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen }
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if (module->pam_session) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if ((status = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen auth_request_log_error(request, "pam",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen "pam_open_session() failed: %s",
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen pam_strerror(pamh, status));
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen return status;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen }
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen if ((status = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen auth_request_log_error(request, "pam",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen "pam_close_session() failed: %s",
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen pam_strerror(pamh, status));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return status;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen status = pam_get_item(pamh, PAM_USER, &item);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (status != PAM_SUCCESS) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_error(request, "pam",
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen "pam_get_item(PAM_USER) failed: %s",
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen pam_strerror(pamh, status));
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen return status;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen }
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen auth_request_set_field(request, "user", item, NULL);
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen return PAM_SUCCESS;
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainen}
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen
e192a3b1ca8ae857e7d87298ea507d32977ba570Timo Sirainenstatic void set_pam_items(struct auth_request *request, pam_handle_t *pamh)
811f2e26d9782d9cb99fdf82e18ffa0a77564fe2Timo Sirainen{
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen const char *host;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
c4877db8b6559846f4b58be8e42422dc734c193fTimo Sirainen /* These shouldn't fail, and we don't really care if they do. */
6bc0f424bcdb9119d8159874cf98adfa53eefd9aTimo Sirainen host = net_ip2addr(&request->remote_ip);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (host != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void)pam_set_item(pamh, PAM_RHOST, host);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen (void)pam_set_item(pamh, PAM_RUSER, request->user);
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen /* TTY is needed by eg. pam_access module */
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen (void)pam_set_item(pamh, PAM_TTY, "dovecot");
8b9342aa96b2f297e23afb261f9f7dd859800952Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic enum passdb_result
37e6cf44d61a81c6839e3ab76234b54309d8d292Timo Sirainenpam_verify_plain_call(struct auth_request *request, const char *service,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen const char *password)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen pam_handle_t *pamh;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct pam_conv_context ctx;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen struct pam_conv conv;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen enum passdb_result result;
a40d26f83af808a0ea1e212c001d682a96d870b0Timo Sirainen int status, status2;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen conv.conv = pam_userpass_conv;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen conv.appdata_ptr = &ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen memset(&ctx, 0, sizeof(ctx));
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen ctx.request = request;
56f45b3f3ae20e5c933701f4657dda5ef1916855Timo Sirainen ctx.pass = password;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen status = pam_start(service, request->user, &conv, &pamh);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen if (status != PAM_SUCCESS) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_error(request, "pam", "pam_start() failed: %s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pam_strerror(pamh, status));
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen return PASSDB_RESULT_INTERNAL_FAILURE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen set_pam_items(request, pamh);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen status = try_pam_auth(request, pamh, service);
6b85bc4b03e552cfaeeae872d63c2d8ac5fcb7c4Timo Sirainen if ((status2 = pam_end(pamh, status)) != PAM_SUCCESS) {
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen auth_request_log_error(request, "pam", "pam_end() failed: %s",
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen pam_strerror(pamh, status2));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return PASSDB_RESULT_INTERNAL_FAILURE;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen switch (status) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen case PAM_SUCCESS:
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen result = PASSDB_RESULT_OK;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen break;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen case PAM_USER_UNKNOWN:
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen result = PASSDB_RESULT_USER_UNKNOWN;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen break;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen case PAM_NEW_AUTHTOK_REQD:
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen case PAM_ACCT_EXPIRED:
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen result = PASSDB_RESULT_PASS_EXPIRED;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen break;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen default:
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen result = PASSDB_RESULT_PASSWORD_MISMATCH;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen break;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen }
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen if (result != PASSDB_RESULT_OK && ctx.failure_msg != NULL) {
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen auth_request_set_field(request, "reason",
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen ctx.failure_msg, NULL);
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen }
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen return result;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen}
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainenstatic void
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainenpam_verify_plain(struct auth_request *request, const char *password,
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen verify_plain_callback_t *callback)
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen{
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen struct passdb_module *_module = request->passdb->passdb;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen enum passdb_result result;
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen string_t *expanded_service;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen const char *service;
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen expanded_service = t_str_new(64);
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen var_expand(expanded_service, module->service_name,
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen auth_request_get_var_expand_table(request, NULL));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen service = str_c(expanded_service);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen auth_request_log_debug(request, "pam", "lookup service=%s", service);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen result = pam_verify_plain_call(request, service, password);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen callback(result, request);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct passdb_module *
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainenpam_preinit(struct auth_passdb *auth_passdb, const char *args)
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen{
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen struct pam_passdb_module *module;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen const char *const *t_args;
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen int i;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen module = p_new(auth_passdb->auth->pool, struct pam_passdb_module, 1);
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen module->service_name = "dovecot";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* we're caching the password by using directly the plaintext password
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen given by the auth mechanism */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen module->module.default_pass_scheme = "PLAIN";
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen module->module.blocking = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_args = t_strsplit_spaces(args, " ");
72cbf33ae81fde08384d30c779ff540752d9256cTimo Sirainen for(i = 0; t_args[i] != NULL; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* -session for backwards compatibility */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (strcmp(t_args[i], "-session") == 0 ||
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen strcmp(t_args[i], "session=yes") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen module->pam_session = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (strcmp(t_args[i], "setcred=yes") == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen module->pam_setcred = TRUE;
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen else if (strncmp(t_args[i], "cache_key=", 10) == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen module->module.cache_key =
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen auth_cache_parse_key(auth_passdb->auth->pool,
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen t_args[i] + 10);
f519e4c2ad4ef826f1b08f3e0138b9b287a52c80Timo Sirainen } else if (strcmp(t_args[i], "blocking=yes") == 0) {
58be9d6bcc3800f5b3d76a064ee767fbe31a5a8aTimo Sirainen /* ignore, for backwards compatibility */
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen } else if (strcmp(t_args[i], "failure_show_msg=yes") == 0) {
d565eaa943f29a49b97230ced57eec40ee65b4f9Timo Sirainen module->failure_show_msg = TRUE;
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen } else if (strcmp(t_args[i], "*") == 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* for backwards compatibility */
f501ad38c51cf1d8f4f84313922c785e6ae6e81fTimo Sirainen module->service_name = "%Ls";
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen } else if (t_args[i+1] == NULL) {
25c22e54d1071d120641e9eecd0023e7373e65ffTimo Sirainen module->service_name =
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen p_strdup(auth_passdb->auth->pool, t_args[i]);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("passdb pam: Unknown setting: %s", t_args[i]);
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen return &module->module;
6a8a4c9f530668cd8961b73d702856ed94f05f80Timo Sirainen}
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenstruct passdb_module_interface passdb_pam = {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen "pam",
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen pam_preinit,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen NULL,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen NULL,
df6478c4cf605bd81b3891c148b84c14eb6c4035Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen pam_verify_plain,
fd2f5fbc1f07aa93e2214a28cdf02437fb7d06c8Timo Sirainen NULL,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen NULL
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#else
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct passdb_module_interface passdb_pam = {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen MEMBER(name) "pam"
abe7afb8f1766fbcef1b9df513109e43d7d16e49Timo Sirainen};
1098fc409a45e7603701dc94635927a673bee0c1Timo Sirainen#endif
e015e2f7e7f48874495f9df8b0dd192b7ffcb5ccTimo Sirainen