/*
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 "auth-common.h"
#include "passdb.h"
#ifdef PASSDB_PAM
#include "lib-signals.h"
#include "str.h"
#include "net.h"
#include "safe-memset.h"
#include "auth-cache.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
# define pam_const
#else
# define pam_const const
#endif
struct pam_passdb_module {
unsigned int requests_left;
};
struct pam_conv_context {
const char *pass;
const char *failure_msg;
};
static int
{
/* @UNSAFE */
char *string;
int i;
for (i = 0; i < num_msg; i++) {
case PAM_PROMPT_ECHO_ON:
/* Assume we're asking for user. We might not ever
get here because PAM already knows the user. */
break;
case PAM_PROMPT_ECHO_OFF:
/* Assume we're asking for password */
if (passdb->failure_show_msg)
break;
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
break;
default:
while (--i >= 0) {
}
}
return PAM_CONV_ERR;
}
}
return PAM_SUCCESS;
}
static const char *
{
#ifdef SUNPAM
return NULL;
#else
static bool service_checked = FALSE;
const char *path;
if (service_checked) {
/* check and complain only once */
return NULL;
}
/* looks like it's missing. but before assuming that the system
return path;
}
/* exists or is unknown */
return NULL;
#endif
}
const char *service)
{
int status;
switch (status) {
case PAM_USER_UNKNOWN:
str = "unknown user";
break;
default:
break;
}
/* log this as error, since it probably is */
} else if (status == PAM_AUTH_ERR) {
")", NULL);
}
} else {
if (status == PAM_USER_UNKNOWN)
else {
"%s", str);
}
}
return status;
}
#ifdef HAVE_PAM_SETCRED
if (module->pam_setcred) {
PAM_SUCCESS) {
"pam_setcred() failed: %s",
return status;
}
}
#endif
"pam_acct_mgmt() failed: %s",
return status;
}
if (module->pam_session) {
"pam_open_session() failed: %s",
return status;
}
"pam_close_session() failed: %s",
return status;
}
}
if (status != PAM_SUCCESS) {
"pam_get_item(PAM_USER) failed: %s",
return status;
}
return PAM_SUCCESS;
}
{
const char *host;
/* These shouldn't fail, and we don't really care if they do. */
if (host[0] != '\0')
/* TTY is needed by eg. pam_access module */
}
static enum passdb_result
const char *password)
{
if (status != PAM_SUCCESS) {
"pam_start() failed: %s",
return PASSDB_RESULT_INTERNAL_FAILURE;
}
"pam_end() failed: %s",
return PASSDB_RESULT_INTERNAL_FAILURE;
}
switch (status) {
case PAM_SUCCESS:
break;
case PAM_USER_UNKNOWN:
break;
case PAM_NEW_AUTHTOK_REQD:
case PAM_ACCT_EXPIRED:
break;
default:
break;
}
}
return result;
}
static void
{
if (module->requests_left > 0) {
if (--module->requests_left == 0)
}
"Failed to expand service %s: %s",
return;
}
"lookup service=%s", service);
}
static struct passdb_module *
{
const char *const *t_args;
int i;
/* we're caching the password by using directly the plaintext password
given by the auth mechanism */
/* -session for backwards compatibility */
/* ignore, for backwards compatibility */
/* for backwards compatibility */
&module->requests_left) < 0) {
i_error("pam: Invalid requests_left value: %s",
t_args[i] + 13);
}
} else {
}
}
}
"pam",
NULL,
NULL,
NULL,
};
#else
.name = "pam"
};
#endif