LCOV - code coverage report
Current view: top level - source3/smbd - smb2_oplock.c (source / functions) Hit Total Coverage
Test: coverage report for recycleplus df22b230 Lines: 55 532 10.3 %
Date: 2024-02-14 10:14:15 Functions: 8 30 26.7 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             :    oplock processing
       4             :    Copyright (C) Andrew Tridgell 1992-1998
       5             :    Copyright (C) Jeremy Allison 1998 - 2001
       6             :    Copyright (C) Volker Lendecke 2005
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #define DBGC_CLASS DBGC_LOCKING
      23             : #include "includes.h"
      24             : #include "lib/util/server_id.h"
      25             : #include "locking/share_mode_lock.h"
      26             : #include "smbd/smbd.h"
      27             : #include "smbd/globals.h"
      28             : #include "messages.h"
      29             : #include "locking/leases_db.h"
      30             : #include "../librpc/gen_ndr/ndr_open_files.h"
      31             : 
      32             : /*
      33             :  * helper function used by the kernel oplock backends to post the break message
      34             :  */
      35           0 : void break_kernel_oplock(struct messaging_context *msg_ctx, files_struct *fsp)
      36             : {
      37             :         uint8_t msg[MSG_SMB_KERNEL_BREAK_SIZE];
      38             : 
      39             :         /* Put the kernel break info into the message. */
      40           0 :         push_file_id_24((char *)msg, &fsp->file_id);
      41           0 :         SIVAL(msg, 24, fh_get_gen_id(fsp->fh));
      42             : 
      43             :         /* Don't need to be root here as we're only ever
      44             :            sending to ourselves. */
      45             : 
      46           0 :         messaging_send_buf(msg_ctx, messaging_server_id(msg_ctx),
      47             :                            MSG_SMB_KERNEL_BREAK,
      48             :                            msg, MSG_SMB_KERNEL_BREAK_SIZE);
      49           0 : }
      50             : 
      51             : /****************************************************************************
      52             :  Attempt to set an oplock on a file. Succeeds if kernel oplocks are
      53             :  disabled (just sets flags).
      54             : ****************************************************************************/
      55             : 
      56         124 : NTSTATUS set_file_oplock(files_struct *fsp)
      57             : {
      58         124 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
      59         124 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
      60         124 :         bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) &&
      61             :                         (koplocks != NULL);
      62             :         struct file_id_buf buf;
      63             : 
      64         124 :         smb_vfs_assert_allowed();
      65             : 
      66         124 :         if (fsp->oplock_type == LEVEL_II_OPLOCK && use_kernel) {
      67           0 :                 DEBUG(10, ("Refusing level2 oplock, kernel oplocks "
      68             :                            "don't support them\n"));
      69           0 :                 return NT_STATUS_NOT_SUPPORTED;
      70             :         }
      71             : 
      72         124 :         if ((fsp->oplock_type != NO_OPLOCK) &&
      73           0 :             use_kernel &&
      74           0 :             !koplocks->ops->set_oplock(koplocks, fsp, fsp->oplock_type))
      75             :         {
      76           0 :                 return map_nt_error_from_unix(errno);
      77             :         }
      78             : 
      79         124 :         fsp->sent_oplock_break = NO_BREAK_SENT;
      80         124 :         if (fsp->oplock_type == LEVEL_II_OPLOCK) {
      81           0 :                 sconn->oplocks.level_II_open++;
      82         124 :         } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
      83         124 :                 sconn->oplocks.exclusive_open++;
      84             :         }
      85             : 
      86         124 :         DBG_INFO("granted oplock on file %s, %s/%"PRIu64", "
      87             :                  "tv_sec = %x, tv_usec = %x\n",
      88             :                  fsp_str_dbg(fsp),
      89             :                  file_id_str_buf(fsp->file_id, &buf),
      90             :                  fh_get_gen_id(fsp->fh),
      91             :                  (int)fsp->open_time.tv_sec,
      92             :                  (int)fsp->open_time.tv_usec);
      93             : 
      94         124 :         return NT_STATUS_OK;
      95             : }
      96             : 
      97         124 : static void release_fsp_kernel_oplock(files_struct *fsp)
      98             : {
      99         124 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
     100         124 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
     101             :         bool use_kernel;
     102             : 
     103         124 :         smb_vfs_assert_allowed();
     104             : 
     105         124 :         if (koplocks == NULL) {
     106         124 :                 return;
     107             :         }
     108           0 :         use_kernel = lp_kernel_oplocks(SNUM(fsp->conn));
     109           0 :         if (!use_kernel) {
     110           0 :                 return;
     111             :         }
     112           0 :         if (fsp->oplock_type == NO_OPLOCK) {
     113           0 :                 return;
     114             :         }
     115           0 :         if (fsp->oplock_type == LEASE_OPLOCK) {
     116             :                 /*
     117             :                  * For leases we don't touch kernel oplocks at all
     118             :                  */
     119           0 :                 return;
     120             :         }
     121             : 
     122           0 :         koplocks->ops->release_oplock(koplocks, fsp, NO_OPLOCK);
     123             : }
     124             : 
     125             : /****************************************************************************
     126             :  Attempt to release an oplock on a file. Decrements oplock count.
     127             : ****************************************************************************/
     128             : 
     129         124 : void release_file_oplock(files_struct *fsp)
     130             : {
     131         124 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
     132             : 
     133         124 :         release_fsp_kernel_oplock(fsp);
     134             : 
     135         124 :         if (fsp->oplock_type == LEVEL_II_OPLOCK) {
     136           0 :                 sconn->oplocks.level_II_open--;
     137         124 :         } else if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
     138         124 :                 sconn->oplocks.exclusive_open--;
     139             :         }
     140             : 
     141         124 :         SMB_ASSERT(sconn->oplocks.exclusive_open>=0);
     142         124 :         SMB_ASSERT(sconn->oplocks.level_II_open>=0);
     143             : 
     144         124 :         fsp->oplock_type = NO_OPLOCK;
     145         124 :         fsp->sent_oplock_break = NO_BREAK_SENT;
     146             : 
     147         124 :         TALLOC_FREE(fsp->oplock_timeout);
     148         124 : }
     149             : 
     150             : /****************************************************************************
     151             :  Attempt to downgrade an oplock on a file. Doesn't decrement oplock count.
     152             : ****************************************************************************/
     153             : 
     154           0 : static void downgrade_file_oplock(files_struct *fsp)
     155             : {
     156           0 :         struct smbd_server_connection *sconn = fsp->conn->sconn;
     157           0 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
     158           0 :         bool use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) &&
     159             :                         (koplocks != NULL);
     160             : 
     161           0 :         smb_vfs_assert_allowed();
     162             : 
     163           0 :         if (!EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type)) {
     164           0 :                 DEBUG(0, ("trying to downgrade an already-downgraded oplock!\n"));
     165           0 :                 return;
     166             :         }
     167             : 
     168           0 :         if (use_kernel) {
     169           0 :                 koplocks->ops->release_oplock(koplocks, fsp, LEVEL_II_OPLOCK);
     170             :         }
     171           0 :         fsp->oplock_type = LEVEL_II_OPLOCK;
     172           0 :         sconn->oplocks.exclusive_open--;
     173           0 :         sconn->oplocks.level_II_open++;
     174           0 :         fsp->sent_oplock_break = NO_BREAK_SENT;
     175             : 
     176           0 :         TALLOC_FREE(fsp->oplock_timeout);
     177             : }
     178             : 
     179          35 : uint32_t get_lease_type(struct share_mode_entry *e, struct file_id id)
     180             : {
     181             :         struct GUID_txt_buf guid_strbuf;
     182             :         struct file_id_buf file_id_strbuf;
     183             :         NTSTATUS status;
     184             :         uint32_t current_state;
     185             : 
     186          35 :         if (e->op_type != LEASE_OPLOCK) {
     187          35 :                 return map_oplock_to_lease_type(e->op_type);
     188             :         }
     189             : 
     190           0 :         status = leases_db_get(&e->client_guid,
     191           0 :                                &e->lease_key,
     192             :                                &id,
     193             :                                &current_state,
     194             :                                NULL,    /* breaking */
     195             :                                NULL,    /* breaking_to_requested */
     196             :                                NULL,    /* breaking_to_required */
     197             :                                NULL,    /* lease_version */
     198             :                                NULL);   /* epoch */
     199           0 :         if (NT_STATUS_IS_OK(status)) {
     200           0 :                 return current_state;
     201             :         }
     202             : 
     203           0 :         if (share_entry_stale_pid(e)) {
     204           0 :                 return 0;
     205             :         }
     206           0 :         DBG_ERR("leases_db_get for client_guid [%s] "
     207             :                 "lease_key [%"PRIu64"/%"PRIu64"] "
     208             :                 "file_id [%s] failed: %s\n",
     209             :                 GUID_buf_string(&e->client_guid, &guid_strbuf),
     210             :                 e->lease_key.data[0],
     211             :                 e->lease_key.data[1],
     212             :                 file_id_str_buf(id, &file_id_strbuf),
     213             :                 nt_errstr(status));
     214           0 :         smb_panic("leases_db_get() failed");
     215             : }
     216             : 
     217             : /****************************************************************************
     218             :  Remove a file oplock. Copes with level II and exclusive.
     219             :  Locks then unlocks the share mode lock. Client can decide to go directly
     220             :  to none even if a "break-to-level II" was sent.
     221             : ****************************************************************************/
     222             : 
     223           0 : bool remove_oplock(files_struct *fsp)
     224             : {
     225             :         bool ret;
     226             :         struct share_mode_lock *lck;
     227             : 
     228           0 :         DBG_DEBUG("remove_oplock called for %s\n", fsp_str_dbg(fsp));
     229             : 
     230             :         /* Remove the oplock flag from the sharemode. */
     231           0 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
     232           0 :         if (lck == NULL) {
     233           0 :                 DBG_ERR("failed to lock share entry for "
     234             :                          "file %s\n", fsp_str_dbg(fsp));
     235           0 :                 return false;
     236             :         }
     237             : 
     238           0 :         ret = remove_share_oplock(lck, fsp);
     239           0 :         if (!ret) {
     240             :                 struct file_id_buf buf;
     241             : 
     242           0 :                 DBG_ERR("failed to remove share oplock for "
     243             :                         "file %s, %s, %s\n",
     244             :                         fsp_str_dbg(fsp), fsp_fnum_dbg(fsp),
     245             :                         file_id_str_buf(fsp->file_id, &buf));
     246             :         }
     247           0 :         release_file_oplock(fsp);
     248             : 
     249           0 :         TALLOC_FREE(lck);
     250           0 :         return ret;
     251             : }
     252             : 
     253             : /*
     254             :  * Deal with a reply when a break-to-level II was sent.
     255             :  */
     256           0 : bool downgrade_oplock(files_struct *fsp)
     257             : {
     258             :         bool ret;
     259             :         struct share_mode_lock *lck;
     260             : 
     261           0 :         DEBUG(10, ("downgrade_oplock called for %s\n",
     262             :                    fsp_str_dbg(fsp)));
     263             : 
     264           0 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
     265           0 :         if (lck == NULL) {
     266           0 :                 DEBUG(0,("downgrade_oplock: failed to lock share entry for "
     267             :                          "file %s\n", fsp_str_dbg(fsp)));
     268           0 :                 return False;
     269             :         }
     270           0 :         ret = downgrade_share_oplock(lck, fsp);
     271           0 :         if (!ret) {
     272             :                 struct file_id_buf idbuf;
     273           0 :                 DBG_ERR("failed to downgrade share oplock "
     274             :                         "for file %s, %s, file_id %s\n",
     275             :                         fsp_str_dbg(fsp),
     276             :                         fsp_fnum_dbg(fsp),
     277             :                         file_id_str_buf(fsp->file_id, &idbuf));
     278             :         }
     279           0 :         downgrade_file_oplock(fsp);
     280             : 
     281           0 :         TALLOC_FREE(lck);
     282           0 :         return ret;
     283             : }
     284             : 
     285           0 : static void lease_timeout_handler(struct tevent_context *ctx,
     286             :                                   struct tevent_timer *te,
     287             :                                   struct timeval now,
     288             :                                   void *private_data)
     289             : {
     290             :         struct fsp_lease *lease =
     291           0 :                 talloc_get_type_abort(private_data,
     292             :                 struct fsp_lease);
     293             :         struct files_struct *fsp;
     294             :         struct share_mode_lock *lck;
     295           0 :         uint16_t old_epoch = lease->lease.lease_epoch;
     296             : 
     297           0 :         fsp = file_find_one_fsp_from_lease_key(lease->sconn,
     298           0 :                                                &lease->lease.lease_key);
     299           0 :         if (fsp == NULL) {
     300             :                 /* race? */
     301           0 :                 TALLOC_FREE(lease->timeout);
     302           0 :                 return;
     303             :         }
     304             : 
     305             :         /*
     306             :          * Paranoia check: There can only be one fsp_lease per lease
     307             :          * key
     308             :          */
     309           0 :         SMB_ASSERT(fsp->lease == lease);
     310             : 
     311           0 :         lck = get_existing_share_mode_lock(
     312             :                         talloc_tos(), fsp->file_id);
     313           0 :         if (lck == NULL) {
     314             :                 /* race? */
     315           0 :                 TALLOC_FREE(lease->timeout);
     316           0 :                 return;
     317             :         }
     318             : 
     319           0 :         fsp_lease_update(fsp);
     320             : 
     321           0 :         if (lease->lease.lease_epoch != old_epoch) {
     322             :                 /*
     323             :                  * If the epoch changed we need to wait for
     324             :                  * the next timeout to happen.
     325             :                  */
     326           0 :                 DEBUG(10, ("lease break timeout race (epoch) for file %s - ignoring\n",
     327             :                            fsp_str_dbg(fsp)));
     328           0 :                 TALLOC_FREE(lck);
     329           0 :                 return;
     330             :         }
     331             : 
     332           0 :         if (!(lease->lease.lease_flags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)) {
     333             :                 /*
     334             :                  * If the epoch changed we need to wait for
     335             :                  * the next timeout to happen.
     336             :                  */
     337           0 :                 DEBUG(10, ("lease break timeout race (flags) for file %s - ignoring\n",
     338             :                            fsp_str_dbg(fsp)));
     339           0 :                 TALLOC_FREE(lck);
     340           0 :                 return;
     341             :         }
     342             : 
     343           0 :         DEBUG(1, ("lease break timed out for file %s -- replying anyway\n",
     344             :                   fsp_str_dbg(fsp)));
     345           0 :         (void)downgrade_lease(lease->sconn->client,
     346             :                         1,
     347           0 :                         &fsp->file_id,
     348           0 :                         &lease->lease.lease_key,
     349             :                         SMB2_LEASE_NONE);
     350             : 
     351           0 :         TALLOC_FREE(lck);
     352             : }
     353             : 
     354           0 : bool fsp_lease_update(struct files_struct *fsp)
     355             : {
     356           0 :         const struct GUID *client_guid = fsp_client_guid(fsp);
     357           0 :         struct fsp_lease *lease = fsp->lease;
     358             :         uint32_t current_state;
     359             :         bool breaking;
     360             :         uint16_t lease_version, epoch;
     361             :         NTSTATUS status;
     362             : 
     363           0 :         status = leases_db_get(client_guid,
     364           0 :                                &lease->lease.lease_key,
     365           0 :                                &fsp->file_id,
     366             :                                &current_state,
     367             :                                &breaking,
     368             :                                NULL, /* breaking_to_requested */
     369             :                                NULL, /* breaking_to_required */
     370             :                                &lease_version,
     371             :                                &epoch);
     372           0 :         if (!NT_STATUS_IS_OK(status)) {
     373           0 :                 DBG_WARNING("Could not find lease entry: %s\n",
     374             :                             nt_errstr(status));
     375           0 :                 TALLOC_FREE(lease->timeout);
     376           0 :                 lease->lease.lease_state = SMB2_LEASE_NONE;
     377           0 :                 lease->lease.lease_epoch += 1;
     378           0 :                 lease->lease.lease_flags = 0;
     379           0 :                 return false;
     380             :         }
     381             : 
     382           0 :         DEBUG(10,("%s: refresh lease state\n", __func__));
     383             : 
     384             :         /* Ensure we're in sync with current lease state. */
     385           0 :         if (lease->lease.lease_epoch != epoch) {
     386           0 :                 DEBUG(10,("%s: cancel outdated timeout\n", __func__));
     387           0 :                 TALLOC_FREE(lease->timeout);
     388             :         }
     389           0 :         lease->lease.lease_epoch = epoch;
     390           0 :         lease->lease.lease_state = current_state;
     391             : 
     392           0 :         if (breaking) {
     393           0 :                 lease->lease.lease_flags |= SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
     394             : 
     395           0 :                 if (lease->timeout == NULL) {
     396           0 :                         struct timeval t = timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0);
     397             : 
     398           0 :                         DEBUG(10,("%s: setup timeout handler\n", __func__));
     399             : 
     400           0 :                         lease->timeout = tevent_add_timer(lease->sconn->ev_ctx,
     401             :                                                           lease, t,
     402             :                                                           lease_timeout_handler,
     403             :                                                           lease);
     404           0 :                         if (lease->timeout == NULL) {
     405           0 :                                 DEBUG(0, ("%s: Could not add lease timeout handler\n",
     406             :                                           __func__));
     407             :                         }
     408             :                 }
     409             :         } else {
     410           0 :                 lease->lease.lease_flags &= ~SMB2_LEASE_FLAG_BREAK_IN_PROGRESS;
     411           0 :                 TALLOC_FREE(lease->timeout);
     412             :         }
     413             : 
     414           0 :         return true;
     415             : }
     416             : 
     417             : struct downgrade_lease_additional_state {
     418             :         struct tevent_immediate *im;
     419             :         struct smbXsrv_client *client;
     420             :         uint32_t break_flags;
     421             :         struct smb2_lease_key lease_key;
     422             :         uint32_t break_from;
     423             :         uint32_t break_to;
     424             :         uint16_t new_epoch;
     425             : };
     426             : 
     427           0 : static void downgrade_lease_additional_trigger(struct tevent_context *ev,
     428             :                                                struct tevent_immediate *im,
     429             :                                                void *private_data)
     430             : {
     431             :         struct downgrade_lease_additional_state *state =
     432           0 :                 talloc_get_type_abort(private_data,
     433             :                 struct downgrade_lease_additional_state);
     434             :         NTSTATUS status;
     435             : 
     436           0 :         status = smbd_smb2_send_lease_break(state->client,
     437           0 :                                             state->new_epoch,
     438             :                                             state->break_flags,
     439             :                                             &state->lease_key,
     440             :                                             state->break_from,
     441             :                                             state->break_to);
     442           0 :         if (!NT_STATUS_IS_OK(status)) {
     443           0 :                 smbd_server_disconnect_client(state->client,
     444             :                                               nt_errstr(status));
     445             :         }
     446           0 :         TALLOC_FREE(state);
     447           0 : }
     448             : 
     449             : struct fsps_lease_update_state {
     450             :         const struct file_id *id;
     451             :         const struct smb2_lease_key *key;
     452             : };
     453             : 
     454           0 : static struct files_struct *fsps_lease_update_fn(
     455             :         struct files_struct *fsp, void *private_data)
     456             : {
     457           0 :         struct fsps_lease_update_state *state =
     458             :                 (struct fsps_lease_update_state *)private_data;
     459             : 
     460           0 :         if (fsp->oplock_type != LEASE_OPLOCK) {
     461           0 :                 return NULL;
     462             :         }
     463           0 :         if (!smb2_lease_key_equal(&fsp->lease->lease.lease_key, state->key)) {
     464           0 :                 return NULL;
     465             :         }
     466           0 :         if (!file_id_equal(&fsp->file_id, state->id)) {
     467           0 :                 return NULL;
     468             :         }
     469             : 
     470           0 :         fsp_lease_update(fsp);
     471             : 
     472           0 :         return NULL;
     473             : }
     474             : 
     475           0 : static void fsps_lease_update(struct smbd_server_connection *sconn,
     476             :                               const struct file_id *id,
     477             :                               const struct smb2_lease_key *key)
     478             : {
     479           0 :         struct fsps_lease_update_state state = { .id = id, .key = key };
     480           0 :         files_forall(sconn, fsps_lease_update_fn, &state);
     481           0 : }
     482             : 
     483           0 : NTSTATUS downgrade_lease(struct smbXsrv_client *client,
     484             :                          uint32_t num_file_ids,
     485             :                          const struct file_id *ids,
     486             :                          const struct smb2_lease_key *key,
     487             :                          uint32_t lease_state)
     488             : {
     489           0 :         struct smbd_server_connection *sconn = client->sconn;
     490           0 :         const struct GUID *client_guid = NULL;
     491             :         struct share_mode_lock *lck;
     492           0 :         const struct file_id id = ids[0];
     493             :         uint32_t current_state, breaking_to_requested, breaking_to_required;
     494             :         bool breaking;
     495             :         uint16_t lease_version, epoch;
     496             :         NTSTATUS status;
     497             :         uint32_t i;
     498             :         struct file_id_buf idbuf;
     499             : 
     500           0 :         DBG_DEBUG("Downgrading %s to %"PRIu32"\n",
     501             :                   file_id_str_buf(id, &idbuf),
     502             :                   lease_state);
     503             : 
     504           0 :         lck = get_existing_share_mode_lock(talloc_tos(), id);
     505           0 :         if (lck == NULL) {
     506           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     507             :         }
     508             : 
     509           0 :         client_guid = &sconn->client->global->client_guid;
     510             : 
     511           0 :         status = leases_db_get(client_guid,
     512             :                                key,
     513             :                                &id,
     514             :                                &current_state,
     515             :                                &breaking,
     516             :                                &breaking_to_requested,
     517             :                                &breaking_to_required,
     518             :                                &lease_version,
     519             :                                &epoch);
     520           0 :         if (!NT_STATUS_IS_OK(status)) {
     521           0 :                 DBG_WARNING("leases_db_get returned %s\n",
     522             :                             nt_errstr(status));
     523           0 :                 TALLOC_FREE(lck);
     524           0 :                 return status;
     525             :         }
     526             : 
     527           0 :         if (!breaking) {
     528           0 :                 DBG_WARNING("Attempt to break from %"PRIu32" to %"PRIu32" - "
     529             :                             "but we're not in breaking state\n",
     530             :                             current_state, lease_state);
     531           0 :                 TALLOC_FREE(lck);
     532           0 :                 return NT_STATUS_UNSUCCESSFUL;
     533             :         }
     534             : 
     535             :         /*
     536             :          * Can't upgrade anything: breaking_to_requested (and current_state)
     537             :          * must be a strict bitwise superset of new_lease_state
     538             :          */
     539           0 :         if ((lease_state & breaking_to_requested) != lease_state) {
     540           0 :                 DBG_WARNING("Attempt to upgrade from %"PRIu32" to %"PRIu32" "
     541             :                             "- expected %"PRIu32"\n",
     542             :                             current_state, lease_state,
     543             :                             breaking_to_requested);
     544           0 :                 TALLOC_FREE(lck);
     545           0 :                 return NT_STATUS_REQUEST_NOT_ACCEPTED;
     546             :         }
     547             : 
     548           0 :         if (current_state != lease_state) {
     549           0 :                 current_state = lease_state;
     550             :         }
     551             : 
     552           0 :         status = NT_STATUS_OK;
     553             : 
     554           0 :         if ((lease_state & ~breaking_to_required) != 0) {
     555             :                 struct downgrade_lease_additional_state *state;
     556             : 
     557           0 :                 DBG_INFO("lease state %"PRIu32" not fully broken from "
     558             :                          "%"PRIu32" to %"PRIu32"\n",
     559             :                          lease_state,
     560             :                          current_state,
     561             :                          breaking_to_required);
     562             : 
     563           0 :                 breaking_to_requested = breaking_to_required;
     564             : 
     565           0 :                 if (current_state & (SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE)) {
     566             :                         /*
     567             :                          * Here we break in steps, as windows does
     568             :                          * see the breaking3 and v2_breaking3 tests.
     569             :                          */
     570           0 :                         breaking_to_requested |= SMB2_LEASE_READ;
     571             :                 }
     572             : 
     573           0 :                 state = talloc_zero(client,
     574             :                                     struct downgrade_lease_additional_state);
     575           0 :                 if (state == NULL) {
     576           0 :                         TALLOC_FREE(lck);
     577           0 :                         return NT_STATUS_NO_MEMORY;
     578             :                 }
     579             : 
     580           0 :                 state->im = tevent_create_immediate(state);
     581           0 :                 if (state->im == NULL) {
     582           0 :                         TALLOC_FREE(state);
     583           0 :                         TALLOC_FREE(lck);
     584           0 :                         return NT_STATUS_NO_MEMORY;
     585             :                 }
     586             : 
     587           0 :                 state->client = client;
     588           0 :                 state->lease_key = *key;
     589           0 :                 state->break_from = current_state;
     590           0 :                 state->break_to = breaking_to_requested;
     591           0 :                 if (lease_version > 1) {
     592           0 :                         state->new_epoch = epoch;
     593             :                 }
     594             : 
     595           0 :                 if (current_state & (SMB2_LEASE_WRITE|SMB2_LEASE_HANDLE)) {
     596           0 :                         state->break_flags =
     597             :                                 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
     598             :                 } else {
     599             :                         /*
     600             :                          * This is an async break without
     601             :                          * SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED
     602             :                          *
     603             :                          * we need to store NONE state in the
     604             :                          * database.
     605             :                          */
     606           0 :                         current_state = 0;
     607           0 :                         breaking_to_requested = 0;
     608           0 :                         breaking_to_required = 0;
     609           0 :                         breaking = false;
     610             : 
     611             :                         {
     612             :                                 NTSTATUS set_status;
     613             : 
     614           0 :                                 set_status = leases_db_set(
     615           0 :                                         &sconn->client->global->client_guid,
     616             :                                         key,
     617             :                                         current_state,
     618             :                                         breaking,
     619             :                                         breaking_to_requested,
     620             :                                         breaking_to_required,
     621             :                                         lease_version,
     622             :                                         epoch);
     623             : 
     624           0 :                                 if (!NT_STATUS_IS_OK(set_status)) {
     625           0 :                                         DBG_DEBUG("leases_db_set failed: %s\n",
     626             :                                                   nt_errstr(set_status));
     627           0 :                                         return set_status;
     628             :                                 }
     629             :                         }
     630             :                 }
     631             : 
     632           0 :                 tevent_schedule_immediate(state->im,
     633             :                                           client->raw_ev_ctx,
     634             :                                           downgrade_lease_additional_trigger,
     635             :                                           state);
     636             : 
     637           0 :                 status = NT_STATUS_OPLOCK_BREAK_IN_PROGRESS;
     638             :         } else {
     639           0 :                 DBG_DEBUG("breaking from %"PRIu32" to %"PRIu32" - "
     640             :                           "expected %"PRIu32"\n",
     641             :                           current_state,
     642             :                           lease_state,
     643             :                           breaking_to_requested);
     644             : 
     645           0 :                 breaking_to_requested = 0;
     646           0 :                 breaking_to_required = 0;
     647           0 :                 breaking = false;
     648             :         }
     649             : 
     650             :         {
     651             :                 NTSTATUS set_status;
     652             : 
     653           0 :                 set_status = leases_db_set(
     654             :                         client_guid,
     655             :                         key,
     656             :                         current_state,
     657             :                         breaking,
     658             :                         breaking_to_requested,
     659             :                         breaking_to_required,
     660             :                         lease_version,
     661             :                         epoch);
     662             : 
     663           0 :                 if (!NT_STATUS_IS_OK(set_status)) {
     664           0 :                         DBG_DEBUG("leases_db_set failed: %s\n",
     665             :                                   nt_errstr(set_status));
     666           0 :                         TALLOC_FREE(lck);
     667           0 :                         return set_status;
     668             :                 }
     669             :         }
     670             : 
     671           0 :         DBG_DEBUG("Downgrading %s to %"PRIu32" => %s\n",
     672             :                   file_id_str_buf(id, &idbuf),
     673             :                   lease_state,
     674             :                   nt_errstr(status));
     675             : 
     676           0 :         share_mode_wakeup_waiters(id);
     677             : 
     678           0 :         fsps_lease_update(sconn, &id, key);
     679             : 
     680           0 :         TALLOC_FREE(lck);
     681             : 
     682           0 :         DBG_DEBUG("Downgrading %s to %"PRIu32" => %s\n",
     683             :                   file_id_str_buf(id, &idbuf),
     684             :                   lease_state,
     685             :                   nt_errstr(status));
     686             : 
     687             :         /*
     688             :          * Dynamic share case. Ensure other opens are copies.
     689             :          * This will only be breaking to NONE.
     690             :          */
     691             : 
     692           0 :         for (i = 1; i < num_file_ids; i++) {
     693           0 :                 lck = get_existing_share_mode_lock(talloc_tos(), ids[i]);
     694           0 :                 if (lck == NULL) {
     695           0 :                         return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     696             :                 }
     697             : 
     698           0 :                 fsps_lease_update(sconn, &ids[i], key);
     699             : 
     700           0 :                 DBG_DEBUG("Downgrading %s to %"PRIu32" => %s\n",
     701             :                           file_id_str_buf(ids[i], &idbuf),
     702             :                           lease_state,
     703             :                           nt_errstr(status));
     704             : 
     705           0 :                 TALLOC_FREE(lck);
     706             :         }
     707             : 
     708           0 :         return status;
     709             : }
     710             : 
     711             : #define SMB1_BREAK_MESSAGE_LENGTH (smb_size + 8*2)
     712             : 
     713             : /****************************************************************************
     714             :  Function to do the waiting before sending a local break.
     715             : ****************************************************************************/
     716             : 
     717           0 : static void wait_before_sending_break(void)
     718             : {
     719           0 :         long wait_time = (long)lp_oplock_break_wait_time();
     720             : 
     721           0 :         if (wait_time) {
     722           0 :                 smb_msleep(wait_time);
     723             :         }
     724           0 : }
     725             : 
     726             : /****************************************************************************
     727             :  Ensure that we have a valid oplock.
     728             : ****************************************************************************/
     729             : 
     730           0 : static files_struct *initial_break_processing(
     731             :         struct smbd_server_connection *sconn, struct file_id id,
     732             :         unsigned long file_id)
     733             : {
     734           0 :         files_struct *fsp = NULL;
     735             :         struct file_id_buf idbuf;
     736             : 
     737           0 :         DBG_NOTICE("called for %s/%u\n"
     738             :                    "Current oplocks_open (exclusive = %d, levelII = %d)\n",
     739             :                    file_id_str_buf(id, &idbuf),
     740             :                    (int)file_id,
     741             :                    sconn->oplocks.exclusive_open,
     742             :                    sconn->oplocks.level_II_open);
     743             : 
     744             :         /*
     745             :          * We need to search the file open table for the
     746             :          * entry containing this dev and inode, and ensure
     747             :          * we have an oplock on it.
     748             :          */
     749             : 
     750           0 :         fsp = file_find_dif(sconn, id, file_id);
     751             : 
     752           0 :         if(fsp == NULL) {
     753             :                 /* The file could have been closed in the meantime - return success. */
     754           0 :                 DBG_NOTICE("cannot find open file "
     755             :                            "with file_id %s gen_id = %lu, allowing break to "
     756             :                            "succeed.\n",
     757             :                            file_id_str_buf(id, &idbuf),
     758             :                            file_id);
     759           0 :                 return NULL;
     760             :         }
     761             : 
     762             :         /* Ensure we have an oplock on the file */
     763             : 
     764             :         /*
     765             :          * There is a potential race condition in that an oplock could
     766             :          * have been broken due to another udp request, and yet there are
     767             :          * still oplock break messages being sent in the udp message
     768             :          * queue for this file. So return true if we don't have an oplock,
     769             :          * as we may have just freed it.
     770             :          */
     771             : 
     772           0 :         if(fsp->oplock_type == NO_OPLOCK) {
     773           0 :                 DBG_NOTICE("file %s (file_id = %s gen_id = %"PRIu64") "
     774             :                            "has no oplock. "
     775             :                            "Allowing break to succeed regardless.\n",
     776             :                            fsp_str_dbg(fsp),
     777             :                            file_id_str_buf(id, &idbuf),
     778             :                            fh_get_gen_id(fsp->fh));
     779           0 :                 return NULL;
     780             :         }
     781             : 
     782           0 :         return fsp;
     783             : }
     784             : 
     785           0 : static void oplock_timeout_handler(struct tevent_context *ctx,
     786             :                                    struct tevent_timer *te,
     787             :                                    struct timeval now,
     788             :                                    void *private_data)
     789             : {
     790           0 :         files_struct *fsp = (files_struct *)private_data;
     791             : 
     792           0 :         SMB_ASSERT(fsp->sent_oplock_break != NO_BREAK_SENT);
     793             : 
     794             :         /* Remove the timed event handler. */
     795           0 :         TALLOC_FREE(fsp->oplock_timeout);
     796           0 :         DEBUG(0, ("Oplock break failed for file %s -- replying anyway\n",
     797             :                   fsp_str_dbg(fsp)));
     798           0 :         remove_oplock(fsp);
     799           0 : }
     800             : 
     801             : /*******************************************************************
     802             :  Add a timeout handler waiting for the client reply.
     803             : *******************************************************************/
     804             : 
     805           0 : static void add_oplock_timeout_handler(files_struct *fsp)
     806             : {
     807           0 :         if (fsp->oplock_timeout != NULL) {
     808           0 :                 DEBUG(0, ("Logic problem -- have an oplock event hanging "
     809             :                           "around\n"));
     810             :         }
     811             : 
     812           0 :         fsp->oplock_timeout =
     813           0 :                 tevent_add_timer(fsp->conn->sconn->ev_ctx, fsp,
     814             :                                  timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0),
     815             :                                  oplock_timeout_handler, fsp);
     816             : 
     817           0 :         if (fsp->oplock_timeout == NULL) {
     818           0 :                 DEBUG(0, ("Could not add oplock timeout handler\n"));
     819             :         }
     820           0 : }
     821             : 
     822             : /*******************************************************************
     823             :  This handles the generic oplock break message from another smbd.
     824             : *******************************************************************/
     825             : 
     826           0 : static void process_oplock_break_message(struct messaging_context *msg_ctx,
     827             :                                          void *private_data,
     828             :                                          uint32_t msg_type,
     829             :                                          struct server_id src,
     830             :                                          DATA_BLOB *data)
     831             : {
     832           0 :         struct oplock_break_message *msg = NULL;
     833             :         enum ndr_err_code ndr_err;
     834             :         files_struct *fsp;
     835             :         bool use_kernel;
     836             :         struct smbd_server_connection *sconn =
     837           0 :                 talloc_get_type_abort(private_data,
     838             :                 struct smbd_server_connection);
     839           0 :         struct server_id self = messaging_server_id(sconn->msg_ctx);
     840           0 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
     841             :         uint16_t break_from;
     842             :         uint16_t break_to;
     843           0 :         bool break_needed = true;
     844             : 
     845           0 :         smb_vfs_assert_allowed();
     846             : 
     847           0 :         msg = talloc(talloc_tos(), struct oplock_break_message);
     848           0 :         if (msg == NULL) {
     849           0 :                 DBG_WARNING("talloc failed\n");
     850           0 :                 return;
     851             :         }
     852             : 
     853           0 :         ndr_err = ndr_pull_struct_blob_all(
     854             :                 data,
     855             :                 msg,
     856             :                 msg,
     857             :                 (ndr_pull_flags_fn_t)ndr_pull_oplock_break_message);
     858           0 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     859           0 :                 DBG_DEBUG("ndr_pull_oplock_break_message failed: %s\n",
     860             :                           ndr_errstr(ndr_err));
     861           0 :                 TALLOC_FREE(msg);
     862           0 :                 return;
     863             :         }
     864           0 :         if (DEBUGLEVEL >= 10) {
     865             :                 struct server_id_buf buf;
     866           0 :                 DBG_DEBUG("Got break message from %s\n",
     867             :                           server_id_str_buf(src, &buf));
     868           0 :                 NDR_PRINT_DEBUG(oplock_break_message, msg);
     869             :         }
     870             : 
     871           0 :         break_to = msg->break_to;
     872           0 :         fsp = initial_break_processing(sconn, msg->id, msg->share_file_id);
     873             : 
     874           0 :         TALLOC_FREE(msg);
     875             : 
     876           0 :         if (fsp == NULL) {
     877             :                 /* We hit a race here. Break messages are sent, and before we
     878             :                  * get to process this message, we have closed the file. */
     879           0 :                 DEBUG(3, ("Did not find fsp\n"));
     880           0 :                 return;
     881             :         }
     882             : 
     883           0 :         break_from = fsp_lease_type(fsp);
     884             : 
     885           0 :         if (fsp->oplock_type != LEASE_OPLOCK) {
     886           0 :                 if (fsp->sent_oplock_break != NO_BREAK_SENT) {
     887             :                         /*
     888             :                          * Nothing to do anymore
     889             :                          */
     890           0 :                         DEBUG(10, ("fsp->sent_oplock_break = %d\n",
     891             :                                    fsp->sent_oplock_break));
     892           0 :                         return;
     893             :                 }
     894             :         }
     895             : 
     896           0 :         if (!(global_client_caps & CAP_LEVEL_II_OPLOCKS)) {
     897           0 :                 DEBUG(10, ("client_caps without level2 oplocks\n"));
     898           0 :                 break_to &= ~SMB2_LEASE_READ;
     899             :         }
     900             : 
     901           0 :         use_kernel = lp_kernel_oplocks(SNUM(fsp->conn)) &&
     902             :                         (koplocks != NULL);
     903           0 :         if (use_kernel) {
     904           0 :                 DEBUG(10, ("Kernel oplocks don't allow level2\n"));
     905           0 :                 break_to &= ~SMB2_LEASE_READ;
     906             :         }
     907             : 
     908           0 :         if (!lp_level2_oplocks(SNUM(fsp->conn))) {
     909           0 :                 DEBUG(10, ("no level2 oplocks by config\n"));
     910           0 :                 break_to &= ~SMB2_LEASE_READ;
     911             :         }
     912             : 
     913           0 :         if (fsp->oplock_type == LEASE_OPLOCK) {
     914           0 :                 const struct GUID *client_guid = fsp_client_guid(fsp);
     915             :                 struct share_mode_lock *lck;
     916             :                 uint32_t current_state;
     917             :                 uint32_t breaking_to_requested, breaking_to_required;
     918             :                 bool breaking;
     919             :                 uint16_t lease_version, epoch;
     920             :                 NTSTATUS status;
     921             : 
     922           0 :                 lck = get_existing_share_mode_lock(
     923             :                         talloc_tos(), fsp->file_id);
     924           0 :                 if (lck == NULL) {
     925             :                         /*
     926             :                          * We hit a race here. Break messages are sent, and
     927             :                          * before we get to process this message, we have closed
     928             :                          * the file.
     929             :                          */
     930           0 :                         DEBUG(3, ("Did not find share_mode\n"));
     931           0 :                         return;
     932             :                 }
     933             : 
     934           0 :                 status = leases_db_get(client_guid,
     935           0 :                                        &fsp->lease->lease.lease_key,
     936           0 :                                        &fsp->file_id,
     937             :                                        &current_state,
     938             :                                        &breaking,
     939             :                                        &breaking_to_requested,
     940             :                                        &breaking_to_required,
     941             :                                        &lease_version,
     942             :                                        &epoch);
     943           0 :                 if (!NT_STATUS_IS_OK(status)) {
     944           0 :                         DBG_WARNING("leases_db_get returned %s\n",
     945             :                                     nt_errstr(status));
     946           0 :                         TALLOC_FREE(lck);
     947           0 :                         return;
     948             :                 }
     949             : 
     950           0 :                 break_from = current_state;
     951           0 :                 break_to &= current_state;
     952             : 
     953           0 :                 if (breaking) {
     954           0 :                         break_to &= breaking_to_required;
     955           0 :                         if (breaking_to_required != break_to) {
     956             :                                 /*
     957             :                                  * Note we don't increment the epoch
     958             :                                  * here, which might be a bug in
     959             :                                  * Windows too...
     960             :                                  */
     961           0 :                                 breaking_to_required = break_to;
     962             :                         }
     963           0 :                         break_needed = false;
     964           0 :                 } else if (current_state == break_to) {
     965           0 :                         break_needed = false;
     966           0 :                 } else if (current_state == SMB2_LEASE_READ) {
     967           0 :                         current_state = SMB2_LEASE_NONE;
     968             :                         /* Need to increment the epoch */
     969           0 :                         epoch += 1;
     970             :                 } else {
     971           0 :                         breaking = true;
     972           0 :                         breaking_to_required = break_to;
     973           0 :                         breaking_to_requested = break_to;
     974             :                         /* Need to increment the epoch */
     975           0 :                         epoch += 1;
     976             :                 }
     977             : 
     978             :                 {
     979             :                         NTSTATUS set_status;
     980             : 
     981           0 :                         set_status = leases_db_set(
     982             :                                 client_guid,
     983           0 :                                 &fsp->lease->lease.lease_key,
     984             :                                 current_state,
     985             :                                 breaking,
     986             :                                 breaking_to_requested,
     987             :                                 breaking_to_required,
     988             :                                 lease_version,
     989             :                                 epoch);
     990             : 
     991           0 :                         if (!NT_STATUS_IS_OK(set_status)) {
     992           0 :                                 DBG_DEBUG("leases_db_set failed: %s\n",
     993             :                                           nt_errstr(set_status));
     994           0 :                                 return;
     995             :                         }
     996             :                 }
     997             : 
     998             :                 /* Ensure we're in sync with current lease state. */
     999           0 :                 fsp_lease_update(fsp);
    1000             : 
    1001           0 :                 TALLOC_FREE(lck);
    1002             :         }
    1003             : 
    1004           0 :         if (!break_needed) {
    1005           0 :                 DEBUG(10,("%s: skip break\n", __func__));
    1006           0 :                 return;
    1007             :         }
    1008             : 
    1009           0 :         if (break_from == SMB2_LEASE_NONE) {
    1010             :                 struct file_id_buf idbuf;
    1011           0 :                 DBG_NOTICE("Already downgraded oplock to none on %s: %s\n",
    1012             :                            file_id_str_buf(fsp->file_id, &idbuf),
    1013             :                            fsp_str_dbg(fsp));
    1014           0 :                 return;
    1015             :         }
    1016             : 
    1017           0 :         DEBUG(10, ("break_from=%u, break_to=%u\n",
    1018             :                    (unsigned)break_from, (unsigned)break_to));
    1019             : 
    1020           0 :         if (break_from == break_to) {
    1021             :                 struct file_id_buf idbuf;
    1022           0 :                 DBG_NOTICE("Already downgraded oplock to %u on %s: %s\n",
    1023             :                            (unsigned)break_to,
    1024             :                            file_id_str_buf(fsp->file_id, &idbuf),
    1025             :                            fsp_str_dbg(fsp));
    1026           0 :                 return;
    1027             :         }
    1028             : 
    1029             :         /* Need to wait before sending a break
    1030             :            message if we sent ourselves this message. */
    1031           0 :         if (server_id_equal(&self, &src)) {
    1032           0 :                 wait_before_sending_break();
    1033             :         }
    1034             : 
    1035             : #if defined(WITH_SMB1SERVER)
    1036           0 :         if (sconn->using_smb2) {
    1037             : #endif
    1038           0 :                 send_break_message_smb2(fsp, break_from, break_to);
    1039             : #if defined(WITH_SMB1SERVER)
    1040             :         } else {
    1041           0 :                 send_break_message_smb1(fsp, (break_to & SMB2_LEASE_READ) ?
    1042             :                                         OPLOCKLEVEL_II : OPLOCKLEVEL_NONE);
    1043             :         }
    1044             : #endif
    1045             : 
    1046           0 :         if ((break_from == SMB2_LEASE_READ) &&
    1047             :             (break_to == SMB2_LEASE_NONE)) {
    1048             :                 /*
    1049             :                  * This is an async break without a reply and thus no timeout
    1050             :                  *
    1051             :                  * leases are handled above.
    1052             :                  */
    1053           0 :                 if (fsp->oplock_type != LEASE_OPLOCK) {
    1054           0 :                         remove_oplock(fsp);
    1055             :                 }
    1056           0 :                 return;
    1057             :         }
    1058           0 :         if (fsp->oplock_type == LEASE_OPLOCK) {
    1059           0 :                 return;
    1060             :         }
    1061             : 
    1062           0 :         fsp->sent_oplock_break = (break_to & SMB2_LEASE_READ) ?
    1063           0 :                 LEVEL_II_BREAK_SENT:BREAK_TO_NONE_SENT;
    1064             : 
    1065           0 :         add_oplock_timeout_handler(fsp);
    1066             : }
    1067             : 
    1068             : /*******************************************************************
    1069             :  This handles the kernel oplock break message.
    1070             : *******************************************************************/
    1071             : 
    1072           0 : static void process_kernel_oplock_break(struct messaging_context *msg_ctx,
    1073             :                                         void *private_data,
    1074             :                                         uint32_t msg_type,
    1075             :                                         struct server_id src,
    1076             :                                         DATA_BLOB *data)
    1077             : {
    1078             :         struct file_id id;
    1079             :         struct file_id_buf idbuf;
    1080             :         unsigned long file_id;
    1081             :         files_struct *fsp;
    1082             :         struct smbd_server_connection *sconn =
    1083           0 :                 talloc_get_type_abort(private_data,
    1084             :                 struct smbd_server_connection);
    1085             :         struct server_id_buf tmp;
    1086             : 
    1087           0 :         if (data->data == NULL) {
    1088           0 :                 DEBUG(0, ("Got NULL buffer\n"));
    1089           0 :                 return;
    1090             :         }
    1091             : 
    1092           0 :         if (data->length != MSG_SMB_KERNEL_BREAK_SIZE) {
    1093           0 :                 DEBUG(0, ("Got invalid msg len %d\n", (int)data->length));
    1094           0 :                 return;
    1095             :         }
    1096             : 
    1097             :         /* Pull the data from the message. */
    1098           0 :         pull_file_id_24((char *)data->data, &id);
    1099           0 :         file_id = (unsigned long)IVAL(data->data, 24);
    1100             : 
    1101           0 :         DBG_DEBUG("Got kernel oplock break message from pid %s: %s/%u\n",
    1102             :                   server_id_str_buf(src, &tmp),
    1103             :                   file_id_str_buf(id, &idbuf),
    1104             :                   (unsigned int)file_id);
    1105             : 
    1106           0 :         fsp = initial_break_processing(sconn, id, file_id);
    1107             : 
    1108           0 :         if (fsp == NULL) {
    1109           0 :                 DEBUG(3, ("Got a kernel oplock break message for a file "
    1110             :                           "I don't know about\n"));
    1111           0 :                 return;
    1112             :         }
    1113             : 
    1114           0 :         if (fsp->sent_oplock_break != NO_BREAK_SENT) {
    1115             :                 /* This is ok, kernel oplocks come in completely async */
    1116           0 :                 DEBUG(3, ("Got a kernel oplock request while waiting for a "
    1117             :                           "break reply\n"));
    1118           0 :                 return;
    1119             :         }
    1120             : 
    1121             : #if defined(WITH_SMB1SERVER)
    1122           0 :         if (sconn->using_smb2) {
    1123             : #endif
    1124           0 :                 send_break_message_smb2(fsp, 0, OPLOCKLEVEL_NONE);
    1125             : #if defined(WITH_SMB1SERVER)
    1126             :         } else {
    1127           0 :                 send_break_message_smb1(fsp, OPLOCKLEVEL_NONE);
    1128             :         }
    1129             : #endif
    1130             : 
    1131           0 :         fsp->sent_oplock_break = BREAK_TO_NONE_SENT;
    1132             : 
    1133           0 :         add_oplock_timeout_handler(fsp);
    1134             : }
    1135             : 
    1136           0 : static void send_break_to_none(struct messaging_context *msg_ctx,
    1137             :                                const struct file_id *id,
    1138             :                                const struct share_mode_entry *e)
    1139             : {
    1140             :         NTSTATUS status;
    1141           0 :         status = send_break_message(msg_ctx, id, e, OPLOCK_NONE);
    1142           0 :         if (!NT_STATUS_IS_OK(status)) {
    1143           0 :                 DBG_DEBUG("send_break_message failed: %s\n",
    1144             :                           nt_errstr(status));
    1145             :         }
    1146           0 : }
    1147             : struct break_to_none_state {
    1148             :         struct smbd_server_connection *sconn;
    1149             :         struct file_id id;
    1150             :         struct smb2_lease_key lease_key;
    1151             :         struct GUID client_guid;
    1152             :         size_t num_read_leases;
    1153             :         uint32_t total_lease_types;
    1154             : };
    1155             : 
    1156           0 : static bool do_break_lease_to_none(struct share_mode_entry *e,
    1157             :                                    void *private_data)
    1158             : {
    1159           0 :         struct break_to_none_state *state = private_data;
    1160           0 :         uint32_t current_state = 0;
    1161             :         bool our_own;
    1162             :         NTSTATUS status;
    1163             : 
    1164           0 :         DBG_DEBUG("lease_key=%"PRIu64"/%"PRIu64"\n",
    1165             :                   e->lease_key.data[0],
    1166             :                   e->lease_key.data[1]);
    1167             : 
    1168           0 :         status = leases_db_get(&e->client_guid,
    1169           0 :                                &e->lease_key,
    1170           0 :                                &state->id,
    1171             :                                &current_state,
    1172             :                                NULL, /* breaking */
    1173             :                                NULL, /* breaking_to_requested */
    1174             :                                NULL, /* breaking_to_required */
    1175             :                                NULL, /* lease_version */
    1176             :                                NULL); /* epoch */
    1177           0 :         if (!NT_STATUS_IS_OK(status)) {
    1178           0 :                 DBG_WARNING("leases_db_get failed: %s\n",
    1179             :                             nt_errstr(status));
    1180           0 :                 return false;
    1181             :         }
    1182             : 
    1183           0 :         state->total_lease_types |= current_state;
    1184             : 
    1185           0 :         if ((current_state & SMB2_LEASE_READ) == 0) {
    1186           0 :                 return false;
    1187             :         }
    1188             : 
    1189           0 :         state->num_read_leases += 1;
    1190             : 
    1191           0 :         our_own = smb2_lease_equal(&state->client_guid,
    1192           0 :                                    &state->lease_key,
    1193           0 :                                    &e->client_guid,
    1194           0 :                                    &e->lease_key);
    1195           0 :         if (our_own) {
    1196           0 :                 DEBUG(10, ("Don't break our own lease\n"));
    1197           0 :                 return false;
    1198             :         }
    1199             : 
    1200           0 :         DBG_DEBUG("Breaking %"PRIu64"/%"PRIu64" to none\n",
    1201             :                   e->lease_key.data[0],
    1202             :                   e->lease_key.data[1]);
    1203             : 
    1204           0 :         send_break_to_none(state->sconn->msg_ctx, &state->id, e);
    1205             : 
    1206           0 :         return false;
    1207             : }
    1208             : 
    1209           0 : static bool do_break_oplock_to_none(struct share_mode_entry *e,
    1210             :                                     bool *modified,
    1211             :                                     void *private_data)
    1212             : {
    1213           0 :         struct break_to_none_state *state = private_data;
    1214             : 
    1215           0 :         if (e->op_type == LEASE_OPLOCK) {
    1216             :                 /*
    1217             :                  * Already being taken care of
    1218             :                  */
    1219           0 :                 return false;
    1220             :         }
    1221             : 
    1222             :         /*
    1223             :          * As there could have been multiple writes waiting at the
    1224             :          * lock_share_entry gate we may not be the first to
    1225             :          * enter. Hence the state of the op_types in the share mode
    1226             :          * entries may be partly NO_OPLOCK and partly LEVEL_II
    1227             :          * oplock. It will do no harm to re-send break messages to
    1228             :          * those smbd's that are still waiting their turn to remove
    1229             :          * their LEVEL_II state, and also no harm to ignore existing
    1230             :          * NO_OPLOCK states. JRA.
    1231             :          */
    1232             : 
    1233           0 :         DBG_DEBUG("e->op_type == %d\n", e->op_type);
    1234             : 
    1235           0 :         state->total_lease_types |= map_oplock_to_lease_type(e->op_type);
    1236             : 
    1237           0 :         if (e->op_type == NO_OPLOCK) {
    1238           0 :                 return false;
    1239             :         }
    1240             : 
    1241           0 :         state->num_read_leases += 1;
    1242             : 
    1243             :         /* Paranoia .... */
    1244           0 :         SMB_ASSERT(!EXCLUSIVE_OPLOCK_TYPE(e->op_type));
    1245             : 
    1246           0 :         send_break_to_none(state->sconn->msg_ctx, &state->id, e);
    1247             : 
    1248           0 :         return false;
    1249             : }
    1250             : 
    1251             : /****************************************************************************
    1252             :  This function is called on any file modification or lock request. If a file
    1253             :  is level 2 oplocked then it must tell all other level 2 holders to break to
    1254             :  none.
    1255             : ****************************************************************************/
    1256             : 
    1257         473 : static void contend_level2_oplocks_begin_default(files_struct *fsp,
    1258             :                                               enum level2_contention_type type)
    1259             : {
    1260         473 :         struct break_to_none_state state = {
    1261         473 :                 .sconn = fsp->conn->sconn, .id = fsp->file_id,
    1262             :         };
    1263         473 :         struct share_mode_lock *lck = NULL;
    1264         473 :         uint32_t fsp_lease = fsp_lease_type(fsp);
    1265             :         bool ok, has_read_lease;
    1266             : 
    1267             :         /*
    1268             :          * If this file is level II oplocked then we need
    1269             :          * to grab the shared memory lock and inform all
    1270             :          * other files with a level II lock that they need
    1271             :          * to flush their read caches. We keep the lock over
    1272             :          * the shared memory area whilst doing this.
    1273             :          */
    1274             : 
    1275         473 :         if (fsp_lease & SMB2_LEASE_WRITE) {
    1276             :                 /*
    1277             :                  * There can't be any level2 oplocks, we're alone.
    1278             :                  */
    1279         473 :                 return;
    1280             :         }
    1281             : 
    1282         469 :         has_read_lease = file_has_read_lease(fsp);
    1283         469 :         if (!has_read_lease) {
    1284         469 :                 DEBUG(10, ("No read oplocks around\n"));
    1285         469 :                 return;
    1286             :         }
    1287             : 
    1288           0 :         if (fsp->oplock_type == LEASE_OPLOCK) {
    1289           0 :                 state.client_guid = *fsp_client_guid(fsp);
    1290           0 :                 state.lease_key = fsp->lease->lease.lease_key;
    1291           0 :                 DEBUG(10, ("Breaking through lease key %"PRIu64"/%"PRIu64"\n",
    1292             :                            state.lease_key.data[0],
    1293             :                            state.lease_key.data[1]));
    1294             :         }
    1295             : 
    1296           0 :         lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
    1297           0 :         if (lck == NULL) {
    1298             :                 struct file_id_buf idbuf;
    1299           0 :                 DBG_WARNING("failed to lock share mode entry for file %s.\n",
    1300             :                             file_id_str_buf(state.id, &idbuf));
    1301           0 :                 return;
    1302             :         }
    1303             : 
    1304             :         /*
    1305             :          * Walk leases and oplocks separately: We have to send one break per
    1306             :          * lease. If we have multiple share_mode_entry having a common lease,
    1307             :          * we would break the lease twice if we don't walk the leases list
    1308             :          * separately.
    1309             :          */
    1310             : 
    1311           0 :         ok = share_mode_forall_leases(lck, do_break_lease_to_none, &state);
    1312           0 :         if (!ok) {
    1313           0 :                 DBG_WARNING("share_mode_forall_leases failed\n");
    1314             :         }
    1315             : 
    1316           0 :         ok = share_mode_forall_entries(lck, do_break_oplock_to_none, &state);
    1317           0 :         if (!ok) {
    1318           0 :                 DBG_WARNING("share_mode_forall_entries failed\n");
    1319             :         }
    1320             : 
    1321             :         {
    1322             :                 /*
    1323             :                  * Lazy update here. It might be that all leases
    1324             :                  * have gone in the meantime.
    1325             :                  */
    1326             :                 uint32_t acc, sh, ls;
    1327           0 :                 share_mode_flags_get(lck, &acc, &sh, &ls);
    1328           0 :                 ls = state.total_lease_types;
    1329           0 :                 share_mode_flags_set(lck, acc, sh, ls, NULL);
    1330             :         }
    1331             : 
    1332           0 :         TALLOC_FREE(lck);
    1333             : }
    1334             : 
    1335         473 : void smbd_contend_level2_oplocks_begin(files_struct *fsp,
    1336             :                                   enum level2_contention_type type)
    1337             : {
    1338         473 :         contend_level2_oplocks_begin_default(fsp, type);
    1339         473 : }
    1340             : 
    1341         473 : void smbd_contend_level2_oplocks_end(files_struct *fsp,
    1342             :                                 enum level2_contention_type type)
    1343             : {
    1344         473 :         return;
    1345             : }
    1346             : 
    1347             : /****************************************************************************
    1348             :  Linearize a share mode entry struct to an internal oplock break message.
    1349             : ****************************************************************************/
    1350             : 
    1351           0 : void share_mode_entry_to_message(char *msg, const struct file_id *id,
    1352             :                                  const struct share_mode_entry *e)
    1353             : {
    1354           0 :         SIVAL(msg,OP_BREAK_MSG_PID_OFFSET,(uint32_t)e->pid.pid);
    1355           0 :         SBVAL(msg,OP_BREAK_MSG_MID_OFFSET,e->op_mid);
    1356           0 :         SSVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET,e->op_type);
    1357           0 :         SIVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET,e->access_mask);
    1358           0 :         SIVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET,e->share_access);
    1359           0 :         SIVAL(msg,OP_BREAK_MSG_PRIV_OFFSET,e->private_options);
    1360           0 :         SIVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET,(uint32_t)e->time.tv_sec);
    1361           0 :         SIVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET,(uint32_t)e->time.tv_usec);
    1362             :         /*
    1363             :          * "id" used to be part of share_mode_entry, thus the strange
    1364             :          * place to put this. Feel free to move somewhere else :-)
    1365             :          */
    1366           0 :         push_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, id);
    1367           0 :         SIVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET,e->share_file_id);
    1368           0 :         SIVAL(msg,OP_BREAK_MSG_UID_OFFSET,e->uid);
    1369           0 :         SSVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET,e->flags);
    1370           0 :         SIVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET,e->name_hash);
    1371           0 :         SIVAL(msg,OP_BREAK_MSG_VNN_OFFSET,e->pid.vnn);
    1372           0 : }
    1373             : 
    1374             : /****************************************************************************
    1375             :  De-linearize an internal oplock break message to a share mode entry struct.
    1376             : ****************************************************************************/
    1377             : 
    1378           0 : void message_to_share_mode_entry(struct file_id *id,
    1379             :                                  struct share_mode_entry *e,
    1380             :                                  const char *msg)
    1381             : {
    1382           0 :         e->pid.pid = (pid_t)IVAL(msg,OP_BREAK_MSG_PID_OFFSET);
    1383           0 :         e->op_mid = BVAL(msg,OP_BREAK_MSG_MID_OFFSET);
    1384           0 :         e->op_type = SVAL(msg,OP_BREAK_MSG_OP_TYPE_OFFSET);
    1385           0 :         e->access_mask = IVAL(msg,OP_BREAK_MSG_ACCESS_MASK_OFFSET);
    1386           0 :         e->share_access = IVAL(msg,OP_BREAK_MSG_SHARE_ACCESS_OFFSET);
    1387           0 :         e->private_options = IVAL(msg,OP_BREAK_MSG_PRIV_OFFSET);
    1388           0 :         e->time.tv_sec = (time_t)IVAL(msg,OP_BREAK_MSG_TIME_SEC_OFFSET);
    1389           0 :         e->time.tv_usec = (int)IVAL(msg,OP_BREAK_MSG_TIME_USEC_OFFSET);
    1390             :         /*
    1391             :          * "id" used to be part of share_mode_entry, thus the strange
    1392             :          * place to put this. Feel free to move somewhere else :-)
    1393             :          */
    1394           0 :         pull_file_id_24(msg+OP_BREAK_MSG_DEV_OFFSET, id);
    1395           0 :         e->share_file_id = (unsigned long)IVAL(msg,OP_BREAK_MSG_FILE_ID_OFFSET);
    1396           0 :         e->uid = (uint32_t)IVAL(msg,OP_BREAK_MSG_UID_OFFSET);
    1397           0 :         e->flags = (uint16_t)SVAL(msg,OP_BREAK_MSG_FLAGS_OFFSET);
    1398           0 :         e->name_hash = IVAL(msg,OP_BREAK_MSG_NAME_HASH_OFFSET);
    1399           0 :         e->pid.vnn = IVAL(msg,OP_BREAK_MSG_VNN_OFFSET);
    1400           0 : }
    1401             : 
    1402             : /****************************************************************************
    1403             :  Setup oplocks for this process.
    1404             : ****************************************************************************/
    1405             : 
    1406        5251 : bool init_oplocks(struct smbd_server_connection *sconn)
    1407             : {
    1408        5251 :         DEBUG(3,("init_oplocks: initializing messages.\n"));
    1409             : 
    1410        5251 :         messaging_register(sconn->msg_ctx, sconn, MSG_SMB_BREAK_REQUEST,
    1411             :                            process_oplock_break_message);
    1412        5251 :         messaging_register(sconn->msg_ctx, sconn, MSG_SMB_KERNEL_BREAK,
    1413             :                            process_kernel_oplock_break);
    1414        5251 :         return true;
    1415             : }
    1416             : 
    1417           0 : void init_kernel_oplocks(struct smbd_server_connection *sconn)
    1418             : {
    1419           0 :         struct kernel_oplocks *koplocks = sconn->oplocks.kernel_ops;
    1420             : 
    1421             :         /* only initialize once */
    1422           0 :         if (koplocks == NULL) {
    1423             : #ifdef HAVE_KERNEL_OPLOCKS_LINUX
    1424           0 :                 koplocks = linux_init_kernel_oplocks(sconn);
    1425             : #endif
    1426           0 :                 sconn->oplocks.kernel_ops = koplocks;
    1427             :         }
    1428           0 : }

Generated by: LCOV version 1.14