s3:smbprofile: Replace sysv shmem with tdb
[samba.git] / source3 / smbd / process.c
index 02d43d529d00a1882bb8e4abc5e45bbb2c8058e6..38edb028636ae4763d5181f2fdc097433171df0a 100644 (file)
@@ -39,6 +39,7 @@
 #include "../libcli/security/dom_sid.h"
 #include "../libcli/security/security_token.h"
 #include "lib/id_cache.h"
+#include "lib/sys_rw_data.h"
 #include "serverid.h"
 #include "system/threads.h"
 
@@ -57,7 +58,7 @@ struct pending_message_list {
        struct deferred_open_record *open_rec;
 };
 
-static void construct_reply_common(struct smb_request *req, const char *inbuf,
+static void construct_reply_common(uint8_t cmd, const uint8_t *inbuf,
                                   char *outbuf);
 static struct pending_message_list *get_deferred_open_message_smb(
        struct smbd_server_connection *sconn, uint64_t mid);
@@ -87,10 +88,8 @@ static bool smbd_echo_active(struct smbXsrv_connection *xconn)
        return false;
 }
 
-static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn)
+static bool smbd_lock_socket_internal(struct smbXsrv_connection *xconn)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
-
        if (!smbd_echo_active(xconn)) {
                return true;
        }
@@ -142,17 +141,15 @@ static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn)
        return true;
 }
 
-void smbd_lock_socket(struct smbd_server_connection *sconn)
+void smbd_lock_socket(struct smbXsrv_connection *xconn)
 {
-       if (!smbd_lock_socket_internal(sconn)) {
+       if (!smbd_lock_socket_internal(xconn)) {
                exit_server_cleanly("failed to lock socket");
        }
 }
 
-static bool smbd_unlock_socket_internal(struct smbd_server_connection *sconn)
+static bool smbd_unlock_socket_internal(struct smbXsrv_connection *xconn)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
-
        if (!smbd_echo_active(xconn)) {
                return true;
        }
@@ -202,9 +199,9 @@ static bool smbd_unlock_socket_internal(struct smbd_server_connection *sconn)
        return true;
 }
 
-void smbd_unlock_socket(struct smbd_server_connection *sconn)
+void smbd_unlock_socket(struct smbXsrv_connection *xconn)
 {
-       if (!smbd_unlock_socket_internal(sconn)) {
+       if (!smbd_unlock_socket_internal(xconn)) {
                exit_server_cleanly("failed to unlock socket");
        }
 }
@@ -215,12 +212,11 @@ void smbd_unlock_socket(struct smbd_server_connection *sconn)
  Send an smb to a fd.
 ****************************************************************************/
 
-bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer,
+bool srv_send_smb(struct smbXsrv_connection *xconn, char *buffer,
                  bool do_signing, uint32_t seqnum,
                  bool do_encrypt,
                  struct smb_perfcount_data *pcd)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
        size_t len = 0;
        ssize_t ret;
        char *buf_out = buffer;
@@ -232,7 +228,7 @@ bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer,
                return true;
        }
 
-       smbd_lock_socket(sconn);
+       smbd_lock_socket(xconn);
 
        if (do_signing) {
                /* Sign the outgoing packet if required. */
@@ -240,7 +236,7 @@ bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer,
        }
 
        if (do_encrypt) {
-               NTSTATUS status = srv_encrypt_buffer(sconn, buffer, &buf_out);
+               NTSTATUS status = srv_encrypt_buffer(xconn, buffer, &buf_out);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0, ("send_smb: SMB encryption failed "
                                "on outgoing packet! Error %s\n",
@@ -265,16 +261,16 @@ bool srv_send_smb(struct smbd_server_connection *sconn, char *buffer,
                         (int)ret, strerror(saved_errno)));
                errno = saved_errno;
 
-               srv_free_enc_buffer(sconn, buf_out);
+               srv_free_enc_buffer(xconn, buf_out);
                goto out;
        }
 
        SMB_PERFCOUNT_SET_MSGLEN_OUT(pcd, len);
-       srv_free_enc_buffer(sconn, buf_out);
+       srv_free_enc_buffer(xconn, buf_out);
 out:
        SMB_PERFCOUNT_END(pcd);
 
-       smbd_unlock_socket(sconn);
+       smbd_unlock_socket(xconn);
        return (ret > 0);
 }
 
@@ -296,10 +292,9 @@ int srv_set_message(char *buf,
        return (smb_size + num_words*2 + num_bytes);
 }
 
