passdb-pam.c revision 1e1ce4654c9ec4749bd8054416287b4a2ff568b9
/*
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 "common.h"
#ifdef PASSDB_PAM
#include "lib-signals.h"
#include "buffer.h"
#include "ioloop.h"
#include "network.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_passdb_module {
struct passdb_module module;
bool pam_setcred, pam_session;
const char *service_name, *pam_cache_key;
};
struct pam_auth_request {
int fd;
struct auth_request *request;
};
struct pam_userpass {
const char *user;
const char *pass;
};
{
/* @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:
break;
case PAM_PROMPT_ECHO_OFF:
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
if (module->pam_setcred) {
PAM_SUCCESS) {
return status;
}
}
#endif
return status;
}
if (module->pam_session) {
*error = t_strdup_printf(
"pam_open_session() failed: %s",
return status;
}
*error = t_strdup_printf(
"pam_close_session() failed: %s",
return status;
}
}
if (status != PAM_SUCCESS) {
return status;
}
return PAM_SUCCESS;
}
static void
{
struct pam_userpass userpass;
enum passdb_result result;
const char *str;
if (status != PAM_SUCCESS) {
} else {
/* Set some PAM items. They shouldn't fail, and we don't really
care if they do. */
/* TTY is needed by eg. pam_access module */
switch (status) {
case PAM_SUCCESS:
break;
case PAM_USER_UNKNOWN:
break;
case PAM_NEW_AUTHTOK_REQD:
case PAM_ACCT_EXPIRED:
break;
default:
break;
}
} else {
}
}
/* Don't send larger writes than what would block. truncated error
message isn't that bad.. */
if (ret < 0)
i_error("write() failed: %m");
else {
}
}
}
static void pam_child_input(void *context)
{
enum passdb_result result;
/* POSIX guarantees that writing PIPE_BUF bytes or less to pipes is
atomic. We rely on that. */
if (ret < 0) {
"read() from child process failed: %m");
} else if (ret == 0) {
/* it died */
"Child process died");
"Child process returned only %d bytes", (int)ret);
} else {
/* error message included */
if (result == PASSDB_RESULT_INTERNAL_FAILURE) {
} else {
}
}
}
"close(child input) failed: %m");
}
}
void *context __attr_unused__)
{
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];
return;
}
if (pid == -1) {
return;
}
if (pid == 0) {
_exit(0);
}
"close(fd[1]) failed: %m");
}
}
static struct passdb_module *
{
struct pam_passdb_module *module;
const char *const *t_args;
int i;
t_push();
/* -session for backwards compatibility */
t_args[i] + 10);
if (*t_args[i] != '\0') {
t_args[i]);
}
} else {
}
}
t_pop();
}
{
}
struct passdb_module_interface passdb_pam = {
"pam",
NULL,
};
#endif