s3: Convert WINBINDD_PAM_AUTH to the new async API
[kai/samba.git] / source3 / winbindd / winbindd_pam.c
index 3117533f316c0bacdbd32ca96e447cdcbd71dec5..2e1bc204e6793a66680ab62085258a6a1e2e7cff 100644 (file)
@@ -26,6 +26,7 @@
 #include "winbindd.h"
 #include "../libcli/auth/libcli_auth.h"
 #include "../librpc/gen_ndr/cli_samr.h"
+#include "smb_krb5.h"
 
 #undef DBGC_CLASS
 #define DBGC_CLASS DBGC_WINBIND
@@ -194,8 +195,8 @@ static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
                DOM_SID user_sid;
                fstring sidstr;
 
-               sid_copy(&user_sid, info3->base.domain_sid);
-               sid_append_rid(&user_sid, info3->base.rid);
+               sid_compose(&user_sid, info3->base.domain_sid,
+                           info3->base.rid);
                sid_to_fstring(sidstr, &user_sid);
                afsname = talloc_string_sub(mem_ctx, afsname,
                                            "%s", sidstr);
@@ -233,8 +234,8 @@ static NTSTATUS append_afs_token(TALLOC_CTX *mem_ctx,
        return NT_STATUS_OK;
 }
 
-NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
-                             const char *group_sid)
+static NTSTATUS check_info3_in_group(struct netr_SamInfo3 *info3,
+                                    const char *group_sid)
 /**
  * Check whether a user belongs to a group or list of groups.
  *
@@ -347,11 +348,8 @@ struct winbindd_domain *find_auth_domain(uint8_t flags,
                return domain;
        }
 
-       if (is_myname(domain_name)) {
-               DEBUG(3, ("Authentication for domain %s (local domain "
-                         "to this server) not supported at this "
-                         "stage\n", domain_name));
-               return NULL;
+       if (strequal(domain_name, get_global_sam_name())) {
+               return find_domain_from_name_noinit(domain_name);
        }
 
        /* we can auth against trusted domains */
@@ -732,10 +730,10 @@ bool check_request_flags(uint32_t flags)
 /****************************************************************
 ****************************************************************/
 
-NTSTATUS append_auth_data(struct winbindd_cli_state *state,
-                         struct netr_SamInfo3 *info3,
-                         const char *name_domain,
-                         const char *name_user)
+static NTSTATUS append_auth_data(struct winbindd_cli_state *state,
+                                struct netr_SamInfo3 *info3,
+                                const char *name_domain,
+                                const char *name_user)
 {
        NTSTATUS result;
        uint32_t flags = state->request->flags;
@@ -797,70 +795,6 @@ NTSTATUS append_auth_data(struct winbindd_cli_state *state,
        return NT_STATUS_OK;
 }
 
-void winbindd_pam_auth(struct winbindd_cli_state *state)
-{
-       struct winbindd_domain *domain;
-       fstring name_domain, name_user, mapped_user;
-       char *mapped = NULL;
-       NTSTATUS result;
-       NTSTATUS name_map_status = NT_STATUS_UNSUCCESSFUL;
-
-       /* Ensure null termination */
-       state->request->data.auth.user
-               [sizeof(state->request->data.auth.user)-1]='\0';
-
-       /* Ensure null termination */
-       state->request->data.auth.pass
-               [sizeof(state->request->data.auth.pass)-1]='\0';
-
-       DEBUG(3, ("[%5lu]: pam auth %s\n", (unsigned long)state->pid,
-                 state->request->data.auth.user));
-
-       if (!check_request_flags(state->request->flags)) {
-               result = NT_STATUS_INVALID_PARAMETER_MIX;
-               goto done;
-       }
-
-       /* Parse domain and username */
-
-       name_map_status = normalize_name_unmap(state->mem_ctx,
-                                              state->request->data.auth.user,
-                                              &mapped);
-
-       /* If the name normalization didnt' actually do anything,
-          just use the original name */
-
-       if (NT_STATUS_IS_OK(name_map_status)
-           ||NT_STATUS_EQUAL(name_map_status, NT_STATUS_FILE_RENAMED)) {
-               fstrcpy(mapped_user, mapped);
-       } else {
-               fstrcpy(mapped_user, state->request->data.auth.user);
-       }
-
-       if (!canonicalize_username(mapped_user, name_domain, name_user)) {
-               result = NT_STATUS_NO_SUCH_USER;
-               goto done;
-       }
-
-       domain = find_auth_domain(state->request->flags, name_domain);
-
-       if (domain == NULL) {
-               result = NT_STATUS_NO_SUCH_USER;
-               goto done;
-       }
-
-       sendto_domain(state, domain);
-       return;
- done:
-       set_auth_errors(state->response, result);
-       DEBUG(5, ("Plain text authentication for %s returned %s "
-                 "(PAM: %d)\n",
-                 state->request->data.auth.user,
-                 state->response->data.auth.nt_status_string,
-                 state->response->data.auth.pam_error));
-       request_error(state);
-}
-
 static NTSTATUS winbindd_dual_pam_auth_cached(struct winbindd_domain *domain,
                                              struct winbindd_cli_state *state,
                                              struct netr_SamInfo3 **info3)
@@ -1178,6 +1112,53 @@ done:
        return result;
 }
 
