passdb-pam.c revision 6c46568fae90840f82435be91d4364d23209cf70
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi/*
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi Based on auth_pam.c from popa3d by Solar Designer <solar@openwall.com>.
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi You're allowed to do whatever you like with this software (including
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi re-distribution in source and/or binary form, with or without
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi modification), provided that credit is given where it is due and any
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi modified versions are marked as such. There's absolutely no warranty.
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi*/
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "common.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#ifdef PASSDB_PAM
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "lib-signals.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "buffer.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "ioloop.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "hash.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "str.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "var-expand.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "network.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "passdb.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "mycrypt.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include "safe-memset.h"
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include <stdlib.h>
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include <fcntl.h>
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include <unistd.h>
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#include <sys/wait.h>
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#define PAM_CHILD_TIMEOUT (60*2)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#define PAM_CHILD_CHECK_TIMEOUT (10*1000)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi#ifdef HAVE_SECURITY_PAM_APPL_H
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi# include <security/pam_appl.h>
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi#elif defined(HAVE_PAM_PAM_APPL_H)
8c3a756ed4cf22f9fdab5f95d067321e6ddcc425KATOH Yasufumi# include <pam/pam_appl.h>
8c3a756ed4cf22f9fdab5f95d067321e6ddcc425KATOH Yasufumi#endif
8c3a756ed4cf22f9fdab5f95d067321e6ddcc425KATOH Yasufumi
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi#if !defined(_SECURITY_PAM_APPL_H) && !defined(LINUX_PAM) && !defined(_OPENPAM)
8c3a756ed4cf22f9fdab5f95d067321e6ddcc425KATOH Yasufumi/* Sun's PAM doesn't use const. we use a bit dirty hack to check it.
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi Originally it was just __sun__ check, but HP/UX also uses Sun's PAM
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi so I thought this might work better. */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi# define linux_const
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#else
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi# define linux_const const
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#endif
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumitypedef linux_const void *pam_item_t;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#ifdef AUTH_PAM_USERPASS
8adef7614d4340b4ee44a4441fadd530f48515edKATOH Yasufumi# include <security/pam_client.h>
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# ifndef PAM_BP_RCONTROL
8c3a756ed4cf22f9fdab5f95d067321e6ddcc425KATOH Yasufumi/* Linux-PAM prior to 0.74 */
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi# define PAM_BP_RCONTROL PAM_BP_CONTROL
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi# define PAM_BP_WDATA PAM_BP_DATA
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define PAM_BP_RDATA PAM_BP_DATA
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi# endif
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define USERPASS_AGENT_ID "userpass"
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define USERPASS_AGENT_ID_LENGTH 8
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define USERPASS_USER_MASK 0x03
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define USERPASS_USER_REQUIRED 1
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define USERPASS_USER_KNOWN 2
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi# define USERPASS_USER_FIXED 3
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi#endif
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumistruct pam_passdb_module {
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi struct passdb_module module;
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi bool pam_setcred, pam_session;
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi const char *service_name, *pam_cache_key;
8adef7614d4340b4ee44a4441fadd530f48515edKATOH Yasufumi};
8adef7614d4340b4ee44a4441fadd530f48515edKATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct pam_auth_request {
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi int refcount;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi int fd;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi struct io *io;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi time_t start_time;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi pid_t pid;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi struct auth_request *request;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi verify_plain_callback_t *callback;
adf4b4083369a8bb7ed3c2ce3dd85dcaed7323c4KATOH Yasufumi};
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistruct pam_userpass {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *user;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *pass;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi};
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic struct hash_table *pam_requests;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic struct timeout *to;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic int pam_userpass_conv(int num_msg, linux_const struct pam_message **msg,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct pam_response **resp, void *appdata_ptr)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* @UNSAFE */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct pam_userpass *userpass = (struct pam_userpass *) appdata_ptr;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#ifdef AUTH_PAM_USERPASS
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pamc_bp_t prompt;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *input;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi char *output;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi char flags;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi size_t userlen, passlen;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (num_msg != 1 || msg[0]->msg_style != PAM_BINARY_PROMPT)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return PAM_CONV_ERR;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi prompt = (pamc_bp_t)msg[0]->msg;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi input = PAM_BP_RDATA(prompt);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi if (PAM_BP_RCONTROL(prompt) != PAM_BPC_SELECT ||
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi strncmp(input, USERPASS_AGENT_ID "/", USERPASS_AGENT_ID_LENGTH + 1))
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi return PAM_CONV_ERR;
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi flags = input[USERPASS_AGENT_ID_LENGTH + 1];
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi input += USERPASS_AGENT_ID_LENGTH + 1 + 1;
92cbfdaf682dca9cf60243f23c2e911181bfc7abKATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((flags & USERPASS_USER_MASK) == USERPASS_USER_FIXED &&
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi strcmp(input, userpass->user))
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return PAM_CONV_AGAIN;
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi
8adef7614d4340b4ee44a4441fadd530f48515edKATOH Yasufumi if (!(*resp = malloc(sizeof(struct pam_response))))
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return PAM_CONV_ERR;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi userlen = strlen(userpass->user);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi passlen = strlen(userpass->pass);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi prompt = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi PAM_BP_RENEW(&prompt, PAM_BPC_DONE, userlen + 1 + passlen);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi output = PAM_BP_WDATA(prompt);
420dfb599b22b8e39e6e51437d17213d4f778735Dwight Engen
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi memcpy(output, userpass->user, userlen + 1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi memcpy(output + userlen + 1, userpass->pass, passlen);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi (*resp)[0].resp_retcode = 0;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi (*resp)[0].resp = (char *)prompt;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#else
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi char *string;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi int i;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (!(*resp = malloc(num_msg * sizeof(struct pam_response))))
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return PAM_CONV_ERR;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi for (i = 0; i < num_msg; i++) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi switch (msg[i]->msg_style) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_PROMPT_ECHO_ON:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi string = strdup(userpass->user);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (string == NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_PROMPT_ECHO_OFF:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi string = strdup(userpass->pass);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (string == NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_fatal_status(FATAL_OUTOFMEM, "Out of memory");
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_ERROR_MSG:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_TEXT_INFO:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi string = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi default:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi while (--i >= 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((*resp)[i].resp == NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi continue;
db821c3a4168c9c1072a433340e6009892e26cf2KATOH Yasufumi safe_memset((*resp)[i].resp, 0,
db821c3a4168c9c1072a433340e6009892e26cf2KATOH Yasufumi strlen((*resp)[i].resp));
db821c3a4168c9c1072a433340e6009892e26cf2KATOH Yasufumi free((*resp)[i].resp);
db821c3a4168c9c1072a433340e6009892e26cf2KATOH Yasufumi (*resp)[i].resp = NULL;
db821c3a4168c9c1072a433340e6009892e26cf2KATOH Yasufumi }
db821c3a4168c9c1072a433340e6009892e26cf2KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi free(*resp);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *resp = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return PAM_CONV_ERR;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi (*resp)[i].resp_retcode = PAM_SUCCESS;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi (*resp)[i].resp = string;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#endif
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return PAM_SUCCESS;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic int pam_auth(struct auth_request *request,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_handle_t *pamh, const char **error)
a1e4c206d5373b8ecd7906bff37f2601d65f022cKATOH Yasufumi{
0dc296145715c36795ad0ad561f115afdd758223KATOH Yasufumi struct passdb_module *_module = request->passdb->passdb;
a1e4c206d5373b8ecd7906bff37f2601d65f022cKATOH Yasufumi struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi void *item;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi int status;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error = NULL;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error = t_strdup_printf("pam_authenticate() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return status;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#ifdef HAVE_PAM_SETCRED
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (module->pam_setcred) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((status = pam_setcred(pamh, PAM_ESTABLISH_CRED)) !=
41e8e807c8e85289bb717a365056b9437555e25aKATOH Yasufumi PAM_SUCCESS) {
41e8e807c8e85289bb717a365056b9437555e25aKATOH Yasufumi *error = t_strdup_printf("pam_setcred() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return status;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi#endif
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error = t_strdup_printf("pam_acct_mgmt() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return status;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (module->pam_session) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((status = pam_open_session(pamh, 0)) != PAM_SUCCESS) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error = t_strdup_printf(
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "pam_open_session() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return status;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((status = pam_close_session(pamh, 0)) != PAM_SUCCESS) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi *error = t_strdup_printf(
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "pam_close_session() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status));
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi return status;
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
bf3e09c00eab82850782ad6ec74e4403d84ae866KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi /* FIXME: this doesn't actually work since we're in the child
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi process.. */
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi status = pam_get_item(pamh, PAM_USER, (linux_const void **)&item);
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi if (status != PAM_SUCCESS) {
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi *error = t_strdup_printf("pam_get_item() failed: %s",
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi pam_strerror(pamh, status));
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi return status;
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi }
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi auth_request_set_field(request, "user", item, NULL);
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi
7a49a081dd1d4f92e3c82df344709e3206457e46KATOH Yasufumi return PAM_SUCCESS;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic enum passdb_result
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumipam_verify_plain_child(struct auth_request *request, const char *service,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *password, int fd)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_handle_t *pamh;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct pam_userpass userpass;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct pam_conv conv;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi enum passdb_result result;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi int ret, status, status2;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *str;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi size_t size;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi buffer_t *buf;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi conv.conv = pam_userpass_conv;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi conv.appdata_ptr = &userpass;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi userpass.user = request->user;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi userpass.pass = password;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi status = pam_start(service, request->user, &conv, &pamh);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (status != PAM_SUCCESS) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_INTERNAL_FAILURE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi str = t_strdup_printf("pam_start() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi const char *host = net_ip2addr(&request->remote_ip);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* Set some PAM items. They shouldn't fail, and we don't really
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi care if they do. */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (host != NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi (void)pam_set_item(pamh, PAM_RHOST, host);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* TTY is needed by eg. pam_access module */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi (void)pam_set_item(pamh, PAM_TTY, "dovecot");
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi status = pam_auth(request, pamh, &str);
420dfb599b22b8e39e6e51437d17213d4f778735Dwight Engen if ((status2 = pam_end(pamh, status)) == PAM_SUCCESS) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi switch (status) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_SUCCESS:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_OK;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_USER_UNKNOWN:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_USER_UNKNOWN;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_NEW_AUTHTOK_REQD:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi case PAM_ACCT_EXPIRED:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_PASS_EXPIRED;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi default:
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_PASSWORD_MISMATCH;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi break;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_INTERNAL_FAILURE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi str = t_strdup_printf("pam_end() failed: %s",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi pam_strerror(pamh, status2));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (worker) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* blocking=yes code path in auth worker */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return result;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi buf = buffer_create_dynamic(pool_datastack_create(), 512);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi buffer_append(buf, &result, sizeof(result));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (str != NULL)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi buffer_append(buf, str, strlen(str));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* Don't send larger writes than what would block. truncated error
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi message isn't that bad.. */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi size = I_MIN(buf->used, PIPE_BUF);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((ret = write(fd, buf->data, size)) != (int)size) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (ret < 0)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_error("write() failed: %m");
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi i_error("write() failed: %d != %"PRIuSIZE_T,
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ret, buf->used);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi return result;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi}
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumistatic void pam_child_input(struct pam_auth_request *request)
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi{
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi struct auth_request *auth_request = request->request;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi enum passdb_result result;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi char buf[PIPE_BUF + 1];
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ssize_t ret;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* POSIX guarantees that writing PIPE_BUF bytes or less to pipes is
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi atomic. We rely on that. */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi ret = read(request->fd, buf, sizeof(buf)-1);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (ret < 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi auth_request_log_error(auth_request, "pam",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "read() from child process failed: %m");
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_INTERNAL_FAILURE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else if (ret == 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* it died */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi auth_request_log_error(auth_request, "pam",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "Child process died");
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_INTERNAL_FAILURE;
8c3a756ed4cf22f9fdab5f95d067321e6ddcc425KATOH Yasufumi } else if ((size_t)ret < sizeof(result)) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi auth_request_log_error(auth_request, "pam",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "Child process returned only %d bytes", (int)ret);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi result = PASSDB_RESULT_INTERNAL_FAILURE;
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi memcpy(&result, buf, sizeof(result));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if ((size_t)ret > sizeof(result)) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi /* error message included */
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi buf[ret] = '\0';
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (result == PASSDB_RESULT_INTERNAL_FAILURE) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi auth_request_log_error(auth_request, "pam",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "%s", buf + sizeof(result));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi } else {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi auth_request_log_info(auth_request, "pam",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "%s", buf + sizeof(result));
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi }
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi io_remove(&request->io);
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi if (close(request->fd) < 0) {
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi auth_request_log_error(auth_request, "pam",
cab79123082bef9ba265c9c8b9176b8b8afedd64KATOH Yasufumi "close(child input) failed: %m");
}
request->callback(result, auth_request);
auth_request_unref(&auth_request);
if (--request->refcount == 0)
i_free(request);
}
static void sigchld_handler(int signo __attr_unused__,
void *context __attr_unused__)
{
struct pam_auth_request *request;
int status;
pid_t pid;
/* FIXME: if we ever do some other kind of forking, this needs fixing */
while ((pid = waitpid(-1, &status, WNOHANG)) != 0) {
if (pid == -1) {
if (errno != ECHILD && errno != EINTR)
i_error("waitpid() failed: %m");
return;
}
request = hash_lookup(pam_requests, POINTER_CAST(pid));
if (request == NULL) {
i_error("PAM: Unknown child %s exited with status %d",
dec2str(pid), status);
continue;
}
if (WIFSIGNALED(status)) {
i_error("PAM: Child %s died with signal %d",
dec2str(pid), WTERMSIG(status));
} else if (WIFEXITED(status) && WEXITSTATUS(status) != 0) {
i_error("PAM: Child %s exited unexpectedly with "
"exit code %d", dec2str(pid),
WEXITSTATUS(status));
}
hash_remove(pam_requests, POINTER_CAST(request->pid));
if (--request->refcount == 0)
i_free(request);
}
}
static void
pam_verify_plain(struct auth_request *request, const char *password,
verify_plain_callback_t *callback)
{
struct passdb_module *_module = request->passdb->passdb;
struct pam_passdb_module *module = (struct pam_passdb_module *)_module;
struct pam_auth_request *pam_auth_request;
enum passdb_result result;
string_t *expanded_service;
const char *service;
int fd[2];
pid_t pid;
expanded_service = t_str_new(64);
var_expand(expanded_service, module->service_name,
auth_request_get_var_expand_table(request, NULL));
service = str_c(expanded_service);
auth_request_log_debug(request, "pam", "lookup service=%s", service);
if (worker) {
/* blocking=yes code path in auth worker */
result = pam_verify_plain_child(request, service, password, -1);
callback(result, request);
return;
}
if (pipe(fd) < 0) {
auth_request_log_error(request, "pam", "pipe() failed: %m");
callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
return;
}
pid = fork();
if (pid == -1) {
auth_request_log_error(request, "pam", "fork() failed: %m");
callback(PASSDB_RESULT_INTERNAL_FAILURE, request);
(void)close(fd[0]);
(void)close(fd[1]);
return;
}
if (pid == 0) {
(void)close(fd[0]);
pam_verify_plain_child(request, service, password, fd[1]);
_exit(0);
}
if (close(fd[1]) < 0) {
auth_request_log_error(request, "pam",
"close(fd[1]) failed: %m");
}
auth_request_ref(request);
pam_auth_request = i_new(struct pam_auth_request, 1);
pam_auth_request->refcount = 2;
pam_auth_request->fd = fd[0];
pam_auth_request->request = request;
pam_auth_request->callback = callback;
pam_auth_request->pid = pid;
pam_auth_request->start_time = ioloop_time;
pam_auth_request->io =
io_add(fd[0], IO_READ, pam_child_input, pam_auth_request);
hash_insert(pam_requests, POINTER_CAST(pid), pam_auth_request);
}
static struct passdb_module *
pam_preinit(struct auth_passdb *auth_passdb, const char *args)
{
struct pam_passdb_module *module;
const char *const *t_args;
int i;
module = p_new(auth_passdb->auth->pool, struct pam_passdb_module, 1);
module->service_name = "dovecot";
t_push();
t_args = t_strsplit(args, " ");
for(i = 0; t_args[i] != NULL; i++) {
/* -session for backwards compatibility */
if (strcmp(t_args[i], "-session") == 0 ||
strcmp(t_args[i], "session=yes") == 0)
module->pam_session = TRUE;
else if (strcmp(t_args[i], "setcred=yes") == 0)
module->pam_setcred = TRUE;
else if (strncmp(t_args[i], "cache_key=", 10) == 0) {
module->module.cache_key =
p_strdup(auth_passdb->auth->pool,
t_args[i] + 10);
} else if (strcmp(t_args[i], "blocking=yes") == 0) {
module->module.blocking = TRUE;
} else if (strcmp(t_args[i], "*") == 0) {
/* for backwards compatibility */
module->service_name = "%s";
} else if (t_args[i+1] == NULL) {
if (*t_args[i] != '\0') {
module->service_name =
p_strdup(auth_passdb->auth->pool,
t_args[i]);
}
} else {
i_fatal("Unexpected PAM parameter: %s", t_args[i]);
}
}
t_pop();
lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL);
return &module->module;
}
static void pam_child_timeout(void *context __attr_unused__)
{
struct hash_iterate_context *iter;
void *key, *value;
time_t timeout = ioloop_time - PAM_CHILD_TIMEOUT;
iter = hash_iterate_init(pam_requests);
while (hash_iterate(iter, &key, &value)) {
struct pam_auth_request *request = value;
if (request->start_time > timeout)
continue;
auth_request_log_error(request->request, "pam",
"PAM child process %s timed out, killing it",
dec2str(request->pid));
if (kill(request->pid, SIGKILL) < 0) {
i_error("PAM: kill(%s) failed: %m",
dec2str(request->pid));
}
}
hash_iterate_deinit(iter);
}
static void pam_init(struct passdb_module *_module __attr_unused__,
const char *args __attr_unused__)
{
if (pam_requests != NULL)
i_fatal("Can't support more than one PAM passdb");
/* we're caching the password by using directly the plaintext password
given by the auth mechanism */
_module->default_pass_scheme = "PLAIN";
if (!_module->blocking) {
pam_requests = hash_create(default_pool, default_pool, 0,
NULL, NULL);
to = timeout_add(PAM_CHILD_CHECK_TIMEOUT,
pam_child_timeout, NULL);
lib_signals_set_handler(SIGCHLD, TRUE, sigchld_handler, NULL);
}
}
static void pam_deinit(struct passdb_module *_module __attr_unused__)
{
if (!_module->blocking) {
lib_signals_unset_handler(SIGCHLD, sigchld_handler, NULL);
hash_destroy(pam_requests);
timeout_remove(&to);
}
}
struct passdb_module_interface passdb_pam = {
"pam",
pam_preinit,
pam_init,
pam_deinit,
pam_verify_plain,
NULL,
NULL
};
#endif