Move client_receive_smb to clientgen.c as a static, as proposed by Elrond.
[kai/samba.git] / source3 / libsmb / clientgen.c
index 8e00bca82a9a6909ccab3efc5d332e767456039e..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;
+}
+
+/****************************************************************************
+  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.
+****************************************************************************/
 
-       return cli->port;
+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,7 +142,6 @@ 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);
@@ -112,6 +152,12 @@ void cli_setup_packet(struct cli_state *cli)
                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);
        }
 }
@@ -125,54 +171,9 @@ void cli_setup_bcc(struct cli_state *cli, void *p)
 }
 
 
-/****************************************************************************
-process an oplock break request from the server
-****************************************************************************/
-static void cli_process_oplock(struct cli_state *cli)
-{
-       char *oldbuf = cli->outbuf;
-       pstring buf;
-       int fnum;
-       unsigned char level;
-
-       fnum = SVAL(cli->inbuf,smb_vwv2);
-       level = CVAL(cli->inbuf,smb_vwv3+1);
-
-       /* 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;
-
-       /* Ignore level II break to none's. */
-       if (level == OPLOCKLEVEL_NONE)
-               return;
-
-       cli->outbuf = buf;
-
-        memset(buf,'\0',smb_size);
-        set_message(buf,8,0,True);
-
-        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);
-       if (cli->use_level_II_oplocks)
-               SSVAL(buf,smb_vwv3,0x102); /* levelII oplock break ack */
-       else
-               SSVAL(buf,smb_vwv3,2); /* exclusive 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 a client structure
+initialise credentials of a client structure
 ****************************************************************************/
 void cli_init_creds(struct cli_state *cli, const struct ntuser_creds *usr)
 {
@@ -194,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) {
@@ -219,25 +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 NULL;
+       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;
        }
 
-       if ((cli->mem_ctx = talloc_init()) == NULL) {
-               free(cli->outbuf);
-               free(cli->inbuf);
-               return NULL;
-       }
+       if (!cli->outbuf || !cli->inbuf)
+                goto error;
 
-       memset(cli->outbuf, '\0', cli->bufsize);
-       memset(cli->inbuf, '\0', cli->bufsize);
+       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;
 }
 
 /****************************************************************************
@@ -245,25 +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);
-       }
+       BOOL allocated;
+       SAFE_FREE(cli->outbuf);
+       SAFE_FREE(cli->inbuf);
+
+       data_blob_free(&cli->secblob);
 
        if (cli->mem_ctx)
                talloc_destroy(cli->mem_ctx);
 
-#ifdef WITH_SSL
-    if (cli->fd != -1)
-      sslutil_disconnect(cli->fd);
-#endif /* WITH_SSL */
        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);
+       } 
 }
 
 
@@ -284,4 +309,3 @@ uint16 cli_setpid(struct cli_state *cli, uint16 pid)
        cli->pid = pid;
        return ret;
 }
-