rewrote the password server code using the new clientgen.c client
authorAndrew Tridgell <tridge@samba.org>
Tue, 21 Oct 1997 09:34:33 +0000 (09:34 +0000)
committerAndrew Tridgell <tridge@samba.org>
Tue, 21 Oct 1997 09:34:33 +0000 (09:34 +0000)
interface

The new code uses a source netbios name equal to the Samba servers
name, not the client name. It also uses NetWkstaUserLogon to do a full
network logon. This means it will honour the servers logon
restrictions (such as login times etc).
(This used to be commit 11de90f972f6d83974425e80014f54e15d495413)

source3/include/smb.h
source3/smbd/password.c
source3/smbd/reply.c
source3/smbd/server.c

index 2b0fc44d2446a8e5f2acfb08ac46770ab07988c1..7921e77108e705abc0b7286b946276ce9ea64b52 100644 (file)
@@ -989,6 +989,32 @@ struct smb_passwd
 };
 
 
+struct cli_state {
+       int fd;
+       int cnum;
+       int pid;
+       int mid;
+       int uid;
+       int protocol;
+       int sec_mode;
+       int error;
+       int privilages;
+       fstring eff_name;
+       fstring desthost;
+       char cryptkey[8];
+       uint32 sesskey;
+       int serverzone;
+       uint32 servertime;
+       int readbraw_supported;
+       int writebraw_supported;
+       int timeout;
+       int max_xmit;
+       char *outbuf;
+       char *inbuf;
+       int bufsize;
+       int initialised;
+};
+
 struct current_user
 {
   int cnum, id;
index 311ef47679f92e6683807d1605bd89415cf9b2c8..24ee52ed692033f39d5af52f2efb55c702d56bdc 100644 (file)
@@ -1475,206 +1475,143 @@ BOOL check_hosts_equiv(char *user)
 }
 
 
-int password_client = -1;
-static fstring pserver;
-static char *secserver_inbuf = NULL;
+static struct cli_state cli;
 
 /****************************************************************************
-attempted support for server level security 
+return the client state structure
 ****************************************************************************/
-BOOL server_cryptkey(char *buf)
+struct cli_state *server_client(void)
 {
-  pstring outbuf;
-  fstring pass_protocol;
-  extern fstring remote_machine;
-  char *p;
-  int len;
-  fstring desthost;
-  struct in_addr dest_ip;
-  int port = SMB_PORT;
-  BOOL ret;
-  
-  if(secserver_inbuf == NULL) {
-    secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-    if(secserver_inbuf == NULL) {
-      DEBUG(0,("server_cryptkey: malloc fail for input buffer.\n"));
-      return False;
-    }
-  }
-
-  if (password_client >= 0)
-    close(password_client);
-  password_client = -1;
-
-  if (Protocol < PROTOCOL_NT1) {
-    strcpy(pass_protocol,"LM1.2X002");
-  } else {
-    strcpy(pass_protocol,"NT LM 0.12");
-  }
-
-  bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN);
-  bzero(outbuf,sizeof(outbuf));
-
-  for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
-    strcpy(desthost,p);
-    standard_sub_basic(desthost);
-    strupper(desthost);
-
-    dest_ip = *interpret_addr2(desthost);
-    if (zero_ip(dest_ip)) {
-      DEBUG(1,("Can't resolve address for %s\n",p));
-      continue;
-    }
-
-    if (ismyip(dest_ip)) {
-      DEBUG(1,("Password server loop - disabling password server %s\n",p));
-      continue;
-    }
-
-    password_client = open_socket_out(SOCK_STREAM, &dest_ip, port, SHORT_CONNECT_TIMEOUT);
-    if (password_client >= 0) {
-      DEBUG(3,("connected to password server %s\n",p));
-      StrnCpy(pserver,p,sizeof(pserver)-1);
-      break;
-    }
-  }
-
-  if (password_client < 0) {
-    DEBUG(1,("password server not available\n"));
-    return(False);
-  }
-
-
-  /* send a session request (RFC 8002) */
-
-  /* put in the destination name */
-  len = 4;
-  p = outbuf+len;
-  name_mangle(desthost,p,' ');
-  len += name_len(p);
-  p = outbuf+len;
-
-  /* and my name */
-  /* Fix from Frank Varnavas <varnavas@ny.ubs.com>.
-     We cannot use the same name as the client to 
-     the NT password server, as NT will drop client
-     connections if the same client name connects
-     twice. Instead, synthesize a name from our pid.
-     and the remote machine name.
-   */
-  {
-    char buf2[32]; /* create name as PIDname */
-    sprintf(buf2,"%d", getpid());
-    strncpy(&buf2[strlen(buf2)], remote_machine, 31 - strlen(buf2));
-    buf2[31] = '\0';
-    DEBUG(1,("negprot w/password server as %s\n",buf2));
-    name_mangle(buf2,p,' ');
-    len += name_len(p);
-  }
-
-  _smb_setlen(outbuf,len);
-  CVAL(outbuf,0) = 0x81;
-
-  send_smb(password_client,outbuf);
-  
-  if (!receive_smb(password_client,secserver_inbuf,5000) ||
-      CVAL(secserver_inbuf,0) != 0x82) {
-    DEBUG(1,("%s rejected the session\n",pserver));
-    close(password_client); password_client = -1;
-    return(False);
-  }
+       return &cli;
+}
 
