summaryrefslogtreecommitdiff
path: root/source3/smbd/sesssetup.c
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/sesssetup.c
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/sesssetup.c')
-rw-r--r--source3/smbd/sesssetup.c356
1 files changed, 159 insertions, 197 deletions
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);
}