LCOV - code coverage report
Current view: top level - source3/smbd - blocking.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 9 269 3.3 %
Date: 2024-06-13 04:01:37 Functions: 1 17 5.9 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    Blocking Locking functions
       4             :    Copyright (C) Jeremy Allison 1998-2003
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "locking/share_mode_lock.h"
      22             : #include "smbd/smbd.h"
      23             : #include "smbd/globals.h"
      24             : #include "messages.h"
      25             : #include "lib/util/tevent_ntstatus.h"
      26             : #include "lib/dbwrap/dbwrap_watch.h"
      27             : #include "librpc/gen_ndr/ndr_open_files.h"
      28             : 
      29             : #undef DBGC_CLASS
      30             : #define DBGC_CLASS DBGC_LOCKING
      31             : 
      32           5 : NTSTATUS smbd_do_locks_try(
      33             :         struct files_struct *fsp,
      34             :         uint16_t num_locks,
      35             :         struct smbd_lock_element *locks,
      36             :         uint16_t *blocker_idx,
      37             :         struct server_id *blocking_pid,
      38             :         uint64_t *blocking_smblctx)
      39             : {
      40           5 :         NTSTATUS status = NT_STATUS_OK;
      41             :         uint16_t i;
      42             : 
      43          10 :         for (i=0; i<num_locks; i++) {
      44           5 :                 struct smbd_lock_element *e = &locks[i];
      45             : 
      46           8 :                 status = do_lock(
      47             :                         fsp,
      48             :                         locks, /* req_mem_ctx */
      49           5 :                         &e->req_guid,
      50             :                         e->smblctx,
      51             :                         e->count,
      52             :                         e->offset,
      53             :                         e->brltype,
      54             :                         e->lock_flav,
      55             :                         blocking_pid,
      56             :                         blocking_smblctx);
      57           5 :                 if (!NT_STATUS_IS_OK(status)) {
      58           0 :                         break;
      59             :                 }
      60             :         }
      61             : 
      62           5 :         if (NT_STATUS_IS_OK(status)) {
      63           5 :                 return NT_STATUS_OK;
      64             :         }
      65             : 
      66           0 :         *blocker_idx = i;
      67             : 
      68             :         /*
      69             :          * Undo the locks we successfully got
      70             :          */
      71           0 :         for (i = i-1; i != UINT16_MAX; i--) {
      72           0 :                 struct smbd_lock_element *e = &locks[i];
      73           0 :                 do_unlock(fsp,
      74             :                           e->smblctx,
      75             :                           e->count,
      76             :                           e->offset,
      77             :                           e->lock_flav);
      78             :         }
      79             : 
      80           0 :         return status;
      81             : }
      82             : 
      83           0 : static bool smbd_smb1_fsp_add_blocked_lock_req(
      84             :         struct files_struct *fsp, struct tevent_req *req)
      85             : {
      86           0 :         size_t num_reqs = talloc_array_length(fsp->blocked_smb1_lock_reqs);
      87           0 :         struct tevent_req **tmp = NULL;
      88             : 
      89           0 :         tmp = talloc_realloc(
      90             :                 fsp,
      91             :                 fsp->blocked_smb1_lock_reqs,
      92             :                 struct tevent_req *,
      93             :                 num_reqs+1);
      94           0 :         if (tmp == NULL) {
      95           0 :                 return false;
      96             :         }
      97           0 :         fsp->blocked_smb1_lock_reqs = tmp;
      98           0 :         fsp->blocked_smb1_lock_reqs[num_reqs] = req;
      99           0 :         return true;
     100             : }
     101             : 
     102             : struct smbd_smb1_do_locks_state {
     103             :         struct tevent_context *ev;
     104             :         struct smb_request *smbreq;
     105             :         struct files_struct *fsp;
     106             :         uint32_t timeout;
     107             :         uint32_t polling_msecs;
     108             :         uint32_t retry_msecs;
     109             :         struct timeval endtime;
     110             :         bool large_offset;      /* required for correct cancel */
     111             :         uint16_t num_locks;
     112             :         struct smbd_lock_element *locks;
     113             :         uint16_t blocker;
     114             :         NTSTATUS deny_status;
     115             : };
     116             : 
     117             : static void smbd_smb1_do_locks_try(struct tevent_req *req);
     118             : static void smbd_smb1_do_locks_retry(struct tevent_req *subreq);
     119             : static void smbd_smb1_blocked_locks_cleanup(
     120             :         struct tevent_req *req, enum tevent_req_state req_state);
     121             : static NTSTATUS smbd_smb1_do_locks_check(
     122             :         struct files_struct *fsp,
     123             :         uint16_t num_locks,
     124             :         struct smbd_lock_element *locks,
     125             :         uint16_t *blocker_idx,
     126             :         struct server_id *blocking_pid,
     127             :         uint64_t *blocking_smblctx);
     128             : 
     129           0 : static void smbd_smb1_do_locks_setup_timeout(
     130             :         struct smbd_smb1_do_locks_state *state,
     131             :         const struct smbd_lock_element *blocker)
     132             : {
     133           0 :         struct files_struct *fsp = state->fsp;
     134             : 
     135           0 :         if (!timeval_is_zero(&state->endtime)) {
     136             :                 /*
     137             :                  * already done
     138             :                  */
     139           0 :                 return;
     140             :         }
     141             : 
     142           0 :         if ((state->timeout != 0) && (state->timeout != UINT32_MAX)) {
     143             :                 /*
     144             :                  * Windows internal resolution for blocking locks
     145             :                  * seems to be about 200ms... Don't wait for less than
     146             :                  * that. JRA.
     147             :                  */
     148           0 :                 state->timeout = MAX(state->timeout, lp_lock_spin_time());
     149             :         }
     150             : 
     151           0 :         if (state->timeout != 0) {
     152           0 :                 goto set_endtime;
     153             :         }
     154             : 
     155           0 :         if (blocker == NULL) {
     156           0 :                 goto set_endtime;
     157             :         }
     158             : 
     159           0 :         if ((blocker->offset >= 0xEF000000) &&
     160           0 :             ((blocker->offset >> 63) == 0)) {
     161             :                 /*
     162             :                  * This must be an optimization of an ancient
     163             :                  * application bug...
     164             :                  */
     165           0 :                 state->timeout = lp_lock_spin_time();
     166             :         }
     167             : 
     168           0 :         if (fsp->fsp_flags.lock_failure_seen &&
     169           0 :             (blocker->offset == fsp->lock_failure_offset)) {
     170             :                 /*
     171             :                  * Delay repeated lock attempts on the same
     172             :                  * lock. Maybe a more advanced version of the
     173             :                  * above check?
     174             :                  */
     175           0 :                 DBG_DEBUG("Delaying lock request due to previous "
     176             :                           "failure\n");
     177           0 :                 state->timeout = lp_lock_spin_time();
     178             :         }
     179             : 
     180           0 : set_endtime:
     181             :         /*
     182             :          * Note state->timeout might still 0,
     183             :          * but that's ok, as we don't want to retry
     184             :          * in that case.
     185             :          */
     186           0 :         state->endtime = timeval_add(&state->smbreq->request_time,
     187           0 :                                      state->timeout / 1000,
     188           0 :                                      (state->timeout % 1000) * 1000);
     189             : }
     190             : 
     191           0 : static void smbd_smb1_do_locks_update_retry_msecs(
     192             :         struct smbd_smb1_do_locks_state *state)
     193             : {
     194             :         /*
     195             :          * The default lp_lock_spin_time() is 200ms,
     196             :          * we just use half of it to trigger the first retry.
     197             :          *
     198             :          * v_min is in the range of 0.001 to 10 secs
     199             :          * (0.1 secs by default)
     200             :          *
     201             :          * v_max is in the range of 0.01 to 100 secs
     202             :          * (1.0 secs by default)
     203             :          *
     204             :          * The typical steps are:
     205             :          * 0.1, 0.2, 0.3, 0.4, ... 1.0
     206             :          */
     207           0 :         uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time()))/2;
     208           0 :         uint32_t v_max = 10 * v_min;
     209             : 
     210           0 :         if (state->retry_msecs >= v_max) {
     211           0 :                 state->retry_msecs = v_max;
     212           0 :                 return;
     213             :         }
     214             : 
     215           0 :         state->retry_msecs += v_min;
     216             : }
     217             : 
     218           0 : static void smbd_smb1_do_locks_update_polling_msecs(
     219             :         struct smbd_smb1_do_locks_state *state)
     220             : {
     221             :         /*
     222             :          * The default lp_lock_spin_time() is 200ms.
     223             :          *
     224             :          * v_min is in the range of 0.002 to 20 secs
     225             :          * (0.2 secs by default)
     226             :          *
     227             :          * v_max is in the range of 0.02 to 200 secs
     228             :          * (2.0 secs by default)
     229             :          *
     230             :          * The typical steps are:
     231             :          * 0.2, 0.4, 0.6, 0.8, ... 2.0
     232             :          */
     233           0 :         uint32_t v_min = MAX(2, MIN(20000, lp_lock_spin_time()));
     234           0 :         uint32_t v_max = 10 * v_min;
     235             : 
     236           0 :         if (state->polling_msecs >= v_max) {
     237           0 :                 state->polling_msecs = v_max;
     238           0 :                 return;
     239             :         }
     240             : 
     241           0 :         state->polling_msecs += v_min;
     242             : }
     243             : 
     244           0 : struct tevent_req *smbd_smb1_do_locks_send(
     245             :         TALLOC_CTX *mem_ctx,
     246             :         struct tevent_context *ev,
     247             :         struct smb_request **smbreq, /* talloc_move()d into our state */
     248             :         struct files_struct *fsp,
     249             :         uint32_t lock_timeout,
     250             :         bool large_offset,
     251             :         uint16_t num_locks,
     252             :         struct smbd_lock_element *locks)
     253             : {
     254           0 :         struct tevent_req *req = NULL;
     255           0 :         struct smbd_smb1_do_locks_state *state = NULL;
     256             :         bool ok;
     257             : 
     258           0 :         req = tevent_req_create(
     259             :                 mem_ctx, &state, struct smbd_smb1_do_locks_state);
     260           0 :         if (req == NULL) {
     261           0 :                 return NULL;
     262             :         }
     263           0 :         state->ev = ev;
     264           0 :         state->smbreq = talloc_move(state, smbreq);
     265           0 :         state->fsp = fsp;
     266           0 :         state->timeout = lock_timeout;
     267           0 :         state->large_offset = large_offset;
     268           0 :         state->num_locks = num_locks;
     269           0 :         state->locks = locks;
     270           0 :         state->deny_status = NT_STATUS_LOCK_NOT_GRANTED;
     271             : 
     272           0 :         DBG_DEBUG("state=%p, state->smbreq=%p\n", state, state->smbreq);
     273             : 
     274           0 :         if (num_locks == 0 || locks == NULL) {
     275           0 :                 DBG_DEBUG("no locks\n");
     276           0 :                 tevent_req_done(req);
     277           0 :                 return tevent_req_post(req, ev);
     278             :         }
     279             : 
     280           0 :         if (state->locks[0].lock_flav == POSIX_LOCK) {
     281             :                 /*
     282             :                  * SMB1 posix locks always use
     283             :                  * NT_STATUS_FILE_LOCK_CONFLICT.
     284             :                  */
     285           0 :                 state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT;
     286             :         }
     287             : 
     288           0 :         smbd_smb1_do_locks_try(req);
     289           0 :         if (!tevent_req_is_in_progress(req)) {
     290           0 :                 return tevent_req_post(req, ev);
     291             :         }
     292             : 
     293           0 :         ok = smbd_smb1_fsp_add_blocked_lock_req(fsp, req);
     294           0 :         if (!ok) {
     295           0 :                 tevent_req_oom(req);
     296           0 :                 return tevent_req_post(req, ev);
     297             :         }
     298           0 :         tevent_req_set_cleanup_fn(req, smbd_smb1_blocked_locks_cleanup);
     299           0 :         return req;
     300             : }
     301             : 
     302           0 : static void smbd_smb1_blocked_locks_cleanup(
     303             :         struct tevent_req *req, enum tevent_req_state req_state)
     304             : {
     305           0 :         struct smbd_smb1_do_locks_state *state = tevent_req_data(
     306             :                 req, struct smbd_smb1_do_locks_state);
     307           0 :         struct files_struct *fsp = state->fsp;
     308           0 :         struct tevent_req **blocked = fsp->blocked_smb1_lock_reqs;
     309           0 :         size_t num_blocked = talloc_array_length(blocked);
     310             :         size_t i;
     311             : 
     312           0 :         DBG_DEBUG("req=%p, state=%p, req_state=%d\n",
     313             :                   req,
     314             :                   state,
     315             :                   (int)req_state);
     316             : 
     317           0 :         if (req_state == TEVENT_REQ_RECEIVED) {
     318           0 :                 DBG_DEBUG("already received\n");
     319           0 :                 return;
     320             :         }
     321             : 
     322           0 :         for (i=0; i<num_blocked; i++) {
     323           0 :                 if (blocked[i] == req) {
     324           0 :                         break;
     325             :                 }
     326             :         }
     327           0 :         SMB_ASSERT(i<num_blocked);
     328             : 
     329           0 :         ARRAY_DEL_ELEMENT(blocked, i, num_blocked);
     330             : 
     331           0 :         fsp->blocked_smb1_lock_reqs = talloc_realloc(
     332             :                 fsp, blocked, struct tevent_req *, num_blocked-1);
     333             : }
     334             : 
     335           0 : static NTSTATUS smbd_smb1_do_locks_check_blocked(
     336             :         uint16_t num_blocked,
     337             :         struct smbd_lock_element *blocked,
     338             :         uint16_t num_locks,
     339             :         struct smbd_lock_element *locks,
     340             :         uint16_t *blocker_idx,
     341             :         uint64_t *blocking_smblctx)
     342             : {
     343             :         uint16_t li;
     344             : 
     345           0 :         for (li=0; li < num_locks; li++) {
     346           0 :                 struct smbd_lock_element *l = &locks[li];
     347             :                 uint16_t bi;
     348             :                 bool valid;
     349             : 
     350           0 :                 valid = byte_range_valid(l->offset, l->count);
     351           0 :                 if (!valid) {
     352           0 :                         return NT_STATUS_INVALID_LOCK_RANGE;
     353             :                 }
     354             : 
     355           0 :                 for (bi = 0; bi < num_blocked; bi++) {
     356           0 :                         struct smbd_lock_element *b = &blocked[li];
     357             :                         bool overlap;
     358             : 
     359             :                         /* Read locks never conflict. */
     360           0 :                         if (l->brltype == READ_LOCK && b->brltype == READ_LOCK) {
     361           0 :                                 continue;
     362             :                         }
     363             : 
     364           0 :                         overlap = byte_range_overlap(l->offset,
     365             :                                                      l->count,
     366             :                                                      b->offset,
     367             :                                                      b->count);
     368           0 :                         if (!overlap) {
     369           0 :                                 continue;
     370             :                         }
     371             : 
     372           0 :                         *blocker_idx = li;
     373           0 :                         *blocking_smblctx = b->smblctx;
     374           0 :                         return NT_STATUS_LOCK_NOT_GRANTED;
     375             :                 }
     376             :         }
     377             : 
     378           0 :         return NT_STATUS_OK;
     379             : }
     380             : 
     381           0 : static NTSTATUS smbd_smb1_do_locks_check(
     382             :         struct files_struct *fsp,
     383             :         uint16_t num_locks,
     384             :         struct smbd_lock_element *locks,
     385             :         uint16_t *blocker_idx,
     386             :         struct server_id *blocking_pid,
     387             :         uint64_t *blocking_smblctx)
     388             : {
     389           0 :         struct tevent_req **blocked = fsp->blocked_smb1_lock_reqs;
     390           0 :         size_t num_blocked = talloc_array_length(blocked);
     391             :         NTSTATUS status;
     392             :         size_t bi;
     393             : 
     394             :         /*
     395             :          * We check the pending/blocked requests
     396             :          * from the oldest to the youngest request.
     397             :          *
     398             :          * Note due to the retry logic the current request
     399             :          * might already be in the list.
     400             :          */
     401             : 
     402           0 :         for (bi = 0; bi < num_blocked; bi++) {
     403           0 :                 struct smbd_smb1_do_locks_state *blocked_state =
     404           0 :                         tevent_req_data(blocked[bi],
     405             :                         struct smbd_smb1_do_locks_state);
     406             : 
     407           0 :                 if (blocked_state->locks == locks) {
     408           0 :                         SMB_ASSERT(blocked_state->num_locks == num_locks);
     409             : 
     410             :                         /*
     411             :                          * We found ourself...
     412             :                          */
     413           0 :                         break;
     414             :                 }
     415             : 
     416           0 :                 status = smbd_smb1_do_locks_check_blocked(
     417           0 :                                 blocked_state->num_locks,
     418             :                                 blocked_state->locks,
     419             :                                 num_locks,
     420             :                                 locks,
     421             :                                 blocker_idx,
     422             :                                 blocking_smblctx);
     423           0 :                 if (!NT_STATUS_IS_OK(status)) {
     424           0 :                         *blocking_pid = messaging_server_id(
     425           0 :                                         fsp->conn->sconn->msg_ctx);
     426           0 :                         return status;
     427             :                 }
     428             :         }
     429             : 
     430           0 :         status = smbd_do_locks_try(
     431             :                 fsp,
     432             :                 num_locks,
     433             :                 locks,
     434             :                 blocker_idx,
     435             :                 blocking_pid,
     436             :                 blocking_smblctx);
     437           0 :         if (!NT_STATUS_IS_OK(status)) {
     438           0 :                 return status;
     439             :         }
     440             : 
     441           0 :         return NT_STATUS_OK;
     442             : }
     443             : 
     444           0 : static void smbd_smb1_do_locks_try(struct tevent_req *req)
     445             : {
     446           0 :         struct smbd_smb1_do_locks_state *state = tevent_req_data(
     447             :                 req, struct smbd_smb1_do_locks_state);
     448           0 :         struct files_struct *fsp = state->fsp;
     449             :         struct share_mode_lock *lck;
     450           0 :         struct timeval endtime = { 0 };
     451           0 :         struct server_id blocking_pid = { 0 };
     452           0 :         uint64_t blocking_smblctx = 0;
     453           0 :         struct tevent_req *subreq = NULL;
     454             :         NTSTATUS status;
     455             :         bool ok;
     456             :         bool expired;
     457             : 
     458           0 :         lck = get_existing_share_mode_lock(state, fsp->file_id);
     459           0 :         if (tevent_req_nomem(lck, req)) {
     460           0 :                 DBG_DEBUG("Could not get share mode lock\n");
     461           0 :                 return;
     462             :         }
     463             : 
     464           0 :         status = smbd_smb1_do_locks_check(
     465             :                 fsp,
     466           0 :                 state->num_locks,
     467             :                 state->locks,
     468             :                 &state->blocker,
     469             :                 &blocking_pid,
     470             :                 &blocking_smblctx);
     471           0 :         if (NT_STATUS_IS_OK(status)) {
     472           0 :                 goto done;
     473             :         }
     474           0 :         if (NT_STATUS_EQUAL(status, NT_STATUS_RETRY)) {
     475             :                 /*
     476             :                  * We got NT_STATUS_RETRY,
     477             :                  * we reset polling_msecs so that
     478             :                  * that the retries based on LOCK_NOT_GRANTED
     479             :                  * will later start with small intervalls again.
     480             :                  */
     481           0 :                 state->polling_msecs = 0;
     482             : 
     483             :                 /*
     484             :                  * The backend wasn't able to decide yet.
     485             :                  * We need to wait even for non-blocking
     486             :                  * locks.
     487             :                  *
     488             :                  * The backend uses blocking_smblctx == UINT64_MAX
     489             :                  * to indicate that we should use retry timers.
     490             :                  *
     491             :                  * It uses blocking_smblctx == 0 to indicate
     492             :                  * it will use share_mode_wakeup_waiters()
     493             :                  * to wake us. Note that unrelated changes in
     494             :                  * locking.tdb may cause retries.
     495             :                  */
     496             : 
     497           0 :                 if (blocking_smblctx != UINT64_MAX) {
     498           0 :                         SMB_ASSERT(blocking_smblctx == 0);
     499           0 :                         goto setup_retry;
     500             :                 }
     501             : 
     502           0 :                 smbd_smb1_do_locks_update_retry_msecs(state);
     503             : 
     504           0 :                 DBG_DEBUG("Waiting for a backend decision. "
     505             :                           "Retry in %"PRIu32" msecs\n",
     506             :                           state->retry_msecs);
     507             : 
     508             :                 /*
     509             :                  * We completely ignore state->endtime here
     510             :                  * we we'll wait for a backend decision forever.
     511             :                  * If the backend is smart enough to implement
     512             :                  * some NT_STATUS_RETRY logic, it has to
     513             :                  * switch to any other status after in order
     514             :                  * to avoid waiting forever.
     515             :                  */
     516           0 :                 endtime = timeval_current_ofs_msec(state->retry_msecs);
     517           0 :                 goto setup_retry;
     518             :         }
     519           0 :         if (!ERROR_WAS_LOCK_DENIED(status)) {
     520           0 :                 goto done;
     521             :         }
     522             :         /*
     523             :          * We got LOCK_NOT_GRANTED, make sure
     524             :          * a following STATUS_RETRY will start
     525             :          * with short intervalls again.
     526             :          */
     527           0 :         state->retry_msecs = 0;
     528             : 
     529           0 :         smbd_smb1_do_locks_setup_timeout(state, &state->locks[state->blocker]);
     530           0 :         DBG_DEBUG("timeout=%"PRIu32", blocking_smblctx=%"PRIu64"\n",
     531             :                   state->timeout,
     532             :                   blocking_smblctx);
     533             : 
     534             :         /*
     535             :          * The client specified timeout expired
     536             :          * avoid further retries.
     537             :          *
     538             :          * Otherwise keep waiting either waiting
     539             :          * for changes in locking.tdb or the polling
     540             :          * mode timers waiting for posix locks.
     541             :          *
     542             :          * If the endtime is not expired yet,
     543             :          * it means we'll retry after a timeout.
     544             :          * In that case we'll have to return
     545             :          * NT_STATUS_FILE_LOCK_CONFLICT
     546             :          * instead of NT_STATUS_LOCK_NOT_GRANTED.
     547             :          */
     548           0 :         expired = timeval_expired(&state->endtime);
     549           0 :         if (expired) {
     550           0 :                 status = state->deny_status;
     551           0 :                 goto done;
     552             :         }
     553           0 :         state->deny_status = NT_STATUS_FILE_LOCK_CONFLICT;
     554             : 
     555           0 :         endtime = state->endtime;
     556             : 
     557           0 :         if (blocking_smblctx == UINT64_MAX) {
     558             :                 struct timeval tmp;
     559             : 
     560           0 :                 smbd_smb1_do_locks_update_polling_msecs(state);
     561             : 
     562           0 :                 DBG_DEBUG("Blocked on a posix lock. Retry in %"PRIu32" msecs\n",
     563             :                           state->polling_msecs);
     564             : 
     565           0 :                 tmp = timeval_current_ofs_msec(state->polling_msecs);
     566           0 :                 endtime = timeval_min(&endtime, &tmp);
     567             :         }
     568             : 
     569           0 : setup_retry:
     570           0 :         subreq = share_mode_watch_send(
     571             :                 state, state->ev, lck, blocking_pid);
     572           0 :         if (tevent_req_nomem(subreq, req)) {
     573           0 :                 goto done;
     574             :         }
     575           0 :         TALLOC_FREE(lck);
     576           0 :         tevent_req_set_callback(subreq, smbd_smb1_do_locks_retry, req);
     577             : 
     578           0 :         if (timeval_is_zero(&endtime)) {
     579           0 :                 return;
     580             :         }
     581             : 
     582           0 :         ok = tevent_req_set_endtime(subreq, state->ev, endtime);
     583           0 :         if (!ok) {
     584           0 :                 status = NT_STATUS_NO_MEMORY;
     585           0 :                 goto done;
     586             :         }
     587           0 :         return;
     588           0 : done:
     589           0 :         TALLOC_FREE(lck);
     590           0 :         smbd_smb1_brl_finish_by_req(req, status);
     591             : }
     592             : 
     593           0 : static void smbd_smb1_do_locks_retry(struct tevent_req *subreq)
     594             : {
     595           0 :         struct tevent_req *req = tevent_req_callback_data(
     596             :                 subreq, struct tevent_req);
     597           0 :         struct smbd_smb1_do_locks_state *state = tevent_req_data(
     598             :                 req, struct smbd_smb1_do_locks_state);
     599             :         NTSTATUS status;
     600             :         bool ok;
     601             : 
     602             :         /*
     603             :          * Make sure we run as the user again
     604             :          */
     605           0 :         ok = change_to_user_and_service_by_fsp(state->fsp);
     606           0 :         if (!ok) {
     607           0 :                 tevent_req_nterror(req, NT_STATUS_ACCESS_DENIED);
     608           0 :                 return;
     609             :         }
     610             : 
     611           0 :         status = share_mode_watch_recv(subreq, NULL, NULL);
     612           0 :         TALLOC_FREE(subreq);
     613             : 
     614           0 :         DBG_DEBUG("share_mode_watch_recv returned %s\n",
     615             :                   nt_errstr(status));
     616             : 
     617             :         /*
     618             :          * We ignore any errors here, it's most likely
     619             :          * we just get NT_STATUS_OK or NT_STATUS_IO_TIMEOUT.
     620             :          *
     621             :          * In any case we can just give it a retry.
     622             :          */
     623             : 
     624           0 :         smbd_smb1_do_locks_try(req);
     625             : }
     626             : 
     627           0 : NTSTATUS smbd_smb1_do_locks_recv(struct tevent_req *req)
     628             : {
     629           0 :         struct smbd_smb1_do_locks_state *state = tevent_req_data(
     630             :                 req, struct smbd_smb1_do_locks_state);
     631           0 :         NTSTATUS status = NT_STATUS_OK;
     632             :         bool err;
     633             : 
     634           0 :         err = tevent_req_is_nterror(req, &status);
     635             : 
     636           0 :         DBG_DEBUG("err=%d, status=%s\n", (int)err, nt_errstr(status));
     637             : 
     638           0 :         if (tevent_req_is_nterror(req, &status)) {
     639           0 :                 struct files_struct *fsp = state->fsp;
     640           0 :                 struct smbd_lock_element *blocker =
     641           0 :                         &state->locks[state->blocker];
     642             : 
     643           0 :                 DBG_DEBUG("Setting lock_failure_offset=%"PRIu64"\n",
     644             :                           blocker->offset);
     645             : 
     646           0 :                 fsp->fsp_flags.lock_failure_seen = true;
     647           0 :                 fsp->lock_failure_offset = blocker->offset;
     648           0 :                 return status;
     649             :         }
     650             : 
     651           0 :         tevent_req_received(req);
     652             : 
     653           0 :         return NT_STATUS_OK;
     654             : }
     655             : 
     656           0 : bool smbd_smb1_do_locks_extract_smbreq(
     657             :         struct tevent_req *req,
     658             :         TALLOC_CTX *mem_ctx,
     659             :         struct smb_request **psmbreq)
     660             : {
     661           0 :         struct smbd_smb1_do_locks_state *state = tevent_req_data(
     662             :                 req, struct smbd_smb1_do_locks_state);
     663             : 
     664           0 :         DBG_DEBUG("req=%p, state=%p, state->smbreq=%p\n",
     665             :                   req,
     666             :                   state,
     667             :                   state->smbreq);
     668             : 
     669           0 :         if (state->smbreq == NULL) {
     670           0 :                 return false;
     671             :         }
     672           0 :         *psmbreq = talloc_move(mem_ctx, &state->smbreq);
     673           0 :         return true;
     674             : }
     675             : 
     676           0 : void smbd_smb1_brl_finish_by_req(struct tevent_req *req, NTSTATUS status)
     677             : {
     678           0 :         DBG_DEBUG("req=%p, status=%s\n", req, nt_errstr(status));
     679             : 
     680           0 :         if (NT_STATUS_IS_OK(status)) {
     681           0 :                 tevent_req_done(req);
     682             :         } else {
     683           0 :                 tevent_req_nterror(req, status);
     684             :         }
     685           0 : }
     686             : 
     687           0 : bool smbd_smb1_brl_finish_by_lock(
     688             :         struct files_struct *fsp,
     689             :         bool large_offset,
     690             :         struct smbd_lock_element lock,
     691             :         NTSTATUS finish_status)
     692             : {
     693           0 :         struct tevent_req **blocked = fsp->blocked_smb1_lock_reqs;
     694           0 :         size_t num_blocked = talloc_array_length(blocked);
     695             :         size_t i;
     696             : 
     697           0 :         DBG_DEBUG("num_blocked=%zu\n", num_blocked);
     698             : 
     699           0 :         for (i=0; i<num_blocked; i++) {
     700           0 :                 struct tevent_req *req = blocked[i];
     701           0 :                 struct smbd_smb1_do_locks_state *state = tevent_req_data(
     702             :                         req, struct smbd_smb1_do_locks_state);
     703             :                 uint16_t j;
     704             : 
     705           0 :                 DBG_DEBUG("i=%zu, req=%p\n", i, req);
     706             : 
     707           0 :                 if (state->large_offset != large_offset) {
     708           0 :                         continue;
     709             :                 }
     710             : 
     711           0 :                 for (j=0; j<state->num_locks; j++) {
     712           0 :                         struct smbd_lock_element *l = &state->locks[j];
     713             : 
     714           0 :                         if ((lock.smblctx == l->smblctx) &&
     715           0 :                             (lock.offset == l->offset) &&
     716           0 :                             (lock.count == l->count)) {
     717           0 :                                 smbd_smb1_brl_finish_by_req(
     718             :                                         req, finish_status);
     719           0 :                                 return true;
     720             :                         }
     721             :                 }
     722             :         }
     723           0 :         return false;
     724             : }
     725             : 
     726           0 : static struct files_struct *smbd_smb1_brl_finish_by_mid_fn(
     727             :         struct files_struct *fsp, void *private_data)
     728             : {
     729           0 :         struct tevent_req **blocked = fsp->blocked_smb1_lock_reqs;
     730           0 :         size_t num_blocked = talloc_array_length(blocked);
     731           0 :         uint64_t mid = *((uint64_t *)private_data);
     732             :         size_t i;
     733             : 
     734           0 :         DBG_DEBUG("fsp=%p, num_blocked=%zu\n", fsp, num_blocked);
     735             : 
     736           0 :         for (i=0; i<num_blocked; i++) {
     737           0 :                 struct tevent_req *req = blocked[i];
     738           0 :                 struct smbd_smb1_do_locks_state *state = tevent_req_data(
     739             :                         req, struct smbd_smb1_do_locks_state);
     740           0 :                 struct smb_request *smbreq = state->smbreq;
     741             : 
     742           0 :                 if (smbreq->mid == mid) {
     743           0 :                         tevent_req_nterror(req, NT_STATUS_FILE_LOCK_CONFLICT);
     744           0 :                         return fsp;
     745             :                 }
     746             :         }
     747             : 
     748           0 :         return NULL;
     749             : }
     750             : 
     751             : /*
     752             :  * This walks the list of fsps, we store the blocked reqs attached to
     753             :  * them. It can be expensive, but this is legacy SMB1 and trying to
     754             :  * remember looking at traces I don't reall many of those calls.
     755             :  */
     756             : 
     757           0 : bool smbd_smb1_brl_finish_by_mid(
     758             :         struct smbd_server_connection *sconn, uint64_t mid)
     759             : {
     760           0 :         struct files_struct *found = files_forall(
     761             :                 sconn, smbd_smb1_brl_finish_by_mid_fn, &mid);
     762           0 :         return (found != NULL);
     763             : }

Generated by: LCOV version 1.13