Better explanation message for dmalloc.
[ira/wip.git] / source3 / smbd / negprot.c
index 11400af7101d9e5687c4816d416f44e505f921c7..af2f91936e1a27d1c2d3cf33f7bf8c4eb5e523a0 100644 (file)
 
 #include "includes.h"
 
-extern int DEBUGLEVEL;
 extern int Protocol;
 extern int max_recv;
 extern fstring global_myworkgroup;
 extern fstring remote_machine;
+BOOL global_encrypted_passwords_negotiated = False;
+BOOL global_spnego_negotiated = False;
+struct auth_context *negprot_global_auth_context = NULL;
+
+static void get_challange(char buff[8]) 
+{
+       NTSTATUS nt_status;
+       const uint8 *cryptkey;
+
+       /* We might be called more than once, muliple negprots are premitted */
+       if (negprot_global_auth_context) {
+               DEBUG(3, ("get challange: is this a secondary negprot?  negprot_global_auth_context is non-NULL!\n"));
+               (negprot_global_auth_context->free)(&negprot_global_auth_context);
+       }
+
+       DEBUG(10, ("get challange: 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", get_nt_error_msg(nt_status)));
+               smb_panic("cannot make_negprot_global_auth_context!\n");
+       }
+       DEBUG(10, ("get challange: getting challange\n"));
+       cryptkey = negprot_global_auth_context->get_ntlm_challenge(negprot_global_auth_context);
+       memcpy(buff, cryptkey, 8);
+}
 
 /****************************************************************************
 reply for the core protocol
 ****************************************************************************/