-  DEBUG(3,("got session\n"));
+/****************************************************************************
+support for server level security 
+****************************************************************************/
+struct cli_state *server_cryptkey(void)
+{
+       fstring desthost;
+       struct in_addr dest_ip;
+       extern fstring local_machine;
+       char *p;
+
+       if (!cli_initialise(&cli))
+               return NULL;
+           
+       for (p=strtok(lp_passwordserver(),LIST_SEP); p ; p = strtok(NULL,LIST_SEP)) {
+               fstrcpy(desthost,p);
+               standard_sub_basic(desthost);
+               strupper(desthost);
+
+               dest_ip = *interpret_addr2(desthost);
+               if (zero_ip(dest_ip)) {
+                       DEBUG(1,("Can't resolve address for %s\n",p));
+                       continue;
+               }
 
-  bzero(outbuf,smb_size);
+               if (ismyip(dest_ip)) {
+                       DEBUG(1,("Password server loop - disabling password server %s\n",p));
+                       continue;
+               }
 
-  /* setup the protocol string */
-  set_message(outbuf,0,strlen(pass_protocol)+2,True);
-  p = smb_buf(outbuf);
-  *p++ = 2;
-  strcpy(p,pass_protocol);
+               if (cli_connect(&cli, desthost, &dest_ip)) {
+                       DEBUG(3,("connected to password server %s\n",p));
+                       break;
+               }
+       }
 
-  CVAL(outbuf,smb_com) = SMBnegprot;
-  CVAL(outbuf,smb_flg) = 0x8;
-  SSVAL(outbuf,smb_flg2,0x1);
+       if (!p) {
+               DEBUG(1,("password server not available\n"));
+               cli_shutdown(&cli);
+               return NULL;
+       }
 
-  send_smb(password_client,outbuf);
-  ret = receive_smb(password_client,secserver_inbuf,5000);
+       if (!cli_session_request(&cli, desthost, 0x20, local_machine)) {
+               DEBUG(1,("%s rejected the session\n",desthost));
+               cli_shutdown(&cli);
+               return NULL;
+       }
 
-  if (!ret || CVAL(secserver_inbuf,smb_rcls) || SVAL(secserver_inbuf,smb_vwv0)) {
-    DEBUG(1,("%s rejected the protocol\n",pserver));
-    close(password_client); password_client= -1;
-    return(False);
-  }
+       DEBUG(3,("got session\n"));
 
-  if (!(CVAL(secserver_inbuf,smb_vwv1) & 1)) {
-    DEBUG(1,("%s isn't in user level security mode\n",pserver));
-    close(password_client); password_client= -1;
-    return(False);
-  }
+       if (!cli_negprot(&cli)) {
+               DEBUG(1,("%s rejected the negprot\n",desthost));
+               cli_shutdown(&cli);
+               return NULL;
+       }
 
-  memcpy(buf,secserver_inbuf,smb_len(secserver_inbuf)+4);
+       if (cli.protocol < PROTOCOL_LANMAN2 ||
+           !(cli.sec_mode & 1)) {
+               DEBUG(1,("%s isn't in user level security mode\n",desthost));
+               cli_shutdown(&cli);
+               return NULL;
+       }
 
-  DEBUG(3,("password server OK\n"));
+       DEBUG(3,("password server OK\n"));
 
-  return(True);
+       return &cli;
 }
 
 /****************************************************************************
-support for server level security 
+validate a password with the password server
 ****************************************************************************/
