r11511: A classic "friday night check-in" :-). This moves much
[abartlet/samba.git/.git] / source3 / smbd / negprot.c
index b91c0c0866b103afd6355fce8ed606bebcc8ca98..db061cb1b8c0b8e3926eda13bbe9a98662217ccf 100644 (file)
 
 #include "includes.h"
 
-extern int Protocol;
+extern fstring remote_proto;
+extern enum protocol_types Protocol;
 extern int max_recv;
+
 BOOL global_encrypted_passwords_negotiated = False;
 BOOL global_spnego_negotiated = False;
 struct auth_context *negprot_global_auth_context = NULL;
@@ -101,6 +103,7 @@ static int reply_lanman1(char *inbuf, char *outbuf)
        /* Create a token value and add it to the outgoing packet. */
        if (global_encrypted_passwords_negotiated) {
                get_challenge(smb_buf(outbuf));
+               SSVAL(outbuf,smb_vwv11, 8);
        }
 
        Protocol = PROTOCOL_LANMAN1;
@@ -113,9 +116,9 @@ static int reply_lanman1(char *inbuf, char *outbuf)
        SSVAL(outbuf,smb_vwv5,raw); /* tell redirector we support
                readbraw writebraw (possibly) */
        SIVAL(outbuf,smb_vwv6,sys_getpid());
-       SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
+       SSVAL(outbuf,smb_vwv10, set_server_zone_offset(t)/60);
 
-       put_dos_date(outbuf,smb_vwv8,t);
+       srv_put_dos_date(outbuf,smb_vwv8,t);
 
        return (smb_len(outbuf)+4);
 }
@@ -144,6 +147,7 @@ static int reply_lanman2(char *inbuf, char *outbuf)
        /* Create a token value and add it to the outgoing packet. */
        if (global_encrypted_passwords_negotiated) {
                get_challenge(smb_buf(outbuf));
+               SSVAL(outbuf,smb_vwv11, 8);
        }
 
        Protocol = PROTOCOL_LANMAN2;
@@ -154,8 +158,8 @@ static int reply_lanman2(char *inbuf, char *outbuf)
        SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
        SSVAL(outbuf,smb_vwv4,1);
        SSVAL(outbuf,smb_vwv5,raw); /* readbraw and/or writebraw */
-       SSVAL(outbuf,smb_vwv10, TimeDiff(t)/60);
-       put_dos_date(outbuf,smb_vwv8,t);
+       SSVAL(outbuf,smb_vwv10, set_server_zone_offset(t)/60);
+       srv_put_dos_date(outbuf,smb_vwv8,t);
 
        return (smb_len(outbuf)+4);
 }
@@ -164,45 +168,69 @@ 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)
+static int negprot_spnego(char *p, uint8 *pkeylen)
 {
        DATA_BLOB blob;
-       uint8 guid[16];
+       nstring dos_name;
+       fstring unix_name;
+       char guid[17];
        const char *OIDs_krb5[] = {OID_KERBEROS5,
                                   OID_KERBEROS5_OLD,
                                   OID_NTLMSSP,
                                   NULL};
-       const char *OIDs_plain[] = {OID_NTLMSSP, NULL};
-       char *principal;
        int len;
 
        global_spnego_negotiated = True;
 
-       memset(guid, 0, 16);
-       safe_strcpy((char *)guid, global_myname(), 16);
-       strlower((char *)guid);
+       ZERO_STRUCT(guid);
+
+       safe_strcpy(unix_name, global_myname(), sizeof(unix_name)-1);
+       strlower_m(unix_name);
+       push_ascii_nstring(dos_name, unix_name);
+       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);
+       }
+#endif
 
-#if 0
        /* strangely enough, NT does not sent the single OID NTLMSSP when
           not a ADS member, it sends no OIDs at all
 
-          we can't do this until we teach our sesssion setup parser to know
-          about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)
+          OLD COMMENT : "we can't do this until we teach our sesssion setup parser to know
+                  about raw NTLMSSP (clients send no ASN.1 wrapping if we do this)"
+
+          Our sessionsetup code now handles raw NTLMSSP connects, so we can go
+          back to doing what W2K3 does here. This is needed to make PocketPC 2003
+          CIFS connections work with SPNEGO. See bugzilla bugs #1828 and #3133
+          for details. JRA.
+
        */
