Better explanation message for dmalloc.
[ira/wip.git] / source3 / smbd / sesssetup.c
index 7361db0205f71e763b35fcc5457bb2551792f892..f809f9ca0c373484979eb664b90104c3bb105794 100644 (file)
 
 #include "includes.h"
 
-#if HAVE_KRB5
+uint32 global_client_caps = 0;
+static struct auth_context *ntlmssp_auth_context = NULL;
+
+/*
+  on a logon error possibly map the error to success if "map to guest"
+  is set approriately
+*/
+static NTSTATUS do_map_to_guest(NTSTATUS status, auth_serversupplied_info **server_info,
+                               const char *user, const char *domain)
+{
+       if (NT_STATUS_EQUAL(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));
+                       make_server_info_guest(server_info);
+                       status = NT_STATUS_OK;
+               }
+       }
+
+       if (NT_STATUS_EQUAL(status, NT_STATUS_WRONG_PASSWORD)) {
+               if (lp_map_to_guest() == MAP_TO_GUEST_ON_BAD_PASSWORD) {
+                       DEBUG(3,("Registered username %s for guest access\n",user));
+                       make_server_info_guest(server_info);
+                       status = NT_STATUS_OK;
+               }
+       }
+
+       return status;
+}
+
+
+/****************************************************************************
+ Add the standard 'Samba' signature to the end of the session setup.
+****************************************************************************/
+static void add_signature(char *outbuf) 
+{
+       char *p;
+       p = smb_buf(outbuf);
+       p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
+       p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
+       p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
+       set_message_end(outbuf,p);
+}
+
+/****************************************************************************
+ Do a 'guest' logon, getting back the 
+****************************************************************************/
+static NTSTATUS check_guest_password(auth_serversupplied_info **server_info) 
+{
+       struct auth_context *auth_context;
+       auth_usersupplied_info *user_info = NULL;
+       
+       NTSTATUS nt_status;
+       unsigned char chal[8];
+
+       ZERO_STRUCT(chal);
+
+       DEBUG(3,("Got anonymous request\n"));
+
+       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_fixed(&auth_context, chal))) {
+               return nt_status;
+       }
+
+       if (!make_user_info_guest(&user_info)) {
+               (auth_context->free)(&auth_context);
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       nt_status = auth_context->check_ntlm_password(auth_context, user_info, server_info);
+       (auth_context->free)(&auth_context);
+       free_user_info(&user_info);
+       return nt_status;
+}
+
+
+#ifdef HAVE_KRB5
 /****************************************************************************
 reply to a session setup spnego negotiate packet for kerberos
 ****************************************************************************/
