LCOV - code coverage report
Current view: top level - source3/smbd - smb2_oplock.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 62 531 11.7 %
Date: 2024-06-13 04:01:37 Functions: 9 30 30.0 %

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

Generated by: LCOV version 1.13