| 1 | /*
|
|---|
| 2 | Unix SMB/CIFS implementation.
|
|---|
| 3 | Core SMB2 server
|
|---|
| 4 |
|
|---|
| 5 | Copyright (C) Stefan Metzmacher 2009
|
|---|
| 6 | Copyright (C) Jeremy Allison 2010
|
|---|
| 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 | #include "includes.h"
|
|---|
| 23 | #include "smbd/smbd.h"
|
|---|
| 24 | #include "smbd/globals.h"
|
|---|
| 25 | #include "../libcli/smb/smb_common.h"
|
|---|
| 26 | #include "../lib/util/tevent_ntstatus.h"
|
|---|
| 27 | #include "messages.h"
|
|---|
| 28 |
|
|---|
| 29 | struct smbd_smb2_lock_element {
|
|---|
| 30 | uint64_t offset;
|
|---|
| 31 | uint64_t length;
|
|---|
| 32 | uint32_t flags;
|
|---|
| 33 | };
|
|---|
| 34 |
|
|---|
| 35 | struct smbd_smb2_lock_state {
|
|---|
| 36 | struct smbd_smb2_request *smb2req;
|
|---|
| 37 | struct smb_request *smb1req;
|
|---|
| 38 | struct blocking_lock_record *blr;
|
|---|
| 39 | uint16_t lock_count;
|
|---|
| 40 | struct smbd_lock_element *locks;
|
|---|
| 41 | };
|
|---|
| 42 |
|
|---|
| 43 | static void remove_pending_lock(struct smbd_smb2_lock_state *state,
|
|---|
| 44 | struct blocking_lock_record *blr);
|
|---|
| 45 |
|
|---|
| 46 | static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
|
|---|
| 47 | struct tevent_context *ev,
|
|---|
| 48 | struct smbd_smb2_request *smb2req,
|
|---|
| 49 | struct files_struct *in_fsp,
|
|---|
| 50 | uint32_t in_smbpid,
|
|---|
| 51 | uint16_t in_lock_count,
|
|---|
| 52 | struct smbd_smb2_lock_element *in_locks);
|
|---|
| 53 | static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req);
|
|---|
| 54 |
|
|---|
| 55 | static void smbd_smb2_request_lock_done(struct tevent_req *subreq);
|
|---|
| 56 | NTSTATUS smbd_smb2_request_process_lock(struct smbd_smb2_request *req)
|
|---|
| 57 | {
|
|---|
| 58 | const uint8_t *inhdr;
|
|---|
| 59 | const uint8_t *inbody;
|
|---|
| 60 | const int i = req->current_idx;
|
|---|
| 61 | uint32_t in_smbpid;
|
|---|
| 62 | uint16_t in_lock_count;
|
|---|
| 63 | uint64_t in_file_id_persistent;
|
|---|
| 64 | uint64_t in_file_id_volatile;
|
|---|
| 65 | struct files_struct *in_fsp;
|
|---|
| 66 | struct smbd_smb2_lock_element *in_locks;
|
|---|
| 67 | struct tevent_req *subreq;
|
|---|
| 68 | const uint8_t *lock_buffer;
|
|---|
| 69 | uint16_t l;
|
|---|
| 70 | NTSTATUS status;
|
|---|
| 71 |
|
|---|
| 72 | status = smbd_smb2_request_verify_sizes(req, 0x30);
|
|---|
| 73 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 74 | return smbd_smb2_request_error(req, status);
|
|---|
| 75 | }
|
|---|
| 76 | inhdr = (const uint8_t *)req->in.vector[i+0].iov_base;
|
|---|
| 77 | inbody = (const uint8_t *)req->in.vector[i+1].iov_base;
|
|---|
| 78 |
|
|---|
| 79 | in_smbpid = IVAL(inhdr, SMB2_HDR_PID);
|
|---|
| 80 |
|
|---|
| 81 | in_lock_count = CVAL(inbody, 0x02);
|
|---|
| 82 | /* 0x04 - 4 bytes reserved */
|
|---|
| 83 | in_file_id_persistent = BVAL(inbody, 0x08);
|
|---|
| 84 | in_file_id_volatile = BVAL(inbody, 0x10);
|
|---|
| 85 |
|
|---|
| 86 | if (in_lock_count < 1) {
|
|---|
| 87 | return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
|
|---|
| 88 | }
|
|---|
| 89 |
|
|---|
| 90 | if (((in_lock_count - 1) * 0x18) > req->in.vector[i+2].iov_len) {
|
|---|
| 91 | return smbd_smb2_request_error(req, NT_STATUS_INVALID_PARAMETER);
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | in_locks = talloc_array(req, struct smbd_smb2_lock_element,
|
|---|
| 95 | in_lock_count);
|
|---|
| 96 | if (in_locks == NULL) {
|
|---|
| 97 | return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
|
|---|
| 98 | }
|
|---|
| 99 |
|
|---|
| 100 | l = 0;
|
|---|
| 101 | lock_buffer = inbody + 0x18;
|
|---|
| 102 |
|
|---|
| 103 | in_locks[l].offset = BVAL(lock_buffer, 0x00);
|
|---|
| 104 | in_locks[l].length = BVAL(lock_buffer, 0x08);
|
|---|
| 105 | in_locks[l].flags = IVAL(lock_buffer, 0x10);
|
|---|
| 106 | /* 0x14 - 4 reserved bytes */
|
|---|
| 107 |
|
|---|
| 108 | lock_buffer = (const uint8_t *)req->in.vector[i+2].iov_base;
|
|---|
| 109 |
|
|---|
| 110 | for (l=1; l < in_lock_count; l++) {
|
|---|
| 111 | in_locks[l].offset = BVAL(lock_buffer, 0x00);
|
|---|
| 112 | in_locks[l].length = BVAL(lock_buffer, 0x08);
|
|---|
| 113 | in_locks[l].flags = IVAL(lock_buffer, 0x10);
|
|---|
| 114 | /* 0x14 - 4 reserved bytes */
|
|---|
| 115 |
|
|---|
| 116 | lock_buffer += 0x18;
|
|---|
| 117 | }
|
|---|
| 118 |
|
|---|
| 119 | in_fsp = file_fsp_smb2(req, in_file_id_persistent, in_file_id_volatile);
|
|---|
| 120 | if (in_fsp == NULL) {
|
|---|
| 121 | return smbd_smb2_request_error(req, NT_STATUS_FILE_CLOSED);
|
|---|
| 122 | }
|
|---|
| 123 |
|
|---|
| 124 | subreq = smbd_smb2_lock_send(req, req->sconn->smb2.event_ctx,
|
|---|
| 125 | req, in_fsp,
|
|---|
| 126 | in_smbpid,
|
|---|
| 127 | in_lock_count,
|
|---|
| 128 | in_locks);
|
|---|
| 129 | if (subreq == NULL) {
|
|---|
| 130 | return smbd_smb2_request_error(req, NT_STATUS_NO_MEMORY);
|
|---|
| 131 | }
|
|---|
| 132 | tevent_req_set_callback(subreq, smbd_smb2_request_lock_done, req);
|
|---|
| 133 |
|
|---|
| 134 | return smbd_smb2_request_pending_queue(req, subreq);
|
|---|
| 135 | }
|
|---|
| 136 |
|
|---|
| 137 | static void smbd_smb2_request_lock_done(struct tevent_req *subreq)
|
|---|
| 138 | {
|
|---|
| 139 | struct smbd_smb2_request *smb2req = tevent_req_callback_data(subreq,
|
|---|
| 140 | struct smbd_smb2_request);
|
|---|
| 141 | DATA_BLOB outbody;
|
|---|
| 142 | NTSTATUS status;
|
|---|
| 143 | NTSTATUS error; /* transport error */
|
|---|
| 144 |
|
|---|
| 145 | if (smb2req->cancelled) {
|
|---|
| 146 | const uint8_t *inhdr = (const uint8_t *)
|
|---|
| 147 | smb2req->in.vector[smb2req->current_idx].iov_base;
|
|---|
| 148 | uint64_t mid = BVAL(inhdr, SMB2_HDR_MESSAGE_ID);
|
|---|
| 149 | struct smbd_smb2_lock_state *state;
|
|---|
| 150 |
|
|---|
| 151 | DEBUG(10,("smbd_smb2_request_lock_done: cancelled mid %llu\n",
|
|---|
| 152 | (unsigned long long)mid ));
|
|---|
| 153 |
|
|---|
| 154 | state = tevent_req_data(smb2req->subreq,
|
|---|
| 155 | struct smbd_smb2_lock_state);
|
|---|
| 156 |
|
|---|
| 157 | SMB_ASSERT(state);
|
|---|
| 158 | SMB_ASSERT(state->blr);
|
|---|
| 159 |
|
|---|
| 160 | remove_pending_lock(state, state->blr);
|
|---|
| 161 |
|
|---|
| 162 | error = smbd_smb2_request_error(smb2req, NT_STATUS_CANCELLED);
|
|---|
| 163 | if (!NT_STATUS_IS_OK(error)) {
|
|---|
| 164 | smbd_server_connection_terminate(smb2req->sconn,
|
|---|
| 165 | nt_errstr(error));
|
|---|
| 166 | return;
|
|---|
| 167 | }
|
|---|
| 168 | return;
|
|---|
| 169 | }
|
|---|
| 170 |
|
|---|
| 171 | status = smbd_smb2_lock_recv(subreq);
|
|---|
| 172 | TALLOC_FREE(subreq);
|
|---|
| 173 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 174 | error = smbd_smb2_request_error(smb2req, status);
|
|---|
| 175 | if (!NT_STATUS_IS_OK(error)) {
|
|---|
| 176 | smbd_server_connection_terminate(smb2req->sconn,
|
|---|
| 177 | nt_errstr(error));
|
|---|
| 178 | return;
|
|---|
| 179 | }
|
|---|
| 180 | return;
|
|---|
| 181 | }
|
|---|
| 182 |
|
|---|
| 183 | outbody = data_blob_talloc(smb2req->out.vector, NULL, 0x04);
|
|---|
| 184 | if (outbody.data == NULL) {
|
|---|
| 185 | error = smbd_smb2_request_error(smb2req, NT_STATUS_NO_MEMORY);
|
|---|
| 186 | if (!NT_STATUS_IS_OK(error)) {
|
|---|
| 187 | smbd_server_connection_terminate(smb2req->sconn,
|
|---|
| 188 | nt_errstr(error));
|
|---|
| 189 | return;
|
|---|
| 190 | }
|
|---|
| 191 | return;
|
|---|
| 192 | }
|
|---|
| 193 |
|
|---|
| 194 | SSVAL(outbody.data, 0x00, 0x04); /* struct size */
|
|---|
| 195 | SSVAL(outbody.data, 0x02, 0); /* reserved */
|
|---|
| 196 |
|
|---|
| 197 | error = smbd_smb2_request_done(smb2req, outbody, NULL);
|
|---|
| 198 | if (!NT_STATUS_IS_OK(error)) {
|
|---|
| 199 | smbd_server_connection_terminate(smb2req->sconn,
|
|---|
| 200 | nt_errstr(error));
|
|---|
| 201 | return;
|
|---|
| 202 | }
|
|---|
| 203 | }
|
|---|
| 204 |
|
|---|
| 205 | static struct tevent_req *smbd_smb2_lock_send(TALLOC_CTX *mem_ctx,
|
|---|
| 206 | struct tevent_context *ev,
|
|---|
| 207 | struct smbd_smb2_request *smb2req,
|
|---|
| 208 | struct files_struct *fsp,
|
|---|
| 209 | uint32_t in_smbpid,
|
|---|
| 210 | uint16_t in_lock_count,
|
|---|
| 211 | struct smbd_smb2_lock_element *in_locks)
|
|---|
| 212 | {
|
|---|
| 213 | struct tevent_req *req;
|
|---|
| 214 | struct smbd_smb2_lock_state *state;
|
|---|
| 215 | struct smb_request *smb1req;
|
|---|
| 216 | int32_t timeout = -1;
|
|---|
| 217 | bool isunlock = false;
|
|---|
| 218 | uint16_t i;
|
|---|
| 219 | struct smbd_lock_element *locks;
|
|---|
| 220 | NTSTATUS status;
|
|---|
| 221 | bool async = false;
|
|---|
| 222 |
|
|---|
| 223 | req = tevent_req_create(mem_ctx, &state,
|
|---|
| 224 | struct smbd_smb2_lock_state);
|
|---|
| 225 | if (req == NULL) {
|
|---|
| 226 | return NULL;
|
|---|
| 227 | }
|
|---|
| 228 | state->smb2req = smb2req;
|
|---|
| 229 | smb2req->subreq = req; /* So we can find this when going async. */
|
|---|
| 230 |
|
|---|
| 231 | smb1req = smbd_smb2_fake_smb_request(smb2req);
|
|---|
| 232 | if (tevent_req_nomem(smb1req, req)) {
|
|---|
| 233 | return tevent_req_post(req, ev);
|
|---|
| 234 | }
|
|---|
| 235 | state->smb1req = smb1req;
|
|---|
| 236 |
|
|---|
| 237 | DEBUG(10,("smbd_smb2_lock_send: %s - fnum[%d]\n",
|
|---|
| 238 | fsp_str_dbg(fsp), fsp->fnum));
|
|---|
| 239 |
|
|---|
| 240 | locks = talloc_array(state, struct smbd_lock_element, in_lock_count);
|
|---|
| 241 | if (locks == NULL) {
|
|---|
| 242 | tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
|
|---|
| 243 | return tevent_req_post(req, ev);
|
|---|
| 244 | }
|
|---|
| 245 |
|
|---|
| 246 | switch (in_locks[0].flags) {
|
|---|
| 247 | case SMB2_LOCK_FLAG_SHARED:
|
|---|
| 248 | case SMB2_LOCK_FLAG_EXCLUSIVE:
|
|---|
| 249 | if (in_lock_count > 1) {
|
|---|
| 250 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
|---|
| 251 | return tevent_req_post(req, ev);
|
|---|
| 252 | }
|
|---|
| 253 | timeout = -1;
|
|---|
| 254 | break;
|
|---|
| 255 |
|
|---|
| 256 | case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
|
|---|
| 257 | case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
|
|---|
| 258 | timeout = 0;
|
|---|
| 259 | break;
|
|---|
| 260 |
|
|---|
| 261 | case SMB2_LOCK_FLAG_UNLOCK:
|
|---|
| 262 | /* only the first lock gives the UNLOCK bit - see
|
|---|
| 263 | MS-SMB2 3.3.5.14 */
|
|---|
| 264 | isunlock = true;
|
|---|
| 265 | timeout = 0;
|
|---|
| 266 | break;
|
|---|
| 267 |
|
|---|
| 268 | default:
|
|---|
| 269 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
|---|
| 270 | return tevent_req_post(req, ev);
|
|---|
| 271 | }
|
|---|
| 272 |
|
|---|
| 273 | for (i=0; i<in_lock_count; i++) {
|
|---|
| 274 | bool invalid = false;
|
|---|
| 275 |
|
|---|
| 276 | switch (in_locks[i].flags) {
|
|---|
| 277 | case SMB2_LOCK_FLAG_SHARED:
|
|---|
| 278 | case SMB2_LOCK_FLAG_EXCLUSIVE:
|
|---|
| 279 | if (isunlock) {
|
|---|
| 280 | invalid = true;
|
|---|
| 281 | break;
|
|---|
| 282 | }
|
|---|
| 283 | if (i > 0) {
|
|---|
| 284 | tevent_req_nterror(req,
|
|---|
| 285 | NT_STATUS_INVALID_PARAMETER);
|
|---|
| 286 | return tevent_req_post(req, ev);
|
|---|
| 287 | }
|
|---|
| 288 | break;
|
|---|
| 289 |
|
|---|
| 290 | case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
|
|---|
| 291 | case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
|
|---|
| 292 | if (isunlock) {
|
|---|
| 293 | invalid = true;
|
|---|
| 294 | }
|
|---|
| 295 | break;
|
|---|
| 296 |
|
|---|
| 297 | case SMB2_LOCK_FLAG_UNLOCK:
|
|---|
| 298 | if (!isunlock) {
|
|---|
| 299 | tevent_req_nterror(req,
|
|---|
| 300 | NT_STATUS_INVALID_PARAMETER);
|
|---|
| 301 | return tevent_req_post(req, ev);
|
|---|
| 302 | }
|
|---|
| 303 | break;
|
|---|
| 304 |
|
|---|
| 305 | default:
|
|---|
| 306 | if (isunlock) {
|
|---|
| 307 | /*
|
|---|
| 308 | * is the first element was a UNLOCK
|
|---|
| 309 | * we need to deferr the error response
|
|---|
| 310 | * to the backend, because we need to process
|
|---|
| 311 | * all unlock elements before
|
|---|
| 312 | */
|
|---|
| 313 | invalid = true;
|
|---|
| 314 | break;
|
|---|
| 315 | }
|
|---|
| 316 | tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
|
|---|
| 317 | return tevent_req_post(req, ev);
|
|---|
| 318 | }
|
|---|
| 319 |
|
|---|
| 320 | locks[i].smblctx = fsp->fnum;
|
|---|
| 321 | locks[i].offset = in_locks[i].offset;
|
|---|
| 322 | locks[i].count = in_locks[i].length;
|
|---|
| 323 |
|
|---|
| 324 | if (in_locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE) {
|
|---|
| 325 | locks[i].brltype = WRITE_LOCK;
|
|---|
| 326 | } else if (in_locks[i].flags & SMB2_LOCK_FLAG_SHARED) {
|
|---|
| 327 | locks[i].brltype = READ_LOCK;
|
|---|
| 328 | } else if (invalid) {
|
|---|
| 329 | /*
|
|---|
| 330 | * this is an invalid UNLOCK element
|
|---|
| 331 | * and the backend needs to test for
|
|---|
| 332 | * brltype != UNLOCK_LOCK and return
|
|---|
| 333 | * NT_STATUS_INVALID_PARAMER
|
|---|
| 334 | */
|
|---|
| 335 | locks[i].brltype = READ_LOCK;
|
|---|
| 336 | } else {
|
|---|
| 337 | locks[i].brltype = UNLOCK_LOCK;
|
|---|
| 338 | }
|
|---|
| 339 |
|
|---|
| 340 | DEBUG(10,("smbd_smb2_lock_send: index %d offset=%llu, count=%llu, "
|
|---|
| 341 | "smblctx = %llu type %d\n",
|
|---|
| 342 | i,
|
|---|
| 343 | (unsigned long long)locks[i].offset,
|
|---|
| 344 | (unsigned long long)locks[i].count,
|
|---|
| 345 | (unsigned long long)locks[i].smblctx,
|
|---|
| 346 | (int)locks[i].brltype ));
|
|---|
| 347 | }
|
|---|
| 348 |
|
|---|
| 349 | state->locks = locks;
|
|---|
| 350 | state->lock_count = in_lock_count;
|
|---|
| 351 |
|
|---|
| 352 | if (isunlock) {
|
|---|
| 353 | status = smbd_do_locking(smb1req, fsp,
|
|---|
| 354 | 0,
|
|---|
| 355 | timeout,
|
|---|
| 356 | in_lock_count,
|
|---|
| 357 | locks,
|
|---|
| 358 | 0,
|
|---|
| 359 | NULL,
|
|---|
| 360 | &async);
|
|---|
| 361 | } else {
|
|---|
| 362 | status = smbd_do_locking(smb1req, fsp,
|
|---|
| 363 | 0,
|
|---|
| 364 | timeout,
|
|---|
| 365 | 0,
|
|---|
| 366 | NULL,
|
|---|
| 367 | in_lock_count,
|
|---|
| 368 | locks,
|
|---|
| 369 | &async);
|
|---|
| 370 | }
|
|---|
| 371 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 372 | if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
|
|---|
| 373 | status = NT_STATUS_LOCK_NOT_GRANTED;
|
|---|
| 374 | }
|
|---|
| 375 | tevent_req_nterror(req, status);
|
|---|
| 376 | return tevent_req_post(req, ev);
|
|---|
| 377 | }
|
|---|
| 378 |
|
|---|
| 379 | if (async) {
|
|---|
| 380 | return req;
|
|---|
| 381 | }
|
|---|
| 382 |
|
|---|
| 383 | tevent_req_done(req);
|
|---|
| 384 | return tevent_req_post(req, ev);
|
|---|
| 385 | }
|
|---|
| 386 |
|
|---|
| 387 | static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req)
|
|---|
| 388 | {
|
|---|
| 389 | NTSTATUS status;
|
|---|
| 390 |
|
|---|
| 391 | if (tevent_req_is_nterror(req, &status)) {
|
|---|
| 392 | tevent_req_received(req);
|
|---|
| 393 | return status;
|
|---|
| 394 | }
|
|---|
| 395 |
|
|---|
| 396 | tevent_req_received(req);
|
|---|
| 397 | return NT_STATUS_OK;
|
|---|
| 398 | }
|
|---|
| 399 |
|
|---|
| 400 | /****************************************************************
|
|---|
| 401 | Cancel an outstanding blocking lock request.
|
|---|
| 402 | *****************************************************************/
|
|---|
| 403 |
|
|---|
| 404 | static bool smbd_smb2_lock_cancel(struct tevent_req *req)
|
|---|
| 405 | {
|
|---|
| 406 | struct smbd_smb2_request *smb2req = NULL;
|
|---|
| 407 | struct smbd_smb2_lock_state *state = tevent_req_data(req,
|
|---|
| 408 | struct smbd_smb2_lock_state);
|
|---|
| 409 | if (!state) {
|
|---|
| 410 | return false;
|
|---|
| 411 | }
|
|---|
| 412 |
|
|---|
| 413 | if (!state->smb2req) {
|
|---|
| 414 | return false;
|
|---|
| 415 | }
|
|---|
| 416 |
|
|---|
| 417 | smb2req = state->smb2req;
|
|---|
| 418 | smb2req->cancelled = true;
|
|---|
| 419 |
|
|---|
| 420 | tevent_req_done(req);
|
|---|
| 421 | return true;
|
|---|
| 422 | }
|
|---|
| 423 |
|
|---|
| 424 | /****************************************************************
|
|---|
| 425 | Got a message saying someone unlocked a file. Re-schedule all
|
|---|
| 426 | blocking lock requests as we don't know if anything overlapped.
|
|---|
| 427 | *****************************************************************/
|
|---|
| 428 |
|
|---|
| 429 | static void received_unlock_msg(struct messaging_context *msg,
|
|---|
| 430 | void *private_data,
|
|---|
| 431 | uint32_t msg_type,
|
|---|
| 432 | struct server_id server_id,
|
|---|
| 433 | DATA_BLOB *data)
|
|---|
| 434 | {
|
|---|
| 435 | struct smbd_server_connection *sconn;
|
|---|
| 436 |
|
|---|
| 437 | DEBUG(10,("received_unlock_msg (SMB2)\n"));
|
|---|
| 438 |
|
|---|
| 439 | sconn = msg_ctx_to_sconn(msg);
|
|---|
| 440 | if (sconn == NULL) {
|
|---|
| 441 | DEBUG(1, ("could not find sconn\n"));
|
|---|
| 442 | return;
|
|---|
| 443 | }
|
|---|
| 444 | process_blocking_lock_queue_smb2(sconn, timeval_current());
|
|---|
| 445 | }
|
|---|
| 446 |
|
|---|
| 447 | /****************************************************************
|
|---|
| 448 | Function to get the blr on a pending record.
|
|---|
| 449 | *****************************************************************/
|
|---|
| 450 |
|
|---|
| 451 | struct blocking_lock_record *get_pending_smb2req_blr(struct smbd_smb2_request *smb2req)
|
|---|
| 452 | {
|
|---|
| 453 | struct smbd_smb2_lock_state *state = NULL;
|
|---|
| 454 | const uint8_t *inhdr;
|
|---|
| 455 |
|
|---|
| 456 | if (!smb2req) {
|
|---|
| 457 | return NULL;
|
|---|
| 458 | }
|
|---|
| 459 | if (smb2req->subreq == NULL) {
|
|---|
| 460 | return NULL;
|
|---|
| 461 | }
|
|---|
| 462 | if (!tevent_req_is_in_progress(smb2req->subreq)) {
|
|---|
| 463 | return NULL;
|
|---|
| 464 | }
|
|---|
| 465 | inhdr = (const uint8_t *)smb2req->in.vector[smb2req->current_idx].iov_base;
|
|---|
| 466 | if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_LOCK) {
|
|---|
| 467 | return NULL;
|
|---|
| 468 | }
|
|---|
| 469 | state = tevent_req_data(smb2req->subreq,
|
|---|
| 470 | struct smbd_smb2_lock_state);
|
|---|
| 471 | if (!state) {
|
|---|
| 472 | return NULL;
|
|---|
| 473 | }
|
|---|
| 474 | return state->blr;
|
|---|
| 475 | }
|
|---|
| 476 | /****************************************************************
|
|---|
| 477 | Set up the next brl timeout.
|
|---|
| 478 | *****************************************************************/
|
|---|
| 479 |
|
|---|
| 480 | static bool recalc_smb2_brl_timeout(struct smbd_server_connection *sconn)
|
|---|
| 481 | {
|
|---|
| 482 | struct smbd_smb2_request *smb2req;
|
|---|
| 483 | struct timeval next_timeout = timeval_zero();
|
|---|
| 484 | int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5);
|
|---|
| 485 |
|
|---|
| 486 | TALLOC_FREE(sconn->smb2.locks.brl_timeout);
|
|---|
| 487 |
|
|---|
| 488 | for (smb2req = sconn->smb2.requests; smb2req; smb2req = smb2req->next) {
|
|---|
| 489 | struct blocking_lock_record *blr =
|
|---|
| 490 | get_pending_smb2req_blr(smb2req);
|
|---|
| 491 | if (!blr) {
|
|---|
| 492 | continue;
|
|---|
| 493 | }
|
|---|
| 494 | if (timeval_is_zero(&blr->expire_time)) {
|
|---|
| 495 | /*
|
|---|
| 496 | * If we're blocked on pid 0xFFFFFFFFFFFFFFFFLL this is
|
|---|
| 497 | * a POSIX lock, so calculate a timeout of
|
|---|
| 498 | * 10 seconds into the future.
|
|---|
| 499 | */
|
|---|
| 500 | if (blr->blocking_smblctx == 0xFFFFFFFFFFFFFFFFLL) {
|
|---|
| 501 | struct timeval psx_to = timeval_current_ofs(10, 0);
|
|---|
| 502 | next_timeout = timeval_brl_min(&next_timeout, &psx_to);
|
|---|
| 503 | }
|
|---|
| 504 |
|
|---|
| 505 | continue;
|
|---|
| 506 | }
|
|---|
| 507 |
|
|---|
| 508 | next_timeout = timeval_brl_min(&next_timeout, &blr->expire_time);
|
|---|
| 509 | }
|
|---|
| 510 |
|
|---|
| 511 | if (timeval_is_zero(&next_timeout)) {
|
|---|
| 512 | DEBUG(10, ("recalc_smb2_brl_timeout:Next "
|
|---|
| 513 | "timeout = Infinite.\n"));
|
|---|
| 514 | return true;
|
|---|
| 515 | }
|
|---|
| 516 |
|
|---|
| 517 | /*
|
|---|
| 518 | * To account for unclean shutdowns by clients we need a
|
|---|
| 519 | * maximum timeout that we use for checking pending locks. If
|
|---|
| 520 | * we have any pending locks at all, then check if the pending
|
|---|
| 521 | * lock can continue at least every brl:recalctime seconds
|
|---|
| 522 | * (default 5 seconds).
|
|---|
| 523 | *
|
|---|
| 524 | * This saves us needing to do a message_send_all() in the
|
|---|
| 525 | * SIGCHLD handler in the parent daemon. That
|
|---|
| 526 | * message_send_all() caused O(n^2) work to be done when IP
|
|---|
| 527 | * failovers happened in clustered Samba, which could make the
|
|---|
| 528 | * entire system unusable for many minutes.
|
|---|
| 529 | */
|
|---|
| 530 |
|
|---|
| 531 | if (max_brl_timeout > 0) {
|
|---|
| 532 | struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0);
|
|---|
| 533 | next_timeout = timeval_brl_min(&next_timeout, &min_to);
|
|---|
| 534 | }
|
|---|
| 535 |
|
|---|
| 536 | if (DEBUGLVL(10)) {
|
|---|
| 537 | struct timeval cur, from_now;
|
|---|
| 538 |
|
|---|
| 539 | cur = timeval_current();
|
|---|
| 540 | from_now = timeval_until(&cur, &next_timeout);
|
|---|
| 541 | DEBUG(10, ("recalc_smb2_brl_timeout: Next "
|
|---|
| 542 | "timeout = %d.%d seconds from now.\n",
|
|---|
| 543 | (int)from_now.tv_sec, (int)from_now.tv_usec));
|
|---|
| 544 | }
|
|---|
| 545 |
|
|---|
| 546 | sconn->smb2.locks.brl_timeout = event_add_timed(
|
|---|
| 547 | smbd_event_context(),
|
|---|
| 548 | NULL,
|
|---|
| 549 | next_timeout,
|
|---|
| 550 | brl_timeout_fn,
|
|---|
| 551 | NULL);
|
|---|
| 552 | if (!sconn->smb2.locks.brl_timeout) {
|
|---|
| 553 | return false;
|
|---|
| 554 | }
|
|---|
| 555 | return true;
|
|---|
| 556 | }
|
|---|
| 557 |
|
|---|
| 558 | /****************************************************************
|
|---|
| 559 | Get an SMB2 lock reqeust to go async. lock_timeout should
|
|---|
| 560 | always be -1 here.
|
|---|
| 561 | *****************************************************************/
|
|---|
| 562 |
|
|---|
| 563 | bool push_blocking_lock_request_smb2( struct byte_range_lock *br_lck,
|
|---|
| 564 | struct smb_request *smb1req,
|
|---|
| 565 | files_struct *fsp,
|
|---|
| 566 | int lock_timeout,
|
|---|
| 567 | int lock_num,
|
|---|
| 568 | uint64_t smblctx,
|
|---|
| 569 | enum brl_type lock_type,
|
|---|
| 570 | enum brl_flavour lock_flav,
|
|---|
| 571 | uint64_t offset,
|
|---|
| 572 | uint64_t count,
|
|---|
| 573 | uint64_t blocking_smblctx)
|
|---|
| 574 | {
|
|---|
| 575 | struct smbd_server_connection *sconn = smb1req->sconn;
|
|---|
| 576 | struct smbd_smb2_request *smb2req = smb1req->smb2req;
|
|---|
| 577 | struct tevent_req *req = NULL;
|
|---|
| 578 | struct smbd_smb2_lock_state *state = NULL;
|
|---|
| 579 | struct blocking_lock_record *blr = NULL;
|
|---|
| 580 | NTSTATUS status = NT_STATUS_OK;
|
|---|
| 581 |
|
|---|
| 582 | if (!smb2req) {
|
|---|
| 583 | return false;
|
|---|
| 584 | }
|
|---|
| 585 | req = smb2req->subreq;
|
|---|
| 586 | if (!req) {
|
|---|
| 587 | return false;
|
|---|
| 588 | }
|
|---|
| 589 | if (!tevent_req_is_in_progress(smb2req->subreq)) {
|
|---|
| 590 | return false;
|
|---|
| 591 | }
|
|---|
| 592 | state = tevent_req_data(req, struct smbd_smb2_lock_state);
|
|---|
| 593 | if (!state) {
|
|---|
| 594 | return false;
|
|---|
| 595 | }
|
|---|
| 596 |
|
|---|
| 597 | blr = talloc_zero(state, struct blocking_lock_record);
|
|---|
| 598 | if (!blr) {
|
|---|
| 599 | return false;
|
|---|
| 600 | }
|
|---|
| 601 | blr->fsp = fsp;
|
|---|
| 602 |
|
|---|
| 603 | if (lock_timeout == -1) {
|
|---|
| 604 | blr->expire_time.tv_sec = 0;
|
|---|
| 605 | blr->expire_time.tv_usec = 0; /* Never expire. */
|
|---|
| 606 | } else {
|
|---|
| 607 | blr->expire_time = timeval_current_ofs(
|
|---|
| 608 | lock_timeout/1000,
|
|---|
| 609 | (lock_timeout % 1000) * 1000);
|
|---|
| 610 | }
|
|---|
| 611 |
|
|---|
| 612 | blr->lock_num = lock_num;
|
|---|
| 613 | blr->smblctx = smblctx;
|
|---|
| 614 | blr->blocking_smblctx = blocking_smblctx;
|
|---|
| 615 | blr->lock_flav = lock_flav;
|
|---|
| 616 | blr->lock_type = lock_type;
|
|---|
| 617 | blr->offset = offset;
|
|---|
| 618 | blr->count = count;
|
|---|
| 619 |
|
|---|
| 620 | /* Specific brl_lock() implementations can fill this in. */
|
|---|
| 621 | blr->blr_private = NULL;
|
|---|
| 622 |
|
|---|
| 623 | /* Add a pending lock record for this. */
|
|---|
| 624 | status = brl_lock(sconn->msg_ctx,
|
|---|
| 625 | br_lck,
|
|---|
| 626 | smblctx,
|
|---|
| 627 | sconn_server_id(sconn),
|
|---|
| 628 | offset,
|
|---|
| 629 | count,
|
|---|
| 630 | lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
|
|---|
| 631 | blr->lock_flav,
|
|---|
| 632 | true,
|
|---|
| 633 | NULL,
|
|---|
| 634 | blr);
|
|---|
| 635 |
|
|---|
| 636 | if (!NT_STATUS_IS_OK(status)) {
|
|---|
| 637 | DEBUG(0,("push_blocking_lock_request_smb2: "
|
|---|
| 638 | "failed to add PENDING_LOCK record.\n"));
|
|---|
| 639 | TALLOC_FREE(blr);
|
|---|
| 640 | return false;
|
|---|
| 641 | }
|
|---|
| 642 | state->blr = blr;
|
|---|
| 643 |
|
|---|
| 644 | DEBUG(10,("push_blocking_lock_request_smb2: file %s timeout %d\n",
|
|---|
| 645 | fsp_str_dbg(fsp),
|
|---|
| 646 | lock_timeout ));
|
|---|
| 647 |
|
|---|
| 648 | recalc_smb2_brl_timeout(sconn);
|
|---|
| 649 |
|
|---|
| 650 | /* Ensure we'll receive messages when this is unlocked. */
|
|---|
| 651 | if (!sconn->smb2.locks.blocking_lock_unlock_state) {
|
|---|
| 652 | messaging_register(sconn->msg_ctx, NULL,
|
|---|
| 653 | MSG_SMB_UNLOCK, received_unlock_msg);
|
|---|
| 654 | sconn->smb2.locks.blocking_lock_unlock_state = true;
|
|---|
| 655 | }
|
|---|
| 656 |
|
|---|
| 657 | /* allow this request to be canceled */
|
|---|
| 658 | tevent_req_set_cancel_fn(req, smbd_smb2_lock_cancel);
|
|---|
| 659 |
|
|---|
| 660 | return true;
|
|---|
| 661 | }
|
|---|
| 662 |
|
|---|
| 663 | /****************************************************************
|
|---|
| 664 | Remove a pending lock record under lock.
|
|---|
| 665 | *****************************************************************/
|
|---|
| 666 |
|
|---|
| 667 | static void remove_pending_lock(struct smbd_smb2_lock_state *state,
|
|---|
| 668 | struct blocking_lock_record *blr)
|
|---|
| 669 | {
|
|---|
| 670 | int i;
|
|---|
| 671 | struct byte_range_lock *br_lck = brl_get_locks(
|
|---|
| 672 | state, blr->fsp);
|
|---|
| 673 |
|
|---|
| 674 | DEBUG(10, ("remove_pending_lock: BLR = %p\n", blr));
|
|---|
| 675 |
|
|---|
| 676 | if (br_lck) {
|
|---|
| 677 | brl_lock_cancel(br_lck,
|
|---|
| 678 | blr->smblctx,
|
|---|
| 679 | sconn_server_id(blr->fsp->conn->sconn),
|
|---|
| 680 | blr->offset,
|
|---|
| 681 | blr->count,
|
|---|
| 682 | blr->lock_flav,
|
|---|
| 683 | blr);
|
|---|
| 684 | TALLOC_FREE(br_lck);
|
|---|
| 685 | }
|
|---|
| 686 |
|
|---|
| 687 | /* Remove the locks we already got. */
|
|---|
| 688 |
|
|---|
| 689 | for(i = blr->lock_num - 1; i >= 0; i--) {
|
|---|
| 690 | struct smbd_lock_element *e = &state->locks[i];
|
|---|
| 691 |
|
|---|
| 692 | do_unlock(blr->fsp->conn->sconn->msg_ctx,
|
|---|
| 693 | blr->fsp,
|
|---|
| 694 | e->smblctx,
|
|---|
| 695 | e->count,
|
|---|
| 696 | e->offset,
|
|---|
| 697 | WINDOWS_LOCK);
|
|---|
| 698 | }
|
|---|
| 699 | }
|
|---|
| 700 |
|
|---|
| 701 | /****************************************************************
|
|---|
| 702 | Re-proccess a blocking lock request.
|
|---|
| 703 | This is equivalent to process_lockingX() inside smbd/blocking.c
|
|---|
| 704 | *****************************************************************/
|
|---|
| 705 |
|
|---|
| 706 | static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req,
|
|---|
| 707 | struct timeval tv_curr)
|
|---|
| 708 | {
|
|---|
| 709 | NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
|
|---|
| 710 | struct blocking_lock_record *blr = NULL;
|
|---|
| 711 | struct smbd_smb2_lock_state *state = NULL;
|
|---|
| 712 | files_struct *fsp = NULL;
|
|---|
| 713 |
|
|---|
| 714 | if (!smb2req->subreq) {
|
|---|
| 715 | return;
|
|---|
| 716 | }
|
|---|
| 717 | state = tevent_req_data(smb2req->subreq, struct smbd_smb2_lock_state);
|
|---|
| 718 | if (!state) {
|
|---|
| 719 | return;
|
|---|
| 720 | }
|
|---|
| 721 |
|
|---|
| 722 | blr = state->blr;
|
|---|
| 723 | fsp = blr->fsp;
|
|---|
| 724 |
|
|---|
| 725 | /* Try and finish off getting all the outstanding locks. */
|
|---|
| 726 |
|
|---|
| 727 | for (; blr->lock_num < state->lock_count; blr->lock_num++) {
|
|---|
| 728 | struct byte_range_lock *br_lck = NULL;
|
|---|
| 729 | struct smbd_lock_element *e = &state->locks[blr->lock_num];
|
|---|
| 730 |
|
|---|
| 731 | br_lck = do_lock(fsp->conn->sconn->msg_ctx,
|
|---|
| 732 | fsp,
|
|---|
| 733 | e->smblctx,
|
|---|
| 734 | e->count,
|
|---|
| 735 | e->offset,
|
|---|
| 736 | e->brltype,
|
|---|
| 737 | WINDOWS_LOCK,
|
|---|
| 738 | true,
|
|---|
| 739 | &status,
|
|---|
| 740 | &blr->blocking_smblctx,
|
|---|
| 741 | blr);
|
|---|
| 742 |
|
|---|
| 743 | TALLOC_FREE(br_lck);
|
|---|
| 744 |
|
|---|
| 745 | if (NT_STATUS_IS_ERR(status)) {
|
|---|
| 746 | break;
|
|---|
| 747 | }
|
|---|
| 748 | }
|
|---|
| 749 |
|
|---|
| 750 | if(blr->lock_num == state->lock_count) {
|
|---|
| 751 | /*
|
|---|
| 752 | * Success - we got all the locks.
|
|---|
| 753 | */
|
|---|
| 754 |
|
|---|
| 755 | DEBUG(3,("reprocess_blocked_smb2_lock SUCCESS file = %s, "
|
|---|
| 756 | "fnum=%d num_locks=%d\n",
|
|---|
| 757 | fsp_str_dbg(fsp),
|
|---|
| 758 | fsp->fnum,
|
|---|
| 759 | (int)state->lock_count));
|
|---|
| 760 |
|
|---|
| 761 | tevent_req_done(smb2req->subreq);
|
|---|
| 762 | return;
|
|---|
| 763 | }
|
|---|
| 764 |
|
|---|
| 765 | if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
|
|---|
| 766 | !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
|
|---|
| 767 | /*
|
|---|
| 768 | * We have other than a "can't get lock"
|
|---|
| 769 | * error. Return an error.
|
|---|
| 770 | */
|
|---|
| 771 | remove_pending_lock(state, blr);
|
|---|
| 772 | tevent_req_nterror(smb2req->subreq, status);
|
|---|
| 773 | return;
|
|---|
| 774 | }
|
|---|
| 775 |
|
|---|
| 776 | /*
|
|---|
| 777 | * We couldn't get the locks for this record on the list.
|
|---|
| 778 | * If the time has expired, return a lock error.
|
|---|
| 779 | */
|
|---|
| 780 |
|
|---|
| 781 | if (!timeval_is_zero(&blr->expire_time) &&
|
|---|
| 782 | timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
|
|---|
| 783 | remove_pending_lock(state, blr);
|
|---|
| 784 | tevent_req_nterror(smb2req->subreq, NT_STATUS_LOCK_NOT_GRANTED);
|
|---|
| 785 | return;
|
|---|
| 786 | }
|
|---|
| 787 |
|
|---|
| 788 | /*
|
|---|
| 789 | * Still can't get all the locks - keep waiting.
|
|---|
| 790 | */
|
|---|
| 791 |
|
|---|
| 792 | DEBUG(10,("reprocess_blocked_smb2_lock: only got %d locks of %d needed "
|
|---|
| 793 | "for file %s, fnum = %d. Still waiting....\n",
|
|---|
| 794 | (int)blr->lock_num,
|
|---|
| 795 | (int)state->lock_count,
|
|---|
| 796 | fsp_str_dbg(fsp),
|
|---|
| 797 | (int)fsp->fnum));
|
|---|
| 798 |
|
|---|
| 799 | return;
|
|---|
| 800 |
|
|---|
| 801 | }
|
|---|
| 802 |
|
|---|
| 803 | /****************************************************************
|
|---|
| 804 | Attempt to proccess all outstanding blocking locks pending on
|
|---|
| 805 | the request queue.
|
|---|
| 806 | *****************************************************************/
|
|---|
| 807 |
|
|---|
| 808 | void process_blocking_lock_queue_smb2(
|
|---|
| 809 | struct smbd_server_connection *sconn, struct timeval tv_curr)
|
|---|
| 810 | {
|
|---|
| 811 | struct smbd_smb2_request *smb2req, *nextreq;
|
|---|
| 812 |
|
|---|
| 813 | for (smb2req = sconn->smb2.requests; smb2req; smb2req = nextreq) {
|
|---|
| 814 | const uint8_t *inhdr;
|
|---|
| 815 |
|
|---|
| 816 | nextreq = smb2req->next;
|
|---|
| 817 |
|
|---|
| 818 | if (smb2req->subreq == NULL) {
|
|---|
| 819 | /* This message has been processed. */
|
|---|
| 820 | continue;
|
|---|
| 821 | }
|
|---|
| 822 | if (!tevent_req_is_in_progress(smb2req->subreq)) {
|
|---|
| 823 | /* This message has been processed. */
|
|---|
| 824 | continue;
|
|---|
| 825 | }
|
|---|
| 826 |
|
|---|
| 827 | inhdr = (const uint8_t *)smb2req->in.vector[smb2req->current_idx].iov_base;
|
|---|
| 828 | if (SVAL(inhdr, SMB2_HDR_OPCODE) == SMB2_OP_LOCK) {
|
|---|
| 829 | reprocess_blocked_smb2_lock(smb2req, tv_curr);
|
|---|
| 830 | }
|
|---|
| 831 | }
|
|---|
| 832 |
|
|---|
| 833 | recalc_smb2_brl_timeout(sconn);
|
|---|
| 834 | }
|
|---|
| 835 |
|
|---|
| 836 | /****************************************************************************
|
|---|
| 837 | Remove any locks on this fd. Called from file_close().
|
|---|
| 838 | ****************************************************************************/
|
|---|
| 839 |
|
|---|
| 840 | void cancel_pending_lock_requests_by_fid_smb2(files_struct *fsp,
|
|---|
| 841 | struct byte_range_lock *br_lck,
|
|---|
| 842 | enum file_close_type close_type)
|
|---|
| 843 | {
|
|---|
| 844 | struct smbd_server_connection *sconn = fsp->conn->sconn;
|
|---|
| 845 | struct smbd_smb2_request *smb2req, *nextreq;
|
|---|
| 846 |
|
|---|
| 847 | for (smb2req = sconn->smb2.requests; smb2req; smb2req = nextreq) {
|
|---|
| 848 | struct smbd_smb2_lock_state *state = NULL;
|
|---|
| 849 | files_struct *fsp_curr = NULL;
|
|---|
| 850 | int i = smb2req->current_idx;
|
|---|
| 851 | struct blocking_lock_record *blr = NULL;
|
|---|
| 852 | const uint8_t *inhdr;
|
|---|
| 853 |
|
|---|
| 854 | nextreq = smb2req->next;
|
|---|
| 855 |
|
|---|
| 856 | if (smb2req->subreq == NULL) {
|
|---|
| 857 | /* This message has been processed. */
|
|---|
| 858 | continue;
|
|---|
| 859 | }
|
|---|
| 860 | if (!tevent_req_is_in_progress(smb2req->subreq)) {
|
|---|
| 861 | /* This message has been processed. */
|
|---|
| 862 | continue;
|
|---|
| 863 | }
|
|---|
| 864 |
|
|---|
| 865 | inhdr = (const uint8_t *)smb2req->in.vector[i].iov_base;
|
|---|
| 866 | if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_LOCK) {
|
|---|
| 867 | /* Not a lock call. */
|
|---|
| 868 | continue;
|
|---|
| 869 | }
|
|---|
| 870 |
|
|---|
| 871 | state = tevent_req_data(smb2req->subreq,
|
|---|
| 872 | struct smbd_smb2_lock_state);
|
|---|
| 873 | if (!state) {
|
|---|
| 874 | /* Strange - is this even possible ? */
|
|---|
| 875 | continue;
|
|---|
| 876 | }
|
|---|
| 877 |
|
|---|
| 878 | fsp_curr = smb2req->compat_chain_fsp;
|
|---|
| 879 | if (fsp_curr == NULL) {
|
|---|
| 880 | /* Strange - is this even possible ? */
|
|---|
| 881 | continue;
|
|---|
| 882 | }
|
|---|
| 883 |
|
|---|
| 884 | if (fsp_curr != fsp) {
|
|---|
| 885 | /* It's not our fid */
|
|---|
| 886 | continue;
|
|---|
| 887 | }
|
|---|
| 888 |
|
|---|
| 889 | blr = state->blr;
|
|---|
| 890 |
|
|---|
| 891 | /* Remove the entries from the lock db. */
|
|---|
| 892 | brl_lock_cancel(br_lck,
|
|---|
| 893 | blr->smblctx,
|
|---|
| 894 | sconn_server_id(sconn),
|
|---|
| 895 | blr->offset,
|
|---|
| 896 | blr->count,
|
|---|
| 897 | blr->lock_flav,
|
|---|
| 898 | blr);
|
|---|
| 899 |
|
|---|
| 900 | /* Finally end the request. */
|
|---|
| 901 | if (close_type == SHUTDOWN_CLOSE) {
|
|---|
| 902 | tevent_req_done(smb2req->subreq);
|
|---|
| 903 | } else {
|
|---|
| 904 | tevent_req_nterror(smb2req->subreq,
|
|---|
| 905 | NT_STATUS_RANGE_NOT_LOCKED);
|
|---|
| 906 | }
|
|---|
| 907 | }
|
|---|
| 908 | }
|
|---|