Move client_receive_smb to clientgen.c as a static, as proposed by Elrond.
[kai/samba.git] / source3 / libsmb / clientgen.c
index 32564aaf82524b2f9f7a4f53e1b8eb49d5bfd136..dee86b2b05d86b32c6c11ca5a4277e776aee79be 100644 (file)
@@ -1,6 +1,5 @@
 /* 
-   Unix SMB/Netbios implementation.
-   Version 1.9.
+   Unix SMB/CIFS implementation.
    SMB client generic functions
    Copyright (C) Andrew Tridgell 1994-1998
    
 
 #include "includes.h"
 
-
-extern int DEBUGLEVEL;
-static void cli_process_oplock(struct cli_state *cli);
-
 /*
  * Change the port number used to call on 
  */
 int cli_set_port(struct cli_state *cli, int port)
 {
-       if (port > 0)
-         cli->port = port;
+       cli->port = port;
+       return port;
+}
 
-       return cli->port;
+/****************************************************************************
+  read an smb from a fd ignoring all keepalive packets. Note that the buffer 
+  *MUST* be of size BUFFER_SIZE+SAFETY_MARGIN.
+  The timeout is in milliseconds
+
+  This is exactly the same as receive_smb except that it never returns
+  a session keepalive packet (just as receive_smb used to do).
+  receive_smb was changed to return keepalives as the oplock processing means this call
+  should never go into a blocking read.
+****************************************************************************/
+
+static BOOL client_receive_smb(int fd,char *buffer, unsigned int timeout)
+{
+  BOOL ret;
+
+  for(;;)
+  {
+    ret = receive_smb(fd, buffer, timeout);
+
+    if (!ret)
+    {
+      DEBUG(10,("client_receive_smb failed\n"));
+      show_msg(buffer);
+      return ret;
+    }
+
+    /* Ignore session keepalive packets. */
+    if(CVAL(buffer,0) != SMBkeepalive)
+      break;
+  }
+  show_msg(buffer);
+  return ret;
 }
 
+
 /****************************************************************************
 recv an smb
 ****************************************************************************/
 BOOL cli_receive_smb(struct cli_state *cli)
 {
        BOOL ret;
+
+       /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+       if (cli->fd == -1) return False; 
+
  again:
        ret = client_receive_smb(cli->fd,cli->inbuf,cli->timeout);
        
@@ -53,38 +85,47 @@ BOOL cli_receive_smb(struct cli_state *cli)
                    CVAL(cli->inbuf,smb_com) == SMBlockingX &&
                    SVAL(cli->inbuf,smb_vwv6) == 0 &&
                    SVAL(cli->inbuf,smb_vwv7) == 0) {
-                       if (cli->use_oplocks) cli_process_oplock(cli);
+                       if (cli->oplock_handler) {
+                               int fnum = SVAL(cli->inbuf,smb_vwv2);
+                               unsigned char level = CVAL(cli->inbuf,smb_vwv3+1);
+                               if (!cli->oplock_handler(cli, fnum, level)) return False;
+                       }
                        /* try to prevent loops */
-                       CVAL(cli->inbuf,smb_com) = 0xFF;
+                       SCVAL(cli->inbuf,smb_com,0xFF);
                        goto again;
                }
        }
 
+        /* If the server is not responding, note that now */
+
+        if (!ret) {
+                close(cli->fd);
+                cli->fd = -1;
+        }
+
        return ret;
 }
 
 /****************************************************************************
-  send an smb to a fd and re-establish if necessary
+  send an smb to a fd.
 ****************************************************************************/