-       if (lp_security() != SEC_ADS) {
+
+       if (lp_security() != SEC_ADS && !lp_use_kerberos_keytab()) {
                memcpy(p, guid, 16);
+               *pkeylen = 0;
                return 16;
-       }
-#endif
-       if (lp_security() != SEC_ADS) {
-               blob = spnego_gen_negTokenInit(guid, OIDs_plain, "NONE");
        } else {
-               asprintf(&principal, "%s$@%s", guid, lp_realm());
-               blob = spnego_gen_negTokenInit(guid, OIDs_krb5, principal);
-               free(principal);
+               fstring myname;
+               char *host_princ_s = NULL;
+               name_to_fqdn(myname, global_myname());
+               strlower_m(myname);
+               asprintf(&host_princ_s, "cifs/%s@%s", myname, lp_realm());
+               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;
+       }
+       *pkeylen = len;
        data_blob_free(&blob);
        return len;
 }
@@ -218,9 +246,9 @@ static int reply_nt1(char *inbuf, char *outbuf)
                CAP_LEVEL_II_OPLOCKS;
 
        int secword=0;
-       time_t t = time(NULL);
        char *p, *q;
        BOOL negotiate_spnego = False;
+       time_t t = time(NULL);
 
        global_encrypted_passwords_negotiated = lp_encrypted_passwords();
 
@@ -233,9 +261,13 @@ static int reply_nt1(char *inbuf, char *outbuf)
            (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
                negotiate_spnego = True;
                capabilities |= CAP_EXTENDED_SECURITY;
+               add_to_common_flags2(FLAGS2_EXTENDED_SECURITY);
+               /* Ensure FLAGS2_EXTENDED_SECURITY gets set in this reply (already
+                       partially constructed. */
+               SSVAL(outbuf,smb_flg2, SVAL(outbuf,smb_flg2) | FLAGS2_EXTENDED_SECURITY);
        }
        
-       capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+       capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS|CAP_UNICODE;
 
        if (lp_unix_extensions()) {
                capabilities |= CAP_UNIX;
@@ -250,10 +282,6 @@ static int reply_nt1(char *inbuf, char *outbuf)
        if (lp_readraw() && lp_writeraw())
                capabilities |= CAP_RAW_MODE;
        
-       /* allow for disabling unicode */
-       if (lp_unicode())
-               capabilities |= CAP_UNICODE;
-
        if (lp_nt_status_support())
                capabilities |= CAP_STATUS32;
        
@@ -265,6 +293,22 @@ static int reply_nt1(char *inbuf, char *outbuf)
        if (global_encrypted_passwords_negotiated)
                secword |= NEGOTIATE_SECURITY_CHALLENGE_RESPONSE;
        
+       if (lp_server_signing()) {
+               if (lp_security() >= SEC_USER) {
+                       secword |= NEGOTIATE_SECURITY_SIGNATURES_ENABLED;
+                       /* No raw mode with smb signing. */
+                       capabilities &= ~CAP_RAW_MODE;
+                       if (lp_server_signing() == Required)
+                               secword |=NEGOTIATE_SECURITY_SIGNATURES_REQUIRED;
+                       srv_set_signing_negotiated();
+               } 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.");
+                       }
+               }
+       }
+
        set_message(outbuf,17,0,True);
        
        SCVAL(outbuf,smb_vwv1,secword);
@@ -278,7 +322,7 @@ static int reply_nt1(char *inbuf, char *outbuf)
        SIVAL(outbuf,smb_vwv7+1,sys_getpid()); /* session key */
        SIVAL(outbuf,smb_vwv9+1,capabilities); /* capabilities */
        put_long_date(outbuf+smb_vwv11+1,t);
