s3/smbd: update some more DEBUG macros in smbd_smb2_create_send
[nivanova/samba-autobuild/.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->xconn,
143                                                          nt_errstr(error));
144                         return;
145                 }
146                 return;
147         }
148
149         outbody = smbd_smb2_generate_outbody(smb2req, 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->xconn,
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->xconn,
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         if (!isunlock && (in_lock_count > 1)) {
239
240                 /*
241                  * 3.3.5.14.2 says we SHOULD fail with INVALID_PARAMETER if we
242                  * have more than one lock and one of those is blocking.
243                  */
244
245                 for (i=0; i<in_lock_count; i++) {
246                         uint32_t flags = in_locks[i].flags;
247
248                         if ((flags & SMB2_LOCK_FLAG_FAIL_IMMEDIATELY) == 0) {
249                                 tevent_req_nterror(
250                                         req, NT_STATUS_INVALID_PARAMETER);
251                                 return tevent_req_post(req, ev);
252                         }
253                 }
254         }
255
256         for (i=0; i<in_lock_count; i++) {
257                 bool invalid = false;
258
259                 switch (in_locks[i].flags) {
260                 case SMB2_LOCK_FLAG_SHARED:
261                 case SMB2_LOCK_FLAG_EXCLUSIVE:
262                         if (isunlock) {
263                                 invalid = true;
264                                 break;
265                         }
266                         break;
267
268                 case SMB2_LOCK_FLAG_SHARED|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
269                 case SMB2_LOCK_FLAG_EXCLUSIVE|SMB2_LOCK_FLAG_FAIL_IMMEDIATELY:
270                         if (isunlock) {
271                                 invalid = true;
272                         }
273                         break;
274
275                 case SMB2_LOCK_FLAG_UNLOCK:
276                         if (!isunlock) {
277                                 tevent_req_nterror(req,
278                                                    NT_STATUS_INVALID_PARAMETER);
279                                 return tevent_req_post(req, ev);
280                         }
281                         break;
282
283                 default:
284                         if (isunlock) {
285                                 /*
286                                  * If the first element was a UNLOCK
287                                  * we need to defer the error response
288                                  * to the backend, because we need to process
289                                  * all unlock elements before
290                                  */
291                                 invalid = true;
292                                 break;
293                         }
294                         tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
295                         return tevent_req_post(req, ev);
296                 }
297
298                 locks[i].smblctx = fsp->op->global->open_persistent_id;
299                 locks[i].offset = in_locks[i].offset;
300                 locks[i].count  = in_locks[i].length;
301
302                 if (in_locks[i].flags & SMB2_LOCK_FLAG_EXCLUSIVE) {
303                         locks[i].brltype = WRITE_LOCK;
304                 } else if (in_locks[i].flags & SMB2_LOCK_FLAG_SHARED) {
305                         locks[i].brltype = READ_LOCK;
306                 } else if (invalid) {
307                         /*
308                          * this is an invalid UNLOCK element
309                          * and the backend needs to test for
310                          * brltype != UNLOCK_LOCK and return
311                          * NT_STATUS_INVALID_PARAMETER
312                          */
313                         locks[i].brltype = READ_LOCK;
314                 } else {
315                         locks[i].brltype = UNLOCK_LOCK;
316                 }
317
318                 DEBUG(10,("smbd_smb2_lock_send: index %d offset=%llu, count=%llu, "
319                         "smblctx = %llu type %d\n",
320                         i,
321                         (unsigned long long)locks[i].offset,
322                         (unsigned long long)locks[i].count,
323                         (unsigned long long)locks[i].smblctx,
324                         (int)locks[i].brltype ));
325         }
326
327         state->locks = locks;
328         state->lock_count = in_lock_count;
329
330         if (isunlock) {
331                 status = smbd_do_unlocking(smb1req, fsp,
332                                            in_lock_count, locks);
333                 async = false;
334         } else {
335                 status = smbd_do_locking(smb1req, fsp,
336                                          0,
337                                          timeout,
338                                          in_lock_count,
339                                          locks,
340                                          &async);
341         }
342         if (!NT_STATUS_IS_OK(status)) {
343                 if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_LOCK_CONFLICT)) {
344                        status = NT_STATUS_LOCK_NOT_GRANTED;
345                 }
346                 tevent_req_nterror(req, status);
347                 return tevent_req_post(req, ev);
348         }
349
350         if (async) {
351                 tevent_req_defer_callback(req, smb2req->sconn->ev_ctx);
352                 SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
353                 return req;
354         }
355
356         tevent_req_done(req);
357         return tevent_req_post(req, ev);
358 }
359
360 static NTSTATUS smbd_smb2_lock_recv(struct tevent_req *req)
361 {
362         NTSTATUS status;
363
364         if (tevent_req_is_nterror(req, &status)) {
365                 tevent_req_received(req);
366                 return status;
367         }
368
369         tevent_req_received(req);
370         return NT_STATUS_OK;
371 }
372
373 /****************************************************************
374  Cancel an outstanding blocking lock request.
375 *****************************************************************/
376
377 static bool smbd_smb2_lock_cancel(struct tevent_req *req)
378 {
379         struct smbd_smb2_request *smb2req = NULL;
380         struct smbd_smb2_lock_state *state = tevent_req_data(req,
381                                 struct smbd_smb2_lock_state);
382         if (!state) {
383                 return false;
384         }
385
386         if (!state->smb2req) {
387                 return false;
388         }
389
390         smb2req = state->smb2req;
391
392         remove_pending_lock(state, state->blr);
393
394         /*
395          * If the request is canceled because of logoff, tdis or close
396          * the status is NT_STATUS_RANGE_NOT_LOCKED instead of
397          * NT_STATUS_CANCELLED.
398          *
399          * Note that the close case is handled in
400          * cancel_pending_lock_requests_by_fid_smb2(SHUTDOWN_CLOSE)
401          * for now.
402          */
403         if (!NT_STATUS_IS_OK(smb2req->session->status)) {
404                 tevent_req_nterror(req, NT_STATUS_RANGE_NOT_LOCKED);
405                 return true;
406         }
407
408         if (!NT_STATUS_IS_OK(smb2req->tcon->status)) {
409                 tevent_req_nterror(req, NT_STATUS_RANGE_NOT_LOCKED);
410                 return true;
411         }
412
413         tevent_req_nterror(req, NT_STATUS_CANCELLED);
414         return true;
415 }
416
417 /****************************************************************
418  Got a message saying someone unlocked a file. Re-schedule all
419  blocking lock requests as we don't know if anything overlapped.
420 *****************************************************************/
421
422 static void received_unlock_msg(struct messaging_context *msg,
423                                 void *private_data,
424                                 uint32_t msg_type,
425                                 struct server_id server_id,
426                                 DATA_BLOB *data)
427 {
428         struct smbd_server_connection *sconn =
429                 talloc_get_type_abort(private_data,
430                 struct smbd_server_connection);
431
432         DEBUG(10,("received_unlock_msg (SMB2)\n"));
433
434         process_blocking_lock_queue_smb2(sconn, timeval_current());
435 }
436
437 /****************************************************************
438  Function to get the blr on a pending record.
439 *****************************************************************/
440
441 struct blocking_lock_record *get_pending_smb2req_blr(struct smbd_smb2_request *smb2req)
442 {
443         struct smbd_smb2_lock_state *state = NULL;
444         const uint8_t *inhdr;
445
446         if (!smb2req) {
447                 return NULL;
448         }
449         if (smb2req->subreq == NULL) {
450                 return NULL;
451         }
452         if (!tevent_req_is_in_progress(smb2req->subreq)) {
453                 return NULL;
454         }
455         inhdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
456         if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_LOCK) {
457                 return NULL;
458         }
459         state = tevent_req_data(smb2req->subreq,
460                         struct smbd_smb2_lock_state);
461         if (!state) {
462                 return NULL;
463         }
464         return state->blr;
465 }
466 /****************************************************************
467  Set up the next brl timeout.
468 *****************************************************************/
469
470 static bool recalc_smb2_brl_timeout(struct smbd_server_connection *sconn)
471 {
472         struct smbXsrv_connection *xconn = NULL;
473         struct timeval next_timeout = timeval_zero();
474         int max_brl_timeout = lp_parm_int(-1, "brl", "recalctime", 5);
475
476         TALLOC_FREE(sconn->smb2.locks.brl_timeout);
477
478         if (sconn->client != NULL) {
479                 xconn = sconn->client->connections;
480         }
481
482         for (; xconn != NULL; xconn = xconn->next) {
483                 struct smbd_smb2_request *smb2req, *nextreq;
484
485                 for (smb2req = xconn->smb2.requests; smb2req; smb2req = nextreq) {
486                         struct blocking_lock_record *blr =
487                                 get_pending_smb2req_blr(smb2req);
488
489                         nextreq = smb2req->next;
490
491                         if (blr == NULL) {
492                                 continue;
493                         }
494
495                         if (!timeval_is_zero(&blr->expire_time)) {
496                                 next_timeout = timeval_brl_min(&next_timeout,
497                                                         &blr->expire_time);
498                                 continue;
499                         }
500
501                         /*
502                          * If we're blocked on pid 0xFFFFFFFFFFFFFFFFLL this is
503                          * a POSIX lock, so calculate a timeout of
504                          * 10 seconds into the future.
505                          */
506                         if (blr->blocking_smblctx == 0xFFFFFFFFFFFFFFFFLL) {
507                                 struct timeval psx_to;
508
509                                 psx_to = timeval_current_ofs(10, 0);
510                                 next_timeout = timeval_brl_min(&next_timeout,
511                                                                &psx_to);
512                         }
513                 }
514         }
515
516         if (timeval_is_zero(&next_timeout)) {
517                 DEBUG(10, ("recalc_smb2_brl_timeout:Next "
518                         "timeout = Infinite.\n"));
519                 return true;
520         }
521
522         /*
523          * To account for unclean shutdowns by clients we need a
524          * maximum timeout that we use for checking pending locks. If
525          * we have any pending locks at all, then check if the pending
526          * lock can continue at least every brl:recalctime seconds
527          * (default 5 seconds).
528          *
529          * This saves us needing to do a message_send_all() in the
530          * SIGCHLD handler in the parent daemon. That
531          * message_send_all() caused O(n^2) work to be done when IP
532          * failovers happened in clustered Samba, which could make the
533          * entire system unusable for many minutes.
534          */
535
536         if (max_brl_timeout > 0) {
537                 struct timeval min_to = timeval_current_ofs(max_brl_timeout, 0);
538                 next_timeout = timeval_brl_min(&next_timeout, &min_to);
539         }
540
541         if (DEBUGLVL(10)) {
542                 struct timeval cur, from_now;
543
544                 cur = timeval_current();
545                 from_now = timeval_until(&cur, &next_timeout);
546                 DEBUG(10, ("recalc_smb2_brl_timeout: Next "
547                         "timeout = %d.%d seconds from now.\n",
548                         (int)from_now.tv_sec, (int)from_now.tv_usec));
549         }
550
551         sconn->smb2.locks.brl_timeout = tevent_add_timer(
552                                 sconn->ev_ctx,
553                                 NULL,
554                                 next_timeout,
555                                 brl_timeout_fn,
556                                 sconn);
557         if (!sconn->smb2.locks.brl_timeout) {
558                 return false;
559         }
560         return true;
561 }
562
563 /****************************************************************
564  Get an SMB2 lock request to go async. lock_timeout should
565  always be -1 here.
566 *****************************************************************/
567
568 bool push_blocking_lock_request_smb2( struct byte_range_lock *br_lck,
569                                 struct smb_request *smb1req,
570                                 files_struct *fsp,
571                                 int lock_timeout,
572                                 int lock_num,
573                                 uint64_t smblctx,
574                                 enum brl_type lock_type,
575                                 enum brl_flavour lock_flav,
576                                 uint64_t offset,
577                                 uint64_t count,
578                                 uint64_t blocking_smblctx)
579 {
580         struct smbd_server_connection *sconn = smb1req->sconn;
581         struct smbd_smb2_request *smb2req = smb1req->smb2req;
582         struct tevent_req *req = NULL;
583         struct smbd_smb2_lock_state *state = NULL;
584         struct blocking_lock_record *blr = NULL;
585         NTSTATUS status = NT_STATUS_OK;
586
587         if (!smb2req) {
588                 return false;
589         }
590         req = smb2req->subreq;
591         if (!req) {
592                 return false;
593         }
594         if (!tevent_req_is_in_progress(smb2req->subreq)) {
595                 return false;
596         }
597         state = tevent_req_data(req, struct smbd_smb2_lock_state);
598         if (!state) {
599                 return false;
600         }
601
602         blr = talloc_zero(state, struct blocking_lock_record);
603         if (!blr) {
604                 return false;
605         }
606         blr->fsp = fsp;
607
608         if (lock_timeout == -1) {
609                 blr->expire_time.tv_sec = 0;
610                 blr->expire_time.tv_usec = 0; /* Never expire. */
611         } else {
612                 blr->expire_time = timeval_current_ofs_msec(lock_timeout);
613         }
614
615         blr->lock_num = lock_num;
616         blr->smblctx = smblctx;
617         blr->blocking_smblctx = blocking_smblctx;
618         blr->lock_flav = lock_flav;
619         blr->lock_type = lock_type;
620         blr->offset = offset;
621         blr->count = count;
622
623         /* Specific brl_lock() implementations can fill this in. */
624         blr->blr_private = NULL;
625
626         /* Add a pending lock record for this. */
627         status = brl_lock(sconn->msg_ctx,
628                         br_lck,
629                         smblctx,
630                         messaging_server_id(sconn->msg_ctx),
631                         offset,
632                         count,
633                         lock_type == READ_LOCK ? PENDING_READ_LOCK : PENDING_WRITE_LOCK,
634                         blr->lock_flav,
635                         true,
636                         NULL);
637
638         if (!NT_STATUS_IS_OK(status)) {
639                 DEBUG(0,("push_blocking_lock_request_smb2: "
640                         "failed to add PENDING_LOCK record.\n"));
641                 TALLOC_FREE(blr);
642                 return false;
643         }
644         state->blr = blr;
645
646         DEBUG(10,("push_blocking_lock_request_smb2: file %s timeout %d\n",
647                 fsp_str_dbg(fsp),
648                 lock_timeout ));
649
650         recalc_smb2_brl_timeout(sconn);
651
652         /* Ensure we'll receive messages when this is unlocked. */
653         if (!sconn->smb2.locks.blocking_lock_unlock_state) {
654                 messaging_register(sconn->msg_ctx, sconn,
655                                 MSG_SMB_UNLOCK, received_unlock_msg);
656                 sconn->smb2.locks.blocking_lock_unlock_state = true;
657         }
658
659         /* allow this request to be canceled */
660         tevent_req_set_cancel_fn(req, smbd_smb2_lock_cancel);
661
662         return true;
663 }
664
665 /****************************************************************
666  Remove a pending lock record under lock.
667 *****************************************************************/
668
669 static void remove_pending_lock(struct smbd_smb2_lock_state *state,
670                         struct blocking_lock_record *blr)
671 {
672         struct byte_range_lock *br_lck = brl_get_locks(
673                                 state, blr->fsp);
674
675         DEBUG(10, ("remove_pending_lock: BLR = %p\n", blr));
676
677         if (br_lck) {
678                 brl_lock_cancel(br_lck,
679                                 blr->smblctx,
680                                 messaging_server_id(blr->fsp->conn->sconn->msg_ctx),
681                                 blr->offset,
682                                 blr->count,
683                                 blr->lock_flav);
684                 TALLOC_FREE(br_lck);
685         }
686 }
687
688 /****************************************************************
689  Re-proccess a blocking lock request.
690  This is equivalent to process_lockingX() inside smbd/blocking.c
691 *****************************************************************/
692
693 static void reprocess_blocked_smb2_lock(struct smbd_smb2_request *smb2req,
694                                 struct timeval tv_curr)
695 {
696         NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
697         struct blocking_lock_record *blr = NULL;
698         struct smbd_smb2_lock_state *state = NULL;
699         struct byte_range_lock *br_lck = NULL;
700         struct smbd_lock_element *e = NULL;
701         files_struct *fsp = NULL;
702
703         if (!smb2req->subreq) {
704                 return;
705         }
706         SMBPROFILE_IOBYTES_ASYNC_SET_BUSY(smb2req->profile);
707
708         state = tevent_req_data(smb2req->subreq, struct smbd_smb2_lock_state);
709         if (!state) {
710                 return;
711         }
712
713         blr = state->blr;
714         fsp = blr->fsp;
715
716         /* We can only have one blocked lock in SMB2. */
717         SMB_ASSERT(state->lock_count == 1);
718         SMB_ASSERT(blr->lock_num == 0);
719
720         /* Try and get the outstanding lock. */
721         e = &state->locks[blr->lock_num];
722
723         br_lck = do_lock(fsp->conn->sconn->msg_ctx,
724                         fsp,
725                         e->smblctx,
726                         e->count,
727                         e->offset,
728                         e->brltype,
729                         WINDOWS_LOCK,
730                         true,
731                         &status,
732                         &blr->blocking_smblctx);
733
734         TALLOC_FREE(br_lck);
735
736         if (NT_STATUS_IS_OK(status)) {
737                 /*
738                  * Success - we got the lock.
739                  */
740
741                 DEBUG(3,("reprocess_blocked_smb2_lock SUCCESS file = %s, "
742                         "%s, num_locks=%d\n",
743                         fsp_str_dbg(fsp),
744                         fsp_fnum_dbg(fsp),
745                         (int)state->lock_count));
746
747                 remove_pending_lock(state, blr);
748                 tevent_req_done(smb2req->subreq);
749                 return;
750         }
751
752         if (!NT_STATUS_EQUAL(status,NT_STATUS_LOCK_NOT_GRANTED) &&
753                         !NT_STATUS_EQUAL(status,NT_STATUS_FILE_LOCK_CONFLICT)) {
754                 /*
755                  * We have other than a "can't get lock"
756                  * error. Return an error.
757                  */
758                 remove_pending_lock(state, blr);
759                 tevent_req_nterror(smb2req->subreq, status);
760                 return;
761         }
762
763         /*
764          * We couldn't get the lock for this record.
765          * If the time has expired, return a lock error.
766          */
767
768         if (!timeval_is_zero(&blr->expire_time) &&
769                         timeval_compare(&blr->expire_time, &tv_curr) <= 0) {
770                 remove_pending_lock(state, blr);
771                 tevent_req_nterror(smb2req->subreq, NT_STATUS_LOCK_NOT_GRANTED);
772                 return;
773         }
774
775         /*
776          * Still can't get the lock - keep waiting.
777          */
778
779         DEBUG(10,("reprocess_blocked_smb2_lock: failed to get lock "
780                 "for file %s, %s. Still waiting....\n",
781                 fsp_str_dbg(fsp),
782                 fsp_fnum_dbg(fsp)));
783
784         SMBPROFILE_IOBYTES_ASYNC_SET_IDLE(smb2req->profile);
785         return;
786 }
787
788 /****************************************************************
789  Attempt to proccess all outstanding blocking locks pending on
790  the request queue.
791 *****************************************************************/
792
793 void process_blocking_lock_queue_smb2(
794         struct smbd_server_connection *sconn, struct timeval tv_curr)
795 {
796         struct smbXsrv_connection *xconn = NULL;
797
798         if (sconn != NULL && sconn->client != NULL) {
799                 xconn = sconn->client->connections;
800         }
801
802         for (; xconn != NULL; xconn = xconn->next) {
803                 struct smbd_smb2_request *smb2req, *nextreq;
804
805                 for (smb2req = xconn->smb2.requests; smb2req; smb2req = nextreq) {
806                         const uint8_t *inhdr;
807
808                         nextreq = smb2req->next;
809
810                         if (smb2req->subreq == NULL) {
811                                 /* This message has been processed. */
812                                 continue;
813                         }
814                         if (!tevent_req_is_in_progress(smb2req->subreq)) {
815                                 /* This message has been processed. */
816                                 continue;
817                         }
818
819                         inhdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
820                         if (SVAL(inhdr, SMB2_HDR_OPCODE) == SMB2_OP_LOCK) {
821                                 reprocess_blocked_smb2_lock(smb2req, tv_curr);
822                         }
823                 }
824         }
825
826         recalc_smb2_brl_timeout(sconn);
827 }
828
829 /****************************************************************************
830  Remove any locks on this fd. Called from file_close().
831 ****************************************************************************/
832
833 void cancel_pending_lock_requests_by_fid_smb2(files_struct *fsp,
834                         struct byte_range_lock *br_lck,
835                         enum file_close_type close_type)
836 {
837         struct smbd_server_connection *sconn = fsp->conn->sconn;
838         struct smbXsrv_connection *xconn = NULL;
839
840         if (sconn != NULL && sconn->client != NULL) {
841                 xconn = sconn->client->connections;
842         }
843
844         for (; xconn != NULL; xconn = xconn->next) {
845                 struct smbd_smb2_request *smb2req, *nextreq;
846
847                 for (smb2req = xconn->smb2.requests; smb2req; smb2req = nextreq) {
848                         struct smbd_smb2_lock_state *state = NULL;
849                         files_struct *fsp_curr = NULL;
850                         struct blocking_lock_record *blr = NULL;
851                         const uint8_t *inhdr;
852
853                         nextreq = smb2req->next;
854
855                         if (smb2req->subreq == NULL) {
856                                 /* This message has been processed. */
857                                 continue;
858                         }
859                         if (!tevent_req_is_in_progress(smb2req->subreq)) {
860                                 /* This message has been processed. */
861                                 continue;
862                         }
863
864                         inhdr = SMBD_SMB2_IN_HDR_PTR(smb2req);
865                         if (SVAL(inhdr, SMB2_HDR_OPCODE) != SMB2_OP_LOCK) {
866                                 /* Not a lock call. */
867                                 continue;
868                         }
869
870                         state = tevent_req_data(smb2req->subreq,
871                                         struct smbd_smb2_lock_state);
872                         if (!state) {
873                                 /* Strange - is this even possible ? */
874                                 continue;
875                         }
876
877                         fsp_curr = smb2req->compat_chain_fsp;
878                         if (fsp_curr == NULL) {
879                                 /* Strange - is this even possible ? */
880                                 continue;
881                         }
882
883                         if (fsp_curr != fsp) {
884                                 /* It's not our fid */
885                                 continue;
886                         }
887
888                         blr = state->blr;
889
890                         /* Remove the entries from the lock db. */
891                         brl_lock_cancel(br_lck,
892                                         blr->smblctx,
893                                         messaging_server_id(sconn->msg_ctx),
894                                         blr->offset,
895                                         blr->count,
896                                         blr->lock_flav);
897
898                         /* Finally end the request. */
899                         if (close_type == SHUTDOWN_CLOSE) {
900                                 tevent_req_done(smb2req->subreq);
901                         } else {
902                                 tevent_req_nterror(smb2req->subreq,
903                                         NT_STATUS_RANGE_NOT_LOCKED);
904                         }
905                 }
906         }
907 }