updated the 3.0 branch from the head branch - ready for alpha18
[ira/wip.git] / source3 / nsswitch / winbindd_pam.c
index ce619ca3d81caa4af066ca25d4bddc4d4871f997..e608f826c917f2f9b64aaa59e9b9382d9885c799 100644 (file)
@@ -1,12 +1,11 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 3.0
+   Unix SMB/CIFS implementation.
 
    Winbind daemon - pam auth funcions
 
    Copyright (C) Andrew Tridgell 2000
    Copyright (C) Tim Potter 2001
-   Copyright (C) Andrew Bartlett 2001
+   Copyright (C) Andrew Bartlett 2001-2002
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -25,6 +24,9 @@
 
 #include "winbindd.h"
 
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_WINBIND
+
 /* Return a password structure from a username.  */
 
 enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) 
@@ -38,7 +40,7 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
         NET_USER_INFO_3 info3;
         struct cli_state *cli = NULL;
        uchar chal[8];
-       TALLOC_CTX *mem_ctx;
+       TALLOC_CTX *mem_ctx = NULL;
        DATA_BLOB lm_resp;
        DATA_BLOB nt_resp;
 
@@ -49,24 +51,22 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
 
        if (!(mem_ctx = talloc_init_named("winbind pam auth for %s", state->request.data.auth.user))) {
                DEBUG(0, ("winbindd_pam_auth: could not talloc_init()!\n"));
-               return WINBINDD_ERROR;
+               result = NT_STATUS_NO_MEMORY;
+               goto done;
        }
 
        /* Parse domain and username */
        
        if (!parse_domain_user(state->request.data.auth.user, name_domain, 
                               name_user)) {
-               DEBUG(5,("no domain seperator (%s) in username (%s) - failing auth\n", lp_winbind_separator(), state->request.data.auth.user));
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+               DEBUG(5,("no domain separator (%s) in username (%s) - failing auth\n", lp_winbind_separator(), state->request.data.auth.user));
+               result = NT_STATUS_INVALID_PARAMETER;
+               goto done;
        }
 
        passlen = strlen(state->request.data.auth.pass);
                
-       if (!*state->request.data.auth.pass) {
-               return WINBINDD_ERROR;
-               talloc_destroy(mem_ctx);
-       } else {
+       {
                unsigned char local_lm_response[24];
                unsigned char local_nt_response[24];
                
@@ -87,8 +87,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
                 lp_workgroup(), trust_passwd, &last_change_time)) {
                DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
                           "password for domain %s\n", lp_workgroup()));
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+               result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               goto done;
        }
 
        /* We really don't care what LUID we give the user. */
@@ -96,7 +96,8 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
        generate_random_buffer( (unsigned char *)&smb_uid_low, 4, False);
 
        ZERO_STRUCT(info3);
-
+       
+       /* Don't shut this down - it belongs to the connection cache code */
         result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
 
         if (!NT_STATUS_IS_OK(result)) {
@@ -113,10 +114,18 @@ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state)
        uni_group_cache_store_netlogon(mem_ctx, &info3);
 done:
 
-       if (cli) 
-               cli_shutdown(cli);
+       state->response.data.auth.nt_status = NT_STATUS_V(result);
+       fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
+       fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
+       state->response.data.auth.pam_error = nt_status_to_pam(result);
+
+       DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("Plain-text authenticaion for user %s returned %s (PAM: %d)\n", 
+             state->request.data.auth.user, 
+             state->response.data.auth.nt_status_string,
+             state->response.data.auth.pam_error));          
 
-       talloc_destroy(mem_ctx);
+       if (mem_ctx) 
+               talloc_destroy(mem_ctx);
        
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
@@ -130,7 +139,7 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
        time_t last_change_time;
         NET_USER_INFO_3 info3;
         struct cli_state *cli = NULL;
-       TALLOC_CTX *mem_ctx;
+       TALLOC_CTX *mem_ctx = NULL;
        const char *domain = NULL;
 
        DATA_BLOB lm_resp, nt_resp;
