Copyright Andrew Tridgell <tridge@samba.org> 2000
Copyright Tim Potter <tpot@samba.org> 2000
- Copyright Andrew Bartlettt <abartlet@samba.org> 2002
+ Copyright Andrew Bartlett <abartlet@samba.org> 2002
largely based on pam_userdb by Christian Gafton <gafton@redhat.com>
also contains large slabs of code from pam_unix by Elliot Lee <sopwith@redhat.com>
#include "pam_winbind.h"
-/* prototypes from common.c */
-void init_request(struct winbindd_request *req,int rq_type);
-int write_sock(void *buffer, int count);
-int read_reply(struct winbindd_response *response);
-
/* data tokens */
#define MAX_PASSWD_TRIES 3
else if (!strcasecmp(*argv, "use_authtok"))
ctrl |= WINBIND_USE_AUTHTOK_ARG;
else if (!strcasecmp(*argv, "use_first_pass"))
- ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
- else if (!strcasecmp(*argv, "try_first_pass"))
ctrl |= WINBIND_USE_FIRST_PASS_ARG;
+ else if (!strcasecmp(*argv, "try_first_pass"))
+ ctrl |= WINBIND_TRY_FIRST_PASS_ARG;
else if (!strcasecmp(*argv, "unknown_ok"))
ctrl |= WINBIND_UNKNOWN_OK_ARG;
+ else if (!strncasecmp(*argv, "required_membership", strlen("required_membership")))
+ ctrl |= WINBIND_REQUIRED_MEMBERSHIP;
else {
_pam_log(LOG_ERR, "pam_parse: unknown option; %s", *argv);
}
}
-int _make_remark(pam_handle_t * pamh, int type, const char *text)
+static int _make_remark(pam_handle_t * pamh, int type, const char *text)
{
int retval = PAM_SUCCESS;
return retval;
}
-static int winbind_request(enum winbindd_cmd req_type,
- struct winbindd_request *request,
- struct winbindd_response *response)
+static int pam_winbind_request(enum winbindd_cmd req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response)
{
+
/* Fill in request and send down pipe */
init_request(request, req_type);
if (write_sock(request, sizeof(*request)) == -1) {
_pam_log(LOG_ERR, "write to socket failed!");
+ close_sock();
return PAM_SERVICE_ERR;
}
/* Wait for reply */
if (read_reply(response) == -1) {
_pam_log(LOG_ERR, "read from socket failed!");
+ close_sock();
return PAM_SERVICE_ERR;
}
+ /* We are done with the socket - close it and avoid mischeif */
+ close_sock();
+
/* Copy reply data from socket */
if (response->result != WINBINDD_OK) {
if (response->data.auth.pam_error != PAM_SUCCESS) {
- _pam_log(LOG_ERR, "request failed, PAM error was %d, NT error was %s",
+ _pam_log(LOG_ERR, "request failed: %s, PAM error was %d, NT error was %s",
+ response->data.auth.error_string,
response->data.auth.pam_error,
response->data.auth.nt_status_string);
return response->data.auth.pam_error;
return PAM_SUCCESS;
}
-/* talk to winbindd */
-static int winbind_auth_request(const char *user, const char *pass, int ctrl)
+static int pam_winbind_request_log(enum winbindd_cmd req_type,
+ struct winbindd_request *request,
+ struct winbindd_response *response,
+ int ctrl,
+ const char *user)
{
- struct winbindd_request request;
- struct winbindd_response response;
int retval;
- 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);
-
- retval = winbind_request(WINBINDD_PAM_AUTH, &request, &response);
+ retval = pam_winbind_request(req_type, request, response);
switch (retval) {
case PAM_AUTH_ERR:
/* incorrect password */
- _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password)", user);
+ _pam_log(LOG_WARNING, "user `%s' denied access (incorrect password or invalid membership)", user);
+ return retval;
+ case PAM_ACCT_EXPIRED:
+ /* account expired */
+ _pam_log(LOG_WARNING, "user `%s' account expired", user);
+ return retval;
+ case PAM_AUTHTOK_EXPIRED:
+ /* password expired */
+ _pam_log(LOG_WARNING, "user `%s' password expired", user);
+ return retval;
+ case PAM_NEW_AUTHTOK_REQD:
+ /* password expired */
+ _pam_log(LOG_WARNING, "user `%s' new password required", user);
return retval;
case PAM_USER_UNKNOWN:
/* the user does not exist */
}
return retval;
case PAM_SUCCESS:
- /* Otherwise, the authentication looked good */
- _pam_log(LOG_NOTICE, "user '%s' granted acces", user);
+ if (req_type == WINBINDD_PAM_AUTH) {
+ /* Otherwise, the authentication looked good */
+ _pam_log(LOG_NOTICE, "user '%s' granted access", user);
+ } else if (req_type == WINBINDD_PAM_CHAUTHTOK) {
+ /* Otherwise, the authentication looked good */
+ _pam_log(LOG_NOTICE, "user '%s' password changed", user);
+ } else {
+ /* Otherwise, the authentication looked good */
+ _pam_log(LOG_NOTICE, "user '%s' OK", user);
+ }
return retval;
default:
/* we don't know anything about this return value */
retval, user);
return retval;
}
- /* should not be reached */
+}
+
+/* talk to winbindd */
+static int winbind_auth_request(const char *user, const char *pass, const char *member, int ctrl)
+{
+ 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);
+
+ if (member == NULL )
+ return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user);
+
+ /* lookup name? */
+ if (!strncmp("S-", member, 2) == 0) {
+
+ struct winbindd_request request;
+ struct winbindd_response response;
+
+ ZERO_STRUCT(request);
+ ZERO_STRUCT(response);
+
+ if (ctrl & WINBIND_DEBUG_ARG)
+ _pam_log(LOG_DEBUG, "no sid given, looking up: %s\n", member);
+
+ /* fortunatly winbindd can handle non-separated names */
+ strcpy(request.data.name.name, member);
+
+ if (pam_winbind_request_log(WINBINDD_LOOKUPNAME, &request, &response, ctrl, user)) {
+ _pam_log(LOG_INFO, "could not lookup name: %s\n", member);
+ return PAM_AUTH_ERR;
+ }
+
+ member = strdup(response.data.sid.sid);
+ }
+
+ strncpy(request.data.auth.required_membership_sid, member,
+ sizeof(request.data.auth.required_membership_sid)-1);
+
+ return pam_winbind_request_log(WINBINDD_PAM_AUTH, &request, &response, ctrl, user);
}
/* talk to winbindd */
static int winbind_chauthtok_request(const char *user, const char *oldpass,
- const char *newpass)
+ const char *newpass, int ctrl)
{
struct winbindd_request request;
struct winbindd_response response;
request.data.chauthtok.newpass[0] = '\0';
}
- return winbind_request(WINBINDD_PAM_CHAUTHTOK, &request, &response);
+ return pam_winbind_request_log(WINBINDD_PAM_CHAUTHTOK, &request, &response, ctrl, user);
}
/*
* obtain a password from the user
*/
-int _winbind_read_password(pam_handle_t * pamh
- ,unsigned int ctrl
- ,const char *comment
- ,const char *prompt1
- ,const char *prompt2
- ,const char **pass)
+static int _winbind_read_password(pam_handle_t * pamh
+ ,unsigned int ctrl
+ ,const char *comment
+ ,const char *prompt1
+ ,const char *prompt2
+ ,const char **pass)
{
int authtok_flag;
int retval;
{
const char *username;
const char *password;
+ const char *member = NULL;
int retval = PAM_AUTH_ERR;
+ int i;
/* parse arguments */
int ctrl = _pam_parse(argc, argv);
&password);
if (retval != PAM_SUCCESS) {
- _pam_log(LOG_ERR, "Could not retrive user's password");
+ _pam_log(LOG_ERR, "Could not retrieve user's password");
return PAM_AUTHTOK_ERR;
}
#endif
}
+ /* Retrieve membership-string here */
+ for ( i=0; i<argc; i++ ) {
+
+ if (!strncmp(argv[i], "required_membership", strlen("required_membership"))) {
+
+ char *p;
+ char *parm = strdup(argv[i]);
+
+ if ( (p = strchr( parm, '=' )) == NULL) {
+ _pam_log(LOG_INFO, "no \"=\" delimiter for \"required_membership\" found\n");
+ break;
+ }
+
+ member = strdup(p+1);
+ }
+ }
+
/* Now use the username to look up password */
- return winbind_auth_request(username, password, ctrl);
+ return winbind_auth_request(username, password, member, ctrl);
}
PAM_EXTERN
return PAM_USER_UNKNOWN;
case 0:
/* Otherwise, the authentication looked good */
- _pam_log(LOG_NOTICE, "user '%s' granted acces", username);
+ _pam_log(LOG_NOTICE, "user '%s' granted access", username);
return PAM_SUCCESS;
default:
/* we don't know anything about this return value */
/* should not be reached */
return PAM_IGNORE;
}
+PAM_EXTERN
+int pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
+{
+ /* parse arguments */
+ int ctrl = _pam_parse(argc, argv);
+ if (ctrl & WINBIND_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)
+{
+ /* parse arguments */
+ int ctrl = _pam_parse(argc, argv);
+ if (ctrl & WINBIND_DEBUG_ARG)
+ _pam_log(LOG_DEBUG,"libpam_winbind:pam_sm_close_session handler");
+ return PAM_SUCCESS;
+}
+
PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
/* <DO NOT free() THESE> */
const char *user;
+ const char *member = NULL;
char *pass_old, *pass_new;
/* </DO NOT free() THESE> */
}
/* verify that this is the password for this user */
- retval = winbind_auth_request(user, pass_old, ctrl);
+ retval = winbind_auth_request(user, pass_old, member, ctrl);
if (retval != PAM_ACCT_EXPIRED
+ && retval != PAM_AUTHTOK_EXPIRED
&& retval != PAM_NEW_AUTHTOK_REQD
&& retval != PAM_SUCCESS) {
pass_old = NULL;
* rebuild the password database file.
*/
- retval = winbind_chauthtok_request(user, pass_old, pass_new);
+ retval = winbind_chauthtok_request(user, pass_old, pass_new, ctrl);
_pam_overwrite(pass_new);
_pam_overwrite(pass_old);
pass_old = pass_new = NULL;
pam_sm_authenticate,
pam_sm_setcred,
pam_sm_acct_mgmt,
- NULL,
- NULL,
+ pam_sm_open_session,
+ pam_sm_close_session,
pam_sm_chauthtok
};