+static NTSTATUS winbindd_dual_auth_passdb(TALLOC_CTX *mem_ctx,
+                                         const char *domain, const char *user,
+                                         const DATA_BLOB *challenge,
+                                         const DATA_BLOB *lm_resp,
+                                         const DATA_BLOB *nt_resp,
+                                         struct netr_SamInfo3 **pinfo3)
+{
+       struct auth_usersupplied_info *user_info = NULL;
+       struct auth_serversupplied_info *server_info = NULL;
+       struct netr_SamInfo3 *info3;
+       NTSTATUS status;
+
+       status = make_user_info(&user_info, user, user, domain, domain,
+                               global_myname(), lm_resp, nt_resp, NULL, NULL,
+                               NULL, True);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("make_user_info failed: %s\n", nt_errstr(status)));
+               return status;
+       }
+
+       status = check_sam_security(challenge, talloc_tos(), user_info,
+                                   &server_info);
+       free_user_info(&user_info);
+
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("check_ntlm_password failed: %s\n",
+                          nt_errstr(status)));
+               return status;
+       }
+
+       info3 = TALLOC_ZERO_P(mem_ctx, struct netr_SamInfo3);
+       if (info3 == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       status = serverinfo_to_SamInfo3(server_info, NULL, 0, info3);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(10, ("serverinfo_to_SamInfo3 failed: %s\n",
+                          nt_errstr(status)));
+               return status;
+       }
+
+       DEBUG(10, ("Authenticated user %s\\%s successfully\n", domain, user));
+       *pinfo3 = info3;
+       return NT_STATUS_OK;
+}
+
 typedef        NTSTATUS (*netlogon_fn_t)(struct rpc_pipe_client *cli,
                                  TALLOC_CTX *mem_ctx,
                                  uint32 logon_parameters,
@@ -1202,7 +1183,6 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
        int attempts = 0;
        unsigned char local_lm_response[24];
        unsigned char local_nt_response[24];
-       struct winbindd_domain *contact_domain;
        fstring name_domain, name_user;
        bool retry;
        NTSTATUS result;
@@ -1218,8 +1198,8 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
 
        /* do password magic */
 
+       generate_random_buffer(chal, sizeof(chal));
 
-       generate_random_buffer(chal, 8);
        if (lp_client_ntlmv2_auth()) {
                DATA_BLOB server_chal;
                DATA_BLOB names_blob;
@@ -1273,24 +1253,13 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                                           sizeof(local_nt_response));
        }
 
