r2482: Fix from Arthur van Dongen <avdongen@xs4all.nl> to fix acces -> access typos.
[ira/wip.git] / source3 / nsswitch / pam_winbind.c
index 7de553da4d67531de54c3cef8c75f761b95e1c50..64e21738221a38539fc8f019aae4a1694e5cae29 100644 (file)
@@ -2,7 +2,7 @@
 
    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
@@ -45,11 +40,13 @@ static int _pam_parse(int argc, const char **argv)
                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);
                }
@@ -79,7 +76,7 @@ static int converse(pam_handle_t *pamh, int nargs,
 }
 
 
-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;
 
@@ -99,28 +96,35 @@ int _make_remark(pam_handle_t * pamh, int type, const char *text)
        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;
@@ -133,27 +137,32 @@ static int winbind_request(enum winbindd_cmd req_type,
        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 */
@@ -165,8 +174,16 @@ static int winbind_auth_request(const char *user, const char *pass, int ctrl)
                }        
                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 */
@@ -174,12 +191,57 @@ static int winbind_auth_request(const char *user, const char *pass, int ctrl)
                         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;
@@ -205,7 +267,7 @@ static int winbind_chauthtok_request(const char *user, const char *oldpass,
             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);
 }
 
 /*
@@ -233,12 +295,12 @@ static char *_pam_delete(register char *xx)
  * 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;
@@ -387,7 +449,9 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
 {
      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);
@@ -405,7 +469,7 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
                                     &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;
      }
      
@@ -421,8 +485,25 @@ int pam_sm_authenticate(pam_handle_t *pamh, int flags,
 #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
@@ -470,7 +551,7 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
            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 */
@@ -482,6 +563,27 @@ int pam_sm_acct_mgmt(pam_handle_t *pamh, int flags,
     /* 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,
@@ -493,6 +595,7 @@ 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> */
 
@@ -553,9 +656,10 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                }
                /* 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;
@@ -630,7 +734,7 @@ PAM_EXTERN int pam_sm_chauthtok(pam_handle_t * pamh, int flags,
                 * 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;
@@ -650,8 +754,8 @@ struct pam_module _pam_winbind_modstruct = {
      pam_sm_authenticate,
      pam_sm_setcred,
      pam_sm_acct_mgmt,
-     NULL,
-     NULL,
+     pam_sm_open_session,
+     pam_sm_close_session,
      pam_sm_chauthtok
 };