-static int reply_corep(char *outbuf)
+static int reply_corep(char *inbuf, char *outbuf)
 {
        int outsize = set_message(outbuf,1,0,True);
 
@@ -43,7 +66,7 @@ static int reply_corep(char *outbuf)
 /****************************************************************************
 reply for the coreplus protocol
 ****************************************************************************/
-static int reply_coreplus(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);
@@ -62,21 +85,23 @@ static int reply_coreplus(char *outbuf)
 /****************************************************************************
 reply for the lanman 1.0 protocol
 ****************************************************************************/
-static int reply_lanman1(char *outbuf)
+static int reply_lanman1(char *inbuf, char *outbuf)
 {
   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
   int secword=0;
-  BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
 
+  global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+
   if (lp_security()>=SEC_USER) secword |= 1;
-  if (doencrypt) secword |= 2;
+  if (global_encrypted_passwords_negotiated) secword |= 2;
 
-  set_message(outbuf,13,doencrypt?8:0,True);
+  set_message(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 (doencrypt) 
-    generate_next_challenge(smb_buf(outbuf));
+  if (global_encrypted_passwords_negotiated) {
+         get_challange(smb_buf(outbuf));
+  }
 
   Protocol = PROTOCOL_LANMAN1;
 
@@ -99,43 +124,25 @@ static int reply_lanman1(char *outbuf)
 /****************************************************************************
 reply for the lanman 2.0 protocol
 ****************************************************************************/
-static int reply_lanman2(char *outbuf)
+static int reply_lanman2(char *inbuf, char *outbuf)
 {
   int raw = (lp_readraw()?1:0) | (lp_writeraw()?2:0);
   int secword=0;
-  BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
-  struct cli_state *cli = NULL;
-  char cryptkey[8];
-  char crypt_len = 0;
-
-  if (lp_security() == SEC_SERVER) {
-         cli = server_cryptkey();
-  }
-
-  if (cli) {
-         DEBUG(3,("using password server validation\n"));
-         doencrypt = ((cli->sec_mode & 2) != 0);
-  }
 
+  global_encrypted_passwords_negotiated = lp_encrypted_passwords();
+  
   if (lp_security()>=SEC_USER) secword |= 1;
-  if (doencrypt) secword |= 2;
-
-  if (doencrypt) {
-         crypt_len = 8;
-         if (!cli) {
-                 generate_next_challenge(cryptkey);
-         } else {
-                 memcpy(cryptkey, cli->cryptkey, 8);
-                 set_challenge(cli->cryptkey);
-         }
-  }
+  if (global_encrypted_passwords_negotiated) secword |= 2;
 
-  set_message(outbuf,13,crypt_len,True);
+  set_message(outbuf,13,global_encrypted_passwords_negotiated?8:0,True);
   SSVAL(outbuf,smb_vwv1,secword); 
   SIVAL(outbuf,smb_vwv6,sys_getpid());
-  if (doencrypt) 
-         memcpy(smb_buf(outbuf), cryptkey, 8);
+
+  /* Create a token value and add it to the outgoing packet. */
+  if (global_encrypted_passwords_negotiated) {
+         get_challange(smb_buf(outbuf));
+  }
 
   Protocol = PROTOCOL_LANMAN2;
 
@@ -152,95 +159,152 @@ static int reply_lanman2(char *outbuf)
 }
 
 
-/****************************************************************************
-reply for the nt protocol
-****************************************************************************/
-static int reply_nt1(char *outbuf)
-{
-  /* dual names + lock_and_read + nt SMBs + remote API calls */
-  int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|CAP_LEVEL_II_OPLOCKS|
-                     (lp_nt_smb_support() ? CAP_NT_SMBS | CAP_RPC_REMOTE_APIS : 0) |
-                                        ((lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) ?
-                                                       CAP_LARGE_READX | CAP_LARGE_WRITEX | CAP_W2K_SMBS : 0) |
-                     (SMB_OFF_T_BITS == 64 ? CAP_LARGE_FILES : 0);
-
-
-/*
-  other valid capabilities which we may support at some time...
-                     CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
- */
-
-  int secword=0;
-  BOOL doencrypt = SMBENCRYPT();
-  time_t t = time(NULL);
-  struct cli_state *cli = NULL;
-  char cryptkey[8];
-  char crypt_len = 0;
-  char *p, *q;
-
-  if (lp_security() == SEC_SERVER) {
-         cli = server_cryptkey();
-  }
-
-  if (cli) {
-         DEBUG(3,("using password server validation\n"));
-         doencrypt = ((cli->sec_mode & 2) != 0);
-  }
-
-  if (doencrypt) {
-         crypt_len = 8;
-         if (!cli) {
-                 generate_next_challenge(cryptkey);
-         } else {
-                 memcpy(cryptkey, cli->cryptkey, 8);
-                 set_challenge(cli->cryptkey);
-         }
-  }
-
-  if (lp_readraw() && lp_writeraw()) {
-         capabilities |= CAP_RAW_MODE;
-  }
-
 
-  /* allow for disabling unicode */
-  if (lp_unicode()) {
-         capabilities |= CAP_UNICODE;
-  }
-
-#ifdef WITH_MSDFS
-  if(lp_host_msdfs())
-       capabilities |= CAP_DFS;
+/* 
+   generate the spnego negprot reply blob. Return the number of bytes used
+*/
+static int negprot_spnego(char *p)
+{
+       DATA_BLOB blob;
+       extern pstring global_myname;
+       uint8 guid[16];
+       const char *OIDs_krb5[] = {OID_NTLMSSP,
+                                  OID_KERBEROS5,
+                                  OID_KERBEROS5_OLD,
+                                  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);
+
+#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)
+       */
+       if (lp_security() != SEC_ADS) {
+               memcpy(p, guid, 16);
+               return 16;
+       }
 #endif
+       {
+               ADS_STRUCT *ads;
+               ads = ads_init(NULL, NULL, NULL, NULL);
+               
+               /* win2000 uses host$@REALM, which we will probably use eventually,
+                  but for now this works */
+               asprintf(&principal, "HOST/%s@%s", guid, ads->realm);
+               blob = spnego_gen_negTokenInit(guid, 
+                                              lp_security()==SEC_ADS ? OIDs_krb5 : OIDs_plain, 
+                                              principal);
+               free(principal);
+               ads_destroy(&ads);
+       }
+       memcpy(p, blob.data, blob.length);
+       len = blob.length;
+       data_blob_free(&blob);
+       return len;
+}
 
-  if (lp_security() >= SEC_USER) secword |= 1;
-  if (doencrypt) secword |= 2;
-
-  set_message(outbuf,17,0,True);
-
-  CVAL(outbuf,smb_vwv1) = secword;
-  SSVALS(outbuf,smb_vwv16+1,crypt_len);
-
-  Protocol = PROTOCOL_NT1;
+               
 
-  SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
-  SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
-  SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
-  SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
-  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);
+/****************************************************************************
+reply for the nt protocol
+****************************************************************************/
+static int reply_nt1(char *inbuf, char *outbuf)
+{
+       /* dual names + lock_and_read + nt SMBs + remote API calls */
+       int capabilities = CAP_NT_FIND|CAP_LOCK_AND_READ|
+               CAP_LEVEL_II_OPLOCKS|CAP_STATUS32;
 
-  p = q = smb_buf(outbuf);
-  if (doencrypt) memcpy(p, cryptkey, 8);
-  p += 8;
-  p += srvstr_push(outbuf, p, global_myworkgroup, -1, 
-                  STR_UNICODE|STR_CONVERT|STR_TERMINATE|STR_NOALIGN);
+       int secword=0;
+       time_t t = time(NULL);
+       char *p, *q;
+       BOOL negotiate_spnego = False;
 
-  SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
-  set_message_end(outbuf, p);
+       global_encrypted_passwords_negotiated = lp_encrypted_passwords();
 
-  return (smb_len(outbuf)+4);
+       /* do spnego in user level security if the client
+          supports it and we can do encrypted passwords */
+       
+       if (global_encrypted_passwords_negotiated && 
+           (lp_security() != SEC_SHARE) &&
+           lp_use_spnego() &&
+           (SVAL(inbuf, smb_flg2) & FLAGS2_EXTENDED_SECURITY)) {
+               negotiate_spnego = True;
+               capabilities |= CAP_EXTENDED_SECURITY;
+       }
+       
+       capabilities |= CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
+       
+       if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) {
+               capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS;
+       }
+       
+       if (SMB_OFF_T_BITS == 64) {
+               capabilities |= CAP_LARGE_FILES;
+       }
+       
+       if (lp_readraw() && lp_writeraw()) {
+               capabilities |= CAP_RAW_MODE;
+       }
+       
+       /* allow for disabling unicode */
+       if (lp_unicode()) {
+               capabilities |= CAP_UNICODE;
+       }
+       
+       if (lp_host_msdfs())
+               capabilities |= CAP_DFS;
+       
+       if (lp_security() >= SEC_USER) secword |= 1;
+       if (global_encrypted_passwords_negotiated) secword |= 2;
+       
+       set_message(outbuf,17,0,True);
+       
+       CVAL(outbuf,smb_vwv1) = secword;
+       
+       Protocol = PROTOCOL_NT1;
+       
+       SSVAL(outbuf,smb_vwv1+1,lp_maxmux()); /* maxmpx */
+       SSVAL(outbuf,smb_vwv2+1,1); /* num vcs */
+       SIVAL(outbuf,smb_vwv3+1,0xffff); /* max buffer. LOTS! */
+       SIVAL(outbuf,smb_vwv5+1,0x10000); /* raw size. full 64k */
+       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);
+       
+       p = q = smb_buf(outbuf);
+       if (!negotiate_spnego) {
+               /* Create a token value and add it to the outgoing packet. */
+               if (global_encrypted_passwords_negotiated) {
+                       get_challange(p);
+               }
+               SSVALS(outbuf,smb_vwv16+1,8);
+               p += 8;
+               p += srvstr_push(outbuf, p, global_myworkgroup, -1, 
+                                STR_UNICODE|STR_TERMINATE|STR_NOALIGN);
+               DEBUG(3,("not using SPNEGO\n"));
+       } else {
+               int len = negprot_spnego(p);
+               
+               SSVALS(outbuf,smb_vwv16+1,len);
+               p += len;
+               DEBUG(3,("using SPNEGO\n"));
+       }
+       
+       SSVAL(outbuf,smb_vwv17, p - q); /* length of challenge+domain strings */
+       set_message_end(outbuf, p);
+       
+       return (smb_len(outbuf)+4);
 }
 
 /* these are the protocol lists used for auto architecture detection:
@@ -316,7 +380,7 @@ protocol [LANMAN2.1]
 static struct {
   char *proto_name;
   char *short_name;
-  int (*proto_reply_fn)(char *);
+  int (*proto_reply_fn)(char *, char *);
   int protocol_level;
 } supported_protocols[] = {
   {"NT LANMAN 1.0",           "NT1",      reply_nt1,      PROTOCOL_NT1},
@@ -407,11 +471,6 @@ int reply_negprot(connection_struct *conn,
   /* possibly reload - change of architecture */
   reload_services(True);      
     
-  /* a special case to stop password server loops */
-  if (Index == 1 && strequal(remote_machine,myhostname()) && 
-      (lp_security()==SEC_SERVER || lp_security()==SEC_DOMAIN))
-    exit_server("Password server loop!");
-  
   /* Check for protocols, most desirable first */
   for (protocol = 0; supported_protocols[protocol].proto_name; protocol++)
     {
@@ -435,7 +494,7 @@ int reply_negprot(connection_struct *conn,
     extern fstring remote_proto;
     fstrcpy(remote_proto,supported_protocols[protocol].short_name);
     reload_services(True);          
-    outsize = supported_protocols[protocol].proto_reply_fn(outbuf);
+    outsize = supported_protocols[protocol].proto_reply_fn(inbuf, outbuf);
     DEBUG(3,("Selected protocol %s\n",supported_protocols[protocol].proto_name));
   }
   else {
@@ -448,3 +507,4 @@ int reply_negprot(connection_struct *conn,
   END_PROFILE(SMBnegprot);
   return(outsize);
 }
+