summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2001-10-31 10:46:25 +0000
committerAndrew Bartlett <abartlet@samba.org>2001-10-31 10:46:25 +0000
commit60f0627afb167faad57385d44f0b587186a7ac2b (patch)
treef7a03b2e1b90d1234c48fffaeaf92986060a0e77 /source3/smbd
parent83575bd3868ef3993107460d2c8e05f382eae351 (diff)
downloadsamba-60f0627afb167faad57385d44f0b587186a7ac2b.tar.gz
samba-60f0627afb167faad57385d44f0b587186a7ac2b.tar.bz2
samba-60f0627afb167faad57385d44f0b587186a7ac2b.zip
This is a farily large patch (3300 lines) and reworks most of the AuthRewrite
code. In particular this assists tpot in some of his work, becouse it provides the connection between the authenticaion and the vuid generation. Major Changes: - Fully malloc'ed structures. - Massive rework of the code so that all structures are made and destroyed using malloc and free, rather than hanging around on the stack. - SAM_ACCOUNT unix uids and gids are now pointers to the same, to allow them to be declared 'invalid' without the chance that people might get ROOT by default. - kill off some of the "DOMAIN\user" lookups. These can be readded at a more appropriate place (probably domain_client_validate.c) in the future. They don't belong in session setups. - Massive introduction of DATA_BLOB structures, particularly for passwords. - Use NTLMSSP flags to tell the backend what its getting, rather than magic lenghths. - Fix winbind back up again, but tpot is redoing this soon anyway. - Abstract much of the work in srv_netlog_nt back into auth helper functions. This is a LARGE change, and any assistance is testing it is appriciated. Domain logons are still broken (as far as I can tell) but other functionality seems intact. Needs testing with a wide variety of MS clients. Andrew Bartlett (This used to be commit f70fb819b2f57bd57232b51808345e2319d52f6c)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/auth.c263
-rw-r--r--source3/smbd/auth_domain.c2
-rw-r--r--source3/smbd/auth_rhosts.c40
-rw-r--r--source3/smbd/auth_server.c27
-rw-r--r--source3/smbd/auth_smbpasswd.c228
-rw-r--r--source3/smbd/auth_unix.c17
-rw-r--r--source3/smbd/auth_util.c564
-rw-r--r--source3/smbd/password.c51
-rw-r--r--source3/smbd/reply.c37
-rw-r--r--source3/smbd/service.c12
-rw-r--r--source3/smbd/sesssetup.c356
11 files changed, 1086 insertions, 511 deletions
diff --git a/source3/smbd/auth.c b/source3/smbd/auth.c
index 4bdbdf5555..4d1a566833 100644
--- a/source3/smbd/auth.c
+++ b/source3/smbd/auth.c
@@ -50,183 +50,160 @@ static BOOL check_domain_match(char *user, char *domain)
This functions does NOT need to be in a become_root()/unbecome_root() pair
as it makes the calls itself when needed.
+
+ The return value takes precedence over the contents of the server_info
+ struct. When the return is other than NT_STATUS_NOPROBLEMO the contents
+ of that structure is undefined.
+
****************************************************************************/
NTSTATUS check_password(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info)
+ auth_serversupplied_info **server_info)
{
NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
BOOL done_pam = False;
-
- DEBUG(3, ("check_password: Checking password for smb user %s\\%s@%s with the new password interface\n",
- user_info->smb_username.str, user_info->requested_domain.str, user_info->wksta_name.str));
- if (!check_domain_match(user_info->smb_username.str, user_info->domain.str)) {
+
+ DEBUG(3, ("check_password: Checking password for unmapped user %s\\%s@%s with the new password interface\n",
+ user_info->smb_name.str, user_info->client_domain.str, user_info->wksta_name.str));
+
+ /* This needs to be sorted: If it doesn't match, what should we do? */
+ if (!check_domain_match(user_info->smb_name.str, user_info->domain.str)) {
return NT_STATUS_LOGON_FAILURE;
}
if (!NT_STATUS_IS_OK(nt_status)) {
nt_status = check_rhosts_security(user_info, server_info);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(7, ("check_password: Password (rhosts) for user %s suceeded\n", user_info->smb_name.str));
+ } else {
+ DEBUG(5, ("check_password: Password (rhosts)for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
+
+ }
}
if ((lp_security() == SEC_DOMAIN) && !NT_STATUS_IS_OK(nt_status)) {
nt_status = check_domain_security(user_info, server_info);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(7, ("check_password: Password (domain) for user %s suceeded\n", user_info->smb_name.str));
+ } else {
+ DEBUG(5, ("check_password: Password (domain) for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
+
+ }
}
if ((lp_security() == SEC_SERVER) && !NT_STATUS_IS_OK(nt_status)) {
nt_status = check_server_security(user_info, server_info);
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(7, ("check_password: Password (server) for user %s suceeded\n", user_info->smb_name.str));
+ } else {
+ DEBUG(5, ("check_password: Password (server) for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
+
+ }
}
if (lp_security() >= SEC_SERVER) {
- smb_user_control(user_info->unix_username.str, nt_status);
+ smb_user_control(user_info, *server_info, nt_status);
}
if (!NT_STATUS_IS_OK(nt_status)) {
- if ((user_info->plaintext_password.len > 0)
- && (!lp_plaintext_to_smbpasswd())) {
+ if (user_info->encrypted || lp_plaintext_to_smbpasswd()) {
+ nt_status = check_smbpasswd_security(user_info, server_info);
+ } else {
nt_status = check_unix_security(user_info, server_info);
done_pam = True;
- } else {
- nt_status = check_smbpasswd_security(user_info, server_info);
}
+
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(7, ("check_password: Password (unix/smbpasswd) for user %s suceeded\n", user_info->smb_name.str));
+ } else {
+ DEBUG(5, ("check_password: Password (unix/smbpasswd) for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
+
+ }
}
+
if (NT_STATUS_IS_OK(nt_status) && !done_pam) {
/* We might not be root if we are an RPC call */
become_root();
- nt_status = smb_pam_accountcheck(user_info->unix_username.str);
+ nt_status = smb_pam_accountcheck(pdb_get_username((*server_info)->sam_account));
unbecome_root();
- }
+ if (NT_STATUS_IS_OK(nt_status)) {
+ DEBUG(5, ("check_password: PAM Account for user %s suceeded\n", user_info->smb_name.str));
+ } else {
+ DEBUG(3, ("check_password: PAM Account for user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
+
+ }
+ }
+
if (NT_STATUS_IS_OK(nt_status)) {
- DEBUG(5, ("check_password: Password for smb user %s suceeded\n", user_info->smb_username.str));
+ DEBUG(5, ("check_password: Password for smb user %s suceeded\n", user_info->smb_name.str));
} else {
- DEBUG(3, ("check_password: Password for smb user %s FAILED with error %s\n", user_info->smb_username.str, get_nt_error_msg(nt_status)));
-
+ DEBUG(3, ("check_password: Password for smb user %s FAILED with error %s\n", user_info->smb_name.str, get_nt_error_msg(nt_status)));
+ ZERO_STRUCTP(server_info);
}
+
return nt_status;
}
/****************************************************************************
- COMPATABILITY INTERFACES:
- ***************************************************************************/
-
-/****************************************************************************
-check if a username/password is OK assuming the password is a 24 byte
-SMB hash
-return True if the password is correct, False otherwise
+ Squash an NT_STATUS return in line with requirements for unauthenticated
+ connections. (session setups in particular)
****************************************************************************/
-NTSTATUS pass_check_smb_with_chal(char *smb_user, char *unix_user,
- char *domain, char* workstation,
- uchar chal[8],
- uchar *lm_pwd, int lm_pwd_len,
- uchar *nt_pwd, int nt_pwd_len)
+NTSTATUS nt_status_squash(NTSTATUS nt_status)
{
-
- auth_usersupplied_info user_info;
- auth_serversupplied_info server_info;
- AUTH_STR ourdomain, theirdomain, unix_username, smb_username,
- wksta_name;
- NTSTATUS result;
+ if NT_STATUS_IS_OK(nt_status) {
+ return nt_status;
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
- ZERO_STRUCT(user_info);
- ZERO_STRUCT(ourdomain);
- ZERO_STRUCT(theirdomain);
- ZERO_STRUCT(smb_username);
- ZERO_STRUCT(wksta_name);
-
- ourdomain.str = lp_workgroup();
- ourdomain.len = strlen(ourdomain.str);
-
- theirdomain.str = domain;
- theirdomain.len = strlen(theirdomain.str);
-
- user_info.requested_domain = theirdomain;
- user_info.domain = ourdomain;
-
- smb_username.str = smb_user;
- smb_username.len = strlen(smb_username.str);
-
- /* If unix user is NULL, use smb user */
-
- unix_username.str = unix_user ? unix_user : smb_user;
- unix_username.len = strlen(unix_username.str);
-
- user_info.unix_username = unix_username;
- user_info.smb_username = smb_username;
-
- wksta_name.str = workstation;
- wksta_name.len = strlen(workstation);
-
- user_info.wksta_name = wksta_name;
-
- memcpy(user_info.chal, chal, 8);
-
- if ((lm_pwd_len >= 24 || nt_pwd_len >= 24) ||
- (lp_encrypted_passwords() && (lm_pwd_len == 0) && lp_null_passwords())) {
- /* if 24 bytes long assume it is an encrypted password */
-
- user_info.lm_resp.buffer = (uint8 *)lm_pwd;
- user_info.lm_resp.len = lm_pwd_len;
- user_info.nt_resp.buffer = (uint8 *)nt_pwd;
- user_info.nt_resp.len = nt_pwd_len;
-
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
+ /* Match WinXP and don't give the game away */
+ return NT_STATUS_LOGON_FAILURE;
} else {
- unsigned char local_lm_response[24];
- unsigned char local_nt_response[24];
-
- /*
- * Not encrypted - do so.
- */
-
- DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n"));
-
- if (lm_pwd_len > 0) {
- SMBencrypt( (uchar *)lm_pwd, user_info.chal, local_lm_response);
- user_info.lm_resp.buffer = (uint8 *)local_lm_response;
- user_info.lm_resp.len = 24;
-
-
- /* WATCH OUT. This doesn't work if the incoming password is incorrectly cased.
- We might want to add a check here and only do an LM in that case */
+ return nt_status;
+ }
+}
- /* This encrypts the lm_pwd feild, which actualy contains the password
- rather than the nt_pwd field becouse that contains nothing */
- SMBNTencrypt((uchar *)lm_pwd, user_info.chal, local_nt_response);
- user_info.nt_resp.buffer = (uint8 *)local_nt_response;
- user_info.nt_resp.len = 24;
- }
-
- user_info.plaintext_password.str = (char *)lm_pwd;
- user_info.plaintext_password.len = lm_pwd_len;
- }
- result = check_password(&user_info, &server_info);
+/****************************************************************************
+ COMPATABILITY INTERFACES:
+ ***************************************************************************/
- free_serversupplied_info(&server_info); /* No info needed */
+/****************************************************************************
+check if a username/password is OK assuming the password is a 24 byte
+SMB hash
+return True if the password is correct, False otherwise
+****************************************************************************/
- return result;
-}
+static NTSTATUS pass_check_smb(char *smb_name,
+ char *domain,
+ DATA_BLOB lm_pwd,
+ DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext_password,
+ BOOL encrypted)
-NTSTATUS pass_check_smb(char *smb_user, char *unix_user,
- char *domain, char *workstation,
- uchar *lm_pwd, int lm_pwd_len,
- uchar *nt_pwd, int nt_pwd_len)
{
- uchar chal[8];
-
- if (!last_challenge(chal)) {
- generate_random_buffer( chal, 8, False);
- }
-
- return pass_check_smb_with_chal(smb_user, unix_user,
- domain, workstation, chal,
- lm_pwd, lm_pwd_len,
- nt_pwd, nt_pwd_len);
-
+ NTSTATUS nt_status;
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+
+ make_user_info_for_reply(&user_info, smb_name,
+ domain,
+ lm_pwd,
+ nt_pwd,
+ plaintext_password,
+ encrypted);
+
+ nt_status = check_password(user_info, &server_info);
+ free_user_info(&user_info);
+ free_server_info(&server_info);
+ return nt_status;
}
/****************************************************************************
@@ -234,36 +211,32 @@ check if a username/password pair is OK either via the system password
database or the encrypted SMB password database
return True if the password is correct, False otherwise
****************************************************************************/
-BOOL password_ok(char *user, char *password, int pwlen)
+BOOL password_ok(char *smb_name, DATA_BLOB password_blob)
{
- extern fstring remote_machine;
- /*
- * This hack must die! But until I rewrite the rest of samba
- * it must stay - abartlet 2001-08-03
- */
-
- if ((pwlen == 0) && !lp_null_passwords()) {
- DEBUG(4,("Null passwords not allowed.\n"));
- return False;
- }
-
- /* The password could be either NTLM or plain LM. Try NTLM first, but fall-through as
- required. */
- if (NT_STATUS_IS_OK(pass_check_smb(user, NULL, remote_machine, lp_workgroup(), NULL, 0, (unsigned char *)password, pwlen))) {
- return True;
- }
+ DATA_BLOB null_password = data_blob(NULL, 0);
+ extern BOOL global_encrypted_passwords_negotiated;
- if (NT_STATUS_IS_OK(pass_check_smb(user, NULL, remote_machine, lp_workgroup(), (unsigned char *)password, pwlen, NULL, 0))) {
- return True;
+ if (global_encrypted_passwords_negotiated) {
+ /*
+ * The password could be either NTLM or plain LM. Try NTLM first,
+ * but fall-through as required.
+ * NTLMv2 makes no sense here.
+ */
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, password_blob, null_password, global_encrypted_passwords_negotiated))) {
+ return True;
+ }
+
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), password_blob, null_password, null_password, global_encrypted_passwords_negotiated))) {
+ return True;
+ }
+ } else {
+ if (NT_STATUS_IS_OK(pass_check_smb(smb_name, lp_workgroup(), null_password, null_password, password_blob, global_encrypted_passwords_negotiated))) {
+ return True;
+ }
}
return False;
}
-/* Free a auth_serversupplied_info structure */
-void free_serversupplied_info(auth_serversupplied_info *server_info)
-{
- SAFE_FREE(server_info->group_rids);
-}
diff --git a/source3/smbd/auth_domain.c b/source3/smbd/auth_domain.c
index bcd41bacdb..f20da19607 100644
--- a/source3/smbd/auth_domain.c
+++ b/source3/smbd/auth_domain.c
@@ -29,7 +29,7 @@ BOOL global_machine_password_needs_changing = False;
****************************************************************************/
NTSTATUS check_domain_security(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info)
+ auth_serversupplied_info **server_info)
{
NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
char *p, *pserver;
diff --git a/source3/smbd/auth_rhosts.c b/source3/smbd/auth_rhosts.c
index 9f5f1e10e5..9c07e48a9b 100644
--- a/source3/smbd/auth_rhosts.c
+++ b/source3/smbd/auth_rhosts.c
@@ -131,11 +131,11 @@ static BOOL check_user_equiv(const char *user, const char *remote, const char *e
/****************************************************************************
check for a possible hosts equiv or rhosts entry for the user
****************************************************************************/
-static BOOL check_hosts_equiv(char *user) /* should be const... */
+
+static BOOL check_hosts_equiv(struct passwd *pass)
{
char *fname = NULL;
pstring rhostsfile;
- struct passwd *pass = Get_Pwnam(user);
if (!pass)
return(False);
@@ -149,15 +149,15 @@ static BOOL check_hosts_equiv(char *user) /* should be const... */
}
if (lp_use_rhosts())
- {
- char *home = pass->pw_dir;
- if (home) {
- slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
- if (check_user_equiv(pass->pw_name,client_name(),rhostsfile))
- return(True);
- }
- }
-
+ {
+ char *home = pass->pw_dir;
+ if (home) {
+ slprintf(rhostsfile, sizeof(rhostsfile)-1, "%s/.rhosts", home);
+ if (check_user_equiv(pass->pw_name,client_name(),rhostsfile))
+ return(True);
+ }
+ }
+
return(False);
}
@@ -166,15 +166,21 @@ static BOOL check_hosts_equiv(char *user) /* should be const... */
****************************************************************************/
NTSTATUS check_rhosts_security(const auth_usersupplied_info *user_info,
- auth_serversupplied_info *server_info)
+ auth_serversupplied_info **server_info)
{
NTSTATUS nt_status = NT_STATUS_LOGON_FAILURE;
-
- become_root();
- if (check_hosts_equiv(user_info->unix_username.str)) {
- nt_status = NT_STATUS_OK;
+ struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
+
+ if (pass) {
+ become_root();
+ if (check_hosts_equiv(pass)) {
+ nt_status = NT_STATUS_OK;
+ make_server_info_pw(server_info, pass);
+ }
+ unbecome_root();
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
}
- unbecome_root();
return nt_status;
}
diff --git a/source3/smbd/auth_server.c b/source3/smbd/auth_server.c
index 520417e3e0..ddbc284d50 100644
--- a/source3/smbd/auth_server.c
+++ b/source3/smbd/auth_server.c
@@ -115,7 +115,7 @@ struct cli_state *server_cryptkey(void)
- Validate a password with the password server.
****************************************************************************/
-NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
+NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info)
{
struct cli_state *cli;
static unsigned char badpass[24];
@@ -134,8 +134,8 @@ NTSTATUS check_server_security(const auth_usersupplied_info *user_info, auth_ser
if(badpass[0] == 0)
memset(badpass, 0x1f, sizeof(badpass));
- if((user_info->nt_resp.len == sizeof(badpass)) &&
- !memcmp(badpass, user_info->nt_resp.buffer, sizeof(badpass))) {
+ if((user_info->nt_resp.length == sizeof(badpass)) &&
+ !memcmp(badpass, user_info->nt_resp.data, sizeof(badpass))) {
/*
* Very unlikely, our random bad password is the same as the users
* password.
@@ -206,11 +206,11 @@ use this machine as the password server.\n"));
* not guest enabled, we can try with the real password.
*/
- if (!cli_session_setup(cli, user_info->smb_username.str,
- (char *)user_info->lm_resp.buffer,
- user_info->lm_resp.len,
- (char *)user_info->nt_resp.buffer,
- user_info->nt_resp.len,
+ if (!cli_session_setup(cli, user_info->smb_name.str,
+ (char *)user_info->lm_resp.data,
+ user_info->lm_resp.length,
+ (char *)user_info->nt_resp.data,
+ user_info->nt_resp.length,
user_info->domain.str)) {
DEBUG(1,("password server %s rejected the password\n", cli->desthost));
/* Make this cli_nt_error() when the conversion is in */
@@ -227,5 +227,16 @@ use this machine as the password server.\n"));
cli_ulogoff(cli);
+ if NT_STATUS_IS_OK(nt_status) {
+ struct passwd *pass = Get_Pwnam(user_info->internal_username.str);
+ if (pass) {
+ if (!make_server_info_pw(server_info, pass)) {
+ nt_status = NT_STATUS_NO_MEMORY;
+ }
+ } else {
+ nt_status = NT_STATUS_NO_SUCH_USER;
+ }
+ }
+
return(nt_status);
}
diff --git a/source3/smbd/auth_smbpasswd.c b/source3/smbd/auth_smbpasswd.c
index 84ca8d03be..d4283429ce 100644
--- a/source3/smbd/auth_smbpasswd.c
+++ b/source3/smbd/auth_smbpasswd.c
@@ -26,53 +26,65 @@
/****************************************************************************
core of smb password checking routine.
****************************************************************************/
-static BOOL smb_pwd_check_ntlmv1(const uchar *password,
+static BOOL smb_pwd_check_ntlmv1(DATA_BLOB nt_response,
const uchar *part_passwd,
- const uchar *c8,
- char user_sess_key[16])
+ DATA_BLOB sec_blob,
+ uint8 user_sess_key[16])
{
- /* Finish the encryption of part_passwd. */
- uchar p24[24];
-
- if (part_passwd == NULL) {
- DEBUG(10,("No password set - DISALLOWING access\n"));
- /* No password set - always false ! */
- return False;
- }
+ /* Finish the encryption of part_passwd. */
+ uchar p24[24];
+
+ if (part_passwd == NULL) {
+ DEBUG(10,("No password set - DISALLOWING access\n"));
+ /* No password set - always false ! */
+ return False;
+ }
+
+ if (sec_blob.length != 8) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect challange size (%d)\n", sec_blob.length));
+ return False;
+ }
+
+ if (nt_response.length != 24) {
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n", nt_response.length));
+ return False;
+ }
- SMBOWFencrypt(part_passwd, c8, p24);
+ SMBOWFencrypt(part_passwd, sec_blob.data, p24);
if (user_sess_key != NULL)
{
SMBsesskeygen_ntv1(part_passwd, NULL, user_sess_key);
}
-
-
-
+
+
+
#if DEBUG_PASSWORD
DEBUG(100,("Part password (P16) was |"));
dump_data(100, part_passwd, 16);
DEBUG(100,("Password from client was |"));
- dump_data(100, password, 24);
+ dump_data(100, nt_response.data, nt_response.length);
DEBUG(100,("Given challenge was |"));
- dump_data(100, c8, 8);
+ dump_data(100, sec_blob.data, sec_blob.length);
DEBUG(100,("Value from encryption was |"));
dump_data(100, p24, 24);
#endif
- return (memcmp(p24, password, 24) == 0);
+ return (memcmp(p24, nt_response.data, 24) == 0);
}
/****************************************************************************
core of smb password checking routine.
****************************************************************************/
-static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len,
+static BOOL smb_pwd_check_ntlmv2(const DATA_BLOB ntv2_response,
const uchar *part_passwd,
- const uchar *c8,
+ const DATA_BLOB sec_blob,
const char *user, const char *domain,
- char user_sess_key[16])
+ uint8 user_sess_key[16])
{
/* Finish the encryption of part_passwd. */
uchar kr[16];
- uchar resp[16];
+ uchar value_from_encryption[16];
+ uchar client_response[16];
+ DATA_BLOB client_key_data;
if (part_passwd == NULL)
{
@@ -81,25 +93,42 @@ static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len,
return False;
}
+ if (ntv2_response.length < 16) {
+ /* We MUST have more than 16 bytes, or the stuff below will go
+ crazy... */
+ DEBUG(0, ("smb_pwd_check_ntlmv1: incorrect password length (%d)\n",
+ ntv2_response.length));
+ return False;
+ }
+
+ client_key_data = data_blob(ntv2_response.data+16, ntv2_response.length-16);
+ memcpy(client_response, ntv2_response.data, ntv2_response.length);
+
+ if (!client_key_data.data) {
+ return False;
+ }
+
ntv2_owf_gen(part_passwd, user, domain, kr);
- SMBOWFencrypt_ntv2(kr, c8, 8, password+16, pwd_len-16, (char *)resp);
+ SMBOWFencrypt_ntv2(kr, sec_blob, client_key_data, (char *)value_from_encryption);
if (user_sess_key != NULL)
{
- SMBsesskeygen_ntv2(kr, resp, user_sess_key);
+ SMBsesskeygen_ntv2(kr, value_from_encryption, user_sess_key);
}
#if DEBUG_PASSWORD
DEBUG(100,("Part password (P16) was |"));
dump_data(100, part_passwd, 16);
DEBUG(100,("Password from client was |"));
- dump_data(100, password, pwd_len);
+ dump_data(100, ntv2_response.data, ntv2_response.length);
+ DEBUG(100,("Variable data from client was |"));
+ dump_data(100, ntv2_response.data, ntv2_response.length);
DEBUG(100,("Given challenge was |"));
- dump_data(100, c8, 8);
+ dump_data(100, sec_blob.data, sec_blob.length);
DEBUG(100,("Value from encryption was |"));
- dump_data(100, resp, 16);
+ dump_data(100, value_from_encryption, 16);
#endif
-
- return (memcmp(resp, password, 16) == 0);
+ data_blob_clear_free(&client_key_data);
+ return (memcmp(value_from_encryption, client_response, 16) == 0);
}
@@ -107,11 +136,12 @@ static BOOL smb_pwd_check_ntlmv2(const uchar *password, size_t pwd_len,
Do a specific test for an smb password being correct, given a smb_password and
the lanman and NT responses.
****************************************************************************/
-NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, char user_sess_key[16])
+NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *user_info, uint8 user_sess_key[16])
{
const uint8 *nt_pw, *lm_pw;
uint16 acct_ctrl = pdb_get_acct_ctrl(sampass);
-
+ uint32 ntlmssp_flags;
+
if (!user_info || !sampass)
return NT_STATUS_LOGON_FAILURE;
@@ -119,12 +149,12 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use
{
if (lp_null_passwords())
{
- DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", sampass->username));
+ DEBUG(3,("Account for user '%s' has no password and null passwords are allowed.\n", pdb_get_username(sampass)));
return(NT_STATUS_OK);
}
else
{
- DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", sampass->username));
+ DEBUG(3,("Account for user '%s' has no password and null passwords are NOT allowed.\n", pdb_get_username(sampass)));
return(NT_STATUS_LOGON_FAILURE);
}
}
@@ -132,61 +162,84 @@ NTSTATUS sam_password_ok(SAM_ACCOUNT *sampass, const auth_usersupplied_info *use
nt_pw = pdb_get_nt_passwd(sampass);
lm_pw = pdb_get_lanman_passwd(sampass);
- if (nt_pw != NULL && user_info->nt_resp.len > 0) {
- if ((user_info->nt_resp.len > 24 )) {
+ ntlmssp_flags = user_info->ntlmssp_flags;
+
+ if (nt_pw == NULL) {
+ DEBUG(3,("smb_password_ok: NO NT password stored for user %s.\n",
+ pdb_get_username(sampass)));
+ /* No return, we want to check the LM hash below in this case */
+ ntlmssp_flags &= (~(NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_NTLM2));
+ }
+
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_NTLM2) {
/* We have the NT MD4 hash challenge available - see if we can
use it (ie. does it exist in the smbpasswd file).
*/
DEBUG(4,("smb_password_ok: Checking NTLMv2 password\n"));
- if (smb_pwd_check_ntlmv2( user_info->nt_resp.buffer,
- user_info->nt_resp.len,
+ if (smb_pwd_check_ntlmv2( user_info->nt_resp,
nt_pw,
- user_info->chal, user_info->smb_username.str,
- user_info->requested_domain.str,
+ user_info->sec_blob, user_info->smb_name.str,
+ user_info->client_domain.str,
user_sess_key))
{
return NT_STATUS_OK;
} else {
- DEBUG(4,("smb_password_ok: NTLMv2 password check failed\n"));
- return NT_STATUS_WRONG_PASSWORD;
+ DEBUG(3,("smb_password_ok: NTLMv2 password check failed\n"));
+ return NT_STATUS_WRONG_PASSWORD;
}
-
- } else if (lp_ntlm_auth() && (user_info->nt_resp.len == 24)) {
+ } else if (ntlmssp_flags & NTLMSSP_NEGOTIATE_NTLM) {
+ if (lp_ntlm_auth()) {
/* We have the NT MD4 hash challenge available - see if we can
use it (ie. does it exist in the smbpasswd file).
*/
- DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
- if (smb_pwd_check_ntlmv1(user_info->nt_resp.buffer,
- nt_pw, user_info->chal,
- user_sess_key))
- {
- return NT_STATUS_OK;
+ DEBUG(4,("smb_password_ok: Checking NT MD4 password\n"));
+ if (smb_pwd_check_ntlmv1(user_info->nt_resp,
+ nt_pw, user_info->sec_blob,
+ user_sess_key))
+ {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(3,("smb_password_ok: NT MD4 password check failed for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
} else {
- DEBUG(4,("smb_password_ok: NT MD4 password check failed\n"));
- return NT_STATUS_WRONG_PASSWORD;
+ DEBUG(2,("smb_password_ok: NTLMv1 passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
+ /* No return, we want to check the LM hash below in this case */
}
- } else {
- return NT_STATUS_LOGON_FAILURE;
- }
}
- if (lm_pw != NULL && user_info->lm_resp.len == 24) {
- if (lp_lanman_auth()) {
- DEBUG(4,("smb_password_ok: Checking LM password\n"));
- if (smb_pwd_check_ntlmv1(user_info->lm_resp.buffer,
- lm_pw, user_info->chal,
- user_sess_key))
- {
- return NT_STATUS_OK;
- } else {
- DEBUG(4,("smb_password_ok: LM password check failed\n"));
- return NT_STATUS_WRONG_PASSWORD;
- }
+ if (lm_pw == NULL) {
+ DEBUG(3,("smb_password_ok: NO LanMan password set for user %s (and no NT password supplied)\n",pdb_get_username(sampass)));
+ ntlmssp_flags &= (~NTLMSSP_NEGOTIATE_OEM);
+ }
+
+ if (ntlmssp_flags & NTLMSSP_NEGOTIATE_OEM) {
+
+ if (user_info->lm_resp.length != 24) {
+ DEBUG(2,("smb_password_ok: invalid LanMan password length (%d) for user %s\n",
+ user_info->nt_resp.length, pdb_get_username(sampass)));
}
+
+ if (!lp_lanman_auth()) {
+ DEBUG(3,("smb_password_ok: Lanman passwords NOT PERMITTED for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_LOGON_FAILURE;
+ }
+
+ DEBUG(4,("smb_password_ok: Checking LM password\n"));
+ if (smb_pwd_check_ntlmv1(user_info->lm_resp,
+ lm_pw, user_info->sec_blob,
+ user_sess_key))
+ {
+ return NT_STATUS_OK;
+ } else {
+ DEBUG(4,("smb_password_ok: LM password check failed for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_WRONG_PASSWORD;
+ }
}
- /* Should not be reached */
- return NT_STATUS_LOGON_FAILURE;
+ /* Should not be reached, but if they send nothing... */
+ DEBUG(3,("smb_password_ok: NEITHER LanMan nor NT password supplied for user %s\n",pdb_get_username(sampass)));
+ return NT_STATUS_WRONG_PASSWORD;
}
/****************************************************************************
@@ -290,33 +343,58 @@ SMB hash supplied in the user_info structure
return an NT_STATUS constant.
****************************************************************************/
-NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
+NTSTATUS check_smbpasswd_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info)
{
SAM_ACCOUNT *sampass=NULL;
BOOL ret;
NTSTATUS nt_status;
+ uint8 user_sess_key[16];
+ const uint8* lm_hash;
pdb_init_sam(&sampass);
/* get the account information */
become_root();
- ret = pdb_getsampwnam(sampass, user_info->unix_username.str);
+ ret = pdb_getsampwnam(sampass, user_info->internal_username.str);
unbecome_root();
if (ret == False)
{
- DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->unix_username.str));
+ DEBUG(1,("Couldn't find user '%s' in passdb file.\n", user_info->internal_username.str));
pdb_free_sam(&sampass);
return NT_STATUS_NO_SUCH_USER;
}
- nt_status = sam_password_ok(sampass, user_info, (char *)(server_info->session_key));
+ nt_status = sam_password_ok(sampass, user_info, user_sess_key);
- if NT_STATUS_IS_OK(nt_status) {
- nt_status = sam_account_ok(sampass, user_info);
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ pdb_free_sam(&sampass);
+ return nt_status;
}
- pdb_free_sam(&sampass);
+ nt_status = sam_account_ok(sampass, user_info);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ pdb_free_sam(&sampass);
+ return nt_status;
+ }
+
+ if (!make_server_info_sam(server_info, sampass)) {
+ DEBUG(0,("failed to malloc memory for server_info\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ lm_hash = pdb_get_lanman_passwd((*server_info)->sam_account);
+ if (lm_hash) {
+ memcpy((*server_info)->first_8_lm_hash, lm_hash, 8);
+ }
+
+ memcpy((*server_info)->session_key, user_sess_key, sizeof(user_sess_key));
+
return nt_status;
}
+
+
+
+
diff --git a/source3/smbd/auth_unix.c b/source3/smbd/auth_unix.c
index 29a2a6eafb..d456da1fdf 100644
--- a/source3/smbd/auth_unix.c
+++ b/source3/smbd/auth_unix.c
@@ -82,22 +82,27 @@ check if a username/password is OK assuming the password
in PLAIN TEXT
****************************************************************************/
-NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info)
+NTSTATUS check_unix_security(const auth_usersupplied_info *user_info, auth_serversupplied_info **server_info)
{
NTSTATUS nt_status;
struct passwd *pass = NULL;
become_root();
-
- pass = Get_Pwnam(user_info->unix_username.str);
+ pass = Get_Pwnam(user_info->internal_username.str);
nt_status = pass_check(pass,
- pass ? pass->pw_name : user_info->unix_username.str,
- user_info->plaintext_password.str,
- user_info->plaintext_password.len,
+ pass ? pass->pw_name : user_info->internal_username.str,
+ (char *)user_info->plaintext_password.data,
+ user_info->plaintext_password.length-1,
lp_update_encrypted() ?
update_smbpassword_file : NULL,
True);
+
+ if NT_STATUS_IS_OK(nt_status) {
+ if (pass) {
+ make_server_info_pw(server_info, pass);
+ }
+ }
unbecome_root();
diff --git a/source3/smbd/auth_util.c b/source3/smbd/auth_util.c
index d3b9aa7001..297c482af5 100644
--- a/source3/smbd/auth_util.c
+++ b/source3/smbd/auth_util.c
@@ -25,6 +25,8 @@
/* Data to do lanman1/2 password challenge. */
static unsigned char saved_challenge[8];
static BOOL challenge_sent=False;
+extern fstring remote_machine;
+extern pstring global_myname;
/*******************************************************************
Get the next challenge value - no repeats.
@@ -64,7 +66,7 @@ BOOL last_challenge(unsigned char *challenge)
Create a UNIX user on demand.
****************************************************************************/
-static int smb_create_user(char *unix_user, char *homedir)
+static int smb_create_user(const char *unix_user, const char *homedir)
{
pstring add_script;
int ret;
@@ -100,40 +102,560 @@ static int smb_delete_user(char *unix_user)
Add and Delete UNIX users on demand, based on NTSTATUS codes.
****************************************************************************/
-void smb_user_control(char *unix_user, NTSTATUS nt_status)
+void smb_user_control(const auth_usersupplied_info *user_info, auth_serversupplied_info *server_info, NTSTATUS nt_status)
{
struct passwd *pwd=NULL;
if (NT_STATUS_IS_OK(nt_status)) {
- /*
- * User validated ok against Domain controller.
- * If the admin wants us to try and create a UNIX
- * user on the fly, do so.
- */
- if(lp_adduser_script() && !(pwd = smb_getpwnam(unix_user,True)))
- smb_create_user(unix_user, NULL);
-
- if(lp_adduser_script() && pwd) {
- SMB_STRUCT_STAT st;
+ if (!(server_info->sam_fill_level & SAM_FILL_UNIX)) {
+
/*
- * Also call smb_create_user if the users home directory
- * doesn't exist. Used with winbindd to allow the script to
- * create the home directory for a user mapped with winbindd.
+ * User validated ok against Domain controller.
+ * If the admin wants us to try and create a UNIX
+ * user on the fly, do so.
*/
+
+ if(lp_adduser_script() && !(pwd = Get_Pwnam(user_info->internal_username.str))) {
+ smb_create_user(user_info->internal_username.str, NULL);
+ }
+ } else {
+ if(lp_adduser_script()) {
+ SMB_STRUCT_STAT st;
+ const char *home_dir = pdb_get_homedir(server_info->sam_account);
+ /*
+ * Also call smb_create_user if the users home directory
+ * doesn't exist. Used with winbindd to allow the script to
+ * create the home directory for a user mapped with winbindd.
+ */
- if (pwd->pw_dir && (sys_stat(pwd->pw_dir, &st) == -1) && (errno == ENOENT))
- smb_create_user(unix_user, pwd->pw_dir);
+ if (home_dir &&
+ (sys_stat(home_dir, &st) == -1) && (errno == ENOENT)) {
+ smb_create_user(user_info->internal_username.str, home_dir);
+ }
+ }
}
-
- } else if (NT_STATUS_V(nt_status) == NT_STATUS_V(NT_STATUS_NO_SUCH_USER)) {
+ } else if (NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER)) {
/*
* User failed to validate ok against Domain controller.
* If the failure was "user doesn't exist" and admin
* wants us to try and delete that UNIX user on the fly,
* do so.
*/
- if(lp_deluser_script() && smb_getpwnam(unix_user,True))
- smb_delete_user(unix_user);
+ if (lp_deluser_script()) {
+ smb_delete_user(user_info->internal_username.str);
+ }
+ }
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+BOOL make_user_info(auth_usersupplied_info **user_info,
+ char *smb_name, char *internal_username,
+ char *client_domain, char *domain,
+ char *wksta_name, DATA_BLOB sec_blob,
+ DATA_BLOB lm_pwd, DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext,
+ uint32 ntlmssp_flags, BOOL encrypted)
+{
+
+ DEBUG(5,("attempting to make a user_info for %s (%s)\n", internal_username, smb_name));
+
+ *user_info = malloc(sizeof(**user_info));
+ if (!user_info) {
+ DEBUG(0,("malloc failed for user_info (size %d)\n", sizeof(*user_info)));
+ return False;
+ }
+
+ ZERO_STRUCTP(*user_info);
+
+ DEBUG(5,("makeing strings for %s's user_info struct\n", internal_username));
+
+ (*user_info)->smb_name.str = strdup(smb_name);
+ if ((*user_info)->smb_name.str) {
+ (*user_info)->smb_name.len = strlen(smb_name);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->internal_username.str = strdup(internal_username);
+ if ((*user_info)->internal_username.str) {
+ (*user_info)->internal_username.len = strlen(internal_username);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->domain.str = strdup(domain);
+ if ((*user_info)->domain.str) {
+ (*user_info)->domain.len = strlen(domain);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->client_domain.str = strdup(client_domain);
+ if ((*user_info)->client_domain.str) {
+ (*user_info)->client_domain.len = strlen(client_domain);
+ } else {
+ free_user_info(user_info);
+ return False;
+ }
+
+ (*user_info)->wksta_name.str = strdup(wksta_name);
+ if ((*user_info)->wksta_name.str) {
+ (*user_info)->wksta_name.len = strlen(wksta_name);
+ } else {
+ free_user_info(user_info);
+ return False;
}
+
+ DEBUG(5,("makeing blobs for %s's user_info struct\n", internal_username));
+
+ (*user_info)->sec_blob = data_blob(sec_blob.data, sec_blob.length);
+ (*user_info)->lm_resp = data_blob(lm_pwd.data, lm_pwd.length);
+ (*user_info)->nt_resp = data_blob(nt_pwd.data, nt_pwd.length);
+ (*user_info)->plaintext_password = data_blob(plaintext.data, plaintext.length);
+
+ (*user_info)->encrypted = encrypted;
+ (*user_info)->ntlmssp_flags = ntlmssp_flags;
+
+ DEBUG(10,("made an %sencrypted user_info for %s (%s)\n", encrypted ? "":"un" , internal_username, smb_name));
+
+ return True;
}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure after appropriate mapping.
+****************************************************************************/
+
+BOOL make_user_info_map(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ char *wksta_name, DATA_BLOB sec_blob,
+ DATA_BLOB lm_pwd, DATA_BLOB nt_pwd,
+ DATA_BLOB plaintext,
+ uint32 ntlmssp_flags, BOOL encrypted)
+{
+ char *domain;
+ fstring internal_username;
+ fstrcpy(internal_username, smb_name);
+ map_username(internal_username);
+
+ if (lp_allow_trusted_domains()) {
+ domain = client_domain;
+ } else {
+ domain = lp_workgroup();
+ }
+
+ return make_user_info(user_info,
+ smb_name, internal_username,
+ client_domain, domain,
+ wksta_name, sec_blob,
+ lm_pwd, nt_pwd,
+ plaintext,
+ ntlmssp_flags, encrypted);
+
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrupt and encrypt the passwords.
+****************************************************************************/
+
+BOOL make_user_info_netlogon_network(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ char *wksta_name, uchar chal[8],
+ uchar *lm_network_pwd, int lm_pwd_len,
+ uchar *nt_network_pwd, int nt_pwd_len)
+{
+ BOOL ret;
+ DATA_BLOB sec_blob = data_blob(chal, sizeof(chal));
+ DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len);
+ DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len);
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+ uint32 ntlmssp_flags = 0;
+
+ if (lm_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ if (nt_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+
+ ret = make_user_info_map(user_info,
+ smb_name, client_domain,
+ wksta_name, sec_blob,
+ nt_blob, lm_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+
+ data_blob_free(&lm_blob);
+ data_blob_free(&nt_blob);
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrupt and encrypt the passwords.
+****************************************************************************/
+
+BOOL make_user_info_netlogon_interactive(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ char *wksta_name,
+ uchar *lm_interactive_pwd, int lm_pwd_len,
+ uchar *nt_interactive_pwd, int nt_pwd_len,
+ uchar *dc_sess_key)
+{
+ char nt_pwd[16];
+ char lm_pwd[16];
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ unsigned char key[16];
+ uint8 chal[8];
+ uint32 ntlmssp_flags = 0;
+
+ generate_random_buffer(chal, 8, False);
+
+ memset(key, 0, 16);
+ memcpy(key, dc_sess_key, 8);
+
+ memcpy(lm_pwd, lm_interactive_pwd, 16);
+ memcpy(nt_pwd, nt_interactive_pwd, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("key:"));
+ dump_data(100, (char *)key, 16);
+
+ DEBUG(100,("lm owf password:"));
+ dump_data(100, lm_pwd, 16);
+
+ DEBUG(100,("nt owf password:"));
+ dump_data(100, nt_pwd, 16);
+#endif
+
+ SamOEMhash((uchar *)lm_pwd, key, 16);
+ SamOEMhash((uchar *)nt_pwd, key, 16);
+
+#ifdef DEBUG_PASSWORD
+ DEBUG(100,("decrypt of lm owf password:"));
+ dump_data(100, lm_pwd, 16);
+
+ DEBUG(100,("decrypt of nt owf password:"));
+ dump_data(100, nt_pwd, 16);
+#endif
+
+ generate_random_buffer(chal, 8, False);
+ SMBOWFencrypt((const unsigned char *)lm_pwd, chal, local_lm_response);
+ SMBOWFencrypt((const unsigned char *)nt_pwd, chal, local_nt_response);
+
+ /* Password info parinoia */
+ ZERO_STRUCT(lm_pwd);
+ ZERO_STRUCT(nt_pwd);
+ ZERO_STRUCT(key);
+
+ {
+ BOOL ret;
+ DATA_BLOB sec_blob = data_blob(chal, sizeof(chal));
+ DATA_BLOB local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response));
+ DATA_BLOB local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response));
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+
+ ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM;
+ ret = make_user_info_map(user_info,
+ smb_name, client_domain,
+ wksta_name, sec_blob,
+ local_nt_blob,
+ local_lm_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ return ret;
+ }
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+BOOL make_user_info_for_winbind(auth_usersupplied_info **user_info,
+ char *username,
+ char *domain,
+ char *password)
+{
+ unsigned char local_lm_response[24];
+ unsigned char local_nt_response[24];
+ char chal[8];
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
+ DATA_BLOB plaintext_blob;
+ uint32 ntlmssp_flags = 0;
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n"));
+
+ generate_random_buffer(chal, 8, False);
+
+ if (*password) {
+ SMBencrypt( (uchar *)password, chal, local_lm_response);
+
+ /* This encrypts the lm_pwd feild, which actualy contains the password
+ rather than the nt_pwd field becouse that contains nothing */
+
+ /* WATCH OUT. This doesn't work if the incoming password is incorrectly cased.
+ We might want to add a check here and only do an LM in that case */
+
+ SMBNTencrypt((uchar *)password, chal, local_nt_response);
+
+ local_lm_blob = data_blob(local_lm_response, sizeof(local_lm_response));
+ local_nt_blob = data_blob(local_nt_response, sizeof(local_nt_response));
+ plaintext_blob = data_blob(password, strlen(password)+1);
+ if ((!local_lm_blob.data) || (!local_nt_blob.data)|| (!plaintext_blob.data)) {
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ data_blob_clear_free(&plaintext_blob);
+ return False;
+ }
+ ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM | NTLMSSP_NEGOTIATE_NTLM;
+ } else {
+ local_lm_blob = data_blob(NULL, 0);
+ local_nt_blob = data_blob(NULL, 0);
+ plaintext_blob = data_blob(NULL, 0);
+ }
+
+ {
+ BOOL ret;
+ DATA_BLOB sec_blob = data_blob(chal, sizeof(chal));
+
+ if (!sec_blob.data) {
+ return False;
+ }
+
+ ret = make_user_info(user_info,
+ username, username,
+ domain, domain,
+ global_myname, sec_blob,
+ local_nt_blob,
+ local_lm_blob,
+ plaintext_blob,
+ ntlmssp_flags, False);
+
+ data_blob_free(&local_lm_blob);
+ data_blob_free(&local_nt_blob);
+ data_blob_clear_free(&plaintext_blob);
+ return ret;
+ }
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data, making the DATA_BLOBs here.
+ Decrupt and encrypt the passwords.
+****************************************************************************/
+
+BOOL make_user_info_winbind_crap(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ uchar chal[8],
+ uchar *lm_network_pwd, int lm_pwd_len,
+ uchar *nt_network_pwd, int nt_pwd_len)
+{
+ BOOL ret;
+ DATA_BLOB sec_blob = data_blob(chal, sizeof(chal));
+ DATA_BLOB lm_blob = data_blob(lm_network_pwd, lm_pwd_len);
+ DATA_BLOB nt_blob = data_blob(nt_network_pwd, nt_pwd_len);
+ DATA_BLOB plaintext_blob = data_blob(NULL, 0);
+ uint32 ntlmssp_flags = 0;
+
+ if (lm_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ if (nt_pwd_len)
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+
+ ret = make_user_info(user_info,
+ smb_name, smb_name,
+ client_domain, client_domain,
+ global_myname, sec_blob,
+ nt_blob, lm_blob,
+ plaintext_blob,
+ ntlmssp_flags, True);
+
+ data_blob_free(&lm_blob);
+ data_blob_free(&nt_blob);
+ return ret;
+}
+
+/****************************************************************************
+ Create an auth_usersupplied_data structure
+****************************************************************************/
+
+BOOL make_user_info_for_reply(auth_usersupplied_info **user_info,
+ char *smb_name,
+ char *client_domain,
+ DATA_BLOB lm_resp, DATA_BLOB nt_resp,
+ DATA_BLOB plaintext_password,
+ BOOL encrypted)
+{
+ uchar chal[8];
+
+ DATA_BLOB local_lm_blob;
+ DATA_BLOB local_nt_blob;
+ DATA_BLOB sec_blob;
+ BOOL ret = False;
+ uint32 ntlmssp_flags = 0;
+
+ if (encrypted) {
+ DATA_BLOB no_plaintext_blob = data_blob(NULL, 0);
+ if (!last_challenge(chal)) {
+ DEBUG(0,("Encrypted login but no challange set!\n"));
+ return False;
+ }
+ sec_blob = data_blob(chal, 8);
+
+ if (lm_resp.length == 24) {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_OEM;
+ }
+ if (nt_resp.length == 0) {
+ } else if (nt_resp.length == 24) {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM;
+ } else {
+ ntlmssp_flags |= NTLMSSP_NEGOTIATE_NTLM2;
+ }
+
+ return make_user_info_map(user_info, smb_name,
+ client_domain,
+ remote_machine, sec_blob,
+ lm_resp,
+ nt_resp,
+ no_plaintext_blob,
+ ntlmssp_flags, encrypted);
+ }
+
+ generate_random_buffer(chal, 8, False);
+
+ sec_blob = data_blob(chal, 8);
+
+ /*
+ * Not encrypted - do so.
+ */
+
+ DEBUG(5,("pass_check_smb: User passwords not in encrypted format.\n"));
+
+ if (plaintext_password.data) {
+ unsigned char local_lm_response[24];
+
+ SMBencrypt( (uchar *)plaintext_password.data, chal, local_lm_response);
+ local_lm_blob = data_blob(local_lm_response, 24);
+
+ /* We can't do an NT hash here, as the password needs to be case insensitive */
+ local_nt_blob = data_blob(NULL, 0);
+
+ ntlmssp_flags = NTLMSSP_NEGOTIATE_OEM;
+ } else {
+ local_lm_blob = data_blob(NULL, 0);
+ local_nt_blob = data_blob(NULL, 0);
+ }
+
+ ret = make_user_info_map(user_info, smb_name,
+ client_domain,
+ remote_machine,
+ sec_blob,
+ local_lm_blob,
+ local_nt_blob,
+ plaintext_password,
+ ntlmssp_flags, encrypted);
+
+ data_blob_free(&local_lm_blob);
+ return ret;
+}
+
+BOOL make_server_info(auth_serversupplied_info **server_info)
+{
+ *server_info = malloc(sizeof(**server_info));
+ if (!*server_info) {
+ DEBUG(0,("make_server_info_sam: malloc failed!\n"));
+ return False;
+ }
+ ZERO_STRUCTP(*server_info);
+ return True;
+}
+
+BOOL make_server_info_sam(auth_serversupplied_info **server_info, SAM_ACCOUNT *sampass)
+{
+ if (!make_server_info(server_info)) {
+ return False;
+ }
+
+ (*server_info)->sam_fill_level = SAM_FILL_ALL;
+ (*server_info)->sam_account = sampass;
+
+ DEBUG(5,("make_server_info_sam: made sever info for user %s\n",
+ pdb_get_username((*server_info)->sam_account)));
+ return True;
+}
+
+BOOL make_server_info_pw(auth_serversupplied_info **server_info, struct passwd *pwd)
+{
+ SAM_ACCOUNT *sampass = NULL;
+ if (!pdb_init_sam_pw(&sampass, pwd)) {
+ return False;
+ }
+ return make_server_info_sam(server_info, sampass);
+}
+
+void free_user_info(auth_usersupplied_info **user_info)
+{
+ DEBUG(5,("attempting to free (and zero) a user_info structure\n"));
+ if (*user_info != NULL) {
+ if ((*user_info)->smb_name.str) {
+ DEBUG(10,("structure was created for %s\n", (*user_info)->smb_name.str));
+ }
+ SAFE_FREE((*user_info)->smb_name.str);
+ SAFE_FREE((*user_info)->internal_username.str);
+ SAFE_FREE((*user_info)->client_domain.str);
+ SAFE_FREE((*user_info)->domain.str);
+ data_blob_free(&(*user_info)->sec_blob);
+ data_blob_free(&(*user_info)->lm_resp);
+ data_blob_free(&(*user_info)->nt_resp);
+ SAFE_FREE((*user_info)->interactive_password);
+ data_blob_clear_free(&(*user_info)->plaintext_password);
+ ZERO_STRUCT(**user_info);
+ }
+ SAFE_FREE(*user_info);
+}
+
+/***************************************************************************
+ Clear out a server_info struct that has been allocated
+***************************************************************************/
+void free_server_info(auth_serversupplied_info **server_info)
+{
+ if (*server_info != NULL) {
+ pdb_free_sam(&(*server_info)->sam_account);
+
+ /* call pam_end here, unless we know we are keeping it */
+ SAFE_FREE((*server_info)->group_rids);
+
+ ZERO_STRUCT(**server_info);
+ }
+ SAFE_FREE(*server_info);
+}
+
+/***************************************************************************
+ Make a server_info struct for a guest user
+***************************************************************************/
+void make_server_info_guest(auth_serversupplied_info **server_info)
+{
+ struct passwd *pass = sys_getpwnam(lp_guestaccount(-1));
+
+ if (pass) {
+ make_server_info_pw(server_info, pass);
+ }
+}
+
diff --git a/source3/smbd/password.c b/source3/smbd/password.c
index e8f40f1fa3..01eabfda5e 100644
--- a/source3/smbd/password.c
+++ b/source3/smbd/password.c
@@ -197,10 +197,11 @@ has been given. vuid is biased by an offset. This allows us to
tell random client vuid's (normally zero) from valid vuids.
****************************************************************************/
-int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
- char *domain,BOOL guest, char *full_name)
+int register_vuid(auth_serversupplied_info *server_info, char *smb_name, BOOL guest)
{
user_struct *vuser = NULL;
+ uid_t *puid;
+ gid_t *pgid;
/* Ensure no vuid gets registered in share level security. */
if(lp_security() == SEC_SHARE)
@@ -217,8 +218,14 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
ZERO_STRUCTP(vuser);
- DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n", (unsigned int)uid, (unsigned int)gid,
- unix_name, requested_name, domain, guest ));
+ puid = pdb_get_uid(server_info->sam_account);
+ pgid = pdb_get_gid(server_info->sam_account);
+
+ if (!puid || !pgid) {
+ DEBUG(0,("Attempted session setup with invalid user. No uid/gid in SAM_ACCOUNT\n"));
+ free(vuser);
+ return UID_FIELD_INVALID;
+ }
/* Allocate a free vuid. Yes this is a linear search... :-) */
while( get_valid_user_struct(next_vuid) != NULL ) {
@@ -231,13 +238,19 @@ int register_vuid(uid_t uid,gid_t gid, char *unix_name, char *requested_name,
DEBUG(10,("register_vuid: allocated vuid = %u\n", (unsigned int)next_vuid ));
vuser->vuid = next_vuid;
- vuser->uid = uid;
- vuser->gid = gid;
+ vuser->uid = *puid;
+ vuser->gid = *pgid;
vuser->guest = guest;
- fstrcpy(vuser->user.unix_name,unix_name);
- fstrcpy(vuser->user.smb_name,requested_name);
- fstrcpy(vuser->user.domain,domain);
- fstrcpy(vuser->user.full_name, full_name);
+ fstrcpy(vuser->user.unix_name, pdb_get_username(server_info->sam_account));
+ fstrcpy(vuser->user.smb_name, smb_name);
+ fstrcpy(vuser->user.domain, pdb_get_domain(server_info->sam_account));
+ fstrcpy(vuser->user.full_name, pdb_get_fullname(server_info->sam_account));
+
+ DEBUG(10,("register_vuid: (%u,%u) %s %s %s guest=%d\n",
+ (unsigned int)vuser->uid,
+ (unsigned int)vuser->gid,
+ vuser->user.unix_name, vuser->user.smb_name, vuser->user.domain, guest ));
+
DEBUG(3, ("User name: %s\tReal name: %s\n",vuser->user.unix_name,vuser->user.full_name));
vuser->n_groups = 0;
@@ -332,7 +345,7 @@ BOOL user_ok(char *user,int snum)
/****************************************************************************
validate a group username entry. Return the username or NULL
****************************************************************************/
-static char *validate_group(char *group,char *password,int pwlen,int snum)
+static char *validate_group(char *group, DATA_BLOB password,int snum)
{
#ifdef HAVE_NETGROUP
{
@@ -341,7 +354,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
while (getnetgrent(&host, &user, &domain)) {
if (user) {
if (user_ok(user, snum) &&
- password_ok(user,password,pwlen)) {
+ password_ok(user,password)) {
endnetgrent();
return(user);
}
@@ -396,7 +409,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
static fstring name;
fstrcpy(name,member);
if (user_ok(name,snum) &&
- password_ok(name,password,pwlen)) {
+ password_ok(name,password)) {
endgrent();
return(&name[0]);
}
@@ -419,7 +432,7 @@ static char *validate_group(char *group,char *password,int pwlen,int snum)
Note this is *NOT* used when logging on using sessionsetup_and_X.
****************************************************************************/
-BOOL authorise_login(int snum,char *user,char *password, int pwlen,
+BOOL authorise_login(int snum,char *user, DATA_BLOB password,
BOOL *guest,BOOL *force,uint16 vuid)
{
BOOL ok = False;
@@ -427,7 +440,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
#if DEBUG_PASSWORD
DEBUG(100,("authorise_login: checking authorisation on user=%s pass=%s\n",
- user,password));
+ user,password.data));
#endif
*guest = False;
@@ -472,7 +485,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
/* check for a previously registered guest username */
if (!ok && (vuser != 0) && vuser->guest) {
if (user_ok(vuser->user.unix_name,snum) &&
- password_ok(vuser->user.unix_name, password, pwlen)) {
+ password_ok(vuser->user.unix_name, password)) {
fstrcpy(user, vuser->user.unix_name);
vuser->guest = False;
DEBUG(3,("authorise_login: ACCEPTED: given password with registered user %s\n", user));
@@ -494,7 +507,7 @@ BOOL authorise_login(int snum,char *user,char *password, int pwlen,
if (!user_ok(user2,snum))
continue;
- if (password_ok(user2,password, pwlen)) {
+ if (password_ok(user2,password)) {
ok = True;
fstrcpy(user,user2);
DEBUG(3,("authorise_login: ACCEPTED: session list username (%s) \
@@ -526,7 +539,7 @@ and given password ok\n", user));
for (auser=strtok(user_list,LIST_SEP); auser && !ok;
auser = strtok(NULL,LIST_SEP)) {
if (*auser == '@') {
- auser = validate_group(auser+1,password,pwlen,snum);
+ auser = validate_group(auser+1,password,snum);
if (auser) {
ok = True;
fstrcpy(user,auser);
@@ -536,7 +549,7 @@ and given password ok (%s)\n", user));
} else {
fstring user2;
fstrcpy(user2,auser);
- if (user_ok(user2,snum) && password_ok(user2,password,pwlen)) {
+ if (user_ok(user2,snum) && password_ok(user2,password)) {
ok = True;
fstrcpy(user,user2);
DEBUG(3,("authorise_login: ACCEPTED: user list username \
diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c
index ca7bcb9c5f..b60738d23d 100644
--- a/source3/smbd/reply.c
+++ b/source3/smbd/reply.c
@@ -159,14 +159,16 @@ int reply_tcon(connection_struct *conn,
int pwlen=0;
NTSTATUS nt_status;
char *p;
-
+ DATA_BLOB password_blob;
+
START_PROFILE(SMBtcon);
*service = *password = *dev = 0;
p = smb_buf(inbuf)+1;
p += srvstr_pull(inbuf, service, p, sizeof(service), -1, STR_TERMINATE) + 1;
- p += srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
+ pwlen = srvstr_pull(inbuf, password, p, sizeof(password), -1, STR_TERMINATE) + 1;
+ p += pwlen;
p += srvstr_pull(inbuf, dev, p, sizeof(dev), -1, STR_TERMINATE) + 1;
p = strrchr_m(service,'\\');
@@ -174,7 +176,9 @@ int reply_tcon(connection_struct *conn,
pstrcpy(service, p+1);
}
- conn = make_connection(service,password,pwlen,dev,vuid,&nt_status);
+ password_blob = data_blob(password, pwlen+1);
+
+ conn = make_connection(service,password_blob,dev,vuid,&nt_status);
if (!conn) {
END_PROFILE(SMBtcon);
@@ -200,16 +204,17 @@ int reply_tcon(connection_struct *conn,
int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int length,int bufsize)
{
fstring service;
- pstring password;
+ DATA_BLOB password;
pstring devicename;
NTSTATUS nt_status;
uint16 vuid = SVAL(inbuf,smb_uid);
int passlen = SVAL(inbuf,smb_vwv3);
pstring path;
char *p, *q;
- START_PROFILE(SMBtconX);
-
- *service = *password = *devicename = 0;
+ extern BOOL global_encrypted_passwords_negotiated;
+ START_PROFILE(SMBtconX);
+
+ *service = *devicename = 0;
/* we might have to close an old one */
if ((SVAL(inbuf,smb_vwv2) & 0x1) && conn) {
@@ -220,17 +225,17 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
return ERROR_DOS(ERRDOS,ERRbuftoosmall);
}
- memcpy(password,smb_buf(inbuf),passlen);
- password[passlen]=0;
+ if (global_encrypted_passwords_negotiated) {
+ password = data_blob(smb_buf(inbuf),passlen);
+ } else {
+ password = data_blob(smb_buf(inbuf),passlen+1);
+ /* Ensure correct termination */
+ password.data[passlen]=0;
+ }
+
p = smb_buf(inbuf) + passlen;
p += srvstr_pull(inbuf, path, p, sizeof(path), -1, STR_TERMINATE);
- if (passlen != 24) {
- if (strequal(password," "))
- *password = 0;
- passlen = strlen(password);
- }
-
/*
* the service name can be either: \\server\share
* or share directly like on the DELL PowerVault 705
@@ -250,7 +255,7 @@ int reply_tcon_and_X(connection_struct *conn, char *inbuf,char *outbuf,int lengt
DEBUG(4,("Got device type %s\n",devicename));
- conn = make_connection(service,password,passlen,devicename,vuid,&nt_status);
+ conn = make_connection(service,password,devicename,vuid,&nt_status);
if (!conn) {
END_PROFILE(SMBtconX);
diff --git a/source3/smbd/service.c b/source3/smbd/service.c
index 37f4610b9d..f6296201ae 100644
--- a/source3/smbd/service.c
+++ b/source3/smbd/service.c
@@ -79,7 +79,7 @@ BOOL set_current_service(connection_struct *conn,BOOL do_chdir)
Add a home service. Returns the new service number or -1 if fail.
****************************************************************************/
-int add_home_service(char *service, char *homedir)
+int add_home_service(const char *service, const char *homedir)
{
int iHomeService;
int iService;
@@ -320,8 +320,8 @@ static void set_admin_user(connection_struct *conn)
Make a connection to a service.
****************************************************************************/
-connection_struct *make_connection(char *service,char *password,
- int pwlen, char *dev,uint16 vuid, NTSTATUS *status)
+connection_struct *make_connection(char *service, DATA_BLOB password,
+ char *dev,uint16 vuid, NTSTATUS *status)
{
int snum;
struct passwd *pass = NULL;
@@ -361,7 +361,7 @@ connection_struct *make_connection(char *service,char *password,
if (validated_username(vuid)) {
fstring unix_username;
fstrcpy(unix_username,validated_username(vuid));
- return(make_connection(unix_username,password,pwlen,dev,vuid,status));
+ return(make_connection(unix_username,password,dev,vuid,status));
}
} else {
/* Security = share. Try with current_user_info.smb_name
@@ -370,7 +370,7 @@ connection_struct *make_connection(char *service,char *password,
fstring unix_username;
fstrcpy(unix_username,current_user_info.smb_name);
map_username(unix_username);
- return(make_connection(unix_username,password,pwlen,dev,vuid,status));
+ return(make_connection(unix_username,password,dev,vuid,status));
}
}
}
@@ -387,7 +387,7 @@ connection_struct *make_connection(char *service,char *password,
/* shall we let them in? */
- if (!authorise_login(snum,user,password,pwlen,&guest,&force,vuid)) {
+ if (!authorise_login(snum,user,password,&guest,&force,vuid)) {
DEBUG( 2, ( "Invalid username/password for %s [%s]\n", service, user ) );
*status = NT_STATUS_WRONG_PASSWORD;
return NULL;
diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c
index 2d9f624b80..5331127cb5 100644
--- a/source3/smbd/sesssetup.c
+++ b/source3/smbd/sesssetup.c
@@ -264,14 +264,16 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
DATA_BLOB auth;
char *workgroup, *user, *machine;
DATA_BLOB lmhash, nthash, sess_key;
+ DATA_BLOB plaintext_password = data_blob(NULL, 0);
+ DATA_BLOB sec_blob;
uint32 ntlmssp_command, neg_flags;
NTSTATUS nt_status;
int sess_vuid;
- gid_t gid;
- uid_t uid;
- char *full_name;
char *p;
- const struct passwd *pw;
+ char chal[8];
+
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
if (!spnego_parse_auth(blob1, &auth)) {
#if 0
@@ -305,36 +307,40 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
file_save("lmhash1.dat", lmhash.data, lmhash.length);
#endif
- nt_status = pass_check_smb(user, user,
- workgroup, machine,
- lmhash.data,
- lmhash.length,
- nthash.data,
- nthash.length);
-
- data_blob_free(&nthash);
+ if (!last_challenge(chal)) {
+ DEBUG(0,("Encrypted login but no challange set!\n"));
+ return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ }
+ sec_blob = data_blob(chal, 8);
+ if (!sec_blob.data) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ if (!make_user_info_map(&user_info,
+ user, workgroup,
+ machine, sec_blob,
+ lmhash, nthash,
+ plaintext_password,
+ neg_flags, True)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ }
+
+ nt_status = check_password(user_info, &server_info);
+
+ free_user_info(&user_info);
+
data_blob_free(&lmhash);
-
+
+ data_blob_free(&nthash);
+
if (!NT_STATUS_IS_OK(nt_status)) {
- return ERROR_NT(nt_status);
+ return ERROR_NT(nt_status_squash(nt_status));
}
- /* the password is good - let them in */
- pw = smb_getpwnam(user,False);
- if (!pw) {
- DEBUG(1,("Username %s is invalid on this system\n",user));
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
- gid = pw->pw_gid;
- uid = pw->pw_uid;
- full_name = pw->pw_gecos;
-
- sess_vuid = register_vuid(uid,gid,user,user,workgroup,False, full_name);
+ sess_vuid = register_vuid(server_info, user, False);
- free(user);
- free(workgroup);
- free(machine);
-
+ free_server_info(&server_info);
+
if (sess_vuid == -1) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
@@ -360,30 +366,16 @@ reply to a session setup spnego anonymous packet
static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *outbuf,
int length, int bufsize)
{
- char *user;
int sess_vuid;
- gid_t gid;
- uid_t uid;
- char *full_name;
char *p;
- const struct passwd *pw;
+ auth_serversupplied_info *server_info = NULL;
DEBUG(3,("Got anonymous request\n"));
- user = lp_guestaccount(-1);
-
- /* the password is good - let them in */
- pw = smb_getpwnam(user,False);
- if (!pw) {
- DEBUG(1,("Guest username %s is invalid on this system\n",user));
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
- gid = pw->pw_gid;
- uid = pw->pw_uid;
- full_name = pw->pw_gecos;
-
- sess_vuid = register_vuid(uid,gid,user,user,lp_workgroup(),True,full_name);
-
+ make_server_info_guest(&server_info);
+ sess_vuid = register_vuid(server_info, lp_guestaccount(-1), False);
+ free_server_info(&server_info);
+
if (sess_vuid == -1) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
@@ -414,7 +406,7 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,cha
extern uint32 global_client_caps;
int ret;
- DEBUG(3,("Doing spego session setup\n"));
+ DEBUG(3,("Doing spnego session setup\n"));
if (global_client_caps == 0) {
global_client_caps = IVAL(inbuf,smb_vwv10);
@@ -464,16 +456,11 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
int length,int bufsize)
{
int sess_vuid;
- gid_t gid;
- uid_t uid;
- char* full_name;
int smb_bufsize;
- int smb_apasslen = 0;
- pstring smb_apasswd;
- int smb_ntpasslen = 0;
- pstring smb_ntpasswd;
+ DATA_BLOB lm_resp;
+ DATA_BLOB nt_resp;
+ DATA_BLOB plaintext_password;
pstring user;
- pstring orig_user;
fstring domain;
fstring native_os;
fstring native_lanman;
@@ -486,9 +473,18 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
extern fstring remote_machine;
extern userdom_struct current_user_info;
extern int max_send;
+
+ auth_usersupplied_info *user_info = NULL;
+ auth_serversupplied_info *server_info = NULL;
+
BOOL doencrypt = global_encrypted_passwords_negotiated;
+
START_PROFILE(SMBsesssetupX);
+ ZERO_STRUCT(lm_resp);
+ ZERO_STRUCT(nt_resp);
+ ZERO_STRUCT(plaintext_password);
+
DEBUG(3,("wct=%d flg2=0x%x\n", CVAL(inbuf, smb_wct), SVAL(inbuf, smb_flg2)));
/* a SPNEGO session setup has 12 command words, whereas a normal
@@ -503,28 +499,35 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
}
- *smb_apasswd = *smb_ntpasswd = 0;
-
smb_bufsize = SVAL(inbuf,smb_vwv2);
-
+
if (Protocol < PROTOCOL_NT1) {
- smb_apasslen = SVAL(inbuf,smb_vwv7);
- if (smb_apasslen > MAX_PASS_LEN) {
+ uint16 passlen1 = SVAL(inbuf,smb_vwv7);
+ if (passlen1 > MAX_PASS_LEN) {
return ERROR_DOS(ERRDOS,ERRbuftoosmall);
}
- memcpy(smb_apasswd,smb_buf(inbuf),smb_apasslen);
- srvstr_pull(inbuf, user, smb_buf(inbuf)+smb_apasslen, sizeof(user), -1, STR_TERMINATE);
-
- if (!doencrypt && (lp_security() != SEC_SERVER)) {
- smb_apasslen = strlen(smb_apasswd);
+ if (doencrypt) {
+ lm_resp = data_blob(smb_buf(inbuf), passlen1);
+ } else {
+ plaintext_password = data_blob(smb_buf(inbuf), passlen1+1);
+ if (!plaintext_password.data) {
+ DEBUG(0,("reply_sesssetup_and_X: malloc failed for plaintext_password!\n"));
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
+ } else {
+ /* Ensure null termination */
+ plaintext_password.data[passlen1] = 0;
+ }
}
+
+ srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE);
+
} else {
uint16 passlen1 = SVAL(inbuf,smb_vwv7);
uint16 passlen2 = SVAL(inbuf,smb_vwv8);
enum remote_arch_types ra_type = get_remote_arch();
char *p = smb_buf(inbuf);
-
+
if(global_client_caps == 0)
global_client_caps = IVAL(inbuf,smb_vwv11);
@@ -539,16 +542,13 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
}
}
- if (passlen1 != 24 && passlen2 < 24)
- doencrypt = False;
-
if (passlen1 > MAX_PASS_LEN) {
return ERROR_DOS(ERRDOS,ERRbuftoosmall);
}
-
+
passlen1 = MIN(passlen1, MAX_PASS_LEN);
passlen2 = MIN(passlen2, MAX_PASS_LEN);
-
+
if (!doencrypt) {
/* both Win95 and WinNT stuff up the password lengths for
non-encrypting systems. Uggh.
@@ -591,23 +591,20 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
passlen1 = 1;
}
}
-
+
/* Save the lanman2 password and the NT md4 password. */
- smb_apasslen = passlen1;
- memcpy(smb_apasswd,p,smb_apasslen);
-
- smb_ntpasslen = passlen2;
- memcpy(smb_ntpasswd,p+passlen1,smb_ntpasslen);
-
- if (smb_apasslen != 24 || !doencrypt) {
- /* trim the password */
- smb_apasslen = strlen(smb_apasswd);
-
- /* wfwg sometimes uses a space instead of a null */
- if (strequal(smb_apasswd," ")) {
- smb_apasslen = 0;
- *smb_apasswd = 0;
- }
+
+ if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
+ doencrypt = False;
+ }
+
+ if (doencrypt) {
+ lm_resp = data_blob(p, passlen1);
+ nt_resp = data_blob(p+passlen1, passlen2);
+ } else {
+ plaintext_password = data_blob(p, passlen1+1);
+ /* Ensure null termination */
+ plaintext_password.data[passlen1] = 0;
}
p += passlen1 + passlen2;
@@ -630,15 +627,29 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
- if (lp_security() == SEC_SHARE) {
- /* in share level we should ignore any passwords */
- smb_ntpasslen = 0;
- smb_apasslen = 0;
+ DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n", domain, user, remote_machine));
+
+ /* If no username is sent use the guest account */
+ if (!*user) {
+ pstrcpy(user,lp_guestaccount(-1));
guest = True;
}
+ pstrcpy(current_user_info.smb_name,user);
+
+ reload_services(True);
+
+ if (lp_security() == SEC_SHARE) {
+ /* in share level we should ignore any passwords */
+
+ data_blob_free(&lm_resp);
+ data_blob_free(&nt_resp);
+ data_blob_free(&plaintext_password);
- DEBUG(3,("sesssetupX:name=[%s]\\[%s]@[%s]\n",user, domain, remote_machine));
+ guest = True;
+ map_username(user);
+ add_session_user(user);
+ }
if (done_sesssetup && lp_restrict_anonymous()) {
/* tests show that even if browsing is done over
@@ -649,106 +660,61 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
* only deny connections that have no session
* information. If a domain has been provided, then
* it's not a purely anonymous connection. AAB */
- if (!*user && !*smb_apasswd && !*domain) {
+ if (!*user && !*domain) {
DEBUG(0, ("restrict anonymous is True and anonymous connection attempted. Denying access.\n"));
+
+ data_blob_free(&lm_resp);
+ data_blob_free(&nt_resp);
+ data_blob_free(&plaintext_password);
+
END_PROFILE(SMBsesssetupX);
return ERROR_DOS(ERRDOS,ERRnoaccess);
}
}
-
- /* If no username is sent use the guest account */
- if (!*user) {
- pstrcpy(user,lp_guestaccount(-1));
- guest = True;
- }
-
- pstrcpy(current_user_info.smb_name,user);
-
- reload_services(True);
-
- /*
- * Save the username before mapping. We will use
- * the original username sent to us for security=server
- * and security=domain checking.
- */
-
- pstrcpy( orig_user, user);
-
- /*
- * Always try the "DOMAIN\user" lookup first, as this is the most
- * specific case. If this fails then try the simple "user" lookup.
- * But don't do this for guests, as this is always a local user.
- */
if (!guest) {
- pstring dom_user;
-
- /* Work out who's who */
-
- slprintf(dom_user, sizeof(dom_user) - 1,"%s%s%s",
- domain, lp_winbind_separator(), user);
-
- if (sys_getpwnam(dom_user) != NULL) {
- pstrcpy(user, dom_user);
- DEBUG(3,("Using unix username %s\n", dom_user));
+ NTSTATUS nt_status;
+ if (!make_user_info_for_reply(&user_info,
+ user, domain,
+ lm_resp, nt_resp,
+ plaintext_password, doencrypt)) {
+ return ERROR_NT(NT_STATUS_NO_MEMORY);
}
- /*
- * Pass the user through the NT -> unix user mapping
- * function.
- */
+ nt_status = check_password(user_info, &server_info);
- (void)map_username(user);
+ free_user_info(&user_info);
- /*
- * Do any UNIX username case mangling.
- */
- smb_getpwnam(user, True);
- }
-
- add_session_user(user);
-
- if (!guest) {
- NTSTATUS nt_status;
- nt_status = pass_check_smb(orig_user, user,
- domain, remote_machine,
- (unsigned char *)smb_apasswd,
- smb_apasslen,
- (unsigned char *)smb_ntpasswd,
- smb_ntpasslen);
-
- if NT_STATUS_IS_OK(nt_status) {
-
- } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
- if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
- (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
- DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
- pstrcpy(user,lp_guestaccount(-1));
- guest = True;
- } else {
- /* Match WinXP and don't give the game away */
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
- }
- } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
- if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
- pstrcpy(user,lp_guestaccount(-1));
- DEBUG(3,("Registered username %s for guest access\n",user));
- guest = True;
- } else {
+ data_blob_free(&lm_resp);
+ data_blob_free(&nt_resp);
+ data_blob_free(&plaintext_password);
+
+ if (!NT_STATUS_IS_OK(nt_status)) {
+ if NT_STATUS_EQUAL(nt_status, NT_STATUS_NO_SUCH_USER) {
+ if ((lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_USER) ||
+ (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD)) {
+ DEBUG(3,("No such user %s [%s] - using guest account\n",user, domain));
+ pstrcpy(user,lp_guestaccount(-1));
+ guest = True;
+
+ }
+ } else if NT_STATUS_EQUAL(nt_status, NT_STATUS_WRONG_PASSWORD) {
+ if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
+ pstrcpy(user,lp_guestaccount(-1));
+ DEBUG(3,("Registered username %s for guest access\n",user));
+ guest = True;
+ }
/* Match WinXP and don't give the game away */
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}
- } else {
- return ERROR_NT(nt_status);
+
+ if (!guest) {
+ free_server_info(&server_info);
+ return ERROR_NT(nt_status_squash(nt_status));
+ }
}
}
- if (!strequal(user,lp_guestaccount(-1)) &&
- lp_servicenumber(user) < 0) {
- add_home_service(user,get_user_home_dir(user));
- }
-
-
/* it's ok - setup a reply */
if (Protocol < PROTOCOL_NT1) {
set_message(outbuf,3,0,True);
@@ -763,30 +729,26 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
/* perhaps grab OS version here?? */
}
- /* Set the correct uid in the outgoing and incoming packets
- We will use this on future requests to determine which
- user we should become.
- */
- {
- const struct passwd *pw = smb_getpwnam(user,False);
- if (!pw) {
- DEBUG(1,("Username %s is invalid on this system\n",user));
- END_PROFILE(SMBsesssetupX);
- return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+ if (guest) {
+ SSVAL(outbuf,smb_vwv2,1);
+ free_server_info(&server_info);
+ make_server_info_guest(&server_info);
+ } else {
+ const char *home_dir = pdb_get_homedir(server_info->sam_account);
+ const char *username = pdb_get_username(server_info->sam_account);
+ if ((home_dir && *home_dir)
+ && (lp_servicenumber(username) < 0)) {
+ add_home_service(username, home_dir);
}
- gid = pw->pw_gid;
- uid = pw->pw_uid;
- full_name = pw->pw_gecos;
}
-
- if (guest)
- SSVAL(outbuf,smb_vwv2,1);
-
+
/* register the name and uid as being validated, so further connections
to a uid can get through without a password, on the same VC */
-
- sess_vuid = register_vuid(uid,gid,user,orig_user,domain,guest, full_name);
-
+
+ sess_vuid = register_vuid(server_info, user, guest);
+
+ free_server_info(&server_info);
+
if (sess_vuid == -1) {
return ERROR_NT(NT_STATUS_LOGON_FAILURE);
}