#include "pam_winbind.h"
void init_request(struct winbindd_request *req,int rq_type);
int write_sock(void *buffer, int count);
int read_reply(struct winbindd_response *response);
static void _pam_log(int err, const char *format, ...)
{
va_list args;
va_start(args, format);
openlog(MODULE_NAME, LOG_CONS|LOG_PID, LOG_AUTH);
vsyslog(err, format, args);
va_end(args);
closelog();
}
static int ctrl = 0;
static int _pam_parse(int argc, const char **argv)
{
for (ctrl = 0; argc-- > 0; ++argv) {
if (!strcmp(*argv,"debug"))
ctrl |= PAM_DEBUG_ARG;
else if (!strcasecmp(*argv, "use_authtok"))
ctrl |= PAM_USE_AUTHTOK_ARG;
else if (!strcasecmp(*argv, "unknown_ok"))
ctrl |= PAM_UNKNOWN_OK_ARG;
else {
_pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
}
}
return ctrl;
}
static int winbind_request(enum winbindd_cmd req_type,
struct winbindd_request *request,
struct winbindd_response *response)
{
init_request(request, req_type);
if (write_sock(request, sizeof(*request)) == -1) {
return -2;
}
if (read_reply(response) == -1) {
return -2;
}
if (response->result != WINBINDD_OK) {
return 1;
}
return 0;
}
static int winbind_auth_request(const char *user, const char *pass)
{
struct winbindd_request request;
struct winbindd_response response;
ZERO_STRUCT(request);
strncpy(request.data.auth.user, user,
sizeof(request.data.auth.user)-1);
strncpy(request.data.auth.pass, pass,
sizeof(request.data.auth.pass)-1);
return winbind_request(WINBINDD_PAM_AUTH, &request, &response);
}
static int winbind_chauthtok_request(const char *user, const char *oldpass,
const char *newpass)
{
struct winbindd_request request;
struct winbindd_response response;
ZERO_STRUCT(request);
if (request.data.chauthtok.user == NULL) return -2;
strncpy(request.data.chauthtok.user, user,
sizeof(request.data.chauthtok.user) - 1);
if (oldpass != NULL) {
strncpy(request.data.chauthtok.oldpass, oldpass,
sizeof(request.data.chauthtok.oldpass) - 1);
} else {
request.data.chauthtok.oldpass[0] = '\0';
}
if (newpass != NULL) {
strncpy(request.data.chauthtok.newpass, newpass,
sizeof(request.data.chauthtok.newpass) - 1);
} else {
request.data.chauthtok.newpass[0] = '\0';
}
return winbind_request(WINBINDD_PAM_CHAUTHTOK, &request, &response);
}
static int user_lookup(const char *user, const char *pass)
{
return winbind_auth_request(user, pass);
}
static int valid_user(const char *user)
{
if (getpwnam(user)) return 0;
return 1;
}
static int converse(pam_handle_t *pamh, int nargs,
struct pam_message **message,
struct pam_response **response)
{
int retval;
struct pam_conv *conv;
retval = pam_get_item(pamh, PAM_CONV, (const void **) &conv ) ;
if (retval == PAM_SUCCESS) {
retval = conv->conv(nargs, (const struct pam_message **)message,
response, conv->appdata_ptr);
}
return retval;
}
static char *_pam_delete(register char *xx)
{
_pam_overwrite(xx);
_pam_drop(xx);
return NULL;
}
static int auth_conversation(pam_handle_t *pamh)
{
struct pam_message msg, *pmsg;
struct pam_response *resp;
int retval;
char * token = NULL;
pmsg = &msg;
msg.msg_style = PAM_PROMPT_ECHO_OFF;
msg.msg = "Password: ";
resp = NULL;
retval = converse(pamh, 1, &pmsg, &resp);
if (resp != NULL) {
char * const item;
if (retval == PAM_SUCCESS) {
token = x_strdup(resp[0].resp);
if (token == NULL) {
return PAM_AUTHTOK_RECOVER_ERR;
}
}
retval = pam_set_item(pamh, PAM_AUTHTOK, token);
token = _pam_delete(token);
if ( (retval != PAM_SUCCESS) ||
(retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &item)) != PAM_SUCCESS ) {
return retval;
}
_pam_drop_reply(resp, 1);
} else {
retval = (retval == PAM_SUCCESS)
? PAM_AUTHTOK_RECOVER_ERR:retval ;
}
return retval;
}
PAM_EXTERN
int pam_sm_authenticate(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
const char *username;
const char *password;
int retval = PAM_AUTH_ERR;
ctrl = _pam_parse(argc, argv);
retval = pam_get_user(pamh, &username, NULL);
if ((retval != PAM_SUCCESS) || (!username)) {
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"can not get the username");
return PAM_SERVICE_ERR;
}
if ((ctrl & PAM_USE_AUTHTOK_ARG) == 0) {
retval = auth_conversation(pamh);
if (retval != PAM_SUCCESS) {
_pam_log(LOG_ERR, "could not obtain password for `%s'",
username);
return PAM_CONV_ERR;
}
}
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **) &password);
if (retval != PAM_SUCCESS) {
_pam_log(LOG_ERR, "Could not retrive user's password");
return PAM_AUTHTOK_ERR;
}
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_INFO, "Verify user `%s' with password `%s'",
username, password);
retval = user_lookup(username, password);
switch (retval) {
case -2:
return PAM_SERVICE_ERR;
case -1:
_pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", username);
return PAM_AUTH_ERR;
case 1:
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_NOTICE, "user `%s' not found",
username);
if (ctrl & PAM_UNKNOWN_OK_ARG) {
return PAM_IGNORE;
}
return PAM_USER_UNKNOWN;
case 0:
_pam_log(LOG_NOTICE, "user '%s' granted access", username);
return PAM_SUCCESS;
default:
_pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
retval, username);
return PAM_SERVICE_ERR;
}
return PAM_IGNORE;
}
PAM_EXTERN
int pam_sm_setcred(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
return PAM_SUCCESS;
}
PAM_EXTERN
int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
const char *username;
int retval = PAM_USER_UNKNOWN;
ctrl = _pam_parse(argc, argv);
retval = pam_get_user(pamh, &username, NULL);
if ((retval != PAM_SUCCESS) || (!username)) {
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"can not get the username");
return PAM_SERVICE_ERR;
}
retval = valid_user(username);
switch (retval) {
case -1:
return PAM_SERVICE_ERR;
case 1:
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_NOTICE, "user `%s' not found",
username);
if (ctrl & PAM_UNKNOWN_OK_ARG)
return PAM_IGNORE;
return PAM_USER_UNKNOWN;
case 0:
_pam_log(LOG_NOTICE, "user '%s' granted access", username);
return PAM_SUCCESS;
default:
_pam_log(LOG_ERR, "internal module error (retval = %d, user = `%s'",
retval, username);
return PAM_SERVICE_ERR;
}
return PAM_IGNORE;
}
PAM_EXTERN
int pam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc,
const char **argv)
{
int retval;
char *newpw, *oldpw;
const char *user;
retval = pam_get_user(pamh, &user, "Username: ");
if (retval != PAM_SUCCESS) {
return retval;
}
if (flags & PAM_PRELIM_CHECK) {
struct pam_message msg[3], *pmsg[3];
struct pam_response *resp;
retval = auth_conversation(pamh);
if (retval != PAM_SUCCESS) {
return retval;
}
pmsg[0] = &msg[0];
msg[0].msg_style = PAM_TEXT_INFO;
msg[0].msg = "Changing password for user %s";
pmsg[1] = &msg[1];
msg[1].msg_style = PAM_PROMPT_ECHO_OFF;
msg[1].msg = "New NT password: ";
pmsg[2] = &msg[2];
msg[2].msg_style = PAM_PROMPT_ECHO_OFF;
msg[2].msg = "Retype new NT password: ";
resp = NULL;
retval = converse(pamh, 3, pmsg, &resp);
if (resp != NULL) {
if (retval == PAM_SUCCESS) {
if (strcmp(resp[1].resp, resp[2].resp) != 0) {
struct pam_response *resp2;
msg[0].msg_style = PAM_ERROR_MSG;
msg[0].msg = "Sorry, passwords do not match";
converse(pamh, 1, pmsg, &resp2);
_pam_drop_reply(resp, 3);
_pam_drop_reply(resp2, 1);
return PAM_AUTHTOK_RECOVER_ERR;
}
retval = pam_set_item(pamh, PAM_OLDAUTHTOK, resp[1].resp);
_pam_drop_reply(resp, 3);
}
}
return retval;
}
if (flags & PAM_UPDATE_AUTHTOK) {
retval = pam_get_item(pamh, PAM_OLDAUTHTOK, (const void **)&newpw);
if (retval != PAM_SUCCESS) {
return PAM_AUTHTOK_ERR;
}
retval = pam_get_item(pamh, PAM_AUTHTOK, (const void **)&oldpw);
if (retval != PAM_SUCCESS) {
return PAM_AUTHTOK_ERR;
}
fprintf(stderr, "oldpw = %s, newpw = %s\n", oldpw, newpw);
if (retval == PAM_SUCCESS &&
winbind_chauthtok_request(user, oldpw, newpw) == 0) {
return PAM_SUCCESS;
}
return PAM_AUTHTOK_ERR;
}
return PAM_SERVICE_ERR;
}
PAM_EXTERN
int pam_sm_open_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
ctrl = _pam_parse(argc, argv);
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_open_session handler") ;
return PAM_SUCCESS;
}
PAM_EXTERN
int pam_sm_close_session(pam_handle_t *pamh, int flags,
int argc, const char **argv)
{
ctrl = _pam_parse(argc, argv);
if (ctrl & PAM_DEBUG_ARG)
_pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_close_session handler");
return PAM_SUCCESS;
}
#ifdef PAM_STATIC
struct pam_module _pam_winbind_modstruct = {
MODULE_NAME,
pam_sm_authenticate,
pam_sm_setcred,
pam_sm_acct_mgmt,
pam_sm_open_session,
pam_sm_close_session,
pam_sm_chauthtok
};
#endif