s3: Fix bug 8360
[idra/samba.git] / source3 / smbd / process.c
index 86e834789f5c11d7beecdb14d1e43057e33eb6b0..6d391df4e0573ec790e20585cf0380c110e0556c 100644 (file)
@@ -41,7 +41,8 @@ extern bool global_machine_password_needs_changing;
 
 static void construct_reply_common(struct smb_request *req, const char *inbuf,
                                   char *outbuf);
-static struct pending_message_list *get_deferred_open_message_smb(uint64_t mid);
+static struct pending_message_list *get_deferred_open_message_smb(
+       struct smbd_server_connection *sconn, uint64_t mid);
 
 static bool smbd_lock_socket_internal(struct smbd_server_connection *sconn)
 {
@@ -580,9 +581,9 @@ static void smbd_deferred_open_timer(struct event_context *ev,
                    msg->seqnum, msg->encrypted, &msg->pcd);
 
        /* If it's still there and was processed, remove it. */
-       msg = get_deferred_open_message_smb(mid);
+       msg = get_deferred_open_message_smb(smbd_server_conn, mid);
        if (msg && msg->processed) {
-               remove_deferred_open_message_smb(mid);
+               remove_deferred_open_message_smb(smbd_server_conn, mid);
        }
 }
 
@@ -640,7 +641,8 @@ static bool push_queued_message(struct smb_request *req,
                return false;
        }
 
-       DLIST_ADD_END(deferred_open_queue, msg, struct pending_message_list *);
+       DLIST_ADD_END(req->sconn->deferred_open_queue, msg,
+                     struct pending_message_list *);
 
        DEBUG(10,("push_message: pushed message length %u on "
                  "deferred_open_queue\n", (unsigned int)msg_len));
