r23779: Change from v2 or later to v3 or later.
[kai/samba.git] / source / smbd / negprot.c
index 5d2ed6a10d14ccd212076a477b00abbc5e65d0f3..7256e2da6d3382d7eb8b6e7b2e7e201628dc7476 100644 (file)
@@ -5,7 +5,7 @@
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
    
    This program is distributed in the hope that it will be useful,
@@ -33,7 +33,8 @@ static void get_challenge(char buff[8])
        NTSTATUS nt_status;
        const uint8 *cryptkey;
 
-       /* We might be called more than once, muliple negprots are premitted */
+       /* We might be called more than once, multiple negprots are
+        * permitted */
        if (negprot_global_auth_context) {
                DEBUG(3, ("get challenge: is this a secondary negprot?  negprot_global_auth_context is non-NULL!\n"));
                (negprot_global_auth_context->free)(&negprot_global_auth_context);
@@ -42,7 +43,7 @@ static void get_challenge(char buff[8])
        DEBUG(10, ("get challenge: creating negprot_global_auth_context\n"));
        if (!NT_STATUS_IS_OK(nt_status = make_auth_context_subsystem(&negprot_global_auth_context))) {
                DEBUG(0, ("make_auth_context_subsystem returned %s", nt_errstr(nt_status)));
-               smb_panic("cannot make_negprot_global_auth_context!\n");
+               smb_panic("cannot make_negprot_global_auth_context!");
        }
        DEBUG(10, ("get challenge: getting challenge\n"));
        cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
@@ -55,7 +56,7 @@ static void get_challenge(char buff[8])
 
 static int reply_corep(char *inbuf, char *outbuf)
 {
-       int outsize = set_message(outbuf,1,0,True);
+       int outsize = set_message(inbuf,outbuf,1,0,True);
 
        Protocol = PROTOCOL_CORE;
        
@@ -69,7 +70,7 @@ static int reply_corep(char *inbuf, char *outbuf)
 static int reply_coreplus(char *inbuf, char *outbuf)
 {
        int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
-       int outsize = set_message(outbuf,13,0,True);
+       int outsize = set_message(inbuf,outbuf,13,0,True);
        SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
                        readbraw and writebraw (possibly) */
        /* Reply, SMBlockread, SMBwritelock supported. */
@@ -98,7 +99,7 @@ static int reply_lanman1(char *inbuf, char *outbuf)
        if (global_encrypted_passwords_negotiated)
                secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
 
-       set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
+       set_message(inbuf,outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
        SSVAL(outbuf,smb_vwv1,secword); 
        /* Create a token value and add it to the outgoing packet. */
        if (global_encrypted_passwords_negotiated) {
@@ -140,7 +141,7 @@ static int reply_lanman2(char *inbuf, char *outbuf)
        if (global_encrypted_passwords_negotiated)
                secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
 
-       set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
+       set_message(inbuf,outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
        SSVAL(outbuf,smb_vwv1,secword); 
        SIVAL(outbuf,smb_vwv6,sys_getpid());
 
@@ -168,22 +169,24 @@ static int reply_lanman2(char *inbuf, char *outbuf)
  Generate the spnego negprot reply blob. Return the number of bytes used.
 ****************************************************************************/
 
-static int negprot_spnego(char *p, uint8 *pkeylen)
+static DATA_BLOB negprot_spnego(void)
 {
        DATA_BLOB blob;
        nstring dos_name;
        fstring unix_name;
+#ifdef DEVELOPER
+       size_t slen;
+#endif
        char guid[17];
        const char *OIDs_krb5[] = {OID_KERBEROS5,
                                   OID_KERBEROS5_OLD,
                                   OID_NTLMSSP,
                                   NULL};
        const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
-       int len;
 
        global_spnego_negotiated = True;
 
-       ZERO_STRUCT(guid);
+       memset(guid, '\0', sizeof(guid));
 
        safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
        strlower_m(unix_name);
@@ -191,11 +194,10 @@ static int negprot_spnego(char *p, uint8 *pkeylen)
        safe_strcpy(guid, dos_name, sizeof(guid)-1);
 
 #ifdef DEVELOPER
-       /* valgrind fixer... */
-       {
-               size_t sl = strlen(guid);
-               if (sizeof(guid)-sl)
-                       memset(&guid[sl], '\0', sizeof(guid)-sl);
+       /* Fix valgrind 'uninitialized bytes' issue. */
+       slen = strlen(dos_name);
+       if (slen < sizeof(guid)) {
+               memset(guid+slen, '\0', sizeof(guid) - slen);
        }
 #endif
 
@@ -226,24 +228,15 @@ static int negprot_spnego(char *p, uint8 *pkeylen)
                name_to_fqdn(myname, global_myname());
                strlower_m(myname);
                asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm());
+               if (host_princ_s == NULL) {
+                       blob = data_blob_null;
+                       return blob;
+               }
                blob = spnego_gen_negTokenInit(guid, OIDs_krb5, host_princ_s);
                SAFE_FREE(host_princ_s);
        }
 
-       memcpy(p, blob.data, blob.length);
-       len = blob.length;
-       if (len > 256) {
-               DEBUG(0,("negprot_spnego: blob length too long (%d)\n", len));
-               len = 255;
-       }
-       data_blob_free(&blob);
-
-       if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
-               *pkeylen = 0;
-       } else {
-               *pkeylen = len;
-       }
-       return len;
+       return blob;
 }
 
 /****************************************************************************
@@ -263,6 +256,18 @@ static int reply_nt1(char *inbuf, char *outbuf)
 
        global_encrypted_passwords_negotiated = lp_encrypted_passwords();
 
+       /* Check the flags field to see if this is Vista.
+          WinXP sets it and Vista does not. But we have to 
+          distinguish from NT which doesn't set it either. */
+
+       if ( (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY) &&
+               ((SVAL(inbuf, smb_flg2) & FLAGS2_UNKNOWN_BIT4) == 0) ) 
+       {
+               if (get_remote_arch() != RA_SAMBA) {
+                       set_remote_arch( RA_VISTA );
+               }
+       }
+
        /* do spnego in user level security if the client
           supports it and we can do encrypted passwords */
        
@@ -315,12 +320,12 @@ static int reply_nt1(char *inbuf, char *outbuf)
                } else {
                        DEBUG(0,("reply_nt1: smb signing is incompatible with share level security !\n"));
                        if (lp_server_signing() == Required) {
-                               exit_server("reply_nt1: smb signing required and share level security selected.");
+                               exit_server_cleanly("reply_nt1: smb signing required and share level security selected.");
                        }
                }
        }
 
-       set_message(outbuf,17,0,True);
+       set_message(inbuf,outbuf,17,0,True);
        
        SCVAL(outbuf,smb_vwv1,secword);
        
@@ -349,16 +354,22 @@ static int reply_nt1(char *inbuf, char *outbuf)
                                 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
                DEBUG(3,("not using SPNEGO\n"));
        } else {
-               uint8 keylen;
-               int len = negprot_spnego(p, &keylen);
-               
-               SCVAL(outbuf,smb_vwv16+1,keylen);
-               p += len;
+               DATA_BLOB spnego_blob = negprot_spnego();
+
+               if (spnego_blob.data == NULL) {
+                       return ERROR_NT(NT_STATUS_NO_MEMORY);
+               }
+
+               memcpy(p, spnego_blob.data, spnego_blob.length);
+               p += spnego_blob.length;
+               data_blob_free(&spnego_blob);
+
+               SCVAL(outbuf,smb_vwv16+1, 0);
                DEBUG(3,("using SPNEGO\n"));
        }
        
        SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
-       set_message_end(outbuf, p);
+       set_message_end(inbuf,outbuf, p);
        
        return (smb_len(outbuf)+4);
 }