-       /* what domain should we contact? */
-
-       if ( IS_DC ) {
-               if (!(contact_domain = find_domain_from_name(name_domain))) {
-                       DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
-                                 state->request->data.auth.user, name_domain, name_user, name_domain));
-                       result = NT_STATUS_NO_SUCH_USER;
-                       goto done;
-               }
-
-       } else {
-               if (is_myname(name_domain)) {
-                       DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
-                       result =  NT_STATUS_NO_SUCH_USER;
-                       goto done;
-               }
+       if (strequal(name_domain, get_global_sam_name())) {
+               DATA_BLOB chal_blob = data_blob_const(chal, sizeof(chal));
 
-               contact_domain = find_our_domain();
+               result = winbindd_dual_auth_passdb(
+                       state->mem_ctx, name_domain, name_user,
+                       &chal_blob, &lm_resp, &nt_resp, info3);
+               goto done;
        }
 
        /* check authentication loop */
@@ -1301,7 +1270,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                ZERO_STRUCTP(my_info3);
                retry = false;
 
-               result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
+               result = cm_connect_netlogon(domain, &netlogon_pipe);
 
                if (!NT_STATUS_IS_OK(result)) {
                        DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
@@ -1329,14 +1298,14 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                 *  -- abartlet 21 April 2008
                 */
 
-               logon_fn = contact_domain->can_do_samlogon_ex
+               logon_fn = domain->can_do_samlogon_ex
                        ? rpccli_netlogon_sam_network_logon_ex
                        : rpccli_netlogon_sam_network_logon;
 
                result = logon_fn(netlogon_pipe,
                                  state->mem_ctx,
                                  0,
-                                 contact_domain->dcname, /* server name */
+                                 domain->dcname,         /* server name */
                                  name_user,              /* user name */
                                  name_domain,            /* target domain */
                                  global_myname(),        /* workstation */
@@ -1347,10 +1316,10 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                attempts += 1;
 
                if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
-                   && contact_domain->can_do_samlogon_ex) {
+                   && domain->can_do_samlogon_ex) {
                        DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
                                  "retrying with NetSamLogon\n"));
-                       contact_domain->can_do_samlogon_ex = false;
+                       domain->can_do_samlogon_ex = false;
                        retry = true;
                        continue;
                }
@@ -1359,7 +1328,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                   might not yet have noticed that the DC has killed
                   our connection. */
 
-               if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
+               if (!rpccli_is_connected(netlogon_pipe)) {
                        retry = true;
                        continue;
                }
@@ -1375,7 +1344,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                                "password was changed and we didn't know it. "
                                 "Killing connections to domain %s\n",
                                name_domain));
-                       invalidate_cm_connection(&contact_domain->conn);
+                       invalidate_cm_connection(&domain->conn);
                        retry = true;
                }
 
@@ -1394,7 +1363,7 @@ static NTSTATUS winbindd_dual_pam_auth_samlogon(struct winbindd_domain *domain,
                NTSTATUS status_tmp;
                uint32 acct_flags;
 
-               status_tmp = cm_connect_sam(contact_domain, state->mem_ctx,
+               status_tmp = cm_connect_sam(domain, state->mem_ctx,
                                            &samr_pipe, &samr_domain_handle);
 
                if (!NT_STATUS_IS_OK(status_tmp)) {
@@ -1548,7 +1517,7 @@ enum winbindd_result winbindd_dual_pam_auth(struct winbindd_domain *domain,
                    NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED) ||
                    NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) ||
                    NT_STATUS_EQUAL(result, NT_STATUS_WRONG_PASSWORD)) {
-                       goto process_result;
+                       goto done;
                }
 
                if (state->request->flags & WBFLAG_PAM_FALLBACK_AFTER_KRB5) {
@@ -1805,7 +1774,6 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
        const char *name_user = NULL;
        const char *name_domain = NULL;
        const char *workstation;
-       struct winbindd_domain *contact_domain;
        int attempts = 0;
        bool retry;
 
@@ -1870,22 +1838,15 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
                                           state->request->data.auth_crap.nt_resp_len);
        }
 
