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