@@ -652,22 +654,23 @@ 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(uint64_t mid)
+void remove_deferred_open_message_smb(struct smbd_server_connection *sconn,
+                                     uint64_t mid)
 {
        struct pending_message_list *pml;
 
-       if (smbd_server_conn->using_smb2) {
-               remove_deferred_open_message_smb2(smbd_server_conn, mid);
+       if (sconn->using_smb2) {
+               remove_deferred_open_message_smb2(sconn, mid);
                return;
        }
 
-       for (pml = deferred_open_queue; pml; pml = pml->next) {
+       for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
                if (mid == (uint64_t)SVAL(pml->buf.data,smb_mid)) {
                        DEBUG(10,("remove_deferred_open_message_smb: "
                                  "deleting mid %llu len %u\n",
                                  (unsigned long long)mid,
                                  (unsigned int)pml->buf.length ));
-                       DLIST_REMOVE(deferred_open_queue, pml);
+                       DLIST_REMOVE(sconn->deferred_open_queue, pml);
                        TALLOC_FREE(pml);
                        return;
                }
@@ -679,17 +682,18 @@ void remove_deferred_open_message_smb(uint64_t mid)
  schedule it for immediate processing.
 ****************************************************************************/
 
-void schedule_deferred_open_message_smb(uint64_t mid)
+void schedule_deferred_open_message_smb(struct smbd_server_connection *sconn,
+                                       uint64_t mid)
 {
        struct pending_message_list *pml;
        int i = 0;
 
-       if (smbd_server_conn->using_smb2) {
-               schedule_deferred_open_message_smb2(smbd_server_conn, mid);
+       if (sconn->using_smb2) {
+               schedule_deferred_open_message_smb2(sconn, mid);
                return;
        }
 
-       for (pml = deferred_open_queue; pml; pml = pml->next) {
+       for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
                uint64_t msg_mid = (uint64_t)SVAL(pml->buf.data,smb_mid);
 
                DEBUG(10,("schedule_deferred_open_message_smb: [%d] "
@@ -727,7 +731,7 @@ void schedule_deferred_open_message_smb(uint64_t mid)
 
                        TALLOC_FREE(pml->te);
                        pml->te = te;
-                       DLIST_PROMOTE(deferred_open_queue, pml);
+                       DLIST_PROMOTE(sconn->deferred_open_queue, pml);
                        return;
                }
        }
@@ -741,15 +745,15 @@ void schedule_deferred_open_message_smb(uint64_t mid)
  Return true if this mid is on the deferred queue and was not yet processed.
 ****************************************************************************/
 
-bool open_was_deferred(uint64_t mid)
+bool open_was_deferred(struct smbd_server_connection *sconn, uint64_t mid)
 {
        struct pending_message_list *pml;
 
-       if (smbd_server_conn->using_smb2) {
-               return open_was_deferred_smb2(smbd_server_conn, mid);
+       if (sconn->using_smb2) {
+               return open_was_deferred_smb2(sconn, mid);
        }
 
-       for (pml = deferred_open_queue; pml; pml = pml->next) {
+       for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
                if (((uint64_t)SVAL(pml->buf.data,smb_mid)) == mid && !pml->processed) {
                        return True;
                }
@@ -761,11 +765,12 @@ bool open_was_deferred(uint64_t mid)
  Return the message queued by this mid.
 ****************************************************************************/
 
-static struct pending_message_list *get_deferred_open_message_smb(uint64_t mid)
+static struct pending_message_list *get_deferred_open_message_smb(
+       struct smbd_server_connection *sconn, uint64_t mid)
 {
        struct pending_message_list *pml;
 
-       for (pml = deferred_open_queue; pml; pml = pml->next) {
+       for (pml = sconn->deferred_open_queue; pml; pml = pml->next) {
                if (((uint64_t)SVAL(pml->buf.data,smb_mid)) == mid) {
                        return pml;
                }
@@ -789,7 +794,7 @@ bool get_deferred_open_message_state(struct smb_request *smbreq,
                                        pp_state);
        }
 
-       pml = get_deferred_open_message_smb(smbreq->mid);
+       pml = get_deferred_open_message_smb(smbreq->sconn, smbreq->mid);
        if (!pml) {
                return false;
        }
@@ -882,7 +887,7 @@ static void smbd_sig_hup_handler(struct tevent_context *ev,
        DEBUG(1,("Reloading services after SIGHUP\n"));
        reload_services(msg_ctx, smbd_server_conn->sock, False);
        if (am_parent) {
-               printing_subsystem_update(ev, msg_ctx);
+               printing_subsystem_update(ev, msg_ctx, true);
        }
 }
 
@@ -898,7 +903,8 @@ void smbd_setup_sig_hup_handler(struct tevent_context *ev,
        }
 }
 
-static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *conn)
+static NTSTATUS smbd_server_connection_loop_once(struct tevent_context *ev_ctx,
+                                                struct smbd_server_connection *conn)
 {
        int timeout;
        int num_pfds = 0;
@@ -912,11 +918,10 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
         * select for longer than it would take to wait for them.
         */
 
-       event_add_to_poll_args(server_event_context(), conn,
-                              &conn->pfds, &num_pfds, &timeout);
+       event_add_to_poll_args(ev_ctx, conn, &conn->pfds, &num_pfds, &timeout);
 
        /* Process a signal and timed events now... */
-       if (run_events_poll(server_event_context(), 0, NULL, 0)) {
+       if (run_events_poll(ev_ctx, 0, NULL, 0)) {
                return NT_STATUS_RETRY;
        }
 
@@ -938,8 +943,7 @@ static NTSTATUS smbd_server_connection_loop_once(struct smbd_server_connection *
                return map_nt_error_from_unix(errno);
        }
 
-       retry = run_events_poll(server_event_context(), ret, conn->pfds,
-                               num_pfds);
+       retry = run_events_poll(ev_ctx, ret, conn->pfds, num_pfds);
        if (retry) {
                return NT_STATUS_RETRY;
        }
@@ -2021,15 +2025,24 @@ void chain_reply(struct smb_request *req)
        SMB_PERFCOUNT_SET_MSGLEN_IN(&req->pcd, smblen);
 
        /*
-        * Check if the client tries to fool us. The request so far uses the
-        * space to the end of the byte buffer in the request just
-        * processed. The chain_offset can't point into that area. If that was
-        * the case, we could end up with an endless processing of the chain,
-        * we would always handle the same request.
+        * Check if the client tries to fool us. The chain offset
+        * needs to point beyond the current request in the chain, it
+        * needs to strictly grow. Otherwise we might be tricked into
+        * an endless loop always processing the same request over and
+        * over again. We used to assume that vwv and the byte buffer
+        * array in a chain are always attached, but OS/2 the
+        * Write&X/Read&X chain puts the Read&X vwv array right behind
+        * the Write&X vwv chain. The Write&X bcc array is put behind
+        * the Read&X vwv array. So now we check whether the chain
+        * offset points strictly behind the previous vwv
+        * array. req->buf points right after the vwv array of the
+        * previous request. See
+        * https://bugzilla.samba.org/show_bug.cgi?id=8360 for more
+        * information.
         */
 
-       already_used = PTR_DIFF(req->buf+req->buflen, smb_base(req->inbuf));
-       if (chain_offset < already_used) {
+       already_used = PTR_DIFF(req->buf, smb_base(req->inbuf));
+       if (chain_offset <= already_used) {
                goto error;
        }
 
@@ -2418,32 +2431,6 @@ static bool housekeeping_fn(const struct timeval *now, void *private_data)
        return true;
 }
 
-static int create_unlink_tmp(const char *dir)
-{
-       char *fname;
-       int fd;
-
-       fname = talloc_asprintf(talloc_tos(), "%s/listenerlock_XXXXXX", dir);
-       if (fname == NULL) {
-               errno = ENOMEM;
-               return -1;
-       }
-       fd = mkstemp(fname);
-       if (fd == -1) {
-               TALLOC_FREE(fname);
-               return -1;
-       }
-       if (unlink(fname) == -1) {
-               int sys_errno = errno;
-               close(fd);
-               TALLOC_FREE(fname);
-               errno = sys_errno;
-               return -1;
-       }
-       TALLOC_FREE(fname);
-       return fd;
-}
-
 /*
  * Read an smb packet in the echo handler child, giving the parent
  * smbd one second to react once the socket becomes readable.
@@ -2955,7 +2942,8 @@ static NTSTATUS smbd_register_ips(struct smbd_server_connection *sconn,
  Process commands from the client
 ****************************************************************************/
 
-void smbd_process(struct smbd_server_connection *sconn)
+void smbd_process(struct tevent_context *ev_ctx,
+                 struct smbd_server_connection *sconn)
 {
        TALLOC_CTX *frame = talloc_stackframe();
        struct sockaddr_storage ss;
@@ -3123,7 +3111,7 @@ void smbd_process(struct smbd_server_connection *sconn)
                           MSG_DEBUG, debug_message);
 
        if ((lp_keepalive() != 0)
-           && !(event_add_idle(server_event_context(), NULL,
+           && !(event_add_idle(ev_ctx, NULL,
                                timeval_set(lp_keepalive(), 0),
                                "keepalive", keepalive_fn,
                                NULL))) {
@@ -3131,14 +3119,14 @@ void smbd_process(struct smbd_server_connection *sconn)
                exit(1);
        }
 
-       if (!(event_add_idle(server_event_context(), NULL,
+       if (!(event_add_idle(ev_ctx, NULL,
                             timeval_set(IDLE_CLOSED_TIMEOUT, 0),
                             "deadtime", deadtime_fn, sconn))) {
                DEBUG(0, ("Could not add deadtime event\n"));
                exit(1);
        }
 
-       if (!(event_add_idle(server_event_context(), NULL,
+       if (!(event_add_idle(ev_ctx, NULL,
                             timeval_set(SMBD_HOUSEKEEPING_INTERVAL, 0),
                             "housekeeping", housekeeping_fn, sconn))) {
                DEBUG(0, ("Could not add housekeeping event\n"));
@@ -3195,7 +3183,7 @@ void smbd_process(struct smbd_server_connection *sconn)
                exit_server("init_dptrs() failed");
        }
 
-       sconn->smb1.fde = event_add_fd(server_event_context(),
+       sconn->smb1.fde = event_add_fd(ev_ctx,
                                                  sconn,
                                                  sconn->sock,
                                                  EVENT_FD_READ,
@@ -3214,7 +3202,7 @@ void smbd_process(struct smbd_server_connection *sconn)
 
                errno = 0;
 
-               status = smbd_server_connection_loop_once(sconn);
+               status = smbd_server_connection_loop_once(ev_ctx, sconn);
                if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY) &&
                    !NT_STATUS_IS_OK(status)) {
                        DEBUG(3, ("smbd_server_connection_loop_once failed: %s,"