diff options
author | Jeremy Allison <jra@samba.org> | 2002-04-30 13:28:41 +0000 |
---|---|---|
committer | Jeremy Allison <jra@samba.org> | 2002-04-30 13:28:41 +0000 |
commit | d04b55f2186fb8af998cf61c576771a5f72f4892 (patch) | |
tree | 9ff8c3a7cf34cefc0ee9a550a3bb1236a9e77595 /source/nsswitch/winbindd_pam.c | |
parent | 73267ca42d9eddabb71b31b4c5068ebbe7bc9f7c (diff) | |
download | samba-d04b55f2186fb8af998cf61c576771a5f72f4892.tar.gz samba-d04b55f2186fb8af998cf61c576771a5f72f4892.tar.xz samba-d04b55f2186fb8af998cf61c576771a5f72f4892.zip |
Start of merge to 2_2_RELEASE branch for release.
Jeremy.
Diffstat (limited to 'source/nsswitch/winbindd_pam.c')
-rw-r--r-- | source/nsswitch/winbindd_pam.c | 261 |
1 files changed, 177 insertions, 84 deletions
diff --git a/source/nsswitch/winbindd_pam.c b/source/nsswitch/winbindd_pam.c index 2b6a79694d2..5adbf98789f 100644 --- a/source/nsswitch/winbindd_pam.c +++ b/source/nsswitch/winbindd_pam.c @@ -1,10 +1,11 @@ /* - Unix SMB/Netbios implementation. - Version 3.0 + Unix SMB/CIFS implementation. - Winbind daemon - pam auuth funcions + Winbind daemon - pam auth funcions Copyright (C) Andrew Tridgell 2000 + Copyright (C) Tim Potter 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 @@ -23,127 +24,207 @@ #include "winbindd.h" -/* Copy of parse_domain_user from winbindd_util.c. Parse a string of the - form DOMAIN\user into a domain and a user */ - -static BOOL wb_parse_domain_user(char *domuser, fstring domain, fstring user) -{ - char *p; - char *sep = lp_winbind_separator(); - - p = strchr(domuser,*sep); - - if (!p) - return False; - - fstrcpy(user, p+1); - fstrcpy(domain, domuser); - domain[PTR_DIFF(p, domuser)] = 0; - strupper(domain); - return True; -} - -/* Return a password structure from a username. Specify whether cached data - can be returned. */ +/* Return a password structure from a username. */ enum winbindd_result winbindd_pam_auth(struct winbindd_cli_state *state) { - BOOL result, user_exists; + NTSTATUS result; fstring name_domain, name_user; int passlen; + unsigned char trust_passwd[16]; + time_t last_change_time; + uint32 smb_uid_low; + NET_USER_INFO_3 info3; + struct cli_state *cli = NULL; + uchar chal[8]; + TALLOC_CTX *mem_ctx = NULL; + DATA_BLOB lm_resp; + DATA_BLOB nt_resp; + + extern pstring global_myname; DEBUG(3, ("[%5d]: pam auth %s\n", state->pid, state->request.data.auth.user)); - /* Parse domain and username */ + 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")); + result = NT_STATUS_NO_MEMORY; + goto done; + } - if (!wb_parse_domain_user(state->request.data.auth.user, name_domain, - name_user)) - return WINBINDD_ERROR; + /* Parse domain and username */ + + if (!parse_domain_user(state->request.data.auth.user, name_domain, + name_user)) { + 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); + + { + unsigned char local_lm_response[24]; + unsigned char local_nt_response[24]; + + generate_random_buffer(chal, 8, False); + SMBencrypt( (const uchar *)state->request.data.auth.pass, chal, local_lm_response); + + SMBNTencrypt((const uchar *)state->request.data.auth.pass, chal, local_nt_response); + + lm_resp = data_blob_talloc(mem_ctx, local_lm_response, sizeof(local_lm_response)); + nt_resp = data_blob_talloc(mem_ctx, local_nt_response, sizeof(local_nt_response)); + } + + /* + * Get the machine account password for our primary domain + */ - /* So domain_client_validate() actually opens a new connection - for each authentication performed. This can theoretically - be optimised to use an already open IPC$ connection. */ + if (!secrets_fetch_trust_account_password( + lp_workgroup(), trust_passwd, &last_change_time)) { + DEBUG(0, ("winbindd_pam_auth: could not fetch trust account " + "password for domain %s\n", lp_workgroup())); + result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto done; + } - result = domain_client_validate(name_user, name_domain, - state->request.data.auth.pass, - passlen, - state->request.data.auth.pass, - passlen, &user_exists, NULL); + /* We really don't care what LUID we give the user. */ - return result ? WINBINDD_OK : WINBINDD_ERROR; -} + 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)) { + DEBUG(3, ("could not open handle to NETLOGON pipe\n")); + goto done; + } + + result = cli_netlogon_sam_network_logon(cli, mem_ctx, + name_user, name_domain, + global_myname, chal, + lm_resp, nt_resp, + &info3); + +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); + + 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)); + + if (mem_ctx) + talloc_destroy(mem_ctx); + + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; +} + /* Challenge Response Authentication Protocol */ -#if ALLOW_WINBIND_AUTH_CRAP enum winbindd_result winbindd_pam_auth_crap(struct winbindd_cli_state *state) { NTSTATUS result; - fstring name_domain, name_user; unsigned char trust_passwd[16]; time_t last_change_time; - uint32 smb_uid_low; NET_USER_INFO_3 info3; - NET_ID_INFO_CTR ctr; - struct cli_state *cli; + struct cli_state *cli = NULL; + TALLOC_CTX *mem_ctx = NULL; + const char *domain = NULL; - DEBUG(3, ("[%5d]: pam auth crap %s\n", state->pid, - state->request.data.auth_crap.user)); + DATA_BLOB lm_resp, nt_resp; - /* Parse domain and username */ + extern pstring global_myname; - if (!wb_parse_domain_user(state->request.data.auth_crap.user, name_domain, - name_user)) - return WINBINDD_ERROR; + DEBUG(3, ("[%5d]: pam auth crap domain: %s user: %s\n", state->pid, + 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")); + result = NT_STATUS_NO_MEMORY; + goto done; + } + + if (*state->request.data.auth_crap.domain) { + domain = talloc_strdup(mem_ctx, state->request.data.auth_crap.domain); + } else if (lp_winbind_use_default_domain()) { + domain = talloc_strdup(mem_ctx, lp_workgroup()); + } else { + DEBUG(5,("no domain specified with username (%s) - failing auth\n", state->request.data.auth.user)); + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + if (!domain) { + DEBUG(0,("winbindd_pam_auth_crap: talloc_strdup failed!\n")); + 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); + nt_resp = data_blob_talloc(mem_ctx, state->request.data.auth_crap.nt_resp, state->request.data.auth_crap.nt_resp_len); + /* * Get the machine account password for our primary domain */ if (!secrets_fetch_trust_account_password( lp_workgroup(), trust_passwd, &last_change_time)) { - DEBUG(0, ("winbindd_pam_auth_crap: could not fetch trust account " + DEBUG(0, ("winbindd_pam_auth: could not fetch trust account " "password for domain %s\n", lp_workgroup())); - return WINBINDD_ERROR; + result = NT_STATUS_CANT_ACCESS_DOMAIN_INFO; + goto done; } - /* We really don't care what LUID we give the user. */ - - 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)) { - DEBUG(3, ("could not open handle to NETLOGON pipe\n")); + DEBUG(3, ("could not open handle to NETLOGON pipe (%s)\n", nt_errstr(result))); goto done; } - result = cli_nt_login_network(cli, name_domain, name_user, smb_uid_low, - state->request.data.auth_crap.chal, - state->request.data.auth_crap.lm_resp, - state->request.data.auth_crap.nt_resp, - &ctr, &info3); - - cli_shutdown(cli); - - done: + result = cli_netlogon_sam_network_logon(cli, mem_ctx, + state->request.data.auth_crap.user, domain, + global_myname, state->request.data.auth_crap.chal, + lm_resp, nt_resp, + &info3); + +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); + + 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; } -#endif /* Change a user password */ 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, state->request.data.chauthtok.user)); @@ -153,26 +234,38 @@ enum winbindd_result winbindd_pam_chauthtok(struct winbindd_cli_state *state) if (state == NULL) return WINBINDD_ERROR; - if (!wb_parse_domain_user(state->request.data.chauthtok.user, domain, user)) - return WINBINDD_ERROR; + if (!parse_domain_user(state->request.data.chauthtok.user, domain, + user)) { + result = NT_STATUS_INVALID_PARAMETER; + goto done; + } + + /* Change password */ oldpass = state->request.data.chauthtok.oldpass; newpass = state->request.data.chauthtok.newpass; - nt_lm_owf_gen(oldpass, nt_oldhash, lm_oldhash); + /* Get sam handle */ - /* Change password */ + 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 0 + if (!cli_oem_change_password(hnd->cli, user, newpass, oldpass)) { + DEBUG(1, ("password change failed for user %s/%s\n", domain, + user)); + result = NT_STATUS_WRONG_PASSWORD; + } else { + result = NT_STATUS_OK; + } - /* XXX */ +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); - if (!msrpc_sam_ntchange_pwd(server_state.controller, domain, user, - lm_oldhash, nt_oldhash, newpass)) { - DEBUG(0, ("password change failed for user %s/%s\n", domain, user)); - return WINBINDD_ERROR; - } -#endif - - return WINBINDD_OK; + return NT_STATUS_IS_OK(result) ? WINBINDD_OK : WINBINDD_ERROR; } |