Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Locking functions
4 : Copyright (C) Andrew Tridgell 1992-2000
5 : Copyright (C) Jeremy Allison 1992-2006
6 : Copyright (C) Volker Lendecke 2005
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 :
21 : Revision History:
22 :
23 : 12 aug 96: Erik.Devriendt@te6.siemens.be
24 : added support for shared memory implementation of share mode locking
25 :
26 : May 1997. Jeremy Allison (jallison@whistle.com). Modified share mode
27 : locking to deal with multiple share modes per open file.
28 :
29 : September 1997. Jeremy Allison (jallison@whistle.com). Added oplock
30 : support.
31 :
32 : rewritten completely to use new tdb code. Tridge, Dec '99
33 :
34 : Added POSIX locking support. Jeremy Allison (jeremy@valinux.com), Apr. 2000.
35 : Added Unix Extensions POSIX locking support. Jeremy Allison Mar 2006.
36 : */
37 :
38 : #include "includes.h"
39 : #include "lib/util/time_basic.h"
40 : #include "system/filesys.h"
41 : #include "lib/util/server_id.h"
42 : #include "share_mode_lock.h"
43 : #include "share_mode_lock_private.h"
44 : #include "locking/proto.h"
45 : #include "smbd/globals.h"
46 : #include "dbwrap/dbwrap.h"
47 : #include "dbwrap/dbwrap_open.h"
48 : #include "../libcli/security/security.h"
49 : #include "serverid.h"
50 : #include "messages.h"
51 : #include "util_tdb.h"
52 : #include "../librpc/gen_ndr/ndr_open_files.h"
53 : #include "librpc/gen_ndr/ndr_file_id.h"
54 : #include "librpc/gen_ndr/ndr_leases_db.h"
55 : #include "locking/leases_db.h"
56 :
57 : #undef DBGC_CLASS
58 : #define DBGC_CLASS DBGC_LOCKING
59 :
60 : #define NO_LOCKING_COUNT (-1)
61 :
62 : /****************************************************************************
63 : Debugging aids :-).
64 : ****************************************************************************/
65 :
66 0 : const char *lock_type_name(enum brl_type lock_type)
67 : {
68 0 : switch (lock_type) {
69 0 : case READ_LOCK:
70 0 : return "READ";
71 0 : case WRITE_LOCK:
72 0 : return "WRITE";
73 0 : default:
74 0 : return "other";
75 : }
76 : }
77 :
78 0 : const char *lock_flav_name(enum brl_flavour lock_flav)
79 : {
80 0 : return (lock_flav == WINDOWS_LOCK) ? "WINDOWS_LOCK" : "POSIX_LOCK";
81 : }
82 :
83 : /****************************************************************************
84 : Utility function called to see if a file region is locked.
85 : Called in the read/write codepath.
86 : ****************************************************************************/
87 :
88 796 : void init_strict_lock_struct(files_struct *fsp,
89 : uint64_t smblctx,
90 : br_off start,
91 : br_off size,
92 : enum brl_type lock_type,
93 : enum brl_flavour lock_flav,
94 : struct lock_struct *plock)
95 : {
96 796 : SMB_ASSERT(lock_type == READ_LOCK || lock_type == WRITE_LOCK);
97 :
98 796 : plock->context.smblctx = smblctx;
99 796 : plock->context.tid = fsp->conn->cnum;
100 796 : plock->context.pid = messaging_server_id(fsp->conn->sconn->msg_ctx);
101 796 : plock->start = start;
102 796 : plock->size = size;
103 796 : plock->fnum = fsp->fnum;
104 796 : plock->lock_type = lock_type;
105 796 : plock->lock_flav = lp_posix_cifsu_locktype(fsp);
106 796 : }
107 :
108 792 : bool strict_lock_check_default(files_struct *fsp, struct lock_struct *plock)
109 : {
110 : struct byte_range_lock *br_lck;
111 792 : int strict_locking = lp_strict_locking(fsp->conn->params);
112 792 : bool ret = False;
113 :
114 792 : if (plock->size == 0) {
115 0 : return True;
116 : }
117 :
118 792 : if (!lp_locking(fsp->conn->params) || !strict_locking) {
119 0 : return True;
120 : }
121 :
122 792 : if (strict_locking == Auto) {
123 792 : uint32_t lease_type = fsp_lease_type(fsp);
124 :
125 792 : if ((lease_type & SMB2_LEASE_READ) &&
126 0 : (plock->lock_type == READ_LOCK))
127 : {
128 0 : DBG_DEBUG("optimisation - read lease on file %s\n",
129 : fsp_str_dbg(fsp));
130 0 : return true;
131 : }
132 :
133 792 : if ((lease_type & SMB2_LEASE_WRITE) &&
134 0 : (plock->lock_type == WRITE_LOCK))
135 : {
136 0 : DBG_DEBUG("optimisation - write lease on file %s\n",
137 : fsp_str_dbg(fsp));
138 0 : return true;
139 : }
140 : }
141 :
142 792 : br_lck = brl_get_locks_readonly(fsp);
143 792 : if (!br_lck) {
144 0 : return true;
145 : }
146 792 : ret = brl_locktest(br_lck, plock);
147 :
148 792 : if (!ret) {
149 : /*
150 : * We got a lock conflict. Retry with rw locks to enable
151 : * autocleanup. This is the slow path anyway.
152 : */
153 0 : br_lck = brl_get_locks(talloc_tos(), fsp);
154 0 : if (br_lck == NULL) {
155 0 : return true;
156 : }
157 0 : ret = brl_locktest(br_lck, plock);
158 0 : TALLOC_FREE(br_lck);
159 : }
160 :
161 792 : DEBUG(10, ("strict_lock_default: flavour = %s brl start=%ju "
162 : "len=%ju %s for fnum %ju file %s\n",
163 : lock_flav_name(plock->lock_flav),
164 : (uintmax_t)plock->start, (uintmax_t)plock->size,
165 : ret ? "unlocked" : "locked",
166 : (uintmax_t)plock->fnum, fsp_str_dbg(fsp)));
167 :
168 792 : return ret;
169 : }
170 :
171 : /****************************************************************************
172 : Find out if a lock could be granted - return who is blocking us if we can't.
173 : ****************************************************************************/
174 :
175 0 : NTSTATUS query_lock(files_struct *fsp,
176 : uint64_t *psmblctx,
177 : uint64_t *pcount,
178 : uint64_t *poffset,
179 : enum brl_type *plock_type,
180 : enum brl_flavour lock_flav)
181 : {
182 0 : struct byte_range_lock *br_lck = NULL;
183 :
184 0 : if (!fsp->fsp_flags.can_lock) {
185 0 : return fsp->fsp_flags.is_directory ?
186 0 : NT_STATUS_INVALID_DEVICE_REQUEST :
187 : NT_STATUS_INVALID_HANDLE;
188 : }
189 :
190 0 : if (!lp_locking(fsp->conn->params)) {
191 0 : return NT_STATUS_OK;
192 : }
193 :
194 0 : br_lck = brl_get_locks_readonly(fsp);
195 0 : if (!br_lck) {
196 0 : return NT_STATUS_NO_MEMORY;
197 : }
198 :
199 0 : return brl_lockquery(br_lck,
200 : psmblctx,
201 0 : messaging_server_id(fsp->conn->sconn->msg_ctx),
202 : poffset,
203 : pcount,
204 : plock_type,
205 : lock_flav);
206 : }
207 :
208 5 : static void increment_current_lock_count(files_struct *fsp,
209 : enum brl_flavour lock_flav)
210 : {
211 8 : if (lock_flav == WINDOWS_LOCK &&
212 5 : fsp->current_lock_count != NO_LOCKING_COUNT) {
213 : /* blocking ie. pending, locks also count here,
214 : * as this is an efficiency counter to avoid checking
215 : * the lock db. on close. JRA. */
216 :
217 5 : fsp->current_lock_count++;
218 : } else {
219 : /* Notice that this has had a POSIX lock request.
220 : * We can't count locks after this so forget them.
221 : */
222 0 : fsp->current_lock_count = NO_LOCKING_COUNT;
223 : }
224 5 : }
225 :
226 4 : static void decrement_current_lock_count(files_struct *fsp,
227 : enum brl_flavour lock_flav)
228 : {
229 6 : if (lock_flav == WINDOWS_LOCK &&
230 4 : fsp->current_lock_count != NO_LOCKING_COUNT) {
231 4 : SMB_ASSERT(fsp->current_lock_count > 0);
232 4 : fsp->current_lock_count--;
233 : }
234 4 : }
235 :
236 : /****************************************************************************
237 : Utility function called by locking requests.
238 : ****************************************************************************/
239 :
240 : struct do_lock_state {
241 : struct files_struct *fsp;
242 : TALLOC_CTX *req_mem_ctx;
243 : const struct GUID *req_guid;
244 : uint64_t smblctx;
245 : uint64_t count;
246 : uint64_t offset;
247 : enum brl_type lock_type;
248 : enum brl_flavour lock_flav;
249 :
250 : struct server_id blocker_pid;
251 : uint64_t blocker_smblctx;
252 : NTSTATUS status;
253 : };
254 :
255 5 : static void do_lock_fn(
256 : const uint8_t *buf,
257 : size_t buflen,
258 : bool *modified_dependent,
259 : void *private_data)
260 : {
261 5 : struct do_lock_state *state = private_data;
262 5 : struct byte_range_lock *br_lck = NULL;
263 :
264 8 : br_lck = brl_get_locks_for_locking(talloc_tos(),
265 5 : state->fsp,
266 : state->req_mem_ctx,
267 : state->req_guid);
268 5 : if (br_lck == NULL) {
269 0 : state->status = NT_STATUS_NO_MEMORY;
270 0 : return;
271 : }
272 :
273 8 : state->status = brl_lock(
274 : br_lck,
275 : state->smblctx,
276 5 : messaging_server_id(state->fsp->conn->sconn->msg_ctx),
277 : state->offset,
278 : state->count,
279 : state->lock_type,
280 : state->lock_flav,
281 : &state->blocker_pid,
282 : &state->blocker_smblctx);
283 :
284 5 : TALLOC_FREE(br_lck);
285 : }
286 :
287 5 : NTSTATUS do_lock(files_struct *fsp,
288 : TALLOC_CTX *req_mem_ctx,
289 : const struct GUID *req_guid,
290 : uint64_t smblctx,
291 : uint64_t count,
292 : uint64_t offset,
293 : enum brl_type lock_type,
294 : enum brl_flavour lock_flav,
295 : struct server_id *pblocker_pid,
296 : uint64_t *psmblctx)
297 : {
298 5 : struct do_lock_state state = {
299 : .fsp = fsp,
300 : .req_mem_ctx = req_mem_ctx,
301 : .req_guid = req_guid,
302 : .smblctx = smblctx,
303 : .count = count,
304 : .offset = offset,
305 : .lock_type = lock_type,
306 : .lock_flav = lock_flav,
307 : };
308 : NTSTATUS status;
309 :
310 : /* silently return ok on print files as we don't do locking there */
311 5 : if (fsp->print_file) {
312 0 : return NT_STATUS_OK;
313 : }
314 :
315 5 : if (!fsp->fsp_flags.can_lock) {
316 0 : if (fsp->fsp_flags.is_directory) {
317 0 : return NT_STATUS_INVALID_DEVICE_REQUEST;
318 : }
319 0 : return NT_STATUS_INVALID_HANDLE;
320 : }
321 :
322 5 : if (!lp_locking(fsp->conn->params)) {
323 0 : return NT_STATUS_OK;
324 : }
325 :
326 : /* NOTE! 0 byte long ranges ARE allowed and should be stored */
327 :
328 5 : DBG_DEBUG("lock flavour %s lock type %s start=%"PRIu64" len=%"PRIu64" "
329 : "requested for %s file %s\n",
330 : lock_flav_name(lock_flav),
331 : lock_type_name(lock_type),
332 : offset,
333 : count,
334 : fsp_fnum_dbg(fsp),
335 : fsp_str_dbg(fsp));
336 :
337 5 : status = share_mode_do_locked(fsp->file_id, do_lock_fn, &state);
338 5 : if (!NT_STATUS_IS_OK(status)) {
339 0 : DBG_DEBUG("share_mode_do_locked returned %s\n",
340 : nt_errstr(status));
341 0 : return status;
342 : }
343 :
344 5 : if (psmblctx != NULL) {
345 5 : *psmblctx = state.blocker_smblctx;
346 : }
347 5 : if (pblocker_pid != NULL) {
348 5 : *pblocker_pid = state.blocker_pid;
349 : }
350 :
351 5 : DBG_DEBUG("returning status=%s\n", nt_errstr(state.status));
352 :
353 5 : increment_current_lock_count(fsp, lock_flav);
354 :
355 5 : return state.status;
356 : }
357 :
358 : /****************************************************************************
359 : Utility function called by unlocking requests.
360 : ****************************************************************************/
361 :
362 8 : NTSTATUS do_unlock(files_struct *fsp,
363 : uint64_t smblctx,
364 : uint64_t count,
365 : uint64_t offset,
366 : enum brl_flavour lock_flav)
367 : {
368 8 : bool ok = False;
369 8 : struct byte_range_lock *br_lck = NULL;
370 :
371 8 : if (!fsp->fsp_flags.can_lock) {
372 0 : return fsp->fsp_flags.is_directory ?
373 0 : NT_STATUS_INVALID_DEVICE_REQUEST :
374 : NT_STATUS_INVALID_HANDLE;
375 : }
376 :
377 8 : if (!lp_locking(fsp->conn->params)) {
378 0 : return NT_STATUS_OK;
379 : }
380 :
381 8 : DBG_DEBUG("unlock start=%"PRIu64" len=%"PRIu64" requested for %s file "
382 : "%s\n",
383 : offset,
384 : count,
385 : fsp_fnum_dbg(fsp),
386 : fsp_str_dbg(fsp));
387 :
388 8 : br_lck = brl_get_locks(talloc_tos(), fsp);
389 8 : if (!br_lck) {
390 0 : return NT_STATUS_NO_MEMORY;
391 : }
392 :
393 8 : ok = brl_unlock(br_lck,
394 : smblctx,
395 8 : messaging_server_id(fsp->conn->sconn->msg_ctx),
396 : offset,
397 : count,
398 : lock_flav);
399 :
400 8 : TALLOC_FREE(br_lck);
401 :
402 8 : if (!ok) {
403 4 : DEBUG(10,("do_unlock: returning ERRlock.\n" ));
404 4 : return NT_STATUS_RANGE_NOT_LOCKED;
405 : }
406 :
407 4 : decrement_current_lock_count(fsp, lock_flav);
408 4 : return NT_STATUS_OK;
409 : }
410 :
411 : /****************************************************************************
412 : Remove any locks on this fd. Called from file_close().
413 : ****************************************************************************/
414 :
415 1850 : void locking_close_file(files_struct *fsp,
416 : enum file_close_type close_type)
417 : {
418 : struct byte_range_lock *br_lck;
419 :
420 1850 : if (!lp_locking(fsp->conn->params)) {
421 0 : return;
422 : }
423 :
424 : /* If we have no outstanding locks or pending
425 : * locks then we don't need to look in the lock db.
426 : */
427 :
428 1850 : if (fsp->current_lock_count == 0) {
429 1849 : return;
430 : }
431 :
432 1 : br_lck = brl_get_locks(talloc_tos(),fsp);
433 :
434 1 : if (br_lck) {
435 : /*
436 : * Unlocks must trigger dbwrap_watch watchers,
437 : * normally in smbd_do_unlocking. Here it's done
438 : * implictly, we're closing the file and thus remove a
439 : * share mode. This will wake the waiters.
440 : */
441 1 : brl_close_fnum(br_lck);
442 1 : TALLOC_FREE(br_lck);
443 : }
444 : }
445 :
446 : /*******************************************************************
447 : Print out a share mode.
448 : ********************************************************************/
449 :
450 0 : char *share_mode_str(TALLOC_CTX *ctx, int num,
451 : const struct file_id *id,
452 : const struct share_mode_entry *e)
453 : {
454 : struct server_id_buf tmp;
455 : struct file_id_buf ftmp;
456 :
457 0 : return talloc_asprintf(ctx, "share_mode_entry[%d]: "
458 : "pid = %s, share_access = 0x%x, private_options = 0x%x, "
459 : "access_mask = 0x%x, mid = 0x%llx, type= 0x%x, gen_id = %llu, "
460 : "uid = %u, flags = %u, file_id %s, name_hash = 0x%x",
461 : num,
462 : server_id_str_buf(e->pid, &tmp),
463 0 : e->share_access, e->private_options,
464 0 : e->access_mask, (unsigned long long)e->op_mid,
465 0 : e->op_type, (unsigned long long)e->share_file_id,
466 0 : (unsigned int)e->uid, (unsigned int)e->flags,
467 : file_id_str_buf(*id, &ftmp),
468 0 : (unsigned int)e->name_hash);
469 : }
470 :
471 : struct rename_share_filename_state {
472 : struct share_mode_lock *lck;
473 : struct messaging_context *msg_ctx;
474 : struct server_id self;
475 : uint32_t orig_name_hash;
476 : uint32_t new_name_hash;
477 : struct file_rename_message msg;
478 : };
479 :
480 0 : static bool rename_lease_fn(struct share_mode_entry *e,
481 : void *private_data)
482 : {
483 0 : struct rename_share_filename_state *state = private_data;
484 0 : struct share_mode_data *d = state->lck->data;
485 : NTSTATUS status;
486 :
487 0 : status = leases_db_rename(&e->client_guid,
488 0 : &e->lease_key,
489 0 : &d->id,
490 : d->servicepath,
491 : d->base_name,
492 : d->stream_name);
493 :
494 0 : if (!NT_STATUS_IS_OK(status)) {
495 : /* Any error recovery possible here ? */
496 0 : DBG_WARNING("Failed to rename lease key for "
497 : "renamed file %s:%s. %s\n",
498 : d->base_name,
499 : d->stream_name,
500 : nt_errstr(status));
501 : }
502 :
503 0 : return false;
504 : }
505 :
506 : /*******************************************************************
507 : Sets the service name and filename for rename.
508 : At this point we emit "file renamed" messages to all
509 : process id's that have this file open.
510 : Based on an initial code idea from SATOH Fumiyasu <fumiya@samba.gr.jp>
511 : ********************************************************************/
512 :
513 20 : static bool rename_share_filename_fn(
514 : struct share_mode_entry *e,
515 : bool *modified,
516 : void *private_data)
517 : {
518 20 : struct rename_share_filename_state *state = private_data;
519 : DATA_BLOB blob;
520 : enum ndr_err_code ndr_err;
521 : bool ok;
522 :
523 : /*
524 : * If this is a hardlink to the inode with a different name,
525 : * skip this.
526 : */
527 20 : if (e->name_hash != state->orig_name_hash) {
528 0 : return false;
529 : }
530 20 : e->name_hash = state->new_name_hash;
531 20 : *modified = true;
532 :
533 20 : ok = server_id_equal(&e->pid, &state->self);
534 20 : if (ok) {
535 20 : return false;
536 : }
537 :
538 0 : state->msg.share_file_id = e->share_file_id;
539 :
540 0 : ndr_err = ndr_push_struct_blob(
541 : &blob,
542 : talloc_tos(),
543 0 : &state->msg,
544 : (ndr_push_flags_fn_t)ndr_push_file_rename_message);
545 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
546 0 : DBG_DEBUG("ndr_push_file_rename_message failed: %s\n",
547 : ndr_errstr(ndr_err));
548 0 : return false;
549 : }
550 0 : if (DEBUGLEVEL >= 10) {
551 : struct server_id_buf tmp;
552 0 : DBG_DEBUG("sending rename message to %s\n",
553 : server_id_str_buf(e->pid, &tmp));
554 0 : NDR_PRINT_DEBUG(file_rename_message, &state->msg);
555 : }
556 :
557 0 : messaging_send(state->msg_ctx, e->pid, MSG_SMB_FILE_RENAME, &blob);
558 :
559 0 : TALLOC_FREE(blob.data);
560 :
561 0 : return false;
562 : }
563 :
564 20 : bool rename_share_filename(struct messaging_context *msg_ctx,
565 : struct share_mode_lock *lck,
566 : struct file_id id,
567 : const char *servicepath,
568 : uint32_t orig_name_hash,
569 : uint32_t new_name_hash,
570 : const struct smb_filename *smb_fname_dst)
571 : {
572 50 : struct rename_share_filename_state state = {
573 : .lck = lck,
574 : .msg_ctx = msg_ctx,
575 10 : .self = messaging_server_id(msg_ctx),
576 : .orig_name_hash = orig_name_hash,
577 : .new_name_hash = new_name_hash,
578 : .msg.id = id,
579 : .msg.servicepath = servicepath,
580 20 : .msg.base_name = smb_fname_dst->base_name,
581 20 : .msg.stream_name = smb_fname_dst->stream_name,
582 : };
583 20 : struct share_mode_data *d = lck->data;
584 : bool ok;
585 :
586 20 : DEBUG(10, ("rename_share_filename: servicepath %s newname %s\n",
587 : servicepath, smb_fname_dst->base_name));
588 :
589 : /*
590 : * rename_internal_fsp() and rename_internals() add './' to
591 : * head of newname if newname does not contain a '/'.
592 : */
593 :
594 20 : if (strncmp(state.msg.base_name, "./", 2) == 0) {
595 0 : state.msg.base_name += 2;
596 : }
597 :
598 20 : d->servicepath = talloc_strdup(d, state.msg.servicepath);
599 20 : d->base_name = talloc_strdup(d, state.msg.base_name);
600 20 : d->stream_name = talloc_strdup(d, state.msg.stream_name);
601 30 : if ((d->servicepath == NULL) ||
602 30 : (d->base_name == NULL) ||
603 20 : ((state.msg.stream_name != NULL) && (d->stream_name == NULL))) {
604 0 : DBG_WARNING("talloc failed\n");
605 0 : return false;
606 : }
607 20 : d->modified = True;
608 :
609 20 : ok = share_mode_forall_entries(
610 : lck, rename_share_filename_fn, &state);
611 20 : if (!ok) {
612 0 : DBG_WARNING("share_mode_forall_entries failed\n");
613 : }
614 :
615 20 : ok = share_mode_forall_leases(lck, rename_lease_fn, &state);
616 20 : if (!ok) {
617 : /*
618 : * Ignore error here. Not sure what to do..
619 : */
620 0 : DBG_WARNING("share_mode_forall_leases failed\n");
621 : }
622 :
623 20 : return True;
624 : }
625 :
626 1826 : void get_file_infos(struct file_id id,
627 : uint32_t name_hash,
628 : bool *delete_on_close,
629 : struct timespec *write_time)
630 : {
631 : struct share_mode_lock *lck;
632 :
633 1826 : if (delete_on_close) {
634 910 : *delete_on_close = false;
635 : }
636 :
637 1826 : if (write_time) {
638 1826 : *write_time = make_omit_timespec();
639 : }
640 :
641 1826 : if (!(lck = fetch_share_mode_unlocked(talloc_tos(), id))) {
642 916 : return;
643 : }
644 :
645 910 : if (delete_on_close) {
646 910 : *delete_on_close = is_delete_on_close_set(lck, name_hash);
647 : }
648 :
649 910 : if (write_time) {
650 910 : *write_time = get_share_mode_write_time(lck);
651 : }
652 :
653 910 : TALLOC_FREE(lck);
654 : }
655 :
656 0 : bool is_valid_share_mode_entry(const struct share_mode_entry *e)
657 : {
658 0 : int num_props = 0;
659 :
660 0 : if (e->stale) {
661 0 : return false;
662 : }
663 :
664 0 : num_props += ((e->op_type == NO_OPLOCK) ? 1 : 0);
665 0 : num_props += (EXCLUSIVE_OPLOCK_TYPE(e->op_type) ? 1 : 0);
666 0 : num_props += (LEVEL_II_OPLOCK_TYPE(e->op_type) ? 1 : 0);
667 0 : num_props += (e->op_type == LEASE_OPLOCK);
668 :
669 0 : if ((num_props > 1) && serverid_exists(&e->pid)) {
670 0 : smb_panic("Invalid share mode entry");
671 : }
672 0 : return (num_props != 0);
673 : }
674 :
675 : struct find_lease_ref_state {
676 : const struct GUID *client_guid;
677 : const struct smb2_lease_key *lease_key;
678 : bool found_same;
679 : };
680 :
681 0 : static bool find_lease_ref_fn(
682 : struct share_mode_entry *e,
683 : bool *modified,
684 : void *private_data)
685 : {
686 0 : struct find_lease_ref_state *state = private_data;
687 :
688 0 : if (e->stale) {
689 0 : return false;
690 : }
691 0 : if (e->op_type != LEASE_OPLOCK) {
692 0 : return false;
693 : }
694 :
695 0 : state->found_same = smb2_lease_equal(
696 0 : &e->client_guid,
697 0 : &e->lease_key,
698 : state->client_guid,
699 : state->lease_key);
700 : /*
701 : * If we found a lease reference, look no further (i.e. return true)
702 : */
703 0 : return state->found_same;
704 : }
705 :
706 0 : NTSTATUS remove_lease_if_stale(struct share_mode_lock *lck,
707 : const struct GUID *client_guid,
708 : const struct smb2_lease_key *lease_key)
709 : {
710 0 : struct find_lease_ref_state state = {
711 : .client_guid = client_guid, .lease_key = lease_key,
712 : };
713 0 : struct share_mode_data *d = lck->data;
714 : NTSTATUS status;
715 : bool ok;
716 :
717 0 : ok = share_mode_forall_entries(lck, find_lease_ref_fn, &state);
718 0 : if (!ok) {
719 0 : return NT_STATUS_INTERNAL_ERROR;
720 : }
721 :
722 0 : if (state.found_same) {
723 0 : return NT_STATUS_RESOURCE_IN_USE;
724 : }
725 :
726 0 : status = leases_db_del(client_guid, lease_key, &d->id);
727 0 : if (!NT_STATUS_IS_OK(status)) {
728 0 : int level = DBGLVL_DEBUG;
729 :
730 0 : if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
731 0 : level = DBGLVL_ERR;
732 : }
733 0 : DBG_PREFIX(level, ("leases_db_del failed: %s\n",
734 : nt_errstr(status)));
735 : }
736 0 : return status;
737 : }
738 :
739 55 : bool share_entry_stale_pid(struct share_mode_entry *e)
740 : {
741 : struct server_id_buf buf;
742 : bool exists;
743 :
744 55 : if (e->stale) {
745 0 : return true;
746 : }
747 :
748 55 : exists = serverid_exists(&e->pid);
749 55 : if (exists) {
750 55 : DBG_DEBUG("PID %s still exists\n",
751 : server_id_str_buf(e->pid, &buf));
752 55 : return false;
753 : }
754 :
755 0 : DBG_DEBUG("PID %s does not exist anymore\n",
756 : server_id_str_buf(e->pid, &buf));
757 :
758 0 : e->stale = true;
759 :
760 0 : return true;
761 : }
762 :
763 : /****************************************************************************
764 : Adds a delete on close token.
765 : ****************************************************************************/
766 :
767 1368 : static bool add_delete_on_close_token(struct share_mode_data *d,
768 : uint32_t name_hash,
769 : const struct security_token *nt_tok,
770 : const struct security_unix_token *tok)
771 : {
772 : struct delete_token *tmp, *dtl;
773 :
774 1368 : tmp = talloc_realloc(d, d->delete_tokens, struct delete_token,
775 : d->num_delete_tokens+1);
776 1368 : if (tmp == NULL) {
777 0 : return false;
778 : }
779 1368 : d->delete_tokens = tmp;
780 1368 : dtl = &d->delete_tokens[d->num_delete_tokens];
781 :
782 1368 : dtl->name_hash = name_hash;
783 1368 : dtl->delete_nt_token = dup_nt_token(d->delete_tokens, nt_tok);
784 1368 : if (dtl->delete_nt_token == NULL) {
785 0 : return false;
786 : }
787 1368 : dtl->delete_token = copy_unix_token(d->delete_tokens, tok);
788 1368 : if (dtl->delete_token == NULL) {
789 0 : return false;
790 : }
791 1368 : d->num_delete_tokens += 1;
792 1368 : d->modified = true;
793 1368 : return true;
794 : }
795 :
796 560 : void reset_delete_on_close_lck(files_struct *fsp,
797 : struct share_mode_lock *lck)
798 : {
799 560 : struct share_mode_data *d = lck->data;
800 : uint32_t i;
801 :
802 1120 : for (i=0; i<d->num_delete_tokens; i++) {
803 560 : struct delete_token *dt = &d->delete_tokens[i];
804 :
805 560 : if (dt->name_hash == fsp->name_hash) {
806 560 : d->modified = true;
807 :
808 : /* Delete this entry. */
809 560 : TALLOC_FREE(dt->delete_nt_token);
810 560 : TALLOC_FREE(dt->delete_token);
811 560 : *dt = d->delete_tokens[d->num_delete_tokens-1];
812 560 : d->num_delete_tokens -= 1;
813 : }
814 : }
815 560 : }
816 :
817 : struct set_delete_on_close_state {
818 : struct messaging_context *msg_ctx;
819 : DATA_BLOB blob;
820 : };
821 :
822 1369 : static bool set_delete_on_close_fn(
823 : struct share_mode_entry *e,
824 : bool *modified,
825 : void *private_data)
826 : {
827 1369 : struct set_delete_on_close_state *state = private_data;
828 : NTSTATUS status;
829 :
830 1369 : status = messaging_send(
831 : state->msg_ctx,
832 : e->pid,
833 : MSG_SMB_NOTIFY_CANCEL_DELETED,
834 1369 : &state->blob);
835 :
836 1369 : if (!NT_STATUS_IS_OK(status)) {
837 : struct server_id_buf tmp;
838 0 : DBG_DEBUG("messaging_send to %s returned %s\n",
839 : server_id_str_buf(e->pid, &tmp),
840 : nt_errstr(status));
841 : }
842 :
843 1369 : return false;
844 : }
845 :
846 : /****************************************************************************
847 : Sets the delete on close flag over all share modes on this file.
848 : Modify the share mode entry for all files open
849 : on this device and inode to tell other smbds we have
850 : changed the delete on close flag. This will be noticed
851 : in the close code, the last closer will delete the file
852 : if flag is set.
853 : This makes a copy of any struct security_unix_token into the
854 : lck entry. This function is used when the lock is already granted.
855 : ****************************************************************************/
856 :
857 1368 : void set_delete_on_close_lck(files_struct *fsp,
858 : struct share_mode_lock *lck,
859 : const struct security_token *nt_tok,
860 : const struct security_unix_token *tok)
861 : {
862 1368 : struct share_mode_data *d = lck->data;
863 2597 : struct set_delete_on_close_state state = {
864 1368 : .msg_ctx = fsp->conn->sconn->msg_ctx
865 : };
866 : uint32_t i;
867 : bool ret;
868 : enum ndr_err_code ndr_err;
869 :
870 1368 : SMB_ASSERT(nt_tok != NULL);
871 1368 : SMB_ASSERT(tok != NULL);
872 :
873 1368 : for (i=0; i<d->num_delete_tokens; i++) {
874 0 : struct delete_token *dt = &d->delete_tokens[i];
875 0 : if (dt->name_hash == fsp->name_hash) {
876 0 : d->modified = true;
877 :
878 : /* Replace this token with the given tok. */
879 0 : TALLOC_FREE(dt->delete_nt_token);
880 0 : dt->delete_nt_token = dup_nt_token(dt, nt_tok);
881 0 : SMB_ASSERT(dt->delete_nt_token != NULL);
882 0 : TALLOC_FREE(dt->delete_token);
883 0 : dt->delete_token = copy_unix_token(dt, tok);
884 0 : SMB_ASSERT(dt->delete_token != NULL);
885 :
886 0 : return;
887 : }
888 : }
889 :
890 1368 : ret = add_delete_on_close_token(lck->data, fsp->name_hash, nt_tok, tok);
891 1368 : SMB_ASSERT(ret);
892 :
893 1368 : ndr_err = ndr_push_struct_blob(
894 : &state.blob,
895 : talloc_tos(),
896 1368 : &fsp->file_id,
897 : (ndr_push_flags_fn_t)ndr_push_file_id);
898 1368 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
899 0 : DEBUG(10, ("ndr_push_file_id failed: %s\n",
900 : ndr_errstr(ndr_err)));
901 : }
902 :
903 1368 : ret = share_mode_forall_entries(
904 : lck, set_delete_on_close_fn, &state);
905 1368 : if (!ret) {
906 0 : DBG_DEBUG("share_mode_forall_entries failed\n");
907 : }
908 :
909 1368 : TALLOC_FREE(state.blob.data);
910 : }
911 :
912 802 : bool set_delete_on_close(files_struct *fsp, bool delete_on_close,
913 : const struct security_token *nt_tok,
914 : const struct security_unix_token *tok)
915 : {
916 : struct share_mode_lock *lck;
917 :
918 802 : DEBUG(10,("set_delete_on_close: %s delete on close flag for "
919 : "%s, file %s\n",
920 : delete_on_close ? "Adding" : "Removing", fsp_fnum_dbg(fsp),
921 : fsp_str_dbg(fsp)));
922 :
923 802 : lck = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
924 802 : if (lck == NULL) {
925 0 : return False;
926 : }
927 :
928 802 : if (delete_on_close) {
929 802 : set_delete_on_close_lck(fsp, lck, nt_tok, tok);
930 : } else {
931 0 : reset_delete_on_close_lck(fsp, lck);
932 : }
933 :
934 802 : if (fsp->fsp_flags.is_directory) {
935 798 : SMB_ASSERT(!is_ntfs_stream_smb_fname(fsp->fsp_name));
936 798 : send_stat_cache_delete_message(fsp->conn->sconn->msg_ctx,
937 798 : fsp->fsp_name->base_name);
938 : }
939 :
940 802 : TALLOC_FREE(lck);
941 :
942 802 : fsp->fsp_flags.delete_on_close = delete_on_close;
943 :
944 802 : return True;
945 : }
946 :
947 26188 : static struct delete_token *find_delete_on_close_token(
948 : struct share_mode_data *d, uint32_t name_hash)
949 : {
950 : uint32_t i;
951 :
952 26188 : DBG_DEBUG("name_hash = 0x%"PRIx32"\n", name_hash);
953 :
954 26188 : for (i=0; i<d->num_delete_tokens; i++) {
955 1929 : struct delete_token *dt = &d->delete_tokens[i];
956 :
957 1929 : DBG_DEBUG("dt->name_hash = 0x%"PRIx32"\n",
958 : dt->name_hash);
959 1929 : if (dt->name_hash == name_hash) {
960 1929 : return dt;
961 : }
962 : }
963 24259 : return NULL;
964 : }
965 :
966 : /****************************************************************************
967 : Return the NT token and UNIX token if there's a match. Return true if
968 : found, false if not.
969 : ****************************************************************************/
970 :
971 10776 : bool get_delete_on_close_token(struct share_mode_lock *lck,
972 : uint32_t name_hash,
973 : const struct security_token **pp_nt_tok,
974 : const struct security_unix_token **pp_tok)
975 : {
976 : struct delete_token *dt;
977 :
978 10776 : dt = find_delete_on_close_token(lck->data, name_hash);
979 10776 : if (dt == NULL) {
980 9408 : return false;
981 : }
982 1368 : *pp_nt_tok = dt->delete_nt_token;
983 1368 : *pp_tok = dt->delete_token;
984 1368 : return true;
985 : }
986 :
987 15412 : bool is_delete_on_close_set(struct share_mode_lock *lck, uint32_t name_hash)
988 : {
989 15412 : return find_delete_on_close_token(lck->data, name_hash) != NULL;
990 : }
991 :
992 1 : bool set_sticky_write_time(struct file_id fileid, struct timespec write_time)
993 : {
994 : struct share_mode_lock *lck;
995 : struct file_id_buf ftmp;
996 : struct timeval_buf tbuf;
997 1 : NTTIME nt = full_timespec_to_nt_time(&write_time);
998 :
999 1 : DBG_INFO("%s id=%s\n",
1000 : timespec_string_buf(&write_time, true, &tbuf),
1001 : file_id_str_buf(fileid, &ftmp));
1002 :
1003 1 : lck = get_existing_share_mode_lock(talloc_tos(), fileid);
1004 1 : if (lck == NULL) {
1005 0 : return False;
1006 : }
1007 :
1008 1 : if (lck->data->changed_write_time != nt) {
1009 1 : lck->data->modified = True;
1010 1 : lck->data->changed_write_time = nt;
1011 : }
1012 :
1013 1 : TALLOC_FREE(lck);
1014 1 : return True;
1015 : }
1016 :
1017 436 : bool set_write_time(struct file_id fileid, struct timespec write_time)
1018 : {
1019 : struct share_mode_lock *lck;
1020 : struct file_id_buf idbuf;
1021 : struct timeval_buf tbuf;
1022 436 : NTTIME nt = full_timespec_to_nt_time(&write_time);
1023 :
1024 436 : DBG_INFO("%s id=%s\n",
1025 : timespec_string_buf(&write_time, true, &tbuf),
1026 : file_id_str_buf(fileid, &idbuf));
1027 :
1028 436 : lck = get_existing_share_mode_lock(talloc_tos(), fileid);
1029 436 : if (lck == NULL) {
1030 0 : return False;
1031 : }
1032 :
1033 436 : if (lck->data->old_write_time != nt) {
1034 436 : lck->data->modified = True;
1035 436 : lck->data->old_write_time = nt;
1036 : }
1037 :
1038 436 : TALLOC_FREE(lck);
1039 436 : return True;
1040 : }
1041 :
1042 12976 : struct timespec get_share_mode_write_time(struct share_mode_lock *lck)
1043 : {
1044 12976 : struct share_mode_data *d = lck->data;
1045 :
1046 12976 : if (!null_nttime(d->changed_write_time)) {
1047 1 : return nt_time_to_full_timespec(d->changed_write_time);
1048 : }
1049 12975 : return nt_time_to_full_timespec(d->old_write_time);
1050 : }
1051 :
1052 : struct file_has_open_streams_state {
1053 : bool found_one;
1054 : };
1055 :
1056 21 : static bool file_has_open_streams_fn(
1057 : struct share_mode_entry *e,
1058 : bool *modified,
1059 : void *private_data)
1060 : {
1061 21 : struct file_has_open_streams_state *state = private_data;
1062 :
1063 21 : if ((e->private_options &
1064 : NTCREATEX_FLAG_STREAM_BASEOPEN) == 0) {
1065 21 : return false;
1066 : }
1067 :
1068 0 : if (share_entry_stale_pid(e)) {
1069 0 : return false;
1070 : }
1071 :
1072 0 : state->found_one = true;
1073 0 : return true;
1074 : }
1075 :
1076 21 : bool file_has_open_streams(files_struct *fsp)
1077 : {
1078 21 : struct file_has_open_streams_state state = { .found_one = false };
1079 21 : struct share_mode_lock *lock = NULL;
1080 : bool ok;
1081 :
1082 21 : lock = get_existing_share_mode_lock(talloc_tos(), fsp->file_id);
1083 21 : if (lock == NULL) {
1084 0 : return false;
1085 : }
1086 :
1087 21 : ok = share_mode_forall_entries(
1088 : lock, file_has_open_streams_fn, &state);
1089 21 : TALLOC_FREE(lock);
1090 :
1091 21 : if (!ok) {
1092 0 : DBG_DEBUG("share_mode_forall_entries failed\n");
1093 0 : return false;
1094 : }
1095 21 : return state.found_one;
1096 : }
1097 :
1098 : /*
1099 : * Walk share mode entries, looking at every lease only once
1100 : */
1101 :
1102 : struct share_mode_forall_leases_state {
1103 : TALLOC_CTX *mem_ctx;
1104 : struct leases_db_key *leases;
1105 : bool (*fn)(struct share_mode_entry *e,
1106 : void *private_data);
1107 : void *private_data;
1108 : NTSTATUS status;
1109 : };
1110 :
1111 20 : static bool share_mode_forall_leases_fn(
1112 : struct share_mode_entry *e,
1113 : bool *modified,
1114 : void *private_data)
1115 : {
1116 20 : struct share_mode_forall_leases_state *state = private_data;
1117 20 : struct leases_db_key *leases = state->leases;
1118 : size_t i, num_leases;
1119 : bool stop;
1120 :
1121 20 : if (e->op_type != LEASE_OPLOCK) {
1122 20 : return false;
1123 : }
1124 :
1125 0 : num_leases = talloc_array_length(leases);
1126 :
1127 0 : for (i=0; i<num_leases; i++) {
1128 0 : struct leases_db_key *l = &leases[i];
1129 0 : bool same = smb2_lease_equal(
1130 0 : &e->client_guid,
1131 0 : &e->lease_key,
1132 0 : &l->client_guid,
1133 0 : &l->lease_key);
1134 0 : if (same) {
1135 0 : return false;
1136 : }
1137 : }
1138 :
1139 0 : leases = talloc_realloc(
1140 : state->mem_ctx,
1141 : leases,
1142 : struct leases_db_key,
1143 : num_leases+1);
1144 0 : if (leases == NULL) {
1145 0 : state->status = NT_STATUS_NO_MEMORY;
1146 0 : return true;
1147 : }
1148 0 : leases[num_leases] = (struct leases_db_key) {
1149 0 : .client_guid = e->client_guid,
1150 0 : .lease_key = e->lease_key,
1151 : };
1152 0 : state->leases = leases;
1153 :
1154 0 : stop = state->fn(e, state->private_data);
1155 0 : return stop;
1156 : }
1157 :
1158 20 : bool share_mode_forall_leases(
1159 : struct share_mode_lock *lck,
1160 : bool (*fn)(struct share_mode_entry *e,
1161 : void *private_data),
1162 : void *private_data)
1163 : {
1164 40 : struct share_mode_forall_leases_state state = {
1165 20 : .mem_ctx = talloc_tos(),
1166 : .fn = fn,
1167 : .private_data = private_data
1168 : };
1169 : bool ok;
1170 :
1171 20 : ok = share_mode_forall_entries(
1172 : lck, share_mode_forall_leases_fn, &state);
1173 20 : TALLOC_FREE(state.leases);
1174 20 : if (!ok) {
1175 0 : DBG_DEBUG("share_mode_forall_entries failed\n");
1176 0 : return false;
1177 : }
1178 :
1179 20 : if (!NT_STATUS_IS_OK(state.status)) {
1180 0 : DBG_DEBUG("share_mode_forall_leases_fn returned %s\n",
1181 : nt_errstr(state.status));
1182 0 : return false;
1183 : }
1184 :
1185 20 : return true;
1186 : }
|