-static bool valid_smb_header(struct smbd_server_connection *sconn,
-                            const uint8_t *inbuf)
+static bool valid_smb_header(const uint8_t *inbuf)
 {
-       if (is_encrypted_packet(sconn, inbuf)) {
+       if (is_encrypted_packet(inbuf)) {
                return true;
        }
        /*
@@ -364,7 +359,7 @@ static NTSTATUS read_packet_remainder(int fd, char *buffer,
 
 static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
                                                    const char lenbuf[4],
-                                                   struct smbd_server_connection *sconn,
+                                                   struct smbXsrv_connection *xconn,
                                                    int sock,
                                                    char **buffer,
                                                    unsigned int timeout,
@@ -388,8 +383,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(0, ("read_fd_with_timeout failed for client %s read "
                          "error = %s.\n",
-                         tsocket_address_string(sconn->remote_address,
-                                                talloc_tos()),
+                         smbXsrv_connection_dbg(xconn),
                          nt_errstr(status)));
                return status;
        }
@@ -399,7 +393,7 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
         * valid writeX call.
         */
 
-       if (is_valid_writeX_buffer(sconn, (uint8_t *)writeX_header)) {
+       if (is_valid_writeX_buffer(xconn, (uint8_t *)writeX_header)) {
                /*
                 * If the data offset is beyond what
                 * we've read, drain the extra bytes.
@@ -480,12 +474,11 @@ static NTSTATUS receive_smb_raw_talloc_partial_read(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
-                                      struct smbd_server_connection *sconn,
+                                      struct smbXsrv_connection *xconn,
                                       int sock,
                                       char **buffer, unsigned int timeout,
                                       size_t *p_unread, size_t *plen)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
        char lenbuf[4];
        size_t len;
        int min_recv_size = lp_min_receive_file_size();
@@ -506,7 +499,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
            xconn->smb1.echo_handler.trusted_fde == NULL) {
 
                return receive_smb_raw_talloc_partial_read(
-                       mem_ctx, lenbuf, sconn, sock, buffer, timeout,
+                       mem_ctx, lenbuf, xconn, sock, buffer, timeout,
                        p_unread, plen);
        }
 
@@ -538,7 +531,7 @@ static NTSTATUS receive_smb_raw_talloc(TALLOC_CTX *mem_ctx,
 }
 
 static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx,
-                                  struct smbd_server_connection *sconn,
+                                  struct smbXsrv_connection *xconn,
                                   int sock,
                                   char **buffer, unsigned int timeout,
                                   size_t *p_unread, bool *p_encrypted,
@@ -546,26 +539,24 @@ static NTSTATUS receive_smb_talloc(TALLOC_CTX *mem_ctx,
                                   uint32_t *seqnum,
                                   bool trusted_channel)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
        size_t len = 0;
        NTSTATUS status;
 
        *p_encrypted = false;
 
-       status = receive_smb_raw_talloc(mem_ctx, sconn, sock, buffer, timeout,
+       status = receive_smb_raw_talloc(mem_ctx, xconn, sock, buffer, timeout,
                                        p_unread, &len);
        if (!NT_STATUS_IS_OK(status)) {
                DEBUG(NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)?5:1,
                      ("receive_smb_raw_talloc failed for client %s "
                       "read error = %s.\n",
-                      tsocket_address_string(sconn->remote_address,
-                                             talloc_tos()),
+                      smbXsrv_connection_dbg(xconn),
                       nt_errstr(status)) );
                return status;
        }
 
-       if (is_encrypted_packet(sconn, (uint8_t *)*buffer)) {
-               status = srv_decrypt_buffer(sconn, *buffer);
+       if (is_encrypted_packet((uint8_t *)*buffer)) {
+               status = srv_decrypt_buffer(xconn, *buffer);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(0, ("receive_smb_talloc: SMB decryption failed on "
                                "incoming packet! Error %s\n",
@@ -627,11 +618,12 @@ static bool init_smb_request(struct smb_request *req,
        req->encrypted = encrypted;
        req->sconn = sconn;
        req->xconn = xconn;
-       status = smb1srv_tcon_lookup(xconn, req->tid, now, &tcon);
-       if (NT_STATUS_IS_OK(status)) {
-               req->conn = tcon->compat;
-       } else {
-               req->conn = NULL;
+       req->conn = NULL;
+       if (xconn != NULL) {
+               status = smb1srv_tcon_lookup(xconn, req->tid, now, &tcon);
+               if (NT_STATUS_IS_OK(status)) {
+                       req->conn = tcon->compat;
+               }
        }
        req->chain_fsp = NULL;
        req->smb2req = NULL;
@@ -701,7 +693,7 @@ static void smbd_deferred_open_timer(struct tevent_context *ev,
        /* If it's still there and was processed, remove it. */
        msg = get_deferred_open_message_smb(sconn, mid);
        if (msg && msg->processed) {
-               remove_deferred_open_message_smb(sconn, mid);
+               remove_deferred_open_message_smb(xconn, mid);
        }
 }
 
@@ -770,13 +762,14 @@ static bool push_queued_message(struct smb_request *req,
  Function to delete a sharing violation open message by mid.
 ****************************************************************************/
 
-void remove_deferred_open_message_smb(struct smbd_server_connection *sconn,
+void remove_deferred_open_message_smb(struct smbXsrv_connection *xconn,
                                      uint64_t mid)
 {
+       struct smbd_server_connection *sconn = xconn->client->sconn;
        struct pending_message_list *pml;
 
        if (sconn->using_smb2) {
-               remove_deferred_open_message_smb2(sconn, mid);
+               remove_deferred_open_message_smb2(xconn, mid);
                return;
        }
 
@@ -798,14 +791,15 @@ void remove_deferred_open_message_smb(struct smbd_server_connection *sconn,
  schedule it for immediate processing.
 ****************************************************************************/
 
-bool schedule_deferred_open_message_smb(struct smbd_server_connection *sconn,
+bool schedule_deferred_open_message_smb(struct smbXsrv_connection *xconn,
                                        uint64_t mid)
 {
+       struct smbd_server_connection *sconn = xconn->client->sconn;
        struct pending_message_list *pml;
        int i = 0;
 
        if (sconn->using_smb2) {
-               return schedule_deferred_open_message_smb2(sconn, mid);
+               return schedule_deferred_open_message_smb2(xconn, mid);
        }
 
        for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
@@ -862,12 +856,13 @@ bool schedule_deferred_open_message_smb(struct smbd_server_connection *sconn,
  Return true if this mid is on the deferred queue and was not yet processed.
 ****************************************************************************/
 
-bool open_was_deferred(struct smbd_server_connection *sconn, uint64_t mid)
+bool open_was_deferred(struct smbXsrv_connection *xconn, uint64_t mid)
 {
+       struct smbd_server_connection *sconn = xconn->client->sconn;
        struct pending_message_list *pml;
 
        if (sconn->using_smb2) {
-               return open_was_deferred_smb2(sconn, mid);
+               return open_was_deferred_smb2(xconn, mid);
        }
 
        for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
@@ -1347,8 +1342,8 @@ static const struct smb_message_struct {
 ********************************************************************/
 
 static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req,
-                         const char *inbuf, char **outbuf, uint8_t num_words,
-                         uint32_t num_bytes)
+                         const uint8_t *inbuf, char **outbuf,
+                         uint8_t num_words, uint32_t num_bytes)
 {
        size_t smb_len = MIN_SMB_SIZE + VWV(num_words) + num_bytes;
 
@@ -1374,7 +1369,7 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req,
                return false;
        }
 
-       construct_reply_common(req, inbuf, *outbuf);
+       construct_reply_common(req->cmd, inbuf, *outbuf);
        srv_set_message(*outbuf, num_words, num_bytes, false);
        /*
         * Zero out the word area, the caller has to take care of the bcc area
@@ -1390,7 +1385,7 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req,
 void reply_outbuf(struct smb_request *req, uint8 num_words, uint32 num_bytes)
 {
        char *outbuf;
-       if (!create_outbuf(req, req, (const char *)req->inbuf, &outbuf, num_words,
+       if (!create_outbuf(req, req, req->inbuf, &outbuf, num_words,
                           num_bytes)) {
                smb_panic("could not allocate output buffer\n");
        }
@@ -1460,6 +1455,24 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req)
 
        errno = 0;
 
+       if (!xconn->smb1.negprot.done) {
+               switch (type) {
+                       /*
+                        * Without a negprot the request must
+                        * either be a negprot, or one of the
+                        * evil old SMB mailslot messaging types.
+                        */
+                       case SMBnegprot:
+                       case SMBsendstrt:
+                       case SMBsendend:
+                       case SMBsendtxt:
+                               break;
+                       default:
+                               exit_server_cleanly("The first request "
+                                       "should be a negprot");
+               }
+       }
+
        if (smb_messages[type].fn == NULL) {
                DEBUG(0,("Unknown message type %d!\n",type));
                smb_dump("Unknown", 1, (const char *)req->inbuf);
@@ -1514,10 +1527,10 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req)
                }
        }
 
-       if (session_tag != xconn->last_session_id) {
+       if (session_tag != xconn->client->last_session_id) {
                struct user_struct *vuser = NULL;
 
-               xconn->last_session_id = session_tag;
+               xconn->client->last_session_id = session_tag;
                if (session) {
                        vuser = session->compat;
                }
@@ -1641,12 +1654,12 @@ static connection_struct *switch_message(uint8 type, struct smb_request *req)
  Construct a reply to the incoming packet.
 ****************************************************************************/
 
-static void construct_reply(struct smbd_server_connection *sconn,
+static void construct_reply(struct smbXsrv_connection *xconn,
                            char *inbuf, int size, size_t unread_bytes,
                            uint32_t seqnum, bool encrypted,
                            struct smb_perfcount_data *deferred_pcd)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
+       struct smbd_server_connection *sconn = xconn->client->sconn;
        struct smb_request *req;
 
        if (!(req = talloc(talloc_tos(), struct smb_request))) {
@@ -1684,7 +1697,7 @@ static void construct_reply(struct smbd_server_connection *sconn,
        smb_request_done(req);
 }
 
-static void construct_reply_chain(struct smbd_server_connection *sconn,
+static void construct_reply_chain(struct smbXsrv_connection *xconn,
                                  char *inbuf, int size, uint32_t seqnum,
                                  bool encrypted,
                                  struct smb_perfcount_data *deferred_pcd)
@@ -1694,13 +1707,13 @@ static void construct_reply_chain(struct smbd_server_connection *sconn,
        unsigned num_reqs;
        bool ok;
 
-       ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, sconn, encrypted,
+       ok = smb1_parse_chain(talloc_tos(), (uint8_t *)inbuf, xconn, encrypted,
                              seqnum, &reqs, &num_reqs);
        if (!ok) {
                char errbuf[smb_size];
                error_packet(errbuf, 0, 0, NT_STATUS_INVALID_PARAMETER,
                             __LINE__, __FILE__);
-               if (!srv_send_smb(sconn, errbuf, true, seqnum, encrypted,
+               if (!srv_send_smb(xconn, errbuf, true, seqnum, encrypted,
                                  NULL)) {
                        exit_server_cleanly("construct_reply_chain: "
                                            "srv_send_smb failed.");
@@ -1764,7 +1777,7 @@ void smb_request_done(struct smb_request *req)
 
                next->vuid = SVAL(req->outbuf, smb_uid);
                next->tid  = SVAL(req->outbuf, smb_tid);
-               status = smb1srv_tcon_lookup(req->sconn->conn, req->tid,
+               status = smb1srv_tcon_lookup(req->xconn, req->tid,
                                             now, &tcon);
                if (NT_STATUS_IS_OK(status)) {
                        req->conn = tcon->compat;
@@ -1821,7 +1834,7 @@ void smb_request_done(struct smb_request *req)
                first_req->outbuf, talloc_get_size(first_req->outbuf) - 4);
 
 shipit:
-       if (!srv_send_smb(first_req->sconn,
+       if (!srv_send_smb(first_req->xconn,
                          (char *)first_req->outbuf,
                          true, first_req->seqnum+1,
                          IS_CONN_ENCRYPTED(req->conn)||first_req->encrypted,
@@ -1837,7 +1850,7 @@ error:
        {
                char errbuf[smb_size];
                error_packet(errbuf, 0, 0, status, __LINE__, __FILE__);
-               if (!srv_send_smb(req->sconn, errbuf, true,
+               if (!srv_send_smb(req->xconn, errbuf, true,
                                  req->seqnum+1, req->encrypted,
                                  NULL)) {
                        exit_server_cleanly("construct_reply_chain: "
@@ -1856,10 +1869,10 @@ static void process_smb(struct smbXsrv_connection *xconn,
                        uint32_t seqnum, bool encrypted,
                        struct smb_perfcount_data *deferred_pcd)
 {
-       struct smbd_server_connection *sconn = xconn->sconn;
+       struct smbd_server_connection *sconn = xconn->client->sconn;
        int msg_type = CVAL(inbuf,0);
 
-       DO_PROFILE_INC(smb_count);
+       DO_PROFILE_INC(request);
 
        DEBUG( 6, ( "got message type 0x%x of len 0x%x\n", msg_type,
                    smb_len(inbuf) ) );
@@ -1870,7 +1883,7 @@ static void process_smb(struct smbXsrv_connection *xconn,
                /*
                 * NetBIOS session request, keepalive, etc.
                 */
-               reply_special(sconn, (char *)inbuf, nread);
+               reply_special(xconn, (char *)inbuf, nread);
                goto done;
        }
 
@@ -1878,9 +1891,11 @@ static void process_smb(struct smbXsrv_connection *xconn,
                /* At this point we're not really using smb2,
                 * we make the decision here.. */
                if (smbd_is_smb2_header(inbuf, nread)) {
-                       smbd_smb2_first_negprot(xconn, inbuf, nread);
+                       const uint8_t *inpdu = inbuf + NBT_HDR_SIZE;
+                       size_t pdulen = nread - NBT_HDR_SIZE;
+                       smbd_smb2_first_negprot(xconn, inpdu, pdulen);
                        return;
-               } else if (nread >= smb_size && valid_smb_header(sconn, inbuf)
+               } else if (nread >= smb_size && valid_smb_header(inbuf)
                                && CVAL(inbuf, smb_com) != 0x72) {
                        /* This is a non-negprot SMB1 packet.
                           Disable SMB2 from now on. */
@@ -1890,7 +1905,7 @@ static void process_smb(struct smbXsrv_connection *xconn,
 
        /* Make sure this is an SMB packet. smb_size contains NetBIOS header
         * so subtract 4 from it. */
-       if ((nread < (smb_size - 4)) || !valid_smb_header(sconn, inbuf)) {
+       if ((nread < (smb_size - 4)) || !valid_smb_header(inbuf)) {
                DEBUG(2,("Non-SMB packet of length %d. Terminating server\n",
                         smb_len(inbuf)));
 
@@ -1910,10 +1925,10 @@ static void process_smb(struct smbXsrv_connection *xconn,
        show_msg((char *)inbuf);
 
        if ((unread_bytes == 0) && smb1_is_chain(inbuf)) {
-               construct_reply_chain(sconn, (char *)inbuf, nread,
+               construct_reply_chain(xconn, (char *)inbuf, nread,
                                      seqnum, encrypted, deferred_pcd);
        } else {
-               construct_reply(sconn, (char *)inbuf, nread, unread_bytes,
+               construct_reply(xconn, (char *)inbuf, nread, unread_bytes,
                                seqnum, encrypted, deferred_pcd);
        }
 
@@ -1964,7 +1979,7 @@ void remove_from_common_flags2(uint32 v)
        common_flags2 &= ~v;
 }
 
-static void construct_reply_common(struct smb_request *req, const char *inbuf,
+static void construct_reply_common(uint8_t cmd, const uint8_t *inbuf,
                                   char *outbuf)
 {
        uint16_t in_flags2 = SVAL(inbuf,smb_flg2);
@@ -1976,7 +1991,7 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf,
 
        srv_set_message(outbuf,0,0,false);
 
-       SCVAL(outbuf, smb_com, req->cmd);
+       SCVAL(outbuf, smb_com, cmd);
        SIVAL(outbuf,smb_rcls,0);
        SCVAL(outbuf,smb_flg, FLAG_REPLY | (CVAL(inbuf,smb_flg) & FLAG_CASELESS_PATHNAMES)); 
        SSVAL(outbuf,smb_flg2, out_flags2);
@@ -1991,7 +2006,7 @@ static void construct_reply_common(struct smb_request *req, const char *inbuf,
 
 void construct_reply_common_req(struct smb_request *req, char *outbuf)
 {
-       construct_reply_common(req, (const char *)req->inbuf, outbuf);
+       construct_reply_common(req->cmd, req->inbuf, outbuf);
 }
 
 /**
@@ -2146,7 +2161,8 @@ static bool smb_splice_chain(uint8_t **poutbuf, const uint8_t *andx_buf)
 
                bytes_addr = outbuf + ofs        /* vwv start */
                        + sizeof(uint16_t) * wct /* vwv array */
-                       + sizeof(uint16_t);      /* bcc */
+                       + sizeof(uint16_t)       /* bcc */
+                       + 1;                     /* padding byte */
 
                SSVAL(outbuf + ofs, 6 * sizeof(uint16_t),
                      bytes_addr - outbuf - 4);
@@ -2384,14 +2400,18 @@ static bool smb1_parse_chain_cb(uint8_t cmd,
 }
 
 bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf,
-                     struct smbd_server_connection *sconn,
+                     struct smbXsrv_connection *xconn,
                      bool encrypted, uint32_t seqnum,
                      struct smb_request ***reqs, unsigned *num_reqs)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
+       struct smbd_server_connection *sconn = NULL;
        struct smb1_parse_chain_state state;
        unsigned i;
 
+       if (xconn != NULL) {
+               sconn = xconn->client->sconn;
+       }
+
        state.mem_ctx = mem_ctx;
        state.buf = buf;
        state.sconn = sconn;
@@ -2449,7 +2469,6 @@ static void smbd_server_connection_write_handler(
 static void smbd_server_connection_read_handler(
        struct smbXsrv_connection *xconn, int fd)
 {
-       struct smbd_server_connection *sconn = xconn->sconn;
        uint8_t *inbuf = NULL;
        size_t inbuf_len = 0;
        size_t unread_bytes = 0;
@@ -2475,17 +2494,17 @@ static void smbd_server_connection_read_handler(
        from_client = (xconn->transport.sock == fd);
 
        if (async_echo && from_client) {
-               smbd_lock_socket(sconn);
+               smbd_lock_socket(xconn);
 
                if (!fd_is_readable(fd)) {
                        DEBUG(10,("the echo listener was faster\n"));
-                       smbd_unlock_socket(sconn);
+                       smbd_unlock_socket(xconn);
                        return;
                }
        }
 
        /* TODO: make this completely nonblocking */
-       status = receive_smb_talloc(mem_ctx, sconn, fd,
+       status = receive_smb_talloc(mem_ctx, xconn, fd,
                                    (char **)(void *)&inbuf,
                                    0, /* timeout */
                                    &unread_bytes,
@@ -2494,7 +2513,7 @@ static void smbd_server_connection_read_handler(
                                    !from_client /* trusted channel */);
 
        if (async_echo && from_client) {
-               smbd_unlock_socket(sconn);
+               smbd_unlock_socket(xconn);
        }
 
        if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
@@ -2716,7 +2735,7 @@ static bool keepalive_fn(const struct timeval *now, void *private_data)
 {
        struct smbd_server_connection *sconn = talloc_get_type_abort(
                private_data, struct smbd_server_connection);
-       struct smbXsrv_connection *xconn = sconn->conn;
+       struct smbXsrv_connection *xconn = NULL;
        bool ret;
 
        if (sconn->using_smb2) {
@@ -2724,9 +2743,13 @@ static bool keepalive_fn(const struct timeval *now, void *private_data)
                return false;
        }
 
-       smbd_lock_socket(sconn);
+       /*
+        * With SMB1 we only have 1 connection
+        */
+       xconn = sconn->client->connections;
+       smbd_lock_socket(xconn);
        ret = send_keepalive(xconn->transport.sock);
-       smbd_unlock_socket(sconn);
+       smbd_unlock_socket(xconn);
 
        if (!ret) {
                int saved_errno = errno;
@@ -2798,7 +2821,7 @@ static bool housekeeping_fn(const struct timeval *now, void *private_data)
 
 struct smbd_echo_read_state {
        struct tevent_context *ev;
-       struct smbd_server_connection *sconn;
+       struct smbXsrv_connection *xconn;
 
        char *buf;
        size_t buflen;
@@ -2810,11 +2833,10 @@ static void smbd_echo_read_waited(struct tevent_req *subreq);
 
 static struct tevent_req *smbd_echo_read_send(
        TALLOC_CTX *mem_ctx, struct tevent_context *ev,
-       struct smbd_server_connection *sconn)
+       struct smbXsrv_connection *xconn)
 {
        struct tevent_req *req, *subreq;
        struct smbd_echo_read_state *state;
-       struct smbXsrv_connection *xconn = sconn->conn;
 
        req = tevent_req_create(mem_ctx, &state,
                                struct smbd_echo_read_state);
@@ -2822,7 +2844,7 @@ static struct tevent_req *smbd_echo_read_send(
                return NULL;
        }
        state->ev = ev;
-       state->sconn = sconn;
+       state->xconn = xconn;
 
        subreq = wait_for_read_send(state, ev, xconn->transport.sock);
        if (tevent_req_nomem(subreq, req)) {
@@ -2866,8 +2888,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                subreq, struct tevent_req);
        struct smbd_echo_read_state *state = tevent_req_data(
                req, struct smbd_echo_read_state);
-       struct smbd_server_connection *sconn = state->sconn;
-       struct smbXsrv_connection *xconn = sconn->conn;
+       struct smbXsrv_connection *xconn = state->xconn;
        bool ok;
        NTSTATUS status;
        size_t unread = 0;
@@ -2880,7 +2901,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                return;
        }
 
-       ok = smbd_lock_socket_internal(sconn);
+       ok = smbd_lock_socket_internal(xconn);
        if (!ok) {
                tevent_req_nterror(req, map_nt_error_from_unix(errno));
                DEBUG(0, ("%s: failed to lock socket\n", __location__));
@@ -2891,7 +2912,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                DEBUG(10,("echo_handler[%d] the parent smbd was faster\n",
                          (int)getpid()));
 
-               ok = smbd_unlock_socket_internal(sconn);
+               ok = smbd_unlock_socket_internal(xconn);
                if (!ok) {
                        tevent_req_nterror(req, map_nt_error_from_unix(errno));
                        DEBUG(1, ("%s: failed to unlock socket\n",
@@ -2908,7 +2929,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                return;
        }
 
-       status = receive_smb_talloc(state, sconn,
+       status = receive_smb_talloc(state, xconn,
                                    xconn->transport.sock,
                                    &state->buf,
                                    0 /* timeout */,
@@ -2925,7 +2946,7 @@ static void smbd_echo_read_waited(struct tevent_req *subreq)
                return;
        }
 
-       ok = smbd_unlock_socket_internal(sconn);
+       ok = smbd_unlock_socket_internal(xconn);
        if (!ok) {
                tevent_req_nterror(req, map_nt_error_from_unix(errno));
                DEBUG(1, ("%s: failed to unlock socket\n", __location__));
@@ -3031,7 +3052,7 @@ static bool smbd_echo_reply(struct smbd_echo_state *state,
                DEBUG(10, ("Got short packet: %d bytes\n", (int)inbuf_len));
                return false;
        }
-       if (!valid_smb_header(state->sconn, inbuf)) {
+       if (!valid_smb_header(inbuf)) {
                DEBUG(10, ("Got invalid SMB header\n"));
                return false;
        }
@@ -3059,7 +3080,7 @@ static bool smbd_echo_reply(struct smbd_echo_state *state,
                return false;
        }
 
-       if (!create_outbuf(talloc_tos(), &req, (const char *)req.inbuf, &outbuf,
+       if (!create_outbuf(talloc_tos(), &req, req.inbuf, &outbuf,
                           1, req.buflen)) {
                DEBUG(10, ("create_outbuf failed\n"));
                return false;
@@ -3072,7 +3093,7 @@ static bool smbd_echo_reply(struct smbd_echo_state *state,
                memcpy(smb_buf(req.outbuf), req.buf, req.buflen);
        }
 
-       ok = srv_send_smb(req.sconn,
+       ok = srv_send_smb(req.xconn,
                          (char *)outbuf,
                          true, seqnum+1,
                          false, &req.pcd);
@@ -3094,19 +3115,17 @@ static void smbd_echo_exit(struct tevent_context *ev,
 
 static void smbd_echo_got_packet(struct tevent_req *req);
 
-static void smbd_echo_loop(struct smbd_server_connection *sconn,
+static void smbd_echo_loop(struct smbXsrv_connection *xconn,
                           int parent_pipe)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
        struct smbd_echo_state *state;
        struct tevent_req *read_req;
 
-       state = talloc_zero(sconn, struct smbd_echo_state);
+       state = talloc_zero(xconn, struct smbd_echo_state);
        if (state == NULL) {
                DEBUG(1, ("talloc failed\n"));
                return;
        }
-       state->sconn = sconn;
        state->xconn = xconn;
        state->parent_pipe = parent_pipe;
        state->ev = s3_tevent_context_init(state);
@@ -3124,7 +3143,7 @@ static void smbd_echo_loop(struct smbd_server_connection *sconn,
                return;
        }
 
-       read_req = smbd_echo_read_send(state, state->ev, sconn);
+       read_req = smbd_echo_read_send(state, state->ev, xconn);
        if (read_req == NULL) {
                DEBUG(1, ("smbd_echo_read_send failed\n"));
                TALLOC_FREE(state);
@@ -3193,7 +3212,7 @@ static void smbd_echo_got_packet(struct tevent_req *req)
                smbd_echo_activate_writer(state);
        }
 
-       req = smbd_echo_read_send(state, state->ev, state->sconn);
+       req = smbd_echo_read_send(state, state->ev, state->xconn);
        if (req == NULL) {
                DEBUG(1, ("smbd_echo_read_send failed\n"));
                exit(1);
@@ -3205,9 +3224,8 @@ static void smbd_echo_got_packet(struct tevent_req *req)
 /*
  * Handle SMBecho requests in a forked child process
  */
-bool fork_echo_handler(struct smbd_server_connection *sconn)
+bool fork_echo_handler(struct smbXsrv_connection *xconn)
 {
-       struct smbXsrv_connection *xconn = sconn->conn;
        int listener_pipe[2];
        int res;
        pid_t child;
@@ -3288,15 +3306,15 @@ bool fork_echo_handler(struct smbd_server_connection *sconn)
                close(listener_pipe[0]);
                set_blocking(listener_pipe[1], false);
 
-               status = reinit_after_fork(sconn->msg_ctx,
-                                          sconn->ev_ctx,
+               status = reinit_after_fork(xconn->msg_ctx,
+                                          xconn->ev_ctx,
                                           true);
                if (!NT_STATUS_IS_OK(status)) {
                        DEBUG(1, ("reinit_after_fork failed: %s\n",
                                  nt_errstr(status)));
                        exit(1);
                }
-               smbd_echo_loop(sconn, listener_pipe[1]);
+               smbd_echo_loop(xconn, listener_pipe[1]);
                exit(0);
        }
        close(listener_pipe[1]);
@@ -3481,31 +3499,56 @@ NTSTATUS smbXsrv_connection_init_tables(struct smbXsrv_connection *conn,
        return NT_STATUS_OK;
 }
 
+struct smbd_tevent_trace_state {
+       struct tevent_context *ev;
+       TALLOC_CTX *frame;
+       SMBPROFILE_BASIC_ASYNC_STATE(profile_idle);
+};
+
 static void smbd_tevent_trace_callback(enum tevent_trace_point point,
                                       void *private_data)
 {
-       struct smbXsrv_connection *conn =
-               talloc_get_type_abort(private_data,
-               struct smbXsrv_connection);
+       struct smbd_tevent_trace_state *state =
+               (struct smbd_tevent_trace_state *)private_data;
 
        switch (point) {
        case TEVENT_TRACE_BEFORE_WAIT:
-               /*
-                * This just removes compiler warning
-                * without profile support
-                */
-               conn->smbd_idle_profstamp = 0;
-               START_PROFILE_STAMP(smbd_idle, conn->smbd_idle_profstamp);
+               if (!smbprofile_dump_pending()) {
+                       /*
+                        * If there's no dump pending
+                        * we don't want to schedule a new 1 sec timer.
+                        *
+                        * Instead we want to sleep as long as nothing happens.
+                        */
+                       smbprofile_dump_setup(NULL);
+               }
+               SMBPROFILE_BASIC_ASYNC_START(idle, profile_p, state->profile_idle);
                break;
        case TEVENT_TRACE_AFTER_WAIT:
-               END_PROFILE_STAMP(smbd_idle, conn->smbd_idle_profstamp);
+               SMBPROFILE_BASIC_ASYNC_END(state->profile_idle);
+               if (!smbprofile_dump_pending()) {
+                       /*
+                        * We need to flush our state after sleeping
+                        * (hopefully a long time).
+                        */
+                       smbprofile_dump();
+                       /*
+                        * future profiling events should trigger timers
+                        * on our main event context.
+                        */
+                       smbprofile_dump_setup(state->ev);
+               }
                break;
-#ifdef TEVENT_HAS_LOOP_ONCE_TRACE_POINTS
        case TEVENT_TRACE_BEFORE_LOOP_ONCE:
+               TALLOC_FREE(state->frame);
+               state->frame = talloc_stackframe_pool(8192);
+               break;
        case TEVENT_TRACE_AFTER_LOOP_ONCE:
+               TALLOC_FREE(state->frame);
                break;
-#endif
        }
+
+       errno = 0;
 }
 
 /**
@@ -3531,18 +3574,11 @@ const char *smbXsrv_connection_dbg(const struct smbXsrv_connection *xconn)
        return ret;
 }
 
-/****************************************************************************
- Process commands from the client
-****************************************************************************/
-
-void smbd_process(struct tevent_context *ev_ctx,
-                 struct messaging_context *msg_ctx,
-                 int sock_fd,
-                 bool interactive)
+NTSTATUS smbd_add_connection(struct smbXsrv_client *client, int sock_fd,
+                            struct smbXsrv_connection **_xconn)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct smbXsrv_connection *xconn;
-       struct smbd_server_connection *sconn;
        struct sockaddr_storage ss_srv;
        void *sp_srv = (void *)&ss_srv;
        struct sockaddr *sa_srv = (struct sockaddr *)sp_srv;
@@ -3552,62 +3588,29 @@ void smbd_process(struct tevent_context *ev_ctx,
        socklen_t sa_socklen;
        struct tsocket_address *local_address = NULL;
        struct tsocket_address *remote_address = NULL;
-       const char *locaddr = NULL;
        const char *remaddr = NULL;
-       char *rhost;
+       char *p;
+       const char *rhost = NULL;
        int ret;
        int tmp;
 
-       xconn = talloc_zero(ev_ctx, struct smbXsrv_connection);
+       *_xconn = NULL;
+
+       DO_PROFILE_INC(connect);
+
+       xconn = talloc_zero(client, struct smbXsrv_connection);
        if (xconn == NULL) {
                DEBUG(0,("talloc_zero(struct smbXsrv_connection)\n"));
-               exit_server_cleanly("talloc_zero(struct smbXsrv_connection).\n");
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
        }
+       talloc_steal(frame, xconn);
 
-       xconn->ev_ctx = ev_ctx;
-       xconn->msg_ctx = msg_ctx;
+       xconn->ev_ctx = client->ev_ctx;
+       xconn->msg_ctx = client->msg_ctx;
        xconn->transport.sock = sock_fd;
        smbd_echo_init(xconn);
-
-       sconn = talloc_zero(xconn, struct smbd_server_connection);
-       if (!sconn) {
-               exit_server("failed to create smbd_server_connection");
-       }
-
-       xconn->sconn = sconn;
-       sconn->conn = xconn;
-
-       /*
-        * TODO: remove this...:-)
-        */
-       global_smbXsrv_connection = xconn;
-
-       sconn->ev_ctx = ev_ctx;
-       sconn->msg_ctx = msg_ctx;
-
-       if (!interactive) {
-               smbd_setup_sig_term_handler(sconn);
-               smbd_setup_sig_hup_handler(sconn);
-
-               if (!serverid_register(messaging_server_id(msg_ctx),
-                                      FLAG_MSG_GENERAL|FLAG_MSG_SMBD
-                                      |FLAG_MSG_DBWRAP
-                                      |FLAG_MSG_PRINT_GENERAL)) {
-                       exit_server_cleanly("Could not register myself in "
-                                           "serverid.tdb");
-               }
-       }
-
-       if (lp_server_max_protocol() >= PROTOCOL_SMB2_02) {
-               /*
-                * We're not making the decision here,
-                * we're just allowing the client
-                * to decide between SMB1 and SMB2
-                * with the first negprot
-                * packet.
-                */
-               sconn->using_smb2 = true;
-       }
+       xconn->protocol = PROTOCOL_NONE;
 
        /* Ensure child is set to blocking mode */
        set_blocking(sock_fd,True);
@@ -3618,69 +3621,58 @@ void smbd_process(struct tevent_context *ev_ctx,
        sa_socklen = sizeof(ss_clnt);
        ret = getpeername(sock_fd, sa_clnt, &sa_socklen);
        if (ret != 0) {
+               int saved_errno = errno;
                int level = (errno == ENOTCONN)?2:0;
-               DEBUG(level,("getpeername() failed - %s\n", strerror(errno)));
-               exit_server_cleanly("getpeername() failed.\n");
+               DEBUG(level,("getpeername() failed - %s\n",
+                     strerror(saved_errno)));
+               TALLOC_FREE(frame);
+               return map_nt_error_from_unix_common(saved_errno);
        }
-       ret = tsocket_address_bsd_from_sockaddr(sconn,
+       ret = tsocket_address_bsd_from_sockaddr(xconn,
                                                sa_clnt, sa_socklen,
                                                &remote_address);
        if (ret != 0) {
+               int saved_errno = errno;
                DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
-                       __location__, strerror(errno)));
-               exit_server_cleanly("tsocket_address_bsd_from_sockaddr remote failed.\n");
+                       __location__, strerror(saved_errno)));
+               TALLOC_FREE(frame);
+               return map_nt_error_from_unix_common(saved_errno);
        }
 
        sa_socklen = sizeof(ss_srv);
        ret = getsockname(sock_fd, sa_srv, &sa_socklen);
        if (ret != 0) {
+               int saved_errno = errno;
                int level = (errno == ENOTCONN)?2:0;
-               DEBUG(level,("getsockname() failed - %s\n", strerror(errno)));
-               exit_server_cleanly("getsockname() failed.\n");
+               DEBUG(level,("getsockname() failed - %s\n",
+                     strerror(saved_errno)));
+               TALLOC_FREE(frame);
+               return map_nt_error_from_unix_common(saved_errno);
        }
-       ret = tsocket_address_bsd_from_sockaddr(sconn,
+       ret = tsocket_address_bsd_from_sockaddr(xconn,
                                                sa_srv, sa_socklen,
                                                &local_address);
        if (ret != 0) {
+               int saved_errno = errno;
                DEBUG(0,("%s: tsocket_address_bsd_from_sockaddr remote failed - %s\n",
-                       __location__, strerror(errno)));
-               exit_server_cleanly("tsocket_address_bsd_from_sockaddr remote failed.\n");
-       }
-
-       sconn->local_address = local_address;
-       sconn->remote_address = remote_address;
-
-       if (tsocket_address_is_inet(local_address, "ip")) {
-               locaddr = tsocket_address_inet_addr_string(
-                               sconn->local_address,
-                               talloc_tos());
-               if (locaddr == NULL) {
-                       DEBUG(0,("%s: tsocket_address_inet_addr_string local failed - %s\n",
-                                __location__, strerror(errno)));
-                       exit_server_cleanly("tsocket_address_inet_addr_string local failed.\n");
-               }
-       } else {
-               locaddr = "0.0.0.0";
+                       __location__, strerror(saved_errno)));
+               TALLOC_FREE(frame);
+               return map_nt_error_from_unix_common(saved_errno);
        }
 
        if (tsocket_address_is_inet(remote_address, "ip")) {
-               remaddr = tsocket_address_inet_addr_string(
-                               sconn->remote_address,
-                               talloc_tos());
+               remaddr = tsocket_address_inet_addr_string(remote_address,
+                                                          talloc_tos());
                if (remaddr == NULL) {
                        DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
                                 __location__, strerror(errno)));
-                       exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
+                       TALLOC_FREE(frame);
+                       return NT_STATUS_NO_MEMORY;
                }
        } else {
                remaddr = "0.0.0.0";
        }
 
-       /* this is needed so that we get decent entries
-          in smbstatus for port 445 connects */
-       set_remote_machine_name(remaddr, false);
-       reload_services(sconn, conn_snum_used, true);
-
        /*
         * Before the first packet, check the global hosts allow/ hosts deny
         * parameters before doing any parsing of packets passed to us by the
@@ -3689,41 +3681,236 @@ void smbd_process(struct tevent_context *ev_ctx,
         */
 
        ret = get_remote_hostname(remote_address,
-                                 &rhost,
-                                 talloc_tos());
+                                 &p, talloc_tos());
        if (ret < 0) {
+               int saved_errno = errno;
                DEBUG(0,("%s: get_remote_hostname failed - %s\n",
-                       __location__, strerror(errno)));
-               exit_server_cleanly("get_remote_hostname failed.\n");
+                       __location__, strerror(saved_errno)));
+               TALLOC_FREE(frame);
+               return map_nt_error_from_unix_common(saved_errno);
        }
+       rhost = p;
        if (strequal(rhost, "UNKNOWN")) {
-               rhost = talloc_strdup(talloc_tos(), remaddr);
+               rhost = remaddr;
        }
-       sconn->remote_hostname = talloc_move(sconn, &rhost);
 
-       sub_set_socket_ids(remaddr,
-                          sconn->remote_hostname,
-                          locaddr);
+       xconn->local_address = local_address;
+       xconn->remote_address = remote_address;
+       xconn->remote_hostname = talloc_strdup(xconn, rhost);
+       if (xconn->remote_hostname == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (!srv_init_signing(xconn)) {
+               DEBUG(0, ("Failed to init smb_signing\n"));
+               TALLOC_FREE(frame);
+               return NT_STATUS_INTERNAL_ERROR;
+       }
 
        if (!allow_access(lp_hosts_deny(-1), lp_hosts_allow(-1),
-                         sconn->remote_hostname,
+                         xconn->remote_hostname,
                          remaddr)) {
+               DEBUG( 1, ("Connection denied from %s to %s\n",
+                          tsocket_address_string(remote_address, talloc_tos()),
+                          tsocket_address_string(local_address, talloc_tos())));
+
+               /*
+                * We return a valid xconn
+                * so that the caller can return an error message
+                * to the client
+                */
+               client->connections = xconn;
+               xconn->client = client;
+               talloc_steal(client, xconn);
+
+               *_xconn = xconn;
+               TALLOC_FREE(frame);
+               return NT_STATUS_NETWORK_ACCESS_DENIED;
+       }
+
+       DEBUG(10, ("Connection allowed from %s to %s\n",
+                  tsocket_address_string(remote_address, talloc_tos()),
+                  tsocket_address_string(local_address, talloc_tos())));
+
+       if (lp_clustering()) {
+               /*
+                * We need to tell ctdb about our client's TCP
+                * connection, so that for failover ctdbd can send
+                * tickle acks, triggering a reconnection by the
+                * client.
+                */
+               NTSTATUS status;
+
+               status = smbd_register_ips(xconn, &ss_srv, &ss_clnt);
+               if (!NT_STATUS_IS_OK(status)) {
+                       DEBUG(0, ("ctdbd_register_ips failed: %s\n",
+                                 nt_errstr(status)));
+               }
+       }
+
+       tmp = lp_max_xmit();
+       tmp = MAX(tmp, SMB_BUFFER_SIZE_MIN);
+       tmp = MIN(tmp, SMB_BUFFER_SIZE_MAX);
+
+       xconn->smb1.negprot.max_recv = tmp;
+
+       xconn->smb1.sessions.done_sesssetup = false;
+       xconn->smb1.sessions.max_send = SMB_BUFFER_SIZE_MAX;
+
+       xconn->transport.fde = tevent_add_fd(client->ev_ctx,
+                                            xconn,
+                                            sock_fd,
+                                            TEVENT_FD_READ,
+                                            smbd_server_connection_handler,
+                                            xconn);
+       if (!xconn->transport.fde) {
+               TALLOC_FREE(frame);
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       /* for now we only have one connection */
+       DLIST_ADD_END(client->connections, xconn, NULL);
+       xconn->client = client;
+       talloc_steal(client, xconn);
+
+       *_xconn = xconn;
+       TALLOC_FREE(frame);
+       return NT_STATUS_OK;
+}
+
+/****************************************************************************
+ Process commands from the client
+****************************************************************************/
+
+void smbd_process(struct tevent_context *ev_ctx,
+                 struct messaging_context *msg_ctx,
+                 int sock_fd,
+                 bool interactive)
+{
+       struct smbd_tevent_trace_state trace_state = {
+               .ev = ev_ctx,
+               .frame = talloc_stackframe(),
+       };
+       struct smbXsrv_client *client = NULL;
+       struct smbd_server_connection *sconn = NULL;
+       struct smbXsrv_connection *xconn = NULL;
+       const char *locaddr = NULL;
+       const char *remaddr = NULL;
+       int ret;
+       NTSTATUS status;
+
+       client = talloc_zero(ev_ctx, struct smbXsrv_client);
+       if (client == NULL) {
+               DEBUG(0,("talloc_zero(struct smbXsrv_client)\n"));
+               exit_server_cleanly("talloc_zero(struct smbXsrv_client).\n");
+       }
+
+       /*
+        * TODO: remove this...:-)
+        */
+       global_smbXsrv_client = client;
+
+       client->ev_ctx = ev_ctx;
+       client->msg_ctx = msg_ctx;
+
+       sconn = talloc_zero(client, struct smbd_server_connection);
+       if (sconn == NULL) {
+               exit_server("failed to create smbd_server_connection");
+       }
+
+       client->sconn = sconn;
+       sconn->client = client;
+
+       sconn->ev_ctx = ev_ctx;
+       sconn->msg_ctx = msg_ctx;
+
+       if (lp_server_max_protocol() >= PROTOCOL_SMB2_02) {
+               /*
+                * We're not making the decision here,
+                * we're just allowing the client
+                * to decide between SMB1 and SMB2
+                * with the first negprot
+                * packet.
+                */
+               sconn->using_smb2 = true;
+       }
+
+       if (!interactive) {
+               smbd_setup_sig_term_handler(sconn);
+               smbd_setup_sig_hup_handler(sconn);
+
+               if (!serverid_register(messaging_server_id(msg_ctx),
+                                      FLAG_MSG_GENERAL|FLAG_MSG_SMBD
+                                      |FLAG_MSG_DBWRAP
+                                      |FLAG_MSG_PRINT_GENERAL)) {
+                       exit_server_cleanly("Could not register myself in "
+                                           "serverid.tdb");
+               }
+       }
+
+       status = smbd_add_connection(client, sock_fd, &xconn);
+       if (NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_ACCESS_DENIED)) {
                /*
                 * send a negative session response "not listening on calling
                 * name"
                 */
                unsigned char buf[5] = {0x83, 0, 0, 1, 0x81};
-               DEBUG( 1, ("Connection denied from %s to %s\n",
-                          tsocket_address_string(remote_address, talloc_tos()),
-                          tsocket_address_string(local_address, talloc_tos())));
-               (void)srv_send_smb(sconn,(char *)buf, false,
+               (void)srv_send_smb(xconn,(char *)buf, false,
                                   0, false, NULL);
                exit_server_cleanly("connection denied");
+       } else if (!NT_STATUS_IS_OK(status)) {
+               exit_server_cleanly(nt_errstr(status));
        }
 
-       DEBUG(10, ("Connection allowed from %s to %s\n",
-                  tsocket_address_string(remote_address, talloc_tos()),
-                  tsocket_address_string(local_address, talloc_tos())));
+       sconn->local_address =
+               tsocket_address_copy(xconn->local_address, sconn);
+       if (sconn->local_address == NULL) {
+               exit_server_cleanly("tsocket_address_copy() failed");
+       }
+       sconn->remote_address =
+               tsocket_address_copy(xconn->remote_address, sconn);
+       if (sconn->remote_address == NULL) {
+               exit_server_cleanly("tsocket_address_copy() failed");
+       }
+       sconn->remote_hostname =
+               talloc_strdup(sconn, xconn->remote_hostname);
+       if (sconn->remote_hostname == NULL) {
+               exit_server_cleanly("tsocket_strdup() failed");
+       }
+
+       if (tsocket_address_is_inet(sconn->local_address, "ip")) {
+               locaddr = tsocket_address_inet_addr_string(
+                               sconn->local_address,
+                               talloc_tos());
+               if (locaddr == NULL) {
+                       DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
+                                __location__, strerror(errno)));
+                       exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
+               }
+       } else {
+               locaddr = "0.0.0.0";
+       }
+
+       if (tsocket_address_is_inet(sconn->remote_address, "ip")) {
+               remaddr = tsocket_address_inet_addr_string(
+                               sconn->remote_address,
+                               talloc_tos());
+               if (remaddr == NULL) {
+                       DEBUG(0,("%s: tsocket_address_inet_addr_string remote failed - %s\n",
+                                __location__, strerror(errno)));
+                       exit_server_cleanly("tsocket_address_inet_addr_string remote failed.\n");
+               }
+       } else {
+               remaddr = "0.0.0.0";
+       }
+
+       /* this is needed so that we get decent entries
+          in smbstatus for port 445 connects */
+       set_remote_machine_name(remaddr, false);
+       reload_services(sconn, conn_snum_used, true);
+       sub_set_socket_ids(remaddr,
+                          sconn->remote_hostname,
+                          locaddr);
 
        if (lp_preload_modules()) {
                smb_load_modules(lp_preload_modules());
@@ -3748,10 +3935,6 @@ void smbd_process(struct tevent_context *ev_ctx,
                DEBUG(0,("Changed root to %s\n", lp_root_directory(talloc_tos())));
        }
 
-       if (!srv_init_signing(xconn)) {
-               exit_server("Failed to init smb_signing");
-       }
-
        if (!file_init(sconn)) {
                exit_server("file_init() failed");
        }
@@ -3818,69 +4001,25 @@ void smbd_process(struct tevent_context *ev_ctx,
                exit(1);
        }
 
-       if (lp_clustering()) {
-               /*
-                * We need to tell ctdb about our client's TCP
-                * connection, so that for failover ctdbd can send
-                * tickle acks, triggering a reconnection by the
-                * client.
-                */
-               NTSTATUS status;
-
-               status = smbd_register_ips(xconn, &ss_srv, &ss_clnt);
-               if (!NT_STATUS_IS_OK(status)) {
-                       DEBUG(0, ("ctdbd_register_ips failed: %s\n",
-                                 nt_errstr(status)));
-               }
-       }
-
-       tmp = lp_max_xmit();
-       tmp = MAX(tmp, SMB_BUFFER_SIZE_MIN);
-       tmp = MIN(tmp, SMB_BUFFER_SIZE_MAX);
-
-       xconn->smb1.negprot.max_recv = tmp;
-
-       xconn->smb1.sessions.done_sesssetup = false;
-       xconn->smb1.sessions.max_send = SMB_BUFFER_SIZE_MAX;
+       smbprofile_dump_setup(ev_ctx);
 
        if (!init_dptrs(sconn)) {
                exit_server("init_dptrs() failed");
        }
 
-       xconn->transport.fde = tevent_add_fd(ev_ctx,
-                                            xconn,
-                                            sock_fd,
-                                            TEVENT_FD_READ,
-                                            smbd_server_connection_handler,
-                                            xconn);
-       if (!xconn->transport.fde) {
-               exit_server("failed to create smbd_server_connection fde");
-       }
-
-       sconn->conn->local_address = sconn->local_address;
-       sconn->conn->remote_address = sconn->remote_address;
-       sconn->conn->remote_hostname = sconn->remote_hostname;
-       sconn->conn->protocol = PROTOCOL_NONE;
+       TALLOC_FREE(trace_state.frame);
 
-       TALLOC_FREE(frame);
-
-       tevent_set_trace_callback(ev_ctx, smbd_tevent_trace_callback, xconn);
-
-       while (True) {
-               frame = talloc_stackframe_pool(8192);
-
-               errno = 0;
-               if (tevent_loop_once(ev_ctx) == -1) {
-                       if (errno != EINTR) {
-                               DEBUG(3, ("tevent_loop_once failed: %s,"
-                                         " exiting\n", strerror(errno) ));
-                               break;
-                       }
-               }
+       tevent_set_trace_callback(ev_ctx, smbd_tevent_trace_callback,
+                                 &trace_state);
 
-               TALLOC_FREE(frame);
+       ret = tevent_loop_wait(ev_ctx);
+       if (ret != 0) {
+               DEBUG(1, ("tevent_loop_wait failed: %d, %s,"
+                         " exiting\n", ret, strerror(errno)));
        }
 
+       TALLOC_FREE(trace_state.frame);
+
        exit_server_cleanly(NULL);
 }