Now conn is part of smb_request, we don't need it as
[nivanova/samba-autobuild/.git] / source3 / smbd / process.c
index 7f307ade63cd9d310c48fa1a5723b4317ba80869..fe32d57ff7ccada3cddfc30e4249df99bab99d9d 100644 (file)
@@ -24,15 +24,9 @@ extern struct auth_context *negprot_global_auth_context;
 extern int smb_echo_count;
 
 const int total_buffer_size = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE + SAFETY_MARGIN);
+static enum smb_read_errors smb_read_error = SMB_READ_OK;
 
-static char *InBuffer = NULL;
-static char *OutBuffer = NULL;
-static const char *current_inbuf = NULL;
-
-static char *NewInBuffer(char **old_inbuf);
-static char *NewOutBuffer(char **old_outbuf);
-
-/* 
+/*
  * Size of data we can send to client. Set
  *  by the client for all protocols above CORE.
  *  Set by us for CORE protocol.
@@ -44,83 +38,433 @@ int max_send = BUFFER_SIZE;
  */
 int max_recv = BUFFER_SIZE;
 
-extern int last_message;
-extern int smb_read_error;
 SIG_ATOMIC_T reload_after_sighup = 0;
 SIG_ATOMIC_T got_sig_term = 0;
-extern BOOL global_machine_password_needs_changing;
+extern bool global_machine_password_needs_changing;
 extern int max_send;
 
-/*
- * Initialize a struct smb_request from an inbuf
- */
+/* Accessor function for smb_read_error for smbd functions. */
 
-void init_smb_request(struct smb_request *req, const uint8 *inbuf)
+enum smb_read_errors *get_srv_read_error(void)
 {
-       req->flags2 = SVAL(inbuf, smb_flg2);
-       req->smbpid = SVAL(inbuf, smb_pid);
-       req->mid    = SVAL(inbuf, smb_mid);
-       req->vuid   = SVAL(inbuf, smb_uid);
-       req->tid    = SVAL(inbuf, smb_tid);
-       req->wct    = CVAL(inbuf, smb_wct);
-       req->inbuf  = inbuf;
-       req->outbuf = NULL;
+       return &smb_read_error;
+}
+
+/****************************************************************************
+ Send an smb to a fd.
+****************************************************************************/
+
+bool srv_send_smb(int fd, char *buffer, bool do_encrypt)
+{
+       size_t len;
+       size_t nwritten=0;
+       ssize_t ret;
+       char *buf_out = buffer;
+
+       /* Sign the outgoing packet if required. */
+       srv_calculate_sign_mac(buf_out);
+
+       if (do_encrypt) {
+               NTSTATUS status = srv_encrypt_buffer(buffer, &buf_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("send_smb: SMB encryption failed "
+                               "on outgoing packet! Error %s\n",
+                               nt_errstr(status) ));
+                       return false;
+               }
+       }
+
+       len = smb_len(buf_out) + 4;
+
+       while (nwritten < len) {
+               ret = write_data(fd,buf_out+nwritten,len - nwritten);
+               if (ret <= 0) {
+                       DEBUG(0,("Error writing %d bytes to client. %d. (%s)\n",
+                               (int)len,(int)ret, strerror(errno) ));
+                       srv_free_enc_buffer(buf_out);
+                       return false;
+               }
+               nwritten += ret;
+       }
+
+       srv_free_enc_buffer(buf_out);
+       return true;
+}
+
+/*******************************************************************
+ Setup the word count and byte count for a smb message.
+********************************************************************/
+
+int srv_set_message(char *buf,
+                        int num_words,
+                        int num_bytes,
+                        bool zero)
+{
+       if (zero && (num_words || num_bytes)) {
+               memset(buf + smb_size,'\0',num_words*2 + num_bytes);
+       }
+       SCVAL(buf,smb_wct,num_words);
+       SSVAL(buf,smb_vwv + num_words*SIZEOFWORD,num_bytes);
+       smb_setlen(buf,(smb_size + num_words*2 + num_bytes - 4));
+       return (smb_size + num_words*2 + num_bytes);
+}
+
+static bool valid_smb_header(const uint8_t *inbuf)
+{
+       if (is_encrypted_packet(inbuf)) {
+               return true;
+       }
+       return (strncmp(smb_base(inbuf),"\377SMB",4) == 0);
+}
+
+/* Socket functions for smbd packet processing. */
+
+static bool valid_packet_size(size_t len)
+{
+       /*
+        * A WRITEX with CAP_LARGE_WRITEX can be 64k worth of data plus 65 bytes
+        * of header. Don't print the error if this fits.... JRA.
+        */
+
+       if (len > (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE)) {
+               DEBUG(0,("Invalid packet length! (%lu bytes).\n",
+                                       (unsigned long)len));
+               if (len > BUFFER_SIZE + (SAFETY_MARGIN/2)) {
+
+                       /*
+                        * Correct fix. smb_read_error may have already been
+                        * set. Only set it here if not already set. Global
+                        * variables still suck :-). JRA.
+                        */
+
+                       cond_set_smb_read_error(get_srv_read_error(),
+                                               SMB_READ_ERROR);
+                       return false;
+               }
+       }
+       return true;
+}
+
+static ssize_t read_packet_remainder(int fd,
+                                       char *buffer,
+                                       unsigned int timeout,
+                                       ssize_t len)
+{
+       ssize_t ret;
+
+       if(len <= 0) {
+               return len;
+       }
+
+       if (timeout > 0) {
+               ret = read_socket_with_timeout(fd,
+                                               buffer,
+                                               len,
+                                               len,
+                                               timeout,
+                                               get_srv_read_error());
+       } else {
+               ret = read_data(fd, buffer, len, get_srv_read_error());
+       }
+
+       if (ret != len) {
+               cond_set_smb_read_error(get_srv_read_error(),
+                                       SMB_READ_ERROR);
+               return -1;
+       }
+
+       return len;
 }
 
+/****************************************************************************
+ Attempt a zerocopy writeX read. We know here that len > smb_size-4
+****************************************************************************/
+
 /*
- * From within a converted call you might have to call non-converted
- * subroutines that still take the old inbuf/outbuf/lenght/bufsize
- * parameters. This takes a struct smb_request and prepares the legacy
- * parameters.
+ * Unfortunately, earlier versions of smbclient/libsmbclient
+ * don't send this "standard" writeX header. I've fixed this
+ * for 3.2 but we'll use the old method with earlier versions.
+ * Windows and CIFSFS at least use this standard size. Not
+ * sure about MacOSX.
  */
 