@@ -393,6 +404,15 @@ protocol [LM1.2X002]
 protocol [LANMAN2.1]
 protocol [NT LM 0.12]
 
+Vista:
+protocol [PC NETWORK PROGRAM 1.0]
+protocol [LANMAN1.0]
+protocol [Windows for Workgroups 3.1a]
+protocol [LM1.2X002]
+protocol [LANMAN2.1]
+protocol [NT LM 0.12]
+protocol [SMB 2.001]
+
 OS/2:
 protocol [PC NETWORK PROGRAM 1.0]
 protocol [XENIX CORE]
@@ -406,18 +426,19 @@ protocol [LANMAN2.1]
   *
   * This appears to be the matrix of which protocol is used by which
   * MS product.
-       Protocol                       WfWg    Win95   WinNT  Win2K  OS/2
-       PC NETWORK PROGRAM 1.0          1       1       1      1      1
+       Protocol                       WfWg    Win95   WinNT  Win2K  OS/2 Vista
+       PC NETWORK PROGRAM 1.0          1       1       1      1      1     1
        XENIX CORE                                      2             2
        MICROSOFT NETWORKS 3.0          2       2       
        DOS LM1.2X002                   3       3       
        MICROSOFT NETWORKS 1.03                         3
        DOS LANMAN2.1                   4       4       
