passdb-pam.c revision 67e26a26c8be946f99a699265139ac5e3409b92c
/*
Based on auth_pam.c from popa3d by Solar Designer <solar@openwall.com>.
You're allowed to do whatever you like with this software (including
modification), provided that credit is given where it is due and any
modified versions are marked as such. There's absolutely no warranty.
*/
#include "config.h"
#ifdef PASSDB_PAM
#include "common.h"
#include "buffer.h"
#include "ioloop.h"
#include "passdb.h"
#include "mycrypt.h"
#include "safe-memset.h"
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_SECURITY_PAM_APPL_H
# include <security/pam_appl.h>
#elif defined(HAVE_PAM_PAM_APPL_H)
# include <pam/pam_appl.h>
#endif
/* Sun's PAM doesn't use const. we use a bit dirty hack to check it.
so I thought this might work better. */
# define linux_const
#else
# define linux_const const
#endif
typedef linux_const void *pam_item_t;
#ifdef AUTH_PAM_USERPASS
# include <security/pam_client.h>
# ifndef PAM_BP_RCONTROL
/* Linux-PAM prior to 0.74 */
# define PAM_BP_RCONTROL PAM_BP_CONTROL
# define PAM_BP_WDATA PAM_BP_DATA
# define PAM_BP_RDATA PAM_BP_DATA
# endif
# define USERPASS_AGENT_ID "userpass"
# define USERPASS_AGENT_ID_LENGTH 8
# define USERPASS_USER_MASK 0x03
# define USERPASS_USER_REQUIRED 1
# define USERPASS_USER_KNOWN 2
# define USERPASS_USER_FIXED 3
#endif
struct pam_auth_request {
int fd;
struct auth_request *request;
};
struct pam_userpass {
const char *user;
const char *pass;
};
static char *service_name;
{
/* @UNSAFE */
#ifdef AUTH_PAM_USERPASS
const char *input;
char *output;
char flags;
return PAM_CONV_ERR;
return PAM_CONV_ERR;
return PAM_CONV_AGAIN;
return PAM_CONV_ERR;
(*resp)[0].resp_retcode = 0;
#else
char *string;
int i;
return PAM_CONV_ERR;
for (i = 0; i < num_msg; i++) {
case PAM_PROMPT_ECHO_ON:
i_fatal("Out of memory");
break;
case PAM_PROMPT_ECHO_OFF:
i_fatal("Out of memory");
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
break;
default:
while (--i >= 0) {
continue;
}
return PAM_CONV_ERR;
}
}
#endif
return PAM_SUCCESS;
}
{
void *item;
int status;
return status;
}
#ifdef HAVE_PAM_SETCRED
return status;
}
#endif
return status;
}
if (status != PAM_SUCCESS) {
return status;
}
return PAM_SUCCESS;
}
static void
{
struct pam_userpass userpass;
enum passdb_result result;
const char *str;
char buf_data[512];
if (status != PAM_SUCCESS) {
} else {
/* FIXME: check for PASSDB_RESULT_UNKNOWN_USER
somehow? */
if (!verbose)
} else {
}
}
/* may truncate the error. tough luck. */
}
}
static void pam_child_input(void *context)
{
enum passdb_result result;
char buf[513];
/* POSIX guarantees that writing 512 bytes or less to pipes is atomic.
We rely on that. */
if (ret < 0) {
i_error("PAM: read() from child process failed: %m");
} else if (ret == 0) {
/* it died */
i_error("PAM: Child process died");
} else {
/* error message included */
if (result == PASSDB_RESULT_INTERNAL_FAILURE)
else
}
}
i_error("PAM: close(child input) failed: %m");
}
{
int status;
/* FIXME: if we ever do some other kind of forking, this needs fixing */
if (pid == -1) {
i_error("waitpid() failed: %m");
return;
}
if (WIFSIGNALED(status)) {
i_error("PAM: Child %s died with signal %d",
}
}
}
static void
{
struct pam_auth_request *pam_auth_request;
const char *service;
int fd[2];
i_error("Unknown protocol %d in auth request",
}
i_error("PAM: pipe() failed: %m");
return;
}
if (pid == -1) {
i_error("PAM: fork() failed: %m");
return;
}
if (pid == 0) {
_exit(0);
}
i_error("PAM: close(fd[1]) failed: %m");
}
{
}
static void pam_deinit(void)
{
}
struct passdb_module passdb_pam = {
};
#endif