-BOOL reply_prep_legacy(struct smb_request *req,
-                      char **pinbuf, char **poutbuf,
-                      int *psize, int *pbufsize)
+#define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
+                               (2*14) + /* word count (including bcc) */ \
+                               1 /* pad byte */)
+
+static ssize_t receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
+                                       const char lenbuf[4],
+                                       int fd,
+                                       char **buffer,
+                                       unsigned int timeout,
+                                       size_t *p_unread)
 {
-       const int bufsize = (BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE
-                            + SAFETY_MARGIN);
-       char *inbuf, *outbuf;
+       /* Size of a WRITEX call (+4 byte len). */
+       char writeX_header[4 + STANDARD_WRITE_AND_X_HEADER_SIZE];
+       ssize_t len = smb_len_large(lenbuf); /* Could be a UNIX large writeX. */
+       ssize_t toread;
+       ssize_t ret;
+
+       memcpy(writeX_header, lenbuf, sizeof(lenbuf));
+
+       if (timeout > 0) {
+               ret = read_socket_with_timeout(fd,
+                                       writeX_header + 4,
+                                       STANDARD_WRITE_AND_X_HEADER_SIZE,
+                                       STANDARD_WRITE_AND_X_HEADER_SIZE,
+                                       timeout,
+                                       get_srv_read_error());
+       } else {
+               ret = read_data(fd,
+                               writeX_header+4,
+                               STANDARD_WRITE_AND_X_HEADER_SIZE,
+                               get_srv_read_error());
+       }
+
+       if (ret != STANDARD_WRITE_AND_X_HEADER_SIZE) {
+               cond_set_smb_read_error(get_srv_read_error(),
+                                       SMB_READ_ERROR);
+               return -1;
+       }
 
-       DEBUG(1, ("reply_prep_legacy called\n"));
+       /*
+        * Ok - now try and see if this is a possible
+        * valid writeX call.
+        */
 
-       if (!(inbuf = TALLOC_ARRAY(req, char, bufsize))) {
-               DEBUG(0, ("Could not allocate legacy inbuf\n"));
-               return False;
+       if (is_valid_writeX_buffer((uint8_t *)writeX_header)) {
+               /*
+                * If the data offset is beyond what
+                * we've read, drain the extra bytes.
+                */
+               uint16_t doff = SVAL(writeX_header,smb_vwv11);
+               ssize_t newlen;
+
+               if (doff > STANDARD_WRITE_AND_X_HEADER_SIZE) {
+                       size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE;
+                       if (drain_socket(smbd_server_fd(), drain) != drain) {
+                               smb_panic("receive_smb_raw_talloc_partial_read:"
+                                       " failed to drain pending bytes");
+                       }
+               } else {
+                       doff = STANDARD_WRITE_AND_X_HEADER_SIZE;
+               }
+
+               /* Spoof down the length and null out the bcc. */
+               set_message_bcc(writeX_header, 0);
+               newlen = smb_len(writeX_header);
+
+               /* Copy the header we've written. */
+
+               *buffer = (char *)TALLOC_MEMDUP(mem_ctx,
+                               writeX_header,
+                               sizeof(writeX_header));
+
+               if (*buffer == NULL) {
+                       DEBUG(0, ("Could not allocate inbuf of length %d\n",
+                                 (int)sizeof(writeX_header)));
+                       cond_set_smb_read_error(get_srv_read_error(),
+                                               SMB_READ_ERROR);
+                       return -1;
+               }
+
+               /* Work out the remaining bytes. */
+               *p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
+
+               return newlen + 4;
        }
-       memcpy(inbuf, req->inbuf, MIN(smb_len(req->inbuf)+4, bufsize));
-       req->inbuf = (uint8 *)inbuf;
 
-       if (!(outbuf = TALLOC_ARRAY(req, char, bufsize))) {
-               DEBUG(0, ("Could not allocate legacy outbuf\n"));
-               return False;
+       if (!valid_packet_size(len)) {
+               return -1;
        }
-       req->outbuf = (uint8 *)outbuf;
 
-       construct_reply_common(inbuf, outbuf);
+       /*
+        * Not a valid writeX call. Just do the standard
+        * talloc and return.
+        */
+
+       *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
 
-       *pinbuf   = inbuf;
-       *poutbuf  = outbuf;
-       *psize    = smb_len(inbuf)+4;
-       *pbufsize = bufsize;
+       if (*buffer == NULL) {
+               DEBUG(0, ("Could not allocate inbuf of length %d\n",
+                         (int)len+4));
+               cond_set_smb_read_error(get_srv_read_error(),
+                                       SMB_READ_ERROR);
+               return -1;
+       }
 
-       return True;
+       /* Copy in what we already read. */
+       memcpy(*buffer,
+               writeX_header,
+               4 + STANDARD_WRITE_AND_X_HEADER_SIZE);
+       toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE;
+
+       if(toread > 0) {
+               ret = read_packet_remainder(fd,
+                       (*buffer) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE,
+                                       timeout,
+                                       toread);
+               if (ret != toread) {
+                       return -1;
+               }
+       }
+
+       return len + 4;
+}
+
+static ssize_t receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
+                                       int fd,
+                                       char **buffer,
+                                       unsigned int timeout,
+                                       size_t *p_unread)
+{
+       char lenbuf[4];
+       ssize_t len,ret;
+       int min_recv_size = lp_min_receive_file_size();
+
+       set_smb_read_error(get_srv_read_error(),SMB_READ_OK);
+       *p_unread = 0;
+
+       len = read_smb_length_return_keepalive(fd, lenbuf,
+                       timeout, get_srv_read_error());
+       if (len < 0) {
+               DEBUG(10,("receive_smb_raw: length < 0!\n"));
+
+               /*
+                * Correct fix. smb_read_error may have already been
+                * set. Only set it here if not already set. Global
+                * variables still suck :-). JRA.
+                */
+
+               cond_set_smb_read_error(get_srv_read_error(),SMB_READ_ERROR);
+               return -1;
+       }
+
+       if (CVAL(lenbuf,0) == 0 &&
+                       min_recv_size &&
+                       smb_len_large(lenbuf) > min_recv_size && /* Could be a UNIX large writeX. */
+                       !srv_is_signing_active()) {
+
+               return receive_smb_raw_talloc_partial_read(mem_ctx,
+                                                       lenbuf,
+                                                       fd,
+                                                       buffer,
+                                                       timeout,
+                                                       p_unread);
+       }
+
+       if (!valid_packet_size(len)) {
+               return -1;
+       }
+
+       /*
+        * The +4 here can't wrap, we've checked the length above already.
+        */
+
+       *buffer = TALLOC_ARRAY(mem_ctx, char, len+4);
+
+       if (*buffer == NULL) {
+               DEBUG(0, ("Could not allocate inbuf of length %d\n",
+                         (int)len+4));
+               cond_set_smb_read_error(get_srv_read_error(),SMB_READ_ERROR);
+               return -1;
+       }
+
+       memcpy(*buffer, lenbuf, sizeof(lenbuf));
+
+       ret = read_packet_remainder(fd, (*buffer)+4, timeout, len);
+       if (ret != len) {
+               return -1;
+       }
+
+       return len + 4;
+}
+
+static ssize_t receive_smb_talloc(TALLOC_CTX *mem_ctx,
+                               int fd,
+                               char **buffer,
+                               unsigned int timeout,
+                               size_t *p_unread,
+                               bool *p_encrypted)
+{
+       ssize_t len;
+
+       *p_encrypted = false;
+
+       len = receive_smb_raw_talloc(mem_ctx, fd, buffer, timeout, p_unread);
+
+       if (len < 0) {
+               return -1;
+       }
+
+       if (is_encrypted_packet((uint8_t *)*buffer)) {
+               NTSTATUS status = srv_decrypt_buffer(*buffer);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("receive_smb_talloc: SMB decryption failed on "
+                               "incoming packet! Error %s\n",
+                               nt_errstr(status) ));
+                       cond_set_smb_read_error(get_srv_read_error(),
+                                       SMB_READ_BAD_DECRYPT);
+                       return -1;
+               }
+               *p_encrypted = true;
+       }
+
+       /* Check the incoming SMB signature. */
+       if (!srv_check_sign_mac(*buffer, true)) {
+               DEBUG(0, ("receive_smb: SMB Signature verification failed on "
+                         "incoming packet!\n"));
+               cond_set_smb_read_error(get_srv_read_error(),SMB_READ_BAD_SIG);
+               return -1;
+       }
+
+       return len;
 }
 
 /*
- * Post-process the output of the legacy routine so that the result fits into
- * the new reply_xxx API
+ * Initialize a struct smb_request from an inbuf
  */
 