-       LANMAN1.0                                       4      2      3
-       Windows for Workgroups 3.1a     5       5       5      3
-       LM1.2X002                                       6      4      4
-       LANMAN2.1                                       7      5      5
-       NT LM 0.12                              6       8      6
+       LANMAN1.0                                       4      2      3     2
+       Windows for Workgroups 3.1a     5       5       5      3            3
+       LM1.2X002                                       6      4      4     4
+       LANMAN2.1                                       7      5      5     5
+       NT LM 0.12                              6       8      6            6
+       SMB 2.001                                                           7
   *
   *  tim@fsg.com 09/29/95
   *  Win2K added by matty 17/7/99
@@ -430,6 +451,7 @@ protocol [LANMAN2.1]
 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
 #define ARCH_SAMBA    0x20
 #define ARCH_CIFSFS   0x40
+#define ARCH_VISTA    0x8C     /* Vista is like XP/2K */
  
 #define ARCH_ALL      0x7F
  
@@ -456,13 +478,14 @@ static const struct {
 
 /****************************************************************************
  Reply to a negprot.
+ conn POINTER CAN BE NULL HERE !
 ****************************************************************************/
 
 int reply_negprot(connection_struct *conn, 
                  char *inbuf,char *outbuf, int dum_size, 
                  int dum_buffsize)
 {
-       int outsize = set_message(outbuf,1,0,True);
+       int outsize = set_message(inbuf,outbuf,1,0,True);
        int Index=0;
        int choice= -1;
        int protocol;
@@ -476,7 +499,7 @@ int reply_negprot(connection_struct *conn,
 
        if (done_negprot) {
                END_PROFILE(SMBnegprot);
-               exit_server("multiple negprot's are not permitted");
+               exit_server_cleanly("multiple negprot's are not permitted");
        }
        done_negprot = True;
 
@@ -492,6 +515,8 @@ int reply_negprot(connection_struct *conn,
                        arch &= ( ARCH_WFWG | ARCH_WIN95 );
                else if (strcsequal(p,"NT LM 0.12"))
                        arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
+               else if (strcsequal(p,"SMB 2.001"))
+                       arch = ARCH_VISTA;              
                else if (strcsequal(p,"LANMAN2.1"))
                        arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
                else if (strcsequal(p,"LM1.2X002"))
@@ -536,7 +561,13 @@ int reply_negprot(connection_struct *conn,
                                set_remote_arch(RA_WINNT);
                        break;
                case ARCH_WIN2K:
-                       set_remote_arch(RA_WIN2K);
+                       /* Vista may have been set in the negprot so don't 
+                          override it here */
+                       if ( get_remote_arch() != RA_VISTA )
+                               set_remote_arch(RA_WIN2K);
+                       break;
+               case ARCH_VISTA:
+                       set_remote_arch(RA_VISTA);
                        break;
                case ARCH_OS2:
                        set_remote_arch(RA_OS2);
@@ -553,7 +584,8 @@ int reply_negprot(connection_struct *conn,
           when the client connects to port 445.  Of course there is a small
           window where we are listening to messages   -- jerry */
 
-       claim_connection(NULL,"",0,True,FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
+       claim_connection(
+               NULL,"",FLAG_MSG_GENERAL|FLAG_MSG_SMBD|FLAG_MSG_PRINT_GENERAL);
     
        /* Check for protocols, most desirable first */
        for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
@@ -585,7 +617,8 @@ int reply_negprot(connection_struct *conn,
        DEBUG( 5, ( "negprot index=%d\n", choice ) );
 
        if ((lp_server_signing() == Required) && (Protocol < PROTOCOL_NT1)) {
-               exit_server("SMB signing is required and client negotiated a downlevel protocol");
+               exit_server_cleanly("SMB signing is required and "
+                       "client negotiated a downlevel protocol");
        }
 
        END_PROFILE(SMBnegprot);