@@ -138,11 +147,12 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
        extern pstring global_myname;
 
        DEBUG(3, ("[%5d]: pam auth crap domain: %s user: %s\n", state->pid,
-                 state->request.data.auth_crap.user, state->request.data.auth_crap.user));
+                 state->request.data.auth_crap.domain, state->request.data.auth_crap.user));
 
        if (!(mem_ctx = talloc_init_named("winbind pam auth crap for %s", state->request.data.auth.user))) {
                DEBUG(0, ("winbindd_pam_auth_crap: could not talloc_init()!\n"));
-               return WINBINDD_ERROR;
+               result = NT_STATUS_NO_MEMORY;
+               goto done;
        }
 
        if (*state->request.data.auth_crap.domain) {
@@ -151,14 +161,14 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                domain = talloc_strdup(mem_ctx, lp_workgroup());
        } else {
                DEBUG(5,("no domain specified with username (%s) - failing auth\n", state->request.data.auth.user));
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+               result = NT_STATUS_INVALID_PARAMETER;
+               goto done;
        }
 
        if (!domain) {
                DEBUG(0,("winbindd_pam_auth_crap: talloc_strdup failed!\n"));
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+               result = NT_STATUS_NO_MEMORY;
+               goto done;
        }
 
        lm_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.lm_resp, state->request.data.auth_crap.lm_resp_len);
@@ -172,16 +182,17 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                 lp_workgroup(), trust_passwd, &last_change_time)) {
                DEBUG(0, ("winbindd_pam_auth: could not fetch trust account "
                           "password for domain %s\n", lp_workgroup()));
-               talloc_destroy(mem_ctx);
-               return WINBINDD_ERROR;
+               result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
+               goto done;
        }
 
        ZERO_STRUCT(info3);
 
+       /* Don't shut this down - it belongs to the connection cache code */
         result = cm_get_netlogon_cli(lp_workgroup(), trust_passwd, &cli);
 
         if (!NT_STATUS_IS_OK(result)) {
-                DEBUG(3, ("could not open handle to NETLOGON pipe\n"));
+                DEBUG(3, ("could not open handle to NETLOGON pipe (error: %s)\n", nt_errstr(result)));
                 goto done;
         }
 
@@ -191,13 +202,26 @@ enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state)
                                                lm_resp, nt_resp, 
                                                &info3);
         
-       uni_group_cache_store_netlogon(mem_ctx, &info3);
+       if (NT_STATUS_IS_OK(result)) {
+               uni_group_cache_store_netlogon(mem_ctx, &info3);
+       }
+
 done:
-       talloc_destroy(mem_ctx);
 
-       if (cli)
-               cli_shutdown(cli);
+       state->response.data.auth.nt_status = NT_STATUS_V(result);
+       fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
+       fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
+       state->response.data.auth.pam_error = nt_status_to_pam(result);
 
+       DEBUG(NT_STATUS_IS_OK(result) ? 5 : 2, ("NTLM CRAP authenticaion for user [%s]\\[%s] returned %s (PAM: %d)\n", 
+             state->request.data.auth_crap.domain, 
+             state->request.data.auth_crap.user, 
+             state->response.data.auth.nt_status_string,
+             state->response.data.auth.pam_error));          
+
+       if (mem_ctx) 
+               talloc_destroy(mem_ctx);
+       
        return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }
 
@@ -205,10 +229,9 @@ done:
 
 enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
 {
+       NTSTATUS result;
        char *oldpass, *newpass;
        fstring domain, user;
-       uchar nt_oldhash[16];
-       uchar lm_oldhash[16];
        CLI_POLICY_HND *hnd;
 
        DEBUG(3, ("[%5d]: pam chauthtok %s\n", state->pid,
@@ -220,8 +243,10 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
                return WINBINDD_ERROR;
 
        if (!parse_domain_user(state->request.data.chauthtok.user, domain, 
-                              user))
-               return WINBINDD_ERROR;
+                              user)) {
+               result = NT_STATUS_INVALID_PARAMETER;
+               goto done;
+       }
 
        /* Change password */
 
@@ -230,14 +255,25 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state)
 
        /* Get sam handle */
 
-       if (!(hnd = cm_get_sam_handle(domain)))
-               return WINBINDD_ERROR;
+       if (!(hnd = cm_get_sam_handle(domain))) {
+               DEBUG(1, ("could not get SAM handle on DC for %s\n", domain));
+               result = NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND;
+               goto done;
+       }
 
        if (!cli_oem_change_password(hnd->cli, user, newpass, oldpass)) {
-               DEBUG(0, ("password change failed for user %s/%s\n", domain, 
+               DEBUG(1, ("password change failed for user %s/%s\n", domain, 
                          user));
-               return WINBINDD_ERROR;
+               result = NT_STATUS_WRONG_PASSWORD;
+       } else {
+               result = NT_STATUS_OK;
        }
-    
-       return WINBINDD_OK;
+
+done:    
+       state->response.data.auth.nt_status = NT_STATUS_V(result);
+       fstrcpy(state->response.data.auth.nt_status_string, nt_errstr(result));
+       fstrcpy(state->response.data.auth.error_string, nt_errstr(result));
+       state->response.data.auth.pam_error = nt_status_to_pam(result);
+
+       return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR;
 }