-BOOL server_validate(char *buf)
+BOOL server_validate(char *user, char *domain, 
+                    char *pass, int passlen,
+                    char *ntpass, int ntpasslen)
 {
-  pstring outbuf;  
-  BOOL ret;
+       extern fstring local_machine;
+       fstring share;
 
-  if(secserver_inbuf == NULL) {
-    secserver_inbuf = (char *)malloc(BUFFER_SIZE + SAFETY_MARGIN);
-    if(secserver_inbuf == NULL) {
-      DEBUG(0,("server_validate: malloc fail for input buffer.\n"));
-      return False;
-    }
-  }
+       if (!cli.initialised) {
+               DEBUG(1,("password server %s is not connected\n", cli.desthost));
+               return(False);
+       }  
 
-  if (password_client < 0) {
-    DEBUG(1,("%s not connected\n",pserver));
-    return(False);
-  }  
+       if (!cli_session_setup(&cli, user, pass, passlen, ntpass, ntpasslen, domain)) {
+               DEBUG(1,("password server %s rejected the password\n", cli.desthost));
+               return False;
+       }
 
-  bzero(secserver_inbuf,BUFFER_SIZE + SAFETY_MARGIN);
-  memcpy(outbuf,buf,sizeof(outbuf));
+       /* if logged in as guest then reject */
+       if ((SVAL(cli.inbuf,smb_vwv2) & 1) != 0) {
+               DEBUG(1,("password server %s gave us guest only\n", cli.desthost));
+               return(False);
+       }
 
-  /* send a session setup command */
-  CVAL(outbuf,smb_flg) = 0x8;
-  SSVAL(outbuf,smb_flg2,0x1);
-  CVAL(outbuf,smb_vwv0) = 0xFF;
 
-  set_message(outbuf,smb_numwords(outbuf),smb_buflen(outbuf),False);
+       sprintf(share,"\\\\%s\\IPC$", cli.desthost);
 
-  SCVAL(secserver_inbuf,smb_rcls,1);
+       if (!cli_send_tconX(&cli, share, "IPC", "", 1)) {
+               DEBUG(1,("password server %s refused IPC$ connect\n", cli.desthost));
+               return False;
+       }
 
-  send_smb(password_client,outbuf);
-  ret = receive_smb(password_client,secserver_inbuf,5000);
 
-  if (!ret || CVAL(secserver_inbuf,smb_rcls) != 0) {
-    DEBUG(1,("password server %s rejected the password\n",pserver));
-    return(False);
-  }
+       if (!cli_NetWkstaUserLogon(&cli,user,local_machine)) {
+               DEBUG(1,("password server %s failed NetWkstaUserLogon\n", cli.desthost));
+               cli_tdis(&cli);
+               return False;
+       }
 
-  /* if logged in as guest then reject */
-  if ((SVAL(secserver_inbuf,smb_vwv2) & 1) != 0) {
-    DEBUG(1,("password server %s gave us guest only\n",pserver));
-    return(False);
-  }
+       if (cli.privilages == 0) {
+               DEBUG(1,("password server %s gave guest privilages\n", cli.desthost));
+               cli_tdis(&cli);
+               return False;
+       }
+
+       if (!strequal(cli.eff_name, user)) {
+               DEBUG(1,("password server %s gave different username %s\n", 
+                        cli.desthost,
+                        cli.eff_name));
+               cli_tdis(&cli);
+               return False;
+       }
 
-  DEBUG(3,("password server %s accepted the password\n",pserver));
+       DEBUG(3,("password server %s accepted the password\n", cli.desthost));
 
-#if !KEEP_PASSWORD_SERVER_OPEN
-  close(password_client); password_client= -1;
-#endif
+       cli_tdis(&cli);
 
-  return(True);
+       return(True);
 }
 
 