-       /* what domain should we contact? */
+       if (strequal(name_domain, get_global_sam_name())) {
+               DATA_BLOB chal_blob = data_blob_const(
+                       state->request->data.auth_crap.chal,
+                       sizeof(state->request->data.auth_crap.chal));
 
-       if ( IS_DC ) {
-               if (!(contact_domain = find_domain_from_name(name_domain))) {
-                       DEBUG(3, ("Authentication for domain for [%s] -> [%s]\\[%s] failed as %s is not a trusted domain\n",
-                                 state->request->data.auth_crap.user, name_domain, name_user, name_domain));
-                       result = NT_STATUS_NO_SUCH_USER;
-                       goto done;
-               }
-       } else {
-               if (is_myname(name_domain)) {
-                       DEBUG(3, ("Authentication for domain %s (local domain to this server) not supported at this stage\n", name_domain));
-                       result =  NT_STATUS_NO_SUCH_USER;
-                       goto done;
-               }
-               contact_domain = find_our_domain();
+               result = winbindd_dual_auth_passdb(
+                       state->mem_ctx, name_domain, name_user,
+                       &chal_blob, &lm_resp, &nt_resp, &info3);
+               goto process_result;
        }
 
        do {
@@ -1894,7 +1855,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
                retry = false;
 
                netlogon_pipe = NULL;
-               result = cm_connect_netlogon(contact_domain, &netlogon_pipe);
+               result = cm_connect_netlogon(domain, &netlogon_pipe);
 
                if (!NT_STATUS_IS_OK(result)) {
                        DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n",
@@ -1902,14 +1863,14 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
                        goto done;
                }
 
-               logon_fn = contact_domain->can_do_samlogon_ex
+               logon_fn = domain->can_do_samlogon_ex
                        ? rpccli_netlogon_sam_network_logon_ex
                        : rpccli_netlogon_sam_network_logon;
 
                result = logon_fn(netlogon_pipe,
                                  state->mem_ctx,
                                  state->request->data.auth_crap.logon_parameters,
-                                 contact_domain->dcname,
+                                 domain->dcname,
                                  name_user,
                                  name_domain,
                                  /* Bug #3248 - found by Stefan Burkei. */
@@ -1920,10 +1881,10 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
                                  &info3);
 
                if ((NT_STATUS_V(result) == DCERPC_FAULT_OP_RNG_ERROR)
-                   && contact_domain->can_do_samlogon_ex) {
+                   && domain->can_do_samlogon_ex) {
                        DEBUG(3, ("Got a DC that can not do NetSamLogonEx, "
                                  "retrying with NetSamLogon\n"));
-                       contact_domain->can_do_samlogon_ex = false;
+                       domain->can_do_samlogon_ex = false;
                        retry = true;
                        continue;
                }
@@ -1934,7 +1895,7 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
                   might not yet have noticed that the DC has killed
                   our connection. */
 
-               if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) {
+               if (!rpccli_is_connected(netlogon_pipe)) {
                        retry = true;
                        continue;
                }
@@ -1949,12 +1910,14 @@ enum winbindd_result winbindd_dual_pam_auth_crap(struct winbindd_domain *domain,
                                "password was changed and we didn't know it. "
                                 "Killing connections to domain %s\n",
                                name_domain));
-                       invalidate_cm_connection(&contact_domain->conn);
+                       invalidate_cm_connection(&domain->conn);
                        retry = true;
                }
 
        } while ( (attempts < 2) && retry );
 
+process_result:
+
        if (NT_STATUS_IS_OK(result)) {
 
                wcache_invalidate_samlogon(find_domain_from_name(name_domain), info3);
@@ -2013,6 +1976,10 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
        struct winbindd_domain *contact_domain;
        NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL;
 
+       /* Ensure null termination */
+       state->request->data.chauthtok.user[
+               sizeof(state->request->data.chauthtok.user)-1]='\0';
+
        DEBUG(3, ("[%5lu]: pam chauthtok %s\n", (unsigned long)state->pid,
                state->request->data.chauthtok.user));
 
@@ -2038,7 +2005,7 @@ void winbindd_pam_chauthtok(struct winbindd_cli_state *state)
                set_auth_errors(state->response, NT_STATUS_NO_SUCH_USER);
                DEBUG(5, ("winbindd_pam_chauthtok: canonicalize_username %s failed with %s"
                          "(PAM: %d)\n",
-                         state->request->data.auth.user,
+                         state->request->data.chauthtok.user,
                          state->response->data.auth.nt_status_string,
                          state->response->data.auth.pam_error));
                request_error(state);
@@ -2219,9 +2186,6 @@ void winbindd_pam_logoff(struct winbindd_cli_state *state)
        uid_t caller_uid = (uid_t)-1;
        uid_t request_uid = state->request->data.logoff.uid;
 
-       DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
-               state->request->data.logoff.user));
-
        /* Ensure null termination */
        state->request->data.logoff.user
                [sizeof(state->request->data.logoff.user)-1]='\0';
@@ -2229,7 +2193,10 @@ void winbindd_pam_logoff(struct winbindd_cli_state *state)
        state->request->data.logoff.krb5ccname
                [sizeof(state->request->data.logoff.krb5ccname)-1]='\0';
 
-       if (request_uid == (gid_t)-1) {
+       DEBUG(3, ("[%5lu]: pam logoff %s\n", (unsigned long)state->pid,
+               state->request->data.logoff.user));
+
+       if (request_uid == (uid_t)-1) {
                goto failed;
        }