+
 BOOL cli_send_smb(struct cli_state *cli)
 {
        size_t len;
        size_t nwritten=0;
        ssize_t ret;
-       BOOL reestablished=False;
+
+       /* fd == -1 causes segfaults -- Tom (tom@ninja.nl) */
+       if (cli->fd == -1) return False;
 
        len = smb_len(cli->outbuf) + 4;
 
        while (nwritten < len) {
                ret = write_socket(cli->fd,cli->outbuf+nwritten,len - nwritten);
-               if (ret <= 0 && errno == EPIPE && !reestablished) {
-                       if (cli_reestablish_connection(cli)) {
-                               reestablished = True;
-                               nwritten=0;
-                               continue;
-                       }
-               }
                if (ret <= 0) {
+                        close(cli->fd);
+                        cli->fd = -1;
                        DEBUG(0,("Error writing %d bytes to client. %d\n",
                                 (int)len,(int)ret));
                        return False;
@@ -101,53 +142,51 @@ setup basics in a outgoing packet
 void cli_setup_packet(struct cli_state *cli)
 {
         cli->rap_error = 0;
-        cli->nt_error = 0;
        SSVAL(cli->outbuf,smb_pid,cli->pid);
        SSVAL(cli->outbuf,smb_uid,cli->vuid);
        SSVAL(cli->outbuf,smb_mid,cli->mid);
        if (cli->protocol > PROTOCOL_CORE) {
+               uint16 flags2;
                SCVAL(cli->outbuf,smb_flg,0x8);
-               SSVAL(cli->outbuf,smb_flg2,0x1);
+               flags2 = FLAGS2_LONG_PATH_COMPONENTS;
+               if (cli->capabilities & CAP_UNICODE) {
+                       flags2 |= FLAGS2_UNICODE_STRINGS;
+               }
+               if (cli->capabilities & CAP_STATUS32) {
+                       flags2 |= FLAGS2_32_BIT_ERROR_CODES;
+               }
+               if (cli->use_spnego) {
+                       flags2 |= FLAGS2_EXTENDED_SECURITY;
+               }
+               SSVAL(cli->outbuf,smb_flg2, flags2);
        }
 }
 
-
-
 /****************************************************************************
-process an oplock break request from the server
+setup the bcc length of the packet from a pointer to the end of the data
 ****************************************************************************/
-static void cli_process_oplock(struct cli_state *cli)
+void cli_setup_bcc(struct cli_state *cli, void *p)
 {
-       char *oldbuf = cli->outbuf;
-       pstring buf;
-       int fnum;
-
-       fnum = SVAL(cli->inbuf,smb_vwv2);
-
-       /* damn, we really need to keep a record of open files so we
-          can detect a oplock break and a close crossing on the
-          wire. for now this swallows the errors */
-       if (fnum == 0) return;
-
-       cli->outbuf = buf;
-
-        memset(buf,'\0',smb_size);
-        set_message(buf,8,0,True);
+       set_message_bcc(cli->outbuf, PTR_DIFF(p, smb_buf(cli->outbuf)));
+}
 
-        CVAL(buf,smb_com) = SMBlockingX;
-       SSVAL(buf,smb_tid, cli->cnum);
-        cli_setup_packet(cli);
-       SSVAL(buf,smb_vwv0,0xFF);
-       SSVAL(buf,smb_vwv1,0);
-       SSVAL(buf,smb_vwv2,fnum);
-       SSVAL(buf,smb_vwv3,2); /* oplock break ack */
-       SIVAL(buf,smb_vwv4,0); /* timoeut */
-       SSVAL(buf,smb_vwv6,0); /* unlockcount */
-       SSVAL(buf,smb_vwv7,0); /* lockcount */
 
-        cli_send_smb(cli);     
 
-       cli->outbuf = oldbuf;
+/****************************************************************************
+initialise credentials of a client structure
+****************************************************************************/
+void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
+{
+        /* copy_nt_creds(&cli->usr, usr); */
+       safe_strcpy(cli->domain   , usr->domain   , sizeof(usr->domain   )-1);
+       safe_strcpy(cli->user_name, usr->user_name, sizeof(usr->user_name)-1);
+       memcpy(&cli->pwd, &usr->pwd, sizeof(usr->pwd));
+        cli->ntlmssp_flags = usr->ntlmssp_flags;
+        cli->ntlmssp_cli_flgs = usr != NULL ? usr->ntlmssp_flags : 0;
+
+        DEBUG(10,("cli_init_creds: user %s domain %s flgs: %x\nntlmssp_cli_flgs:%x\n",
+               cli->user_name, cli->domain,
+               cli->ntlmssp_flags,cli->ntlmssp_cli_flgs));
 }
 
 
@@ -156,11 +195,20 @@ initialise a client structure
 ****************************************************************************/
 struct cli_state *cli_initialise(struct cli_state *cli)
 {
+        BOOL alloced_cli = False;
+
+       /* Check the effective uid - make sure we are not setuid */
+       if (is_setuid_root()) {
+               DEBUG(0,("libsmb based programs must *NOT* be setuid root.\n"));
+               return NULL;
+       }
+
        if (!cli) {
                cli = (struct cli_state *)malloc(sizeof(*cli));
                if (!cli)
                        return NULL;
                ZERO_STRUCTP(cli);
+                alloced_cli = True;
        }
 
        if (cli->initialised) {
@@ -181,17 +229,43 @@ struct cli_state *cli_initialise(struct cli_state *cli)
        cli->max_xmit = cli->bufsize;
        cli->outbuf = (char *)malloc(cli->bufsize);
        cli->inbuf = (char *)malloc(cli->bufsize);
-       if (!cli->outbuf || !cli->inbuf)
-       {
-               return False;
+       cli->oplock_handler = cli_oplock_ack;
+       cli->use_spnego = True;
+
+       /* Set the CLI_FORCE_DOSERR environment variable to test
+          client routines using DOS errors instead of STATUS32
+          ones.  This intended only as a temporary hack. */    
+       if (getenv("CLI_FORCE_DOSERR")) {
+               cli->force_dos_errors = True;
        }
 
-       memset(cli->outbuf, '\0', cli->bufsize);
-       memset(cli->inbuf, '\0', cli->bufsize);
+       if (!cli->outbuf || !cli->inbuf)
+                goto error;
+
+       if ((cli->mem_ctx = talloc_init_named("cli based talloc")) == NULL)
+                goto error;
+
+       memset(cli->outbuf, 0, cli->bufsize);
+       memset(cli->inbuf, 0, cli->bufsize);
+
+       cli->nt_pipe_fnum = 0;
 
        cli->initialised = 1;
+       cli->allocated = alloced_cli;
 
        return cli;
+
+        /* Clean up after malloc() error */
+
+ error:
+
+        SAFE_FREE(cli->inbuf);
+        SAFE_FREE(cli->outbuf);
+
+        if (alloced_cli)
+                SAFE_FREE(cli);
+
+        return NULL;
 }
 
 /****************************************************************************
@@ -199,21 +273,22 @@ shutdown a client structure
 ****************************************************************************/
 void cli_shutdown(struct cli_state *cli)
 {
-       if (cli->outbuf)
-       {
-               free(cli->outbuf);
-       }
-       if (cli->inbuf)
-       {
-               free(cli->inbuf);
-       }
-#ifdef WITH_SSL
-    if (cli->fd != -1)
-      sslutil_disconnect(cli->fd);
-#endif /* WITH_SSL */
+       BOOL allocated;
+       SAFE_FREE(cli->outbuf);
+       SAFE_FREE(cli->inbuf);
+
+       data_blob_free(&cli->secblob);
+
+       if (cli->mem_ctx)
+               talloc_destroy(cli->mem_ctx);
+
        if (cli->fd != -1) 
-      close(cli->fd);
-       memset(cli, 0, sizeof(*cli));
+               close(cli->fd);
+       allocated = cli->allocated;
+       ZERO_STRUCTP(cli);
+       if (allocated) {
+               free(cli);
+       } 
 }
 
 
@@ -234,4 +309,3 @@ uint16 cli_setpid(struct cli_state *cli, uint16 pid)
        cli->pid = pid;
        return ret;
 }
-