index 424c7d818321a5c6c7212f1abe483434ccf20980..3643b6eed0d015cf4a235f88cd0e569e33d2b445 100644 (file)
@@ -379,8 +379,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   BOOL computer_id=False;
   static BOOL done_sesssetup = False;
   BOOL doencrypt = SMBENCRYPT();
+  char *domain = "";
 
   *smb_apasswd = 0;
+  *smb_ntpasswd = 0;
   
   smb_bufsize = SVAL(inbuf,smb_vwv2);
   smb_mpxmax = SVAL(inbuf,smb_vwv3);
@@ -469,8 +471,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
     
     p += passlen1 + passlen2;
     fstrcpy(user,p); p = skip_string(p,1);
+    domain = p;
+
     DEBUG(3,("Domain=[%s]  NativeOS=[%s] NativeLanMan=[%s]\n",
-            p,skip_string(p,1),skip_string(p,2)));
+            domain,skip_string(p,1),skip_string(p,2)));
   }
 
 
@@ -533,7 +537,10 @@ int reply_sesssetup_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   if(!guest && strequal(user,lp_guestaccount(-1)) && (*smb_apasswd == 0))
     guest = True;
 
-  if (!guest && !(lp_security() == SEC_SERVER && server_validate(inbuf)) &&
+  if (!guest && !(lp_security() == SEC_SERVER && 
+                 server_validate(user, domain, 
+                                 smb_apasswd, smb_apasslen, 
+                                 smb_ntpasswd, smb_ntpasslen)) &&
       !check_hosts_equiv(user))
     {
 
index 7639c5940be1f2542b96974213a6d590a85ab709..f6a43a536da336236e4c4de3d738eadd38200814 100644 (file)
@@ -2320,22 +2320,21 @@ static int sig_cld()
   **************************************************************************/
 static int sig_pipe()
 {
-  extern int password_client;
-  BlockSignals(True,SIGPIPE);
+       struct cli_state *cli;
+       BlockSignals(True,SIGPIPE);
 
-  if (password_client != -1) {
-    DEBUG(3,("lost connection to password server\n"));
-    close(password_client);
-    password_client = -1;
+       if ((cli = server_client()) && cli->initialised) {
+               DEBUG(3,("lost connection to password server\n"));
+               cli_shutdown(cli);
 #ifndef DONT_REINSTALL_SIG
-    signal(SIGPIPE, SIGNAL_CAST sig_pipe);
+               signal(SIGPIPE, SIGNAL_CAST sig_pipe);
 #endif
-    BlockSignals(False,SIGPIPE);
-    return 0;
-  }
+               BlockSignals(False,SIGPIPE);
+               return 0;
+       }
 
-  exit_server("Got sigpipe\n");
-  return(0);
+       exit_server("Got sigpipe\n");
+       return(0);
 }
 
 /****************************************************************************
@@ -3564,11 +3563,6 @@ int reply_lanman1(char *outbuf)
 
   Protocol = PROTOCOL_LANMAN1;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-  if (doencrypt) set_challenge(smb_buf(outbuf));    
-  }
-
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
   SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
   SSVAL(outbuf,smb_vwv2,max_recv);
@@ -3594,32 +3588,42 @@ int reply_lanman2(char *outbuf)
   int secword=0;
   BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
-  /* We need to save and restore this as it can be destroyed
-     if we call another server if security=server
-     Thanks to Paul Nelson @ Thursby for pointing this out.
-   */
-  uint16 mid = SVAL(outbuf, smb_mid);
+  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);
+  }
 
   if (lp_security()>=SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
 
-  set_message(outbuf,13,doencrypt?8:0,True);
+  if (doencrypt) {
+         crypt_len = 8;
+         if (!cli) {
+                 generate_next_challenge(cryptkey);
+         } else {
+                 memcpy(cryptkey, cli->cryptkey, 8);
+                 set_challenge(cli->cryptkey);
+         }
+  }
+
+  set_message(outbuf,13,crypt_len,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));
+         memcpy(smb_buf(outbuf), cryptkey, 8);
 
   SIVAL(outbuf,smb_vwv6,getpid());
 
   Protocol = PROTOCOL_LANMAN2;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-    if (doencrypt) set_challenge(smb_buf(outbuf));    
-  }
-
   CVAL(outbuf,smb_flg) = 0x81; /* Reply, SMBlockread, SMBwritelock supported */