@@ -32,48 +108,25 @@ static int reply_spnego_kerberos(connection_struct *conn,
                                 DATA_BLOB *secblob)
 {
        DATA_BLOB ticket;
-       krb5_context context;
-       krb5_auth_context auth_context = NULL;
-       krb5_keytab keytab = NULL;
-       krb5_data packet;
-       krb5_ticket *tkt = NULL;
-       int ret;
-       char *realm, *client, *p;
+       char *client, *p;
        const struct passwd *pw;
        char *user;
        int sess_vuid;
+       NTSTATUS ret;
+       DATA_BLOB auth_data;
        auth_serversupplied_info *server_info = NULL;
-
-       realm = lp_realm();
+       ADS_STRUCT *ads;
 
        if (!spnego_parse_krb5_wrap(*secblob, &ticket)) {
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
-       ret = krb5_init_context(&context);
-       if (ret) {
-               DEBUG(1,("krb5_init_context failed (%s)\n", error_message(ret)));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
-
-       packet.length = ticket.length;
-       packet.data = (krb5_pointer)ticket.data;
-
-#if 0
-       file_save("/tmp/ticket.dat", ticket.data, ticket.length);
-#endif
-
-       if ((ret = krb5_rd_req(context, &auth_context, &packet, 
-                              NULL, keytab, NULL, &tkt))) {
-               DEBUG(3,("krb5_rd_req failed (%s)\n", 
-                        error_message(ret)));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
-       }
+       ads = ads_init(NULL, NULL, NULL, NULL);
 
-       if ((ret = krb5_unparse_name(context, tkt->enc_part2->client,
-                                    &client))) {
-               DEBUG(3,("krb5_unparse_name failed (%s)\n", 
-                        error_message(ret)));
+       ret = ads_verify_ticket(ads, &ticket, &client, &auth_data);
+       if (!NT_STATUS_IS_OK(ret)) {
+               DEBUG(1,("Failed to verify incoming ticket!\n"));       
+               ads_destroy(&ads);
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
@@ -82,22 +135,40 @@ static int reply_spnego_kerberos(connection_struct *conn,
        p = strchr_m(client, '@');
        if (!p) {
                DEBUG(3,("Doesn't look like a valid principal\n"));
+               ads_destroy(&ads);
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
        }
 
        *p = 0;
-       if (strcasecmp(p+1, realm) != 0) {
-               DEBUG(3,("Ticket for incorrect realm %s\n", p+1));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       if (strcasecmp(p+1, ads->realm) != 0) {
+               DEBUG(3,("Ticket for foreign realm %s@%s\n", client, p+1));
+               if (!lp_allow_trusted_domains()) {
+                       return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+               }
+               /* this gives a fully qualified user name (ie. with full realm).
+                  that leads to very long usernames, but what else can we do? */
+               asprintf(&user, "%s%s%s", p+1, lp_winbind_separator(), client);
+       } else {
+               user = strdup(client);
        }
-       
-       user = client;
+       ads_destroy(&ads);
 
        /* the password is good - let them in */
        pw = smb_getpwnam(user,False);
+       if (!pw && !strstr(user, lp_winbind_separator())) {
+               char *user2;
+               /* try it with a winbind domain prefix */
+               asprintf(&user2, "%s%s%s", lp_workgroup(), lp_winbind_separator(), user);
+               pw = smb_getpwnam(user2,False);
+               if (pw) {
+                       free(user);
+                       user = user2;
+               }
+       }
+
        if (!pw) {
                DEBUG(1,("Username %s is invalid on this system\n",user));
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+               return ERROR_NT(NT_STATUS_NO_SUCH_USER);
        }
 
        if (!make_server_info_pw(&server_info,pw)) {
@@ -105,8 +176,9 @@ static int reply_spnego_kerberos(connection_struct *conn,
                return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
        
-       sess_vuid = register_vuid(server_info, user, False);
+       sess_vuid = register_vuid(server_info, user);
 
+       free(user);
        free_server_info(&server_info);
 
        if (sess_vuid == -1) {
@@ -115,11 +187,7 @@ static int reply_spnego_kerberos(connection_struct *conn,
 
        set_message(outbuf,4,0,True);
        SSVAL(outbuf, smb_vwv3, 0);
-       p = smb_buf(outbuf);
-       p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
-       set_message_end(outbuf,p);
+       add_signature(outbuf);
  
        SSVAL(outbuf,smb_uid,sess_vuid);
        SSVAL(inbuf,smb_uid,sess_vuid);
@@ -170,8 +238,9 @@ static int reply_spnego_negotiate(connection_struct *conn,
        int i;
        uint32 ntlmssp_command, neg_flags;
        DATA_BLOB sess_key, chal, spnego_chal;
-       uint8 cryptkey[8];
+       const uint8 *cryptkey;
        BOOL got_kerberos = False;
+       NTSTATUS nt_status;
 
        /* parse out the OIDs and the first sec blob */
        if (!parse_negTokenTarg(blob1, OIDs, &secblob)) {
@@ -188,7 +257,7 @@ static int reply_spnego_negotiate(connection_struct *conn,
        }
        DEBUG(3,("Got secblob of size %d\n", secblob.length));
 
-#if HAVE_KRB5
+#ifdef HAVE_KRB5
        if (got_kerberos) {
                int ret = reply_spnego_kerberos(conn, inbuf, outbuf, 
                                                length, bufsize, &secblob);
@@ -219,10 +288,16 @@ static int reply_spnego_negotiate(connection_struct *conn,
 
        DEBUG(3,("Got neg_flags=%08x\n", neg_flags));
 
-       if (!last_challenge(cryptkey)) {
-               return ERROR_NT(NT_STATUS_LOGON_FAILURE);
+       if (ntlmssp_auth_context) {
+               (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
+       }
+
+       if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&ntlmssp_auth_context))) {
+               return ERROR_NT(nt_status);
        }
 
+       cryptkey = ntlmssp_auth_context->get_ntlm_challenge(ntlmssp_auth_context);
+
        /* Give them the challenge. For now, ignore neg_flags and just
           return the flags we want. Obviously this is not correct */
        
@@ -264,15 +339,13 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
                             DATA_BLOB blob1)
 {
        DATA_BLOB auth;
-       char *workgroup, *user, *machine;
+       char *workgroup = NULL, *user = NULL, *machine = NULL;
        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;
-       char *p;
-       char chal[8];
+       BOOL as_guest;
 
        auth_usersupplied_info *user_info = NULL;
        auth_serversupplied_info *server_info = NULL;
@@ -309,39 +382,43 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
        file_save("lmhash1.dat", lmhash.data, lmhash.length);
 #endif
 
-       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,
+                               machine, 
                                lmhash, nthash,
                                plaintext_password, 
                                neg_flags, True)) {
                return ERROR_NT(NT_STATUS_NO_MEMORY);
        }
-       
-       nt_status = check_password(user_info, &server_info); 
-       
+
+       nt_status = ntlmssp_auth_context->check_ntlm_password(ntlmssp_auth_context, user_info, &server_info); 
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               nt_status = do_map_to_guest(nt_status, &server_info, user, workgroup);
+       }
+
+       SAFE_FREE(workgroup);
+       SAFE_FREE(machine);
+                       
+       (ntlmssp_auth_context->free)(&ntlmssp_auth_context);
+
        free_user_info(&user_info);
        
        data_blob_free(&lmhash);
        
        data_blob_free(&nthash);
-       
+
        if (!NT_STATUS_IS_OK(nt_status)) {
+               SAFE_FREE(user);
                return ERROR_NT(nt_status_squash(nt_status));
        }
 
-       sess_vuid = register_vuid(server_info, user, False);
+       as_guest = server_info->guest;
 
+       sess_vuid = register_vuid(server_info, user);
        free_server_info(&server_info);
+
+       SAFE_FREE(user);
   
        if (sess_vuid == -1) {
                return ERROR_NT(NT_STATUS_LOGON_FAILURE);
@@ -349,11 +426,12 @@ static int reply_spnego_auth(connection_struct *conn, char *inbuf, char *outbuf,
 
        set_message(outbuf,4,0,True);
        SSVAL(outbuf, smb_vwv3, 0);
-       p = smb_buf(outbuf);
-       p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
-       set_message_end(outbuf,p);
+
+       if (as_guest) {
+               SSVAL(outbuf,smb_vwv2,1);
+       }
+
+       add_signature(outbuf);
  
        SSVAL(outbuf,smb_uid,sess_vuid);
        SSVAL(inbuf,smb_uid,sess_vuid);
@@ -369,13 +447,17 @@ static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *ou
                                  int length, int bufsize)
 {
        int sess_vuid;
-       char *p;
        auth_serversupplied_info *server_info = NULL;
+       NTSTATUS nt_status;
 
-       DEBUG(3,("Got anonymous request\n"));
+       nt_status = check_guest_password(&server_info);
+
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return ERROR_NT(nt_status_squash(nt_status));
+       }
+
+       sess_vuid = register_vuid(server_info, lp_guestaccount());
 
-       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) {
@@ -384,11 +466,7 @@ static int reply_spnego_anonymous(connection_struct *conn, char *inbuf, char *ou
 
        set_message(outbuf,4,0,True);
        SSVAL(outbuf, smb_vwv3, 0);
-       p = smb_buf(outbuf);
-       p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
-       p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
-       set_message_end(outbuf,p);
+       add_signature(outbuf);
  
        SSVAL(outbuf,smb_uid,sess_vuid);
        SSVAL(inbuf,smb_uid,sess_vuid);
@@ -405,7 +483,6 @@ static int reply_sesssetup_and_X_spnego(connection_struct *conn, char *inbuf,cha
 {
        uint8 *p;
        DATA_BLOB blob1;
-       extern uint32 global_client_caps;
        int ret;
 
        DEBUG(3,("Doing spnego session setup\n"));
@@ -463,22 +540,24 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        DATA_BLOB nt_resp;
        DATA_BLOB plaintext_password;
        pstring user;
+       pstring sub_user; /* Sainitised username for substituion */
        fstring domain;
        fstring native_os;
        fstring native_lanman;
-       BOOL guest=False;
        static BOOL done_sesssetup = False;
        extern BOOL global_encrypted_passwords_negotiated;
        extern BOOL global_spnego_negotiated;
-       extern uint32 global_client_caps;
        extern int Protocol;
        extern fstring remote_machine;
        extern userdom_struct current_user_info;
        extern int max_send;
 
        auth_usersupplied_info *user_info = NULL;
+       extern struct auth_context *negprot_global_auth_context;
        auth_serversupplied_info *server_info = NULL;
 
+       NTSTATUS nt_status;
+
        BOOL doencrypt = global_encrypted_passwords_negotiated;
 
        START_PROFILE(SMBsesssetupX);
@@ -488,17 +567,17 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        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
           NT1 session setup has 13. See the cifs spec. */
        if (CVAL(inbuf, smb_wct) == 12 &&
            (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
-               return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
-       }
+               if (!global_spnego_negotiated) {
+                       DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at SPNEGO session setup when it was not negoitiated.\n"));
+                       return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+               }
 
-       if (global_spnego_negotiated) {
-               DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
-               return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+               return reply_sesssetup_and_X_spnego(conn, inbuf, outbuf, length, bufsize);
        }
 
        smb_bufsize = SVAL(inbuf,smb_vwv2);
@@ -513,16 +592,12 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                        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;
-                       }
+                       /* Ensure null termination */
+                       plaintext_password.data[passlen1] = 0;
                }
 
                srvstr_pull(inbuf, user, smb_buf(inbuf)+passlen1, sizeof(user), -1, STR_TERMINATE);
+               *domain = 0;
   
        } else {
                uint16 passlen1 = SVAL(inbuf,smb_vwv7);
@@ -568,32 +643,6 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
                                passlen2 = 0;
                }
                
-               if (lp_restrict_anonymous()) {
-                       /* there seems to be no reason behind the
-                        * differences in MS clients formatting
-                        * various info like the domain, NativeOS, and
-                        * NativeLanMan fields. Win95 in particular
-                        * seems to have an extra null byte between
-                        * the username and the domain, or the
-                        * password length calculation is wrong, which
-                        * throws off the string extraction routines
-                        * below.  This makes the value of domain be
-                        * the empty string, which fails the restrict
-                        * anonymous check further down.  This
-                        * compensates for that, and allows browsing
-                        * to work in mixed NT and win95 environments
-                        * even when restrict anonymous is true. AAB
-                        * */
-                       dump_data(100, p, 0x70);
-                       DEBUG(9, ("passlen1=%d, passlen2=%d\n", passlen1, passlen2));
-                       if (ra_type == RA_WIN95 && !passlen1 && !passlen2 && p[0] == 0 && p[1] == 0) {
-                               DEBUG(0, ("restrict anonymous parameter used in a win95 environment!\n"));
-                               DEBUG(0, ("client is win95 and broken passlen1 offset -- attempting fix\n"));
-                               DEBUG(0, ("if win95 cilents are having difficulty browsing, you will be unable to use restrict anonymous\n"));
-                               passlen1 = 1;
-                       }
-               }
-               
                /* Save the lanman2 password and the NT md4 password. */
                
                if ((doencrypt) && (passlen1 != 0) && (passlen1 != 24)) {
@@ -631,13 +680,20 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
 
        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;
+       if (*user) {
+               if (global_spnego_negotiated) {
+                       
+                       /* This has to be here, becouse this is a perfectly valid behaviour for guest logons :-( */
+                       
+                       DEBUG(0,("reply_sesssetup_and_X:  Rejecting attempt at 'normal' session setup after negotiating spnego.\n"));
+                       return ERROR_NT(NT_STATUS_UNSUCCESSFUL);
+               }
+               pstrcpy(sub_user, user);
+       } else {
+               pstrcpy(sub_user, lp_guestaccount());
        }
 
-       pstrcpy(current_user_info.smb_name,user);
+       pstrcpy(current_user_info.smb_name,sub_user);
 
        reload_services(True);
        
@@ -646,95 +702,75 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
 
                data_blob_free(&lm_resp);
                data_blob_free(&nt_resp);
-               data_blob_free(&plaintext_password);
+               data_blob_clear_free(&plaintext_password);
 
-               guest = True;
-               map_username(user);
-               add_session_user(user);
+               map_username(sub_user);
+               add_session_user(sub_user);
+               /* Then force it to null for the benfit of the code below */
+               *user = 0;
        }
        
-       if (done_sesssetup && lp_restrict_anonymous()) {
-               /* tests show that even if browsing is done over
-                * already validated connections without a username
-                * and password the domain is still provided, which it
-                * wouldn't be if it was a purely anonymous
-                * connection.  So, in order to restrict anonymous, we
-                * 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 && !*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);
+       if (!*user) {
 
-                       END_PROFILE(SMBsesssetupX);
-                       return ERROR_DOS(ERRDOS,ERRnoaccess);
-               }
-       }
-       
-       if (!guest) {
-               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);
+               nt_status = check_guest_password(&server_info);
+
+       } else if (doencrypt) {
+               if (!make_user_info_for_reply_enc(&user_info, 
+                                                 user, domain, 
+                                                 lm_resp, nt_resp)) {
+                       nt_status = NT_STATUS_NO_MEMORY;
+               } else {
+                       nt_status = negprot_global_auth_context->check_ntlm_password(negprot_global_auth_context, 
+                                                                                    user_info, 
+                                                                                    &server_info);
                }
+       } else {
+               struct auth_context *plaintext_auth_context = NULL;
+               const uint8 *chal;
+               if (NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&plaintext_auth_context))) {
+                       chal = plaintext_auth_context->get_ntlm_challenge(plaintext_auth_context);
+                       
+                       if (!make_user_info_for_reply(&user_info, 
+                                                     user, domain, chal,
+                                                     plaintext_password)) {
+                               nt_status = NT_STATUS_NO_MEMORY;
+                       }
                
-               nt_status = check_password(user_info, &server_info); 
-               
-               free_user_info(&user_info);
-               
-               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);
+                       if (NT_STATUS_IS_OK(nt_status)) {
+                               nt_status = plaintext_auth_context->check_ntlm_password(plaintext_auth_context, 
+                                                                                       user_info, 
+                                                                                       &server_info); 
+                               
+                               (plaintext_auth_context->free)(&plaintext_auth_context);
                        }
-                       
-                       if (!guest) {
-                               free_server_info(&server_info);
-                               return ERROR_NT(nt_status_squash(nt_status));
-                       }  
                }
        }
+
+       free_user_info(&user_info);
+       
+       data_blob_free(&lm_resp);
+       data_blob_free(&nt_resp);
+       data_blob_clear_free(&plaintext_password);
+       
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               nt_status = do_map_to_guest(nt_status, &server_info, user, domain);
+       }
+       
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return ERROR_NT(nt_status_squash(nt_status));
+       }
        
        /* it's ok - setup a reply */
        if (Protocol < PROTOCOL_NT1) {
                set_message(outbuf,3,0,True);
        } else {
-               char *p;
                set_message(outbuf,3,0,True);
-               p = smb_buf(outbuf);
-               p += srvstr_push(outbuf, p, "Unix", -1, STR_TERMINATE);
-               p += srvstr_push(outbuf, p, "Samba", -1, STR_TERMINATE);
-               p += srvstr_push(outbuf, p, lp_workgroup(), -1, STR_TERMINATE);
-               set_message_end(outbuf,p);
+               add_signature(outbuf);
                /* perhaps grab OS version here?? */
        }
        
-       if (guest) {
+       if (server_info->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);
@@ -747,7 +783,7 @@ int reply_sesssetup_and_X(connection_struct *conn, char *inbuf,char *outbuf,
        /* 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(server_info, user, guest);
+       sess_vuid = register_vuid(server_info, sub_user);
 
        free_server_info(&server_info);