-       SSVALS(outbuf,smb_vwv15+1,TimeDiff(t)/60);
+       SSVALS(outbuf,smb_vwv15+1,set_server_zone_offset(t)/60);
        
        p = q = smb_buf(outbuf);
        if (!negotiate_spnego) {
@@ -287,16 +331,17 @@ static int reply_nt1(char *inbuf, char *outbuf)
                        /* note that we do not send a challenge at all if
                           we are using plaintext */
                        get_challenge(p);
-                       SSVALS(outbuf,smb_vwv16+1,8);
+                       SCVAL(outbuf,smb_vwv16+1,8);
                        p += 8;
                }
                p += srvstr_push(outbuf, p, lp_workgroup(), -1, 
                                 STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
                DEBUG(3,("not using SPNEGO\n"));
        } else {
-               int len = negprot_spnego(p);
+               uint8 keylen;
+               int len = negprot_spnego(p, &keylen);
                
-               SSVALS(outbuf,smb_vwv16+1,len);
+               SCVAL(outbuf,smb_vwv16+1,keylen);
                p += len;
                DEBUG(3,("using SPNEGO\n"));
        }
@@ -373,18 +418,21 @@ protocol [LANMAN2.1]
 #define ARCH_WIN2K    0xC      /* Win2K is like NT */
 #define ARCH_OS2      0x14     /* Again OS/2 is like NT */
 #define ARCH_SAMBA    0x20
+#define ARCH_CIFSFS   0x40
  
-#define ARCH_ALL      0x3F
+#define ARCH_ALL      0x7F
  
 /* List of supported protocols, most desired first */
-static struct {
-       char *proto_name;
-       char *short_name;
+static const struct {
+       const char *proto_name;
+       const char *short_name;
        int (*proto_reply_fn)(char *, char *);
        int protocol_level;
 } supported_protocols[] = {
        {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
        {"NT LM 0.12",              "NT1",      reply_nt1,      PROTOCOL_NT1},
+       {"POSIX 2",                 "NT1",      reply_nt1,      PROTOCOL_NT1},
+       {"LANMAN2.1",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
        {"LM1.2X002",               "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
        {"Samba",                   "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
        {"DOS LM1.2X002",           "LANMAN2",  reply_lanman2,  PROTOCOL_LANMAN2},
@@ -432,7 +480,7 @@ int reply_negprot(connection_struct *conn,
                else if (strcsequal(p,"DOS LANMAN2.1"))
                        arch &= ( ARCH_WFWG | ARCH_WIN95 );
                else if (strcsequal(p,"NT LM 0.12"))
-                       arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K );
+                       arch &= ( ARCH_WIN95 | ARCH_WINNT | ARCH_WIN2K | ARCH_CIFSFS);
                else if (strcsequal(p,"LANMAN2.1"))
                        arch &= ( ARCH_WINNT | ARCH_WIN2K | ARCH_OS2 );
                else if (strcsequal(p,"LM1.2X002"))
@@ -444,12 +492,23 @@ int reply_negprot(connection_struct *conn,
                else if (strcsequal(p,"Samba")) {
                        arch = ARCH_SAMBA;
                        break;
+               } else if (strcsequal(p,"POSIX 2")) {
+                       arch = ARCH_CIFSFS;
+                       break;
                }
  
                p += strlen(p) + 2;
        }
-    
+
+       /* CIFSFS can send one arch only, NT LM 0.12. */
+       if (Index == 1 && (arch & ARCH_CIFSFS)) {
+               arch = ARCH_CIFSFS;
+       }
+
        switch ( arch ) {
+               case ARCH_CIFSFS:
+                       set_remote_arch(RA_CIFSFS);
+                       break;
                case ARCH_SAMBA:
                        set_remote_arch(RA_SAMBA);
                        break;
@@ -478,6 +537,12 @@ int reply_negprot(connection_struct *conn,
  
        /* possibly reload - change of architecture */
        reload_services(True);      
+       
+       /* moved from the netbios session setup code since we don't have that 
+          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);
     
        /* Check for protocols, most desirable first */
        for (protocol = 0; supported_protocols[protocol].proto_name; protocol++) {
@@ -497,7 +562,6 @@ int reply_negprot(connection_struct *conn,
   
        SSVAL(outbuf,smb_vwv0,choice);
        if(choice != -1) {
-               extern fstring remote_proto;
                fstrcpy(remote_proto,supported_protocols[protocol].short_name);
                reload_services(True);          
                outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
@@ -509,6 +573,10 @@ 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");
+       }
+
        END_PROFILE(SMBnegprot);
        return(outsize);
 }