-  SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
   SSVAL(outbuf,smb_vwv2,max_recv);
   SSVAL(outbuf,smb_vwv3,lp_maxmux()); 
   SSVAL(outbuf,smb_vwv4,1);
@@ -3641,67 +3645,58 @@ int reply_nt1(char *outbuf)
 /*
   other valid capabilities which we may support at some time...
                      CAP_LARGE_FILES|CAP_NT_SMBS|CAP_RPC_REMOTE_APIS;
-                     CAP_LARGE_FILES|CAP_LARGE_READX|
-                     CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
+                     CAP_LARGE_READX|CAP_STATUS32|CAP_LEVEL_II_OPLOCKS;
  */
 
   int secword=0;
   BOOL doencrypt = SMBENCRYPT();
   time_t t = time(NULL);
   int data_len;
-  int encrypt_len;
-  char challenge_len = 8;
-  /* We need to save and restore this as it can be destroyed
-     if we call another server if security=server
-     Thanks to Paul Nelson @ Thursby for pointing this out.
-   */
-  uint16 mid = SVAL(outbuf, smb_mid);
+  struct cli_state *cli = NULL;
+  char cryptkey[8];
+  char crypt_len = 0;
 
-  if (lp_readraw() && lp_writeraw())
-  {
-    capabilities |= CAP_RAW_MODE;
+  if (lp_security() == SEC_SERVER) {
+         cli = server_cryptkey();
   }
 
-  if (lp_security()>=SEC_USER) secword |= 1;
+  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;
+  }
+
+  if (lp_security() >= SEC_USER) secword |= 1;
   if (doencrypt) secword |= 2;
 
   /* decide where (if) to put the encryption challenge, and
      follow it with the OEM'd domain name
    */
-  encrypt_len = doencrypt?challenge_len:0;
-#if UNICODE
-  data_len = encrypt_len + 2*(strlen(myworkgroup)+1);
-#else
-  data_len = encrypt_len + strlen(myworkgroup) + 1;
-#endif
+  data_len = crypt_len + strlen(myworkgroup) + 1;
 
   set_message(outbuf,17,data_len,True);
-
-#if UNICODE
-  /* put the OEM'd domain name */
-  PutUniCode(smb_buf(outbuf)+encrypt_len,myworkgroup);
-#else
-  strcpy(smb_buf(outbuf)+encrypt_len, myworkgroup);
-#endif
+  strcpy(smb_buf(outbuf)+crypt_len, myworkgroup);
 
   CVAL(outbuf,smb_vwv1) = secword;
-  /* Create a token value and add it to the outgoing packet. */
-  if (doencrypt)
-  {
-    generate_next_challenge(smb_buf(outbuf));
-
-    /* Tell the nt machine how long the challenge is. */
-    SSVALS(outbuf,smb_vwv16+1,challenge_len);
-  }
+  SSVALS(outbuf,smb_vwv16+1,crypt_len);
+  if (doencrypt) 
+         memcpy(smb_buf(outbuf), cryptkey, 8);
 
   Protocol = PROTOCOL_NT1;
 
-  if (lp_security() == SEC_SERVER && server_cryptkey(outbuf)) {
-    DEBUG(3,("using password server validation\n"));
-    if (doencrypt) set_challenge(smb_buf(outbuf));    
-  }
-
-  SSVAL(outbuf,smb_mid,mid); /* Restore possibly corrupted mid */
   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! */
@@ -4766,17 +4761,16 @@ static void process(void)
 
       if (keepalive && (counter-last_keepalive)>keepalive) 
       {
-        extern int password_client;
-        if (!send_keepalive(Client))
-        { 
-          DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
-          return;
-        }          
-        /* also send a keepalive to the password server if its still
-           connected */
-        if (password_client != -1)
-          send_keepalive(password_client);
-        last_keepalive = counter;
+             struct cli_state *cli = server_client();
+             if (!send_keepalive(Client)) { 
+                     DEBUG(2,("%s Keepalive failed - exiting\n",timestring()));
+                     return;
+             }     
+             /* also send a keepalive to the password server if its still
+                connected */
+             if (cli && cli->initialised)
+                     send_keepalive(cli->fd);
+             last_keepalive = counter;
       }
 
       /* check for connection timeouts */