-void reply_post_legacy(struct smb_request *req, int outsize)
+void init_smb_request(struct smb_request *req,
+                       const uint8 *inbuf,
+                       size_t unread_bytes,
+                       bool encrypted)
 {
-       if (outsize > 0) {
-               smb_setlen((char *)req->inbuf, (char *)req->outbuf,
-                          outsize);
+       size_t req_size = smb_len(inbuf) + 4;
+       /* Ensure we have at least smb_size bytes. */
+       if (req_size < smb_size) {
+               DEBUG(0,("init_smb_request: invalid request size %u\n",
+                       (unsigned int)req_size ));
+               exit_server_cleanly("Invalid SMB request");
        }
-       else {
-               TALLOC_FREE(req->outbuf);
+       req->flags2 = SVAL(inbuf, smb_flg2);
+       req->smbpid = SVAL(inbuf, smb_pid);
+       req->mid    = SVAL(inbuf, smb_mid);
+       req->vuid   = SVAL(inbuf, smb_uid);
+       req->tid    = SVAL(inbuf, smb_tid);
+       req->wct    = CVAL(inbuf, smb_wct);
+       req->unread_bytes = unread_bytes;
+       req->encrypted = encrypted;
+       req->conn = conn_find(req->tid);
+
+       /* Ensure we have at least wct words and 2 bytes of bcc. */
+       if (smb_size + req->wct*2 > req_size) {
+               DEBUG(0,("init_smb_request: invalid wct number %u (size %u)\n",
+                       (unsigned int)req->wct,
+                       (unsigned int)req_size));
+               exit_server_cleanly("Invalid SMB request");
+       }
+       /* Ensure bcc is correct. */
+       if (((uint8 *)smb_buf(inbuf)) + smb_buflen(inbuf) > inbuf + req_size) {
+               DEBUG(0,("init_smb_request: invalid bcc number %u "
+                       "(wct = %u, size %u)\n",
+                       (unsigned int)smb_buflen(inbuf),
+                       (unsigned int)req->wct,
+                       (unsigned int)req_size));
+               exit_server_cleanly("Invalid SMB request");
        }
+       req->inbuf  = inbuf;
+       req->outbuf = NULL;
 }
 
 /****************************************************************************
@@ -131,15 +475,16 @@ void reply_post_legacy(struct smb_request *req, int outsize)
 static struct pending_message_list *deferred_open_queue;
 
 /****************************************************************************
- Function to push a message onto the tail of a linked list of smb messages
ready for processing.
+ Function to push a message onto the tail of a linked list of smb messages ready
+ for processing.
 ****************************************************************************/
 
-static BOOL push_queued_message(const char *buf, int msg_len,
+static bool push_queued_message(struct smb_request *req,
                                struct timeval request_time,
                                struct timeval end_time,
                                char *private_data, size_t private_len)
 {
+       int msg_len = smb_len(req->inbuf) + 4;
        struct pending_message_list *msg;
 
        msg = TALLOC_ZERO_P(NULL, struct pending_message_list);
@@ -149,7 +494,7 @@ static BOOL push_queued_message(const char *buf, int msg_len,
                return False;
        }
 
-       msg->buf = data_blob_talloc(msg, buf, msg_len);
+       msg->buf = data_blob_talloc(msg, req->inbuf, msg_len);
        if(msg->buf.data == NULL) {
                DEBUG(0,("push_message: malloc fail (2)\n"));
                TALLOC_FREE(msg);
@@ -158,6 +503,7 @@ static BOOL push_queued_message(const char *buf, int msg_len,
 
        msg->request_time = request_time;
        msg->end_time = end_time;
+       msg->encrypted = req->encrypted;
 
        if (private_data) {
                msg->private_data = data_blob_talloc(msg, private_data,
@@ -187,7 +533,7 @@ void remove_deferred_open_smb_message(uint16 mid)
 
        for (pml = deferred_open_queue; pml; pml = pml->next) {
                if (mid == SVAL(pml->buf.data,smb_mid)) {
-                       DEBUG(10,("remove_deferred_open_smb_message: "
+                       DEBUG(10,("remove_sharing_violation_open_smb_message: "
                                  "deleting mid %u len %u\n",
                                  (unsigned int)mid,
                                  (unsigned int)pml->buf.length ));
@@ -210,11 +556,11 @@ void schedule_deferred_open_smb_message(uint16 mid)
 
        for (pml = deferred_open_queue; pml; pml = pml->next) {
                uint16 msg_mid = SVAL(pml->buf.data,smb_mid);
-               DEBUG(10, ("schedule_deferred_open_smb_message: [%d] "
-                          "msg_mid = %u\n", i++, (unsigned int)msg_mid ));
+               DEBUG(10,("schedule_deferred_open_smb_message: [%d] msg_mid = %u\n", i++,
+                       (unsigned int)msg_mid ));
                if (mid == msg_mid) {
-                       DEBUG(10, ("schedule_deferred_open_smb_message: "
-                                  "scheduling mid %u\n", mid));
+                       DEBUG(10,("schedule_deferred_open_smb_message: scheduling mid %u\n",
+                               mid ));
                        pml->end_time.tv_sec = 0;
                        pml->end_time.tv_usec = 0;
                        DLIST_PROMOTE(deferred_open_queue, pml);
@@ -222,15 +568,15 @@ void schedule_deferred_open_smb_message(uint16 mid)
                }
        }
 
-       DEBUG(10, ("schedule_deferred_open_smb_message: failed to find "
-                  "message mid %u\n", mid ));
+       DEBUG(10,("schedule_deferred_open_smb_message: failed to find message mid %u\n",
+               mid ));
 }
 
 /****************************************************************************
  Return true if this mid is on the deferred queue.
 ****************************************************************************/
 
-BOOL open_was_deferred(uint16 mid)
+bool open_was_deferred(uint16 mid)
 {
        struct pending_message_list *pml;
 
@@ -263,23 +609,30 @@ struct pending_message_list *get_open_deferred_message(uint16 mid)
  messages ready for processing.
 ****************************************************************************/
 
-BOOL push_deferred_smb_message(uint16 mid,
+bool push_deferred_smb_message(struct smb_request *req,
                               struct timeval request_time,
                               struct timeval timeout,
                               char *private_data, size_t priv_len)
 {
        struct timeval end_time;
 
+       if (req->unread_bytes) {
+               DEBUG(0,("push_deferred_smb_message: logic error ! "
+                       "unread_bytes = %u\n",
+                       (unsigned int)req->unread_bytes ));
+               smb_panic("push_deferred_smb_message: "
+                       "logic error unread_bytes != 0" );
+       }
+
        end_time = timeval_sum(&request_time, &timeout);
 
        DEBUG(10,("push_deferred_open_smb_message: pushing message len %u mid %u "
                  "timeout time [%u.%06u]\n",
-                 (unsigned int) smb_len(current_inbuf)+4, (unsigned int)mid,
+                 (unsigned int) smb_len(req->inbuf)+4, (unsigned int)req->mid,
                  (unsigned int)end_time.tv_sec,
                  (unsigned int)end_time.tv_usec));
 
-       return push_queued_message(current_inbuf, smb_len(current_inbuf)+4,
-                                  request_time, end_time,
+       return push_queued_message(req, request_time, end_time,
                                   private_data, priv_len);
 }
 
@@ -287,7 +640,7 @@ struct idle_event {
        struct timed_event *te;
        struct timeval interval;
        char *name;
-       BOOL (*handler)(const struct timeval *now, void *private_data);
+       bool (*handler)(const struct timeval *now, void *private_data);
        void *private_data;
 };
 
@@ -320,7 +673,7 @@ struct idle_event *event_add_idle(struct event_context *event_ctx,
                                  TALLOC_CTX *mem_ctx,
                                  struct timeval interval,
                                  const char *name,
-                                 BOOL (*handler)(const struct timeval *now,
+                                 bool (*handler)(const struct timeval *now,
                                                  void *private_data),
                                  void *private_data)
 {
@@ -422,8 +775,12 @@ static int select_on_fd(int fd, int maxfd, fd_set *fds)
 The timeout is in milliseconds
 ****************************************************************************/
 
-static BOOL receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
-                                  size_t *buffer_len, int timeout)
+static bool receive_message_or_smb(TALLOC_CTX *mem_ctx,
+                               char **buffer,
+                               size_t *buffer_len,
+                               int timeout,
+                               size_t *p_unread,
+                               bool *p_encrypted)
 {
        fd_set r_fds, w_fds;
        int selrtn;
@@ -431,7 +788,8 @@ static BOOL receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
        int maxfd = 0;
        ssize_t len;
 
-       smb_read_error = 0;
+       *p_unread = 0;
+       set_smb_read_error(get_srv_read_error(),SMB_READ_OK);
 
  again:
 
@@ -455,7 +813,7 @@ static BOOL receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
         * and it's time to schedule.
         */
        if(deferred_open_queue != NULL) {
-               BOOL pop_message = False;
+               bool pop_message = False;
                struct pending_message_list *msg = deferred_open_queue;
 
                if (timeval_is_zero(&msg->end_time)) {
@@ -485,10 +843,11 @@ static BOOL receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
                                                        msg->buf.length);
                        if (*buffer == NULL) {
                                DEBUG(0, ("talloc failed\n"));
-                               smb_read_error = READ_ERROR;
+                               set_smb_read_error(get_srv_read_error(),SMB_READ_ERROR);
                                return False;
                        }
                        *buffer_len = msg->buf.length;
+                       *p_encrypted = msg->encrypted;
 
                        /* We leave this message on the queue so the open code can
                           know this is a retry. */
@@ -579,13 +938,13 @@ static BOOL receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
        /* Check if error */
        if (selrtn == -1) {
                /* something is wrong. Maybe the socket is dead? */
-               smb_read_error = READ_ERROR;
+               set_smb_read_error(get_srv_read_error(),SMB_READ_ERROR);
                return False;
        } 
     
        /* Did we timeout ? */
        if (selrtn == 0) {
-               smb_read_error = READ_TIMEOUT;
+               set_smb_read_error(get_srv_read_error(),SMB_READ_TIMEOUT);
                return False;
        }
 
@@ -605,7 +964,8 @@ static BOOL receive_message_or_smb(TALLOC_CTX *mem_ctx, char **buffer,
                goto again;
        }
 
-       len = receive_smb_talloc(mem_ctx, smbd_server_fd(), buffer, 0);
+       len = receive_smb_talloc(mem_ctx, smbd_server_fd(),
+                               buffer, 0, p_unread, p_encrypted);
 
        if (len == -1) {
                return False;
@@ -685,267 +1045,266 @@ force write permissions on print services.
 */
 static const struct smb_message_struct {
        const char *name;
-       int (*fn)(connection_struct *conn, char *, char *, int, int);
-       void (*fn_new)(connection_struct *conn, struct smb_request *req);
+       void (*fn_new)(struct smb_request *req);
        int flags;
 } smb_messages[256] = {
 
-/* 0x00 */ { "SMBmkdir",NULL,reply_mkdir,AS_USER | NEED_WRITE},
-/* 0x01 */ { "SMBrmdir",NULL,reply_rmdir,AS_USER | NEED_WRITE},
-/* 0x02 */ { "SMBopen",NULL,reply_open,AS_USER },
-/* 0x03 */ { "SMBcreate",NULL,reply_mknew,AS_USER},
-/* 0x04 */ { "SMBclose",NULL,reply_close,AS_USER | CAN_IPC },
-/* 0x05 */ { "SMBflush",NULL,reply_flush,AS_USER},
-/* 0x06 */ { "SMBunlink",NULL,reply_unlink,AS_USER | NEED_WRITE },
-/* 0x07 */ { "SMBmv",NULL,reply_mv,AS_USER | NEED_WRITE },
-/* 0x08 */ { "SMBgetatr",NULL,reply_getatr,AS_USER},
-/* 0x09 */ { "SMBsetatr",NULL,reply_setatr,AS_USER | NEED_WRITE},
-/* 0x0a */ { "SMBread",NULL,reply_read,AS_USER},
-/* 0x0b */ { "SMBwrite",NULL,reply_write,AS_USER | CAN_IPC },
-/* 0x0c */ { "SMBlock",NULL,reply_lock,AS_USER},
-/* 0x0d */ { "SMBunlock",NULL,reply_unlock,AS_USER},
-/* 0x0e */ { "SMBctemp",NULL,reply_ctemp,AS_USER },
-/* 0x0f */ { "SMBmknew",NULL,reply_mknew,AS_USER},
-/* 0x10 */ { "SMBcheckpath",NULL,reply_checkpath,AS_USER},
-/* 0x11 */ { "SMBexit",NULL,reply_exit,DO_CHDIR},
-/* 0x12 */ { "SMBlseek",NULL,reply_lseek,AS_USER},
-/* 0x13 */ { "SMBlockread",NULL,reply_lockread,AS_USER},
-/* 0x14 */ { "SMBwriteunlock",NULL,reply_writeunlock,AS_USER},
-/* 0x15 */ { NULL, NULL, NULL, 0 },
-/* 0x16 */ { NULL, NULL, NULL, 0 },
-/* 0x17 */ { NULL, NULL, NULL, 0 },
-/* 0x18 */ { NULL, NULL, NULL, 0 },
-/* 0x19 */ { NULL, NULL, NULL, 0 },
-/* 0x1a */ { "SMBreadbraw",NULL,reply_readbraw,AS_USER},
-/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,NULL,AS_USER},
-/* 0x1c */ { "SMBreadBs",NULL, NULL,0 },
-/* 0x1d */ { "SMBwritebraw",reply_writebraw,NULL,AS_USER},
-/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,NULL,AS_USER},
-/* 0x1f */ { "SMBwriteBs",reply_writebs,NULL,AS_USER},
-/* 0x20 */ { "SMBwritec",NULL, NULL,0},
-/* 0x21 */ { NULL, NULL, NULL, 0 },
-/* 0x22 */ { "SMBsetattrE",NULL,reply_setattrE,AS_USER | NEED_WRITE },
-/* 0x23 */ { "SMBgetattrE",NULL,reply_getattrE,AS_USER },
-/* 0x24 */ { "SMBlockingX",NULL,reply_lockingX,AS_USER },
-/* 0x25 */ { "SMBtrans",NULL,reply_trans,AS_USER | CAN_IPC },
-/* 0x26 */ { "SMBtranss",NULL,reply_transs,AS_USER | CAN_IPC},
-/* 0x27 */ { "SMBioctl",NULL,reply_ioctl,0},
-/* 0x28 */ { "SMBioctls",NULL, NULL,AS_USER},
-/* 0x29 */ { "SMBcopy",NULL,reply_copy,AS_USER | NEED_WRITE },
-/* 0x2a */ { "SMBmove",NULL, NULL,AS_USER | NEED_WRITE },
-/* 0x2b */ { "SMBecho",NULL,reply_echo,0},
-/* 0x2c */ { "SMBwriteclose",NULL,reply_writeclose,AS_USER},
-/* 0x2d */ { "SMBopenX",NULL,reply_open_and_X,AS_USER | CAN_IPC },
-/* 0x2e */ { "SMBreadX",NULL,reply_read_and_X,AS_USER | CAN_IPC },
-/* 0x2f */ { "SMBwriteX",NULL,reply_write_and_X,AS_USER | CAN_IPC },
-/* 0x30 */ { NULL, NULL, NULL, 0 },
-/* 0x31 */ { NULL, NULL, NULL, 0 },
-/* 0x32 */ { "SMBtrans2", NULL,reply_trans2, AS_USER | CAN_IPC },
-/* 0x33 */ { "SMBtranss2", NULL,reply_transs2, AS_USER},
-/* 0x34 */ { "SMBfindclose", reply_findclose,NULL,AS_USER},
-/* 0x35 */ { "SMBfindnclose", reply_findnclose,NULL, AS_USER},
-/* 0x36 */ { NULL, NULL, NULL, 0 },
-/* 0x37 */ { NULL, NULL, NULL, 0 },
-/* 0x38 */ { NULL, NULL, NULL, 0 },
-/* 0x39 */ { NULL, NULL, NULL, 0 },
-/* 0x3a */ { NULL, NULL, NULL, 0 },
-/* 0x3b */ { NULL, NULL, NULL, 0 },
-/* 0x3c */ { NULL, NULL, NULL, 0 },
-/* 0x3d */ { NULL, NULL, NULL, 0 },
-/* 0x3e */ { NULL, NULL, NULL, 0 },
-/* 0x3f */ { NULL, NULL, NULL, 0 },
-/* 0x40 */ { NULL, NULL, NULL, 0 },
-/* 0x41 */ { NULL, NULL, NULL, 0 },
-/* 0x42 */ { NULL, NULL, NULL, 0 },
-/* 0x43 */ { NULL, NULL, NULL, 0 },
-/* 0x44 */ { NULL, NULL, NULL, 0 },
-/* 0x45 */ { NULL, NULL, NULL, 0 },
-/* 0x46 */ { NULL, NULL, NULL, 0 },
-/* 0x47 */ { NULL, NULL, NULL, 0 },
-/* 0x48 */ { NULL, NULL, NULL, 0 },
-/* 0x49 */ { NULL, NULL, NULL, 0 },
-/* 0x4a */ { NULL, NULL, NULL, 0 },
-/* 0x4b */ { NULL, NULL, NULL, 0 },
-/* 0x4c */ { NULL, NULL, NULL, 0 },
-/* 0x4d */ { NULL, NULL, NULL, 0 },
-/* 0x4e */ { NULL, NULL, NULL, 0 },
-/* 0x4f */ { NULL, NULL, NULL, 0 },
-/* 0x50 */ { NULL, NULL, NULL, 0 },
-/* 0x51 */ { NULL, NULL, NULL, 0 },
-/* 0x52 */ { NULL, NULL, NULL, 0 },
-/* 0x53 */ { NULL, NULL, NULL, 0 },
-/* 0x54 */ { NULL, NULL, NULL, 0 },
-/* 0x55 */ { NULL, NULL, NULL, 0 },
-/* 0x56 */ { NULL, NULL, NULL, 0 },
-/* 0x57 */ { NULL, NULL, NULL, 0 },
-/* 0x58 */ { NULL, NULL, NULL, 0 },
-/* 0x59 */ { NULL, NULL, NULL, 0 },
-/* 0x5a */ { NULL, NULL, NULL, 0 },
-/* 0x5b */ { NULL, NULL, NULL, 0 },
-/* 0x5c */ { NULL, NULL, NULL, 0 },
-/* 0x5d */ { NULL, NULL, NULL, 0 },
-/* 0x5e */ { NULL, NULL, NULL, 0 },
-/* 0x5f */ { NULL, NULL, NULL, 0 },
-/* 0x60 */ { NULL, NULL, NULL, 0 },
-/* 0x61 */ { NULL, NULL, NULL, 0 },
-/* 0x62 */ { NULL, NULL, NULL, 0 },
-/* 0x63 */ { NULL, NULL, NULL, 0 },
-/* 0x64 */ { NULL, NULL, NULL, 0 },
-/* 0x65 */ { NULL, NULL, NULL, 0 },
-/* 0x66 */ { NULL, NULL, NULL, 0 },
-/* 0x67 */ { NULL, NULL, NULL, 0 },
-/* 0x68 */ { NULL, NULL, NULL, 0 },
-/* 0x69 */ { NULL, NULL, NULL, 0 },
-/* 0x6a */ { NULL, NULL, NULL, 0 },
-/* 0x6b */ { NULL, NULL, NULL, 0 },
-/* 0x6c */ { NULL, NULL, NULL, 0 },
-/* 0x6d */ { NULL, NULL, NULL, 0 },
-/* 0x6e */ { NULL, NULL, NULL, 0 },
-/* 0x6f */ { NULL, NULL, NULL, 0 },
-/* 0x70 */ { "SMBtcon",reply_tcon,NULL,0},
-/* 0x71 */ { "SMBtdis",NULL,reply_tdis,DO_CHDIR},
-/* 0x72 */ { "SMBnegprot",NULL,reply_negprot,0},
-/* 0x73 */ { "SMBsesssetupX",NULL,reply_sesssetup_and_X,0},
-/* 0x74 */ { "SMBulogoffX", NULL,reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
-/* 0x75 */ { "SMBtconX",NULL,reply_tcon_and_X,0},
-/* 0x76 */ { NULL, NULL, NULL, 0 },
-/* 0x77 */ { NULL, NULL, NULL, 0 },
-/* 0x78 */ { NULL, NULL, NULL, 0 },
-/* 0x79 */ { NULL, NULL, NULL, 0 },
-/* 0x7a */ { NULL, NULL, NULL, 0 },
-/* 0x7b */ { NULL, NULL, NULL, 0 },
-/* 0x7c */ { NULL, NULL, NULL, 0 },
-/* 0x7d */ { NULL, NULL, NULL, 0 },
-/* 0x7e */ { NULL, NULL, NULL, 0 },
-/* 0x7f */ { NULL, NULL, NULL, 0 },
-/* 0x80 */ { "SMBdskattr",NULL,reply_dskattr,AS_USER},
-/* 0x81 */ { "SMBsearch",NULL,reply_search,AS_USER},
-/* 0x82 */ { "SMBffirst",NULL,reply_search,AS_USER},
-/* 0x83 */ { "SMBfunique",NULL,reply_search,AS_USER},
-/* 0x84 */ { "SMBfclose",NULL,reply_fclose,AS_USER},
-/* 0x85 */ { NULL, NULL, NULL, 0 },
-/* 0x86 */ { NULL, NULL, NULL, 0 },
-/* 0x87 */ { NULL, NULL, NULL, 0 },
-/* 0x88 */ { NULL, NULL, NULL, 0 },
-/* 0x89 */ { NULL, NULL, NULL, 0 },
-/* 0x8a */ { NULL, NULL, NULL, 0 },
-/* 0x8b */ { NULL, NULL, NULL, 0 },
-/* 0x8c */ { NULL, NULL, NULL, 0 },
-/* 0x8d */ { NULL, NULL, NULL, 0 },
-/* 0x8e */ { NULL, NULL, NULL, 0 },
-/* 0x8f */ { NULL, NULL, NULL, 0 },
-/* 0x90 */ { NULL, NULL, NULL, 0 },
-/* 0x91 */ { NULL, NULL, NULL, 0 },
-/* 0x92 */ { NULL, NULL, NULL, 0 },
-/* 0x93 */ { NULL, NULL, NULL, 0 },
-/* 0x94 */ { NULL, NULL, NULL, 0 },
-/* 0x95 */ { NULL, NULL, NULL, 0 },
-/* 0x96 */ { NULL, NULL, NULL, 0 },
-/* 0x97 */ { NULL, NULL, NULL, 0 },
-/* 0x98 */ { NULL, NULL, NULL, 0 },
-/* 0x99 */ { NULL, NULL, NULL, 0 },
-/* 0x9a */ { NULL, NULL, NULL, 0 },
-/* 0x9b */ { NULL, NULL, NULL, 0 },
-/* 0x9c */ { NULL, NULL, NULL, 0 },
-/* 0x9d */ { NULL, NULL, NULL, 0 },
-/* 0x9e */ { NULL, NULL, NULL, 0 },
-/* 0x9f */ { NULL, NULL, NULL, 0 },
-/* 0xa0 */ { "SMBnttrans", NULL,reply_nttrans, AS_USER | CAN_IPC },
-/* 0xa1 */ { "SMBnttranss", NULL,reply_nttranss, AS_USER | CAN_IPC },
-/* 0xa2 */ { "SMBntcreateX", NULL,reply_ntcreate_and_X, AS_USER | CAN_IPC },
-/* 0xa3 */ { NULL, NULL, NULL, 0 },
-/* 0xa4 */ { "SMBntcancel", NULL,reply_ntcancel, 0 },
-/* 0xa5 */ { "SMBntrename", NULL,reply_ntrename, AS_USER | NEED_WRITE },
-/* 0xa6 */ { NULL, NULL, NULL, 0 },
-/* 0xa7 */ { NULL, NULL, NULL, 0 },
-/* 0xa8 */ { NULL, NULL, NULL, 0 },
-/* 0xa9 */ { NULL, NULL, NULL, 0 },
-/* 0xaa */ { NULL, NULL, NULL, 0 },
-/* 0xab */ { NULL, NULL, NULL, 0 },
-/* 0xac */ { NULL, NULL, NULL, 0 },
-/* 0xad */ { NULL, NULL, NULL, 0 },
-/* 0xae */ { NULL, NULL, NULL, 0 },
-/* 0xaf */ { NULL, NULL, NULL, 0 },
-/* 0xb0 */ { NULL, NULL, NULL, 0 },
-/* 0xb1 */ { NULL, NULL, NULL, 0 },
-/* 0xb2 */ { NULL, NULL, NULL, 0 },
-/* 0xb3 */ { NULL, NULL, NULL, 0 },
-/* 0xb4 */ { NULL, NULL, NULL, 0 },
-/* 0xb5 */ { NULL, NULL, NULL, 0 },
-/* 0xb6 */ { NULL, NULL, NULL, 0 },
-/* 0xb7 */ { NULL, NULL, NULL, 0 },
-/* 0xb8 */ { NULL, NULL, NULL, 0 },
-/* 0xb9 */ { NULL, NULL, NULL, 0 },
-/* 0xba */ { NULL, NULL, NULL, 0 },
-/* 0xbb */ { NULL, NULL, NULL, 0 },
-/* 0xbc */ { NULL, NULL, NULL, 0 },
-/* 0xbd */ { NULL, NULL, NULL, 0 },
-/* 0xbe */ { NULL, NULL, NULL, 0 },
-/* 0xbf */ { NULL, NULL, NULL, 0 },
-/* 0xc0 */ { "SMBsplopen",NULL,reply_printopen,AS_USER},
-/* 0xc1 */ { "SMBsplwr",NULL,reply_printwrite,AS_USER},
-/* 0xc2 */ { "SMBsplclose",NULL,reply_printclose,AS_USER},
-/* 0xc3 */ { "SMBsplretq",NULL,reply_printqueue,AS_USER},
-/* 0xc4 */ { NULL, NULL, NULL, 0 },
-/* 0xc5 */ { NULL, NULL, NULL, 0 },
-/* 0xc6 */ { NULL, NULL, NULL, 0 },
-/* 0xc7 */ { NULL, NULL, NULL, 0 },
-/* 0xc8 */ { NULL, NULL, NULL, 0 },
-/* 0xc9 */ { NULL, NULL, NULL, 0 },
-/* 0xca */ { NULL, NULL, NULL, 0 },
-/* 0xcb */ { NULL, NULL, NULL, 0 },
-/* 0xcc */ { NULL, NULL, NULL, 0 },
-/* 0xcd */ { NULL, NULL, NULL, 0 },
-/* 0xce */ { NULL, NULL, NULL, 0 },
-/* 0xcf */ { NULL, NULL, NULL, 0 },
-/* 0xd0 */ { "SMBsends",NULL,reply_sends,AS_GUEST},
-/* 0xd1 */ { "SMBsendb",NULL, NULL,AS_GUEST},
-/* 0xd2 */ { "SMBfwdname",NULL, NULL,AS_GUEST},
-/* 0xd3 */ { "SMBcancelf",NULL, NULL,AS_GUEST},
-/* 0xd4 */ { "SMBgetmac",NULL, NULL,AS_GUEST},
-/* 0xd5 */ { "SMBsendstrt",NULL,reply_sendstrt,AS_GUEST},
-/* 0xd6 */ { "SMBsendend",NULL,reply_sendend,AS_GUEST},
-/* 0xd7 */ { "SMBsendtxt",NULL,reply_sendtxt,AS_GUEST},
-/* 0xd8 */ { NULL, NULL, NULL, 0 },
-/* 0xd9 */ { NULL, NULL, NULL, 0 },
-/* 0xda */ { NULL, NULL, NULL, 0 },
-/* 0xdb */ { NULL, NULL, NULL, 0 },
-/* 0xdc */ { NULL, NULL, NULL, 0 },
-/* 0xdd */ { NULL, NULL, NULL, 0 },
-/* 0xde */ { NULL, NULL, NULL, 0 },
-/* 0xdf */ { NULL, NULL, NULL, 0 },
-/* 0xe0 */ { NULL, NULL, NULL, 0 },
-/* 0xe1 */ { NULL, NULL, NULL, 0 },
-/* 0xe2 */ { NULL, NULL, NULL, 0 },
-/* 0xe3 */ { NULL, NULL, NULL, 0 },
-/* 0xe4 */ { NULL, NULL, NULL, 0 },
-/* 0xe5 */ { NULL, NULL, NULL, 0 },
-/* 0xe6 */ { NULL, NULL, NULL, 0 },
-/* 0xe7 */ { NULL, NULL, NULL, 0 },
-/* 0xe8 */ { NULL, NULL, NULL, 0 },
-/* 0xe9 */ { NULL, NULL, NULL, 0 },
-/* 0xea */ { NULL, NULL, NULL, 0 },
-/* 0xeb */ { NULL, NULL, NULL, 0 },
-/* 0xec */ { NULL, NULL, NULL, 0 },
-/* 0xed */ { NULL, NULL, NULL, 0 },
-/* 0xee */ { NULL, NULL, NULL, 0 },
-/* 0xef */ { NULL, NULL, NULL, 0 },
-/* 0xf0 */ { NULL, NULL, NULL, 0 },
-/* 0xf1 */ { NULL, NULL, NULL, 0 },
-/* 0xf2 */ { NULL, NULL, NULL, 0 },
-/* 0xf3 */ { NULL, NULL, NULL, 0 },
-/* 0xf4 */ { NULL, NULL, NULL, 0 },
-/* 0xf5 */ { NULL, NULL, NULL, 0 },
-/* 0xf6 */ { NULL, NULL, NULL, 0 },
-/* 0xf7 */ { NULL, NULL, NULL, 0 },
-/* 0xf8 */ { NULL, NULL, NULL, 0 },
-/* 0xf9 */ { NULL, NULL, NULL, 0 },
-/* 0xfa */ { NULL, NULL, NULL, 0 },
-/* 0xfb */ { NULL, NULL, NULL, 0 },
-/* 0xfc */ { NULL, NULL, NULL, 0 },
-/* 0xfd */ { NULL, NULL, NULL, 0 },
-/* 0xfe */ { NULL, NULL, NULL, 0 },
-/* 0xff */ { NULL, NULL, NULL, 0 }
+/* 0x00 */ { "SMBmkdir",reply_mkdir,AS_USER | NEED_WRITE},
+/* 0x01 */ { "SMBrmdir",reply_rmdir,AS_USER | NEED_WRITE},
+/* 0x02 */ { "SMBopen",reply_open,AS_USER },
+/* 0x03 */ { "SMBcreate",reply_mknew,AS_USER},
+/* 0x04 */ { "SMBclose",reply_close,AS_USER | CAN_IPC },
+/* 0x05 */ { "SMBflush",reply_flush,AS_USER},
+/* 0x06 */ { "SMBunlink",reply_unlink,AS_USER | NEED_WRITE },
+/* 0x07 */ { "SMBmv",reply_mv,AS_USER | NEED_WRITE },
+/* 0x08 */ { "SMBgetatr",reply_getatr,AS_USER},
+/* 0x09 */ { "SMBsetatr",reply_setatr,AS_USER | NEED_WRITE},
+/* 0x0a */ { "SMBread",reply_read,AS_USER},
+/* 0x0b */ { "SMBwrite",reply_write,AS_USER | CAN_IPC },
+/* 0x0c */ { "SMBlock",reply_lock,AS_USER},
+/* 0x0d */ { "SMBunlock",reply_unlock,AS_USER},
+/* 0x0e */ { "SMBctemp",reply_ctemp,AS_USER },
+/* 0x0f */ { "SMBmknew",reply_mknew,AS_USER},
+/* 0x10 */ { "SMBcheckpath",reply_checkpath,AS_USER},
+/* 0x11 */ { "SMBexit",reply_exit,DO_CHDIR},
+/* 0x12 */ { "SMBlseek",reply_lseek,AS_USER},
+/* 0x13 */ { "SMBlockread",reply_lockread,AS_USER},
+/* 0x14 */ { "SMBwriteunlock",reply_writeunlock,AS_USER},
+/* 0x15 */ { NULL, NULL, 0 },
+/* 0x16 */ { NULL, NULL, 0 },
+/* 0x17 */ { NULL, NULL, 0 },
+/* 0x18 */ { NULL, NULL, 0 },
+/* 0x19 */ { NULL, NULL, 0 },
+/* 0x1a */ { "SMBreadbraw",reply_readbraw,AS_USER},
+/* 0x1b */ { "SMBreadBmpx",reply_readbmpx,AS_USER},
+/* 0x1c */ { "SMBreadBs",reply_readbs,AS_USER },
+/* 0x1d */ { "SMBwritebraw",reply_writebraw,AS_USER},
+/* 0x1e */ { "SMBwriteBmpx",reply_writebmpx,AS_USER},
+/* 0x1f */ { "SMBwriteBs",reply_writebs,AS_USER},
+/* 0x20 */ { "SMBwritec", NULL,0},
+/* 0x21 */ { NULL, NULL, 0 },
+/* 0x22 */ { "SMBsetattrE",reply_setattrE,AS_USER | NEED_WRITE },
+/* 0x23 */ { "SMBgetattrE",reply_getattrE,AS_USER },
+/* 0x24 */ { "SMBlockingX",reply_lockingX,AS_USER },
+/* 0x25 */ { "SMBtrans",reply_trans,AS_USER | CAN_IPC },
+/* 0x26 */ { "SMBtranss",reply_transs,AS_USER | CAN_IPC},
+/* 0x27 */ { "SMBioctl",reply_ioctl,0},
+/* 0x28 */ { "SMBioctls", NULL,AS_USER},
+/* 0x29 */ { "SMBcopy",reply_copy,AS_USER | NEED_WRITE },
+/* 0x2a */ { "SMBmove", NULL,AS_USER | NEED_WRITE },
+/* 0x2b */ { "SMBecho",reply_echo,0},
+/* 0x2c */ { "SMBwriteclose",reply_writeclose,AS_USER},
+/* 0x2d */ { "SMBopenX",reply_open_and_X,AS_USER | CAN_IPC },
+/* 0x2e */ { "SMBreadX",reply_read_and_X,AS_USER | CAN_IPC },
+/* 0x2f */ { "SMBwriteX",reply_write_and_X,AS_USER | CAN_IPC },
+/* 0x30 */ { NULL, NULL, 0 },
+/* 0x31 */ { NULL, NULL, 0 },
+/* 0x32 */ { "SMBtrans2",reply_trans2, AS_USER | CAN_IPC },
+/* 0x33 */ { "SMBtranss2",reply_transs2, AS_USER},
+/* 0x34 */ { "SMBfindclose",reply_findclose,AS_USER},
+/* 0x35 */ { "SMBfindnclose",reply_findnclose,AS_USER},
+/* 0x36 */ { NULL, NULL, 0 },
+/* 0x37 */ { NULL, NULL, 0 },
+/* 0x38 */ { NULL, NULL, 0 },
+/* 0x39 */ { NULL, NULL, 0 },
+/* 0x3a */ { NULL, NULL, 0 },
+/* 0x3b */ { NULL, NULL, 0 },
+/* 0x3c */ { NULL, NULL, 0 },
+/* 0x3d */ { NULL, NULL, 0 },
+/* 0x3e */ { NULL, NULL, 0 },
+/* 0x3f */ { NULL, NULL, 0 },
+/* 0x40 */ { NULL, NULL, 0 },
+/* 0x41 */ { NULL, NULL, 0 },
+/* 0x42 */ { NULL, NULL, 0 },
+/* 0x43 */ { NULL, NULL, 0 },
+/* 0x44 */ { NULL, NULL, 0 },
+/* 0x45 */ { NULL, NULL, 0 },
+/* 0x46 */ { NULL, NULL, 0 },
+/* 0x47 */ { NULL, NULL, 0 },
+/* 0x48 */ { NULL, NULL, 0 },
+/* 0x49 */ { NULL, NULL, 0 },
+/* 0x4a */ { NULL, NULL, 0 },
+/* 0x4b */ { NULL, NULL, 0 },
+/* 0x4c */ { NULL, NULL, 0 },
+/* 0x4d */ { NULL, NULL, 0 },
+/* 0x4e */ { NULL, NULL, 0 },
+/* 0x4f */ { NULL, NULL, 0 },
+/* 0x50 */ { NULL, NULL, 0 },
+/* 0x51 */ { NULL, NULL, 0 },
+/* 0x52 */ { NULL, NULL, 0 },
+/* 0x53 */ { NULL, NULL, 0 },
+/* 0x54 */ { NULL, NULL, 0 },
+/* 0x55 */ { NULL, NULL, 0 },
+/* 0x56 */ { NULL, NULL, 0 },
+/* 0x57 */ { NULL, NULL, 0 },
+/* 0x58 */ { NULL, NULL, 0 },
+/* 0x59 */ { NULL, NULL, 0 },
+/* 0x5a */ { NULL, NULL, 0 },
+/* 0x5b */ { NULL, NULL, 0 },
+/* 0x5c */ { NULL, NULL, 0 },
+/* 0x5d */ { NULL, NULL, 0 },
+/* 0x5e */ { NULL, NULL, 0 },
+/* 0x5f */ { NULL, NULL, 0 },
+/* 0x60 */ { NULL, NULL, 0 },
+/* 0x61 */ { NULL, NULL, 0 },
+/* 0x62 */ { NULL, NULL, 0 },
+/* 0x63 */ { NULL, NULL, 0 },
+/* 0x64 */ { NULL, NULL, 0 },
+/* 0x65 */ { NULL, NULL, 0 },
+/* 0x66 */ { NULL, NULL, 0 },
+/* 0x67 */ { NULL, NULL, 0 },
+/* 0x68 */ { NULL, NULL, 0 },
+/* 0x69 */ { NULL, NULL, 0 },
+/* 0x6a */ { NULL, NULL, 0 },
+/* 0x6b */ { NULL, NULL, 0 },
+/* 0x6c */ { NULL, NULL, 0 },
+/* 0x6d */ { NULL, NULL, 0 },
+/* 0x6e */ { NULL, NULL, 0 },
+/* 0x6f */ { NULL, NULL, 0 },
+/* 0x70 */ { "SMBtcon",reply_tcon,0},
+/* 0x71 */ { "SMBtdis",reply_tdis,DO_CHDIR},
+/* 0x72 */ { "SMBnegprot",reply_negprot,0},
+/* 0x73 */ { "SMBsesssetupX",reply_sesssetup_and_X,0},
+/* 0x74 */ { "SMBulogoffX",reply_ulogoffX, 0}, /* ulogoff doesn't give a valid TID */
+/* 0x75 */ { "SMBtconX",reply_tcon_and_X,0},
+/* 0x76 */ { NULL, NULL, 0 },
+/* 0x77 */ { NULL, NULL, 0 },
+/* 0x78 */ { NULL, NULL, 0 },
+/* 0x79 */ { NULL, NULL, 0 },
+/* 0x7a */ { NULL, NULL, 0 },
+/* 0x7b */ { NULL, NULL, 0 },
+/* 0x7c */ { NULL, NULL, 0 },
+/* 0x7d */ { NULL, NULL, 0 },
+/* 0x7e */ { NULL, NULL, 0 },
+/* 0x7f */ { NULL, NULL, 0 },
+/* 0x80 */ { "SMBdskattr",reply_dskattr,AS_USER},
+/* 0x81 */ { "SMBsearch",reply_search,AS_USER},
+/* 0x82 */ { "SMBffirst",reply_search,AS_USER},
+/* 0x83 */ { "SMBfunique",reply_search,AS_USER},
+/* 0x84 */ { "SMBfclose",reply_fclose,AS_USER},
+/* 0x85 */ { NULL, NULL, 0 },
+/* 0x86 */ { NULL, NULL, 0 },
+/* 0x87 */ { NULL, NULL, 0 },
+/* 0x88 */ { NULL, NULL, 0 },
+/* 0x89 */ { NULL, NULL, 0 },
+/* 0x8a */ { NULL, NULL, 0 },
+/* 0x8b */ { NULL, NULL, 0 },
+/* 0x8c */ { NULL, NULL, 0 },
+/* 0x8d */ { NULL, NULL, 0 },
+/* 0x8e */ { NULL, NULL, 0 },
+/* 0x8f */ { NULL, NULL, 0 },
+/* 0x90 */ { NULL, NULL, 0 },
+/* 0x91 */ { NULL, NULL, 0 },
+/* 0x92 */ { NULL, NULL, 0 },
+/* 0x93 */ { NULL, NULL, 0 },
+/* 0x94 */ { NULL, NULL, 0 },
+/* 0x95 */ { NULL, NULL, 0 },
+/* 0x96 */ { NULL, NULL, 0 },
+/* 0x97 */ { NULL, NULL, 0 },
+/* 0x98 */ { NULL, NULL, 0 },
+/* 0x99 */ { NULL, NULL, 0 },
+/* 0x9a */ { NULL, NULL, 0 },
+/* 0x9b */ { NULL, NULL, 0 },
+/* 0x9c */ { NULL, NULL, 0 },
+/* 0x9d */ { NULL, NULL, 0 },
+/* 0x9e */ { NULL, NULL, 0 },
+/* 0x9f */ { NULL, NULL, 0 },
+/* 0xa0 */ { "SMBnttrans",reply_nttrans, AS_USER | CAN_IPC },
+/* 0xa1 */ { "SMBnttranss",reply_nttranss, AS_USER | CAN_IPC },
+/* 0xa2 */ { "SMBntcreateX",reply_ntcreate_and_X, AS_USER | CAN_IPC },
+/* 0xa3 */ { NULL, NULL, 0 },
+/* 0xa4 */ { "SMBntcancel",reply_ntcancel, 0 },
+/* 0xa5 */ { "SMBntrename",reply_ntrename, AS_USER | NEED_WRITE },
+/* 0xa6 */ { NULL, NULL, 0 },
+/* 0xa7 */ { NULL, NULL, 0 },
+/* 0xa8 */ { NULL, NULL, 0 },
+/* 0xa9 */ { NULL, NULL, 0 },
+/* 0xaa */ { NULL, NULL, 0 },
+/* 0xab */ { NULL, NULL, 0 },
+/* 0xac */ { NULL, NULL, 0 },
+/* 0xad */ { NULL, NULL, 0 },
+/* 0xae */ { NULL, NULL, 0 },
+/* 0xaf */ { NULL, NULL, 0 },
+/* 0xb0 */ { NULL, NULL, 0 },
+/* 0xb1 */ { NULL, NULL, 0 },
+/* 0xb2 */ { NULL, NULL, 0 },
+/* 0xb3 */ { NULL, NULL, 0 },
+/* 0xb4 */ { NULL, NULL, 0 },
+/* 0xb5 */ { NULL, NULL, 0 },
+/* 0xb6 */ { NULL, NULL, 0 },
+/* 0xb7 */ { NULL, NULL, 0 },
+/* 0xb8 */ { NULL, NULL, 0 },
+/* 0xb9 */ { NULL, NULL, 0 },
+/* 0xba */ { NULL, NULL, 0 },
+/* 0xbb */ { NULL, NULL, 0 },
+/* 0xbc */ { NULL, NULL, 0 },
+/* 0xbd */ { NULL, NULL, 0 },
+/* 0xbe */ { NULL, NULL, 0 },
+/* 0xbf */ { NULL, NULL, 0 },
+/* 0xc0 */ { "SMBsplopen",reply_printopen,AS_USER},
+/* 0xc1 */ { "SMBsplwr",reply_printwrite,AS_USER},
+/* 0xc2 */ { "SMBsplclose",reply_printclose,AS_USER},
+/* 0xc3 */ { "SMBsplretq",reply_printqueue,AS_USER},
+/* 0xc4 */ { NULL, NULL, 0 },
+/* 0xc5 */ { NULL, NULL, 0 },
+/* 0xc6 */ { NULL, NULL, 0 },
+/* 0xc7 */ { NULL, NULL, 0 },
+/* 0xc8 */ { NULL, NULL, 0 },
+/* 0xc9 */ { NULL, NULL, 0 },
+/* 0xca */ { NULL, NULL, 0 },
+/* 0xcb */ { NULL, NULL, 0 },
+/* 0xcc */ { NULL, NULL, 0 },
+/* 0xcd */ { NULL, NULL, 0 },
+/* 0xce */ { NULL, NULL, 0 },
+/* 0xcf */ { NULL, NULL, 0 },
+/* 0xd0 */ { "SMBsends",reply_sends,AS_GUEST},
+/* 0xd1 */ { "SMBsendb", NULL,AS_GUEST},
+/* 0xd2 */ { "SMBfwdname", NULL,AS_GUEST},
+/* 0xd3 */ { "SMBcancelf", NULL,AS_GUEST},
+/* 0xd4 */ { "SMBgetmac", NULL,AS_GUEST},
+/* 0xd5 */ { "SMBsendstrt",reply_sendstrt,AS_GUEST},
+/* 0xd6 */ { "SMBsendend",reply_sendend,AS_GUEST},
+/* 0xd7 */ { "SMBsendtxt",reply_sendtxt,AS_GUEST},
+/* 0xd8 */ { NULL, NULL, 0 },
+/* 0xd9 */ { NULL, NULL, 0 },
+/* 0xda */ { NULL, NULL, 0 },
+/* 0xdb */ { NULL, NULL, 0 },
+/* 0xdc */ { NULL, NULL, 0 },
+/* 0xdd */ { NULL, NULL, 0 },
+/* 0xde */ { NULL, NULL, 0 },
+/* 0xdf */ { NULL, NULL, 0 },
+/* 0xe0 */ { NULL, NULL, 0 },
+/* 0xe1 */ { NULL, NULL, 0 },
+/* 0xe2 */ { NULL, NULL, 0 },
+/* 0xe3 */ { NULL, NULL, 0 },
+/* 0xe4 */ { NULL, NULL, 0 },
+/* 0xe5 */ { NULL, NULL, 0 },
+/* 0xe6 */ { NULL, NULL, 0 },
+/* 0xe7 */ { NULL, NULL, 0 },
+/* 0xe8 */ { NULL, NULL, 0 },
+/* 0xe9 */ { NULL, NULL, 0 },
+/* 0xea */ { NULL, NULL, 0 },
+/* 0xeb */ { NULL, NULL, 0 },
+/* 0xec */ { NULL, NULL, 0 },
+/* 0xed */ { NULL, NULL, 0 },
+/* 0xee */ { NULL, NULL, 0 },
+/* 0xef */ { NULL, NULL, 0 },
+/* 0xf0 */ { NULL, NULL, 0 },
+/* 0xf1 */ { NULL, NULL, 0 },
+/* 0xf2 */ { NULL, NULL, 0 },
+/* 0xf3 */ { NULL, NULL, 0 },
+/* 0xf4 */ { NULL, NULL, 0 },
+/* 0xf5 */ { NULL, NULL, 0 },
+/* 0xf6 */ { NULL, NULL, 0 },
+/* 0xf7 */ { NULL, NULL, 0 },
+/* 0xf8 */ { NULL, NULL, 0 },
+/* 0xf9 */ { NULL, NULL, 0 },
+/* 0xfa */ { NULL, NULL, 0 },
+/* 0xfb */ { NULL, NULL, 0 },
+/* 0xfc */ { NULL, NULL, 0 },
+/* 0xfd */ { NULL, NULL, 0 },
+/* 0xfe */ { NULL, NULL, 0 },
+/* 0xff */ { NULL, NULL, 0 }
 
 };
 
@@ -973,8 +1332,7 @@ void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes)
        }
 
        construct_reply_common((char *)req->inbuf, (char *)req->outbuf);
-       set_message((char *)req->inbuf, (char *)req->outbuf,
-                   num_words, num_bytes, False);
+       srv_set_message((char *)req->outbuf, num_words, num_bytes, false);
        /*
         * Zero out the word area, the caller has to take care of the bcc area
         * himself
@@ -994,13 +1352,18 @@ void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes)
 static void smb_dump(const char *name, int type, const char *data, ssize_t len)
 {
        int fd, i;
-       pstring fname;
-       if (DEBUGLEVEL < 50) return;
+       char *fname = NULL;
+       if (DEBUGLEVEL < 50) {
+               return;
+       }
 
        if (len < 4) len = smb_len(data)+4;
        for (i=1;i<100;i++) {
-               slprintf(fname,sizeof(fname)-1, "/tmp/%s.%d.%s", name, i,
+               asprintf(&fname, "/tmp/%s.%d.%s", name, i,
                                type ? "req" : "resp");
+               if (!fname) {
+                       return;
+               }
                fd = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0644);
                if (fd != -1 || errno != EEXIST) break;
        }
@@ -1011,6 +1374,7 @@ static void smb_dump(const char *name, int type, const char *data, ssize_t len)
                close(fd);
                DEBUG(0,("created %s len %lu\n", fname, (unsigned long)len));
        }
+       SAFE_FREE(fname);
 }
 
 /****************************************************************************
@@ -1026,35 +1390,30 @@ static void smb_dump(const char *name, int type, const char *data, ssize_t len)
  find.
 ****************************************************************************/
 
-static BOOL switch_message_new(uint8 type, struct smb_request *req, int size,
-                              connection_struct **pconn)
+static connection_struct *switch_message(uint8 type, struct smb_request *req, int size)
 {
        int flags;
        uint16 session_tag;
-       connection_struct *conn;
+       connection_struct *conn = NULL;
 
        static uint16 last_session_tag = UID_FIELD_INVALID;
 
        errno = 0;
 
-       last_message = type;
-
        /* Make sure this is an SMB packet. smb_size contains NetBIOS header
         * so subtract 4 from it. */
-       if ((strncmp(smb_base(req->inbuf),"\377SMB",4) != 0)
+       if (!valid_smb_header(req->inbuf)
            || (size < (smb_size - 4))) {
                DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
                         smb_len(req->inbuf)));
                exit_server_cleanly("Non-SMB packet");
-               return True;
        }
 
-       if ((smb_messages[type].fn == NULL)
-           && (smb_messages[type].fn_new == NULL)) {
+       if (smb_messages[type].fn_new == NULL) {
                DEBUG(0,("Unknown message type %d!\n",type));
                smb_dump("Unknown", 1, (char *)req->inbuf, size);
                reply_unknown_new(req, type);
-               goto done;
+               return NULL;
        }
 
        flags = smb_messages[type].flags;
@@ -1062,7 +1421,7 @@ static BOOL switch_message_new(uint8 type, struct smb_request *req, int size,
        /* In share mode security we must ignore the vuid. */
        session_tag = (lp_security() == SEC_SHARE)
                ? UID_FIELD_INVALID : req->vuid;
-       conn = conn_find(req->tid);
+       conn = req->conn;
 
        DEBUG(3,("switch message %s (pid %d) conn 0x%lx\n", smb_fn_name(type),
                 (int)sys_getpid(), (unsigned long)conn));
@@ -1107,12 +1466,12 @@ static BOOL switch_message_new(uint8 type, struct smb_request *req, int size,
                        } else {
                                reply_doserror(req, ERRSRV, ERRinvnid);
                        }
-                       goto done;
+                       return NULL;
                }
 
                if (!change_to_user(conn,session_tag)) {
                        reply_nterror(req, NT_STATUS_DOS(ERRSRV, ERRbaduid));
-                       goto done;
+                       return conn;
                }
 
                /* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
@@ -1120,13 +1479,13 @@ static BOOL switch_message_new(uint8 type, struct smb_request *req, int size,
                /* Does it need write permission? */
                if ((flags & NEED_WRITE) && !CAN_WRITE(conn)) {
                        reply_nterror(req, NT_STATUS_MEDIA_WRITE_PROTECTED);
-                       goto done;
+                       return conn;
                }
 
                /* IPC services are limited */
                if (IS_IPC(conn) && !(flags & CAN_IPC)) {
                        reply_doserror(req, ERRSRV,ERRaccess);
-                       goto done;
+                       return conn;
                }
        } else {
                /* This call needs to be run as root */
@@ -1135,11 +1494,24 @@ static BOOL switch_message_new(uint8 type, struct smb_request *req, int size,
 
        /* load service specific parameters */
        if (conn) {
+               if (req->encrypted) {
+                       conn->encrypted_tid = true;
+                       /* encrypted required from now on. */
+                       conn->encrypt_level = Required;
+               } else if (ENCRYPTION_REQUIRED(conn)) {
+                       uint8 com = CVAL(req->inbuf,smb_com);
+                       if (com != SMBtrans2 && com != SMBtranss2) {
+                               exit_server_cleanly("encryption required "
+                                       "on connection");
+                               return conn;
+                       }
+               }
+
                if (!set_current_service(conn,SVAL(req->inbuf,smb_flg),
                                         (flags & (AS_USER|DO_CHDIR)
                                          ?True:False))) {
                        reply_doserror(req, ERRSRV, ERRaccess);
-                       goto done;
+                       return conn;
                }
                conn->num_smb_operations++;
        }
@@ -1150,112 +1522,55 @@ static BOOL switch_message_new(uint8 type, struct smb_request *req, int size,
                !check_access(smbd_server_fd(), lp_hostsallow(-1),
                              lp_hostsdeny(-1)))) {
                reply_doserror(req, ERRSRV, ERRaccess);
-               goto done;
-       }
-
-       current_inbuf = (char *)req->inbuf; /* In case we need to defer this
-                                            * message in open... */
-
-       if (smb_messages[type].fn_new != NULL) {
-               smb_messages[type].fn_new(conn, req);
-               goto done;
-       }
-
-       /*
-        * Indicate the upper layer that there's still work.
-        */
-       *pconn = conn;
-       return False;
-
- done:
-       return True;
-}
-
-
-/****************************************************************************
- Do a switch on the message type, and return the response size
-****************************************************************************/
-
-static int switch_message(uint8 type, struct smb_request *req, char **outbuf,
-                         int size, int bufsize)
-{
-       int outsize = 0;
-       connection_struct *conn = NULL;
-
-       if (switch_message_new(type, req, size, &conn)) {
-               if (req->outbuf != NULL) {
-                       *outbuf = (char *)req->outbuf;
-                       return smb_len(req->outbuf)+4;
-               }
-               return -1;
-       }
-
-       if (InBuffer == NULL) {
-               DEBUG(1, ("have to alloc InBuffer for %s\n",
-                         smb_fn_name(type)));
-               if (NewInBuffer(NULL) == NULL) {
-                       smb_panic("Could not allocate InBuffer");
-               }
-       }
-
-       if ((OutBuffer == NULL) && (NewOutBuffer(NULL) == NULL)) {
-               smb_panic("Could not allocate OutBuffer");
+               return conn;
        }
 
-       clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer,
-                      total_buffer_size);
-
-       memcpy(InBuffer, req->inbuf, MIN(size, total_buffer_size));
-
-       construct_reply_common(InBuffer, OutBuffer);
-
-       outsize = smb_messages[type].fn(conn, InBuffer, OutBuffer, size,
-                                       bufsize);
-
-       smb_dump(smb_fn_name(type), 0, OutBuffer, outsize);
-
-       *outbuf = OutBuffer;
-
-       return(outsize);
+       smb_messages[type].fn_new(req);
+       return req->conn;
 }
 
 /****************************************************************************
  Construct a reply to the incoming packet.
 ****************************************************************************/
 
-static void construct_reply(char *inbuf, int size)
+static void construct_reply(char *inbuf, int size, size_t unread_bytes, bool encrypted)
 {
        uint8 type = CVAL(inbuf,smb_com);
-       int outsize = 0;
+       connection_struct *conn;
        struct smb_request *req;
-       char *outbuf;
 
        chain_size = 0;
        file_chain_reset();
        reset_chain_p();
 
-       if (!(req = talloc(tmp_talloc_ctx(), struct smb_request))) {
+       if (!(req = talloc(talloc_tos(), struct smb_request))) {
                smb_panic("could not allocate smb_request");
        }
-       init_smb_request(req, (uint8 *)inbuf);
+       init_smb_request(req, (uint8 *)inbuf, unread_bytes, encrypted);
 
-       outsize = switch_message(type, req, &outbuf, size, max_send);
+       conn = switch_message(type, req, size);
 
-       if (outsize > 4) {
-               smb_setlen(inbuf,outbuf,outsize - 4);
+       if (req->unread_bytes) {
+               /* writeX failed. drain socket. */
+               if (drain_socket(smbd_server_fd(), req->unread_bytes) !=
+                               req->unread_bytes) {
+                       smb_panic("failed to drain pending bytes");
+               }
+               req->unread_bytes = 0;
        }
 
-       if (outsize > 0) {
-               if (CVAL(outbuf,0) == 0)
-                       show_msg(outbuf);
+       if (req->outbuf == NULL) {
+               return;
+       }
 
-               if (outsize != smb_len(outbuf) + 4) {
-                       DEBUG(0,("ERROR: Invalid message response size! "
-                                "%d %d\n", outsize, smb_len(outbuf)));
-               } else if (!send_smb(smbd_server_fd(),outbuf)) {
-                       exit_server_cleanly("construct_reply: send_smb "
-                                           "failed.");
-               }
+       if (CVAL(req->outbuf,0) == 0) {
+               show_msg((char *)req->outbuf);
+       }
+
+       if (!srv_send_smb(smbd_server_fd(),
+                       (char *)req->outbuf,
+                       IS_CONN_ENCRYPTED(conn)||req->encrypted)) {
+               exit_server_cleanly("construct_reply: srv_send_smb failed.");
        }
 
        TALLOC_FREE(req);
@@ -1267,7 +1582,7 @@ static void construct_reply(char *inbuf, int size)
  Process an smb from the client
 ****************************************************************************/
 
-static void process_smb(char *inbuf, size_t nread)
+static void process_smb(char *inbuf, size_t nread, size_t unread_bytes, bool encrypted)
 {
        static int trans_num;
        int msg_type = CVAL(inbuf,0);
@@ -1275,23 +1590,29 @@ static void process_smb(char *inbuf, size_t nread)
        DO_PROFILE_INC(smb_count);
 
        if (trans_num == 0) {
+               char addr[INET6_ADDRSTRLEN];
+
                /* on the first packet, check the global hosts allow/ hosts
                deny parameters before doing any parsing of the packet
                passed to us by the client.  This prevents attacks on our
                parsing code from hosts not in the hosts allow list */
+
                if (!check_access(smbd_server_fd(), lp_hostsallow(-1),
                                  lp_hostsdeny(-1))) {
                        /* send a negative session response "not listening on calling name" */
                        static unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
-                       DEBUG( 1, ( "Connection denied from %s\n", client_addr() ) );
-                       (void)send_smb(smbd_server_fd(),(char *)buf);
+                       DEBUG( 1, ( "Connection denied from %s\n",
+                               client_addr(get_client_fd(),addr,sizeof(addr)) ) );
+                       (void)srv_send_smb(smbd_server_fd(),(char *)buf,false);
                        exit_server_cleanly("connection denied");
                }
        }
 
        DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type,
                    smb_len(inbuf) ) );
-       DEBUG( 3, ( "Transaction %d of length %d\n", trans_num, (int)nread ) );
+       DEBUG( 3, ( "Transaction %d of length %d (%u toread)\n", trans_num,
+                               (int)nread,
+                               (unsigned int)unread_bytes ));
 
        if (msg_type != 0) {
                /*
@@ -1303,8 +1624,8 @@ static void process_smb(char *inbuf, size_t nread)
 
        show_msg(inbuf);
 
-       construct_reply(inbuf,nread);
-      
+       construct_reply(inbuf,nread,unread_bytes,encrypted);
+
        trans_num++;
 }
 
@@ -1340,7 +1661,7 @@ void remove_from_common_flags2(uint32 v)
 
 void construct_reply_common(const char *inbuf, char *outbuf)
 {
-       set_message(inbuf,outbuf,0,0,False);
+       srv_set_message(outbuf,0,0,false);
        
        SCVAL(outbuf,smb_com,CVAL(inbuf,smb_com));
        SIVAL(outbuf,smb_rcls,0);
@@ -1360,29 +1681,37 @@ void construct_reply_common(const char *inbuf, char *outbuf)
  Construct a chained reply and add it to the already made reply
 ****************************************************************************/
 
-int chain_reply(char *inbuf,char **poutbuf,int size,int bufsize)
+void chain_reply(struct smb_request *req)
 {
        static char *orig_inbuf;
+
+       /*
+        * Dirty little const_discard: We mess with req->inbuf, which is
+        * declared as const. If maybe at some point this routine gets
+        * rewritten, this const_discard could go away.
+        */
+       char *inbuf = CONST_DISCARD(char *, req->inbuf);
+       int size = smb_len(req->inbuf)+4;
+
        int smb_com1, smb_com2 = CVAL(inbuf,smb_vwv0);
        unsigned smb_off2 = SVAL(inbuf,smb_vwv1);
        char *inbuf2;
-       char *outbuf2 = NULL;
        int outsize2;
        int new_size;
        char inbuf_saved[smb_wct];
-       char *outbuf = *poutbuf;
+       char *outbuf = (char *)req->outbuf;
        size_t outsize = smb_len(outbuf) + 4;
        size_t outsize_padded;
        size_t ofs, to_move;
 
-       struct smb_request *req;
+       struct smb_request *req2;
        size_t caller_outputlen;
        char *caller_output;
 
        /* Maybe its not chained, or it's an error packet. */
        if (smb_com2 == 0xFF || SVAL(outbuf,smb_rcls) != 0) {
                SCVAL(outbuf,smb_vwv0,0xFF);
-               return outsize;
+               return;
        }
 
        if (chain_size == 0) {
@@ -1443,28 +1772,28 @@ int chain_reply(char *inbuf,char **poutbuf,int size,int bufsize)
                         "(orig size = %d, offset = %d)\n",
                         size, (int)(inbuf2 - inbuf) ));
                exit_server_cleanly("Bad chained packet");
-               return(-1);
+               return;
        }
 
        /* And set it in the header. */
-       smb_setlen(inbuf, inbuf2, new_size - 4);
+       smb_setlen(inbuf2, new_size - 4);
 
        DEBUG(3,("Chained message\n"));
        show_msg(inbuf2);
 
-       if (!(req = talloc(tmp_talloc_ctx(), struct smb_request))) {
+       if (!(req2 = talloc(talloc_tos(), struct smb_request))) {
                smb_panic("could not allocate smb_request");
        }
-       init_smb_request(req, (uint8 *)inbuf2);
+       init_smb_request(req2, (uint8 *)inbuf2,0, req->encrypted);
 
        /* process the request */
-       outsize2 = switch_message(smb_com2, req, &outbuf2, new_size,
-                                 bufsize-chain_size);
+       switch_message(smb_com2, req2, new_size);
 
        /*
         * We don't accept deferred operations in chained requests.
         */
-       SMB_ASSERT(outsize2 >= smb_wct);
+       SMB_ASSERT(req2->outbuf != NULL);
+       outsize2 = smb_len(req2->outbuf)+4;
 
        /*
         * Move away the new command output so that caller_output fits in,
@@ -1497,24 +1826,22 @@ int chain_reply(char *inbuf,char **poutbuf,int size,int bufsize)
         * which is always large enough.
         */
 
-       if (outbuf != OutBuffer) {
-               outbuf = TALLOC_REALLOC_ARRAY(NULL, outbuf, char,
-                                             to_move + ofs + smb_wct);
-               if (outbuf == NULL) {
-                       smb_panic("could not realloc outbuf");
-               }
+       outbuf = TALLOC_REALLOC_ARRAY(NULL, outbuf, char,
+                                     to_move + ofs + smb_wct);
+       if (outbuf == NULL) {
+               smb_panic("could not realloc outbuf");
        }
 
-       *poutbuf = outbuf;
+       req->outbuf = (uint8 *)outbuf;
 
-       memmove(outbuf + smb_wct + ofs, outbuf2 + smb_wct, to_move);
+       memmove(outbuf + smb_wct + ofs, req2->outbuf + smb_wct, to_move);
        memcpy(outbuf + smb_wct, caller_output, caller_outputlen);
 
        /*
         * copy the new reply header over the old one but preserve the smb_com
         * field
         */
-       memmove(outbuf,outbuf2,smb_wct);
+       memmove(outbuf, req2->outbuf, smb_wct);
        SCVAL(outbuf, smb_com, smb_com1);
 
        /*
@@ -1536,7 +1863,7 @@ int chain_reply(char *inbuf,char **poutbuf,int size,int bufsize)
                memset(outbuf + outsize, 0, outsize_padded - outsize);
        }
 
-       smb_setlen(NULL, outbuf, outsize2 + chain_size - 4);
+       smb_setlen(outbuf, outsize2 + chain_size - 4);
 
        /*
         * restore the saved data, being careful not to overwrite any data
@@ -1545,17 +1872,9 @@ int chain_reply(char *inbuf,char **poutbuf,int size,int bufsize)
        memcpy(inbuf2,inbuf_saved,smb_wct);
 
        SAFE_FREE(caller_output);
-       TALLOC_FREE(req);
-
-       return outsize2 + chain_size;
-}
+       TALLOC_FREE(req2);
 
-void chain_reply_new(struct smb_request *req)
-{
-       chain_reply(CONST_DISCARD(char *, req->inbuf),
-                   (char **)(void *)&req->outbuf,
-                   smb_len(req->inbuf)+4,
-                   smb_len(req->outbuf)+4);
+       return;
 }
 
 /****************************************************************************
@@ -1632,25 +1951,25 @@ void check_reload(time_t t)
  Process any timeout housekeeping. Return False if the caller should exit.
 ****************************************************************************/
 
-static BOOL timeout_processing(int *select_timeout,
+static bool timeout_processing(int *select_timeout,
                               time_t *last_timeout_processing_time)
 {
        time_t t;
 
-       if (smb_read_error == READ_EOF) {
+       if (*get_srv_read_error() == SMB_READ_EOF) {
                DEBUG(3,("timeout_processing: End of file from client (client has disconnected).\n"));
-               return False;
+               return false;
        }
 
-       if (smb_read_error == READ_ERROR) {
+       if (*get_srv_read_error() == SMB_READ_ERROR) {
                DEBUG(3,("timeout_processing: receive_smb error (%s) Exiting\n",
                        strerror(errno)));
-               return False;
+               return false;
        }
 
-       if (smb_read_error == READ_BAD_SIG) {
+       if (*get_srv_read_error() == SMB_READ_BAD_SIG) {
                DEBUG(3,("timeout_processing: receive_smb error bad smb signature. Exiting\n"));
-               return False;
+               return false;
        }
 
        *last_timeout_processing_time = t = time(NULL);
@@ -1734,55 +2053,6 @@ machine %s in domain %s.\n", global_myname(), lp_workgroup()));
        return True;
 }
 
-/****************************************************************************
- Accessor functions for InBuffer, OutBuffer.
-****************************************************************************/
-
-char *get_InBuffer(void)
-{
-       return InBuffer;
-}
-
-/****************************************************************************
- Allocate a new InBuffer. Returns the new and old ones.
-****************************************************************************/
-
-static char *NewInBuffer(char **old_inbuf)
-{
-       char *new_inbuf = (char *)SMB_MALLOC(total_buffer_size);
-       if (!new_inbuf) {
-               return NULL;
-       }
-       if (old_inbuf) {
-               *old_inbuf = InBuffer;
-       }
-       InBuffer = new_inbuf;
-#if defined(DEVELOPER)
-       clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size);
-#endif
-       return InBuffer;
-}
-
-/****************************************************************************
- Allocate a new OutBuffer. Returns the new and old ones.
-****************************************************************************/
-
-static char *NewOutBuffer(char **old_outbuf)
-{
-       char *new_outbuf = (char *)SMB_MALLOC(total_buffer_size);
-       if (!new_outbuf) {
-               return NULL;
-       }
-       if (old_outbuf) {
-               *old_outbuf = OutBuffer;
-       }
-       OutBuffer = new_outbuf;
-#if defined(DEVELOPER)
-       clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, OutBuffer, total_buffer_size);
-#endif
-       return OutBuffer;
-}
-
 /****************************************************************************
  Process commands from the client
 ****************************************************************************/
@@ -1791,6 +2061,7 @@ void smbd_process(void)
 {
        time_t last_timeout_processing_time = time(NULL);
        unsigned int num_smbs = 0;
+       size_t unread_bytes = 0;
 
        max_recv = MIN(lp_maxxmit(),BUFFER_SIZE);
 
@@ -1799,12 +2070,10 @@ void smbd_process(void)
                int num_echos;
                char *inbuf;
                size_t inbuf_len;
+               bool encrypted = false;
+               TALLOC_CTX *frame = talloc_stackframe();
 
-               errno = 0;      
-               
-               /* free up temporary memory */
-               lp_TALLOC_FREE();
-               main_loop_TALLOC_FREE();
+               errno = 0;
 
                /* Did someone ask for immediate checks on things like blocking locks ? */
                if (select_timeout == 0) {
@@ -1817,7 +2086,9 @@ void smbd_process(void)
                run_events(smbd_event_context(), 0, NULL, NULL);
 
                while (!receive_message_or_smb(NULL, &inbuf, &inbuf_len,
-                                              select_timeout)) {
+                                               select_timeout,
+                                               &unread_bytes,
+                                               &encrypted)) {
                        if(!timeout_processing(&select_timeout,
                                               &last_timeout_processing_time))
                                return;
@@ -1833,10 +2104,10 @@ void smbd_process(void)
                 * faster than the select timeout, thus starving out the
                 * essential processing (change notify, blocking locks) that
                 * the timeout code does. JRA.
-                */ 
+                */
                num_echos = smb_echo_count;
 
-               process_smb(inbuf, inbuf_len);
+               process_smb(inbuf, inbuf_len, unread_bytes, encrypted);
 
                TALLOC_FREE(inbuf);
 
@@ -1878,5 +2149,6 @@ void smbd_process(void)
                        change_to_root_user();
                        check_log_size();
                }
+               TALLOC_FREE(frame);
        }
 }