s3:libsmb/cliconnect: make use of ntlmssp_is_anonymous()
[Samba/gebeck_regimport.git] / source3 / smbd / notify_internal.c
blob6e6bdf7b0368294c9c60397c9976bb1ac34b6f14
1 /*
2 Unix SMB/CIFS implementation.
4 Copyright (C) Andrew Tridgell 2006
5 Copyright (C) Volker Lendecke 2012
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 this is the change notify database. It implements mechanisms for
23 storing current change notify waiters in a tdb, and checking if a
24 given event matches any of the stored notify waiiters.
27 #include "includes.h"
28 #include "system/filesys.h"
29 #include "librpc/gen_ndr/ndr_notify.h"
30 #include "dbwrap/dbwrap.h"
31 #include "dbwrap/dbwrap_open.h"
32 #include "dbwrap/dbwrap_tdb.h"
33 #include "smbd/smbd.h"
34 #include "messages.h"
35 #include "lib/tdb_wrap/tdb_wrap.h"
36 #include "util_tdb.h"
37 #include "lib/param/param.h"
38 #include "lib/dbwrap/dbwrap_cache.h"
39 #include "ctdb_srvids.h"
40 #include "ctdbd_conn.h"
41 #include "ctdb_conn.h"
42 #include "lib/util/tevent_unix.h"
44 struct notify_list {
45 struct notify_list *next, *prev;
46 const char *path;
47 void (*callback)(void *, const struct notify_event *);
48 void *private_data;
51 struct notify_context {
52 struct messaging_context *msg;
53 struct notify_list *list;
56 * The notify database is split up into two databases: One
57 * relatively static index db and the real notify db with the
58 * volatile entries.
62 * "db_notify" is indexed by pathname. Per record it stores an
63 * array of notify_db_entry structs. These represent the
64 * notify records as requested by the smb client. This
65 * database is always held locally, it is never clustered.
67 struct db_context *db_notify;
70 * "db_index" is indexed by pathname. The records are an array
71 * of VNNs which have any interest in notifies for this path
72 * name.
74 * In the non-clustered case this database is cached in RAM by
75 * means of db_cache_open, which maintains a cache per
76 * process. Cache consistency is maintained by the tdb
77 * sequence number.
79 * In the clustered case right now we can not use the tdb
80 * sequence number, but by means of read only records we
81 * should be able to avoid a lot of full migrations.
83 * In both cases, it is important to keep the update
84 * operations to db_index to a minimum. This is achieved by
85 * delayed deletion. When a db_notify is initially created,
86 * the db_index record is also created. When more notifies are
87 * add for a path, then only the db_notify record needs to be
88 * modified, the db_index record is not touched. When the last
89 * entry from the db_notify record is deleted, the db_index
90 * record is not immediately deleted. Instead, the db_notify
91 * record is replaced with a current timestamp. A regular
92 * cleanup process will delete all db_index records that are
93 * older than a minute.
95 struct db_context *db_index;
98 static void notify_trigger_local(struct notify_context *notify,
99 uint32_t action, uint32_t filter,
100 const char *path, size_t path_len,
101 bool recursive);
102 static NTSTATUS notify_send(struct notify_context *notify,
103 struct server_id *pid,
104 const char *path, uint32_t action,
105 void *private_data);
106 static NTSTATUS notify_add_entry(struct db_record *rec,
107 const struct notify_db_entry *e,
108 bool *p_add_idx);
109 static NTSTATUS notify_add_idx(struct db_record *rec, uint32_t vnn);
111 static NTSTATUS notify_del_entry(struct db_record *rec,
112 const struct server_id *pid,
113 void *private_data);
114 static NTSTATUS notify_del_idx(struct db_record *rec, uint32_t vnn);
116 static int notify_context_destructor(struct notify_context *notify);
118 static void notify_handler(struct messaging_context *msg_ctx,
119 void *private_data, uint32_t msg_type,
120 struct server_id server_id, DATA_BLOB *data);
122 struct notify_context *notify_init(TALLOC_CTX *mem_ctx,
123 struct messaging_context *msg,
124 struct event_context *ev)
126 struct notify_context *notify;
128 notify = talloc(mem_ctx, struct notify_context);
129 if (notify == NULL) {
130 goto fail;
132 notify->msg = msg;
133 notify->list = NULL;
135 notify->db_notify = db_open_tdb(
136 notify, lock_path("notify.tdb"),
137 0, TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
138 O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_2);
139 if (notify->db_notify == NULL) {
140 goto fail;
142 notify->db_index = db_open(
143 notify, lock_path("notify_index.tdb"),
144 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST|TDB_INCOMPATIBLE_HASH,
145 O_RDWR|O_CREAT, 0644, DBWRAP_LOCK_ORDER_3);
146 if (notify->db_index == NULL) {
147 goto fail;
149 if (!lp_clustering()) {
150 notify->db_index = db_open_cache(notify, notify->db_index);
151 if (notify->db_index == NULL) {
152 goto fail;
156 if (notify->msg != NULL) {
157 NTSTATUS status;
159 status = messaging_register(notify->msg, notify,
160 MSG_PVFS_NOTIFY, notify_handler);
161 if (!NT_STATUS_IS_OK(status)) {
162 DEBUG(1, ("messaging_register returned %s\n",
163 nt_errstr(status)));
164 goto fail;
168 talloc_set_destructor(notify, notify_context_destructor);
170 return notify;
171 fail:
172 TALLOC_FREE(notify);
173 return NULL;
176 static int notify_context_destructor(struct notify_context *notify)
178 DEBUG(10, ("notify_context_destructor called\n"));
180 if (notify->msg != NULL) {
181 messaging_deregister(notify->msg, MSG_PVFS_NOTIFY, notify);
184 while (notify->list != NULL) {
185 DEBUG(10, ("Removing private_data=%p\n",
186 notify->list->private_data));
187 notify_remove(notify, notify->list->private_data);
189 return 0;
192 NTSTATUS notify_add(struct notify_context *notify,
193 const char *path, uint32_t filter, uint32_t subdir_filter,
194 void (*callback)(void *, const struct notify_event *),
195 void *private_data)
197 struct notify_db_entry e;
198 struct notify_list *listel;
199 struct db_record *notify_rec, *idx_rec;
200 bool add_idx;
201 NTSTATUS status;
202 TDB_DATA key, notify_copy;
204 if (notify == NULL) {
205 return NT_STATUS_NOT_IMPLEMENTED;
208 DEBUG(10, ("notify_add: path=[%s], private_data=%p\n", path,
209 private_data));
211 listel = talloc(notify, struct notify_list);
212 if (listel == NULL) {
213 return NT_STATUS_NO_MEMORY;
215 listel->callback = callback;
216 listel->private_data = private_data;
217 listel->path = talloc_strdup(listel, path);
218 if (listel->path == NULL) {
219 TALLOC_FREE(listel);
220 return NT_STATUS_NO_MEMORY;
222 DLIST_ADD(notify->list, listel);
224 ZERO_STRUCT(e);
225 e.filter = filter;
226 e.subdir_filter = subdir_filter;
227 e.server = messaging_server_id(notify->msg);
228 e.private_data = private_data;
230 key = string_tdb_data(path);
232 notify_rec = dbwrap_fetch_locked(notify->db_notify,
233 talloc_tos(), key);
234 if (notify_rec == NULL) {
235 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
236 goto fail;
240 * Make a copy of the notify_rec for easy restore in case
241 * updating the index_rec fails;
243 notify_copy = dbwrap_record_get_value(notify_rec);
244 if (notify_copy.dsize != 0) {
245 notify_copy.dptr = (uint8_t *)talloc_memdup(
246 notify_rec, notify_copy.dptr,
247 notify_copy.dsize);
248 if (notify_copy.dptr == NULL) {
249 TALLOC_FREE(notify_rec);
250 status = NT_STATUS_NO_MEMORY;
251 goto fail;
255 if (DEBUGLEVEL >= 10) {
256 NDR_PRINT_DEBUG(notify_db_entry, &e);
259 status = notify_add_entry(notify_rec, &e, &add_idx);
260 if (!NT_STATUS_IS_OK(status)) {
261 goto fail;
263 if (!add_idx) {
265 * Someone else has added the idx entry already
267 TALLOC_FREE(notify_rec);
268 return NT_STATUS_OK;
271 idx_rec = dbwrap_fetch_locked(notify->db_index,
272 talloc_tos(), key);
273 if (idx_rec == NULL) {
274 status = NT_STATUS_INTERNAL_DB_CORRUPTION;
275 goto restore_notify;
277 status = notify_add_idx(idx_rec, get_my_vnn());
278 if (!NT_STATUS_IS_OK(status)) {
279 goto restore_notify;
282 TALLOC_FREE(idx_rec);
283 TALLOC_FREE(notify_rec);
284 return NT_STATUS_OK;
286 restore_notify:
287 if (notify_copy.dsize != 0) {
288 dbwrap_record_store(notify_rec, notify_copy, 0);
289 } else {
290 dbwrap_record_delete(notify_rec);
292 TALLOC_FREE(notify_rec);
293 fail:
294 DLIST_REMOVE(notify->list, listel);
295 TALLOC_FREE(listel);
296 return status;
299 static NTSTATUS notify_add_entry(struct db_record *rec,
300 const struct notify_db_entry *e,
301 bool *p_add_idx)
303 TDB_DATA value = dbwrap_record_get_value(rec);
304 struct notify_db_entry *entries;
305 size_t num_entries;
306 bool add_idx = true;
307 NTSTATUS status;
309 if (value.dsize == sizeof(time_t)) {
310 DEBUG(10, ("Re-using deleted entry\n"));
311 value.dsize = 0;
312 add_idx = false;
315 if ((value.dsize % sizeof(struct notify_db_entry)) != 0) {
316 DEBUG(1, ("Invalid value.dsize = %u\n",
317 (unsigned)value.dsize));
318 return NT_STATUS_INTERNAL_DB_CORRUPTION;
320 num_entries = value.dsize / sizeof(struct notify_db_entry);
322 if (num_entries != 0) {
323 add_idx = false;
326 entries = talloc_array(rec, struct notify_db_entry, num_entries + 1);
327 if (entries == NULL) {
328 return NT_STATUS_NO_MEMORY;
330 memcpy(entries, value.dptr, value.dsize);
332 entries[num_entries] = *e;
333 value = make_tdb_data((uint8_t *)entries, talloc_get_size(entries));
334 status = dbwrap_record_store(rec, value, 0);
335 TALLOC_FREE(entries);
336 if (!NT_STATUS_IS_OK(status)) {
337 return status;
339 *p_add_idx = add_idx;
340 return NT_STATUS_OK;
343 static NTSTATUS notify_add_idx(struct db_record *rec, uint32_t vnn)
345 TDB_DATA value = dbwrap_record_get_value(rec);
346 uint32_t *vnns;
347 size_t i, num_vnns;
348 NTSTATUS status;
350 if ((value.dsize % sizeof(uint32_t)) != 0) {
351 DEBUG(1, ("Invalid value.dsize = %u\n",
352 (unsigned)value.dsize));
353 return NT_STATUS_INTERNAL_DB_CORRUPTION;
355 num_vnns = value.dsize / sizeof(uint32_t);
356 vnns = (uint32_t *)value.dptr;
358 for (i=0; i<num_vnns; i++) {
359 if (vnns[i] == vnn) {
360 return NT_STATUS_OK;
362 if (vnns[i] > vnn) {
363 break;
367 value.dptr = (uint8_t *)talloc_realloc(
368 rec, value.dptr, uint32_t, num_vnns + 1);
369 if (value.dptr == NULL) {
370 return NT_STATUS_NO_MEMORY;
372 value.dsize = talloc_get_size(value.dptr);
374 vnns = (uint32_t *)value.dptr;
376 memmove(&vnns[i+1], &vnns[i], sizeof(uint32_t) * (num_vnns - i));
377 vnns[i] = vnn;
379 status = dbwrap_record_store(rec, value, 0);
380 if (!NT_STATUS_IS_OK(status)) {
381 return status;
383 return NT_STATUS_OK;
386 NTSTATUS notify_remove(struct notify_context *notify, void *private_data)
388 struct server_id pid = messaging_server_id(notify->msg);
389 struct notify_list *listel;
390 struct db_record *notify_rec;
391 NTSTATUS status;
393 if (notify == NULL) {
394 return NT_STATUS_NOT_IMPLEMENTED;
397 DEBUG(10, ("notify_remove: private_data=%p\n", private_data));
399 for (listel=notify->list;listel;listel=listel->next) {
400 if (listel->private_data == private_data) {
401 DLIST_REMOVE(notify->list, listel);
402 break;
405 if (listel == NULL) {
406 DEBUG(10, ("%p not found\n", private_data));
407 return NT_STATUS_NOT_FOUND;
409 notify_rec = dbwrap_fetch_locked(notify->db_notify, talloc_tos(),
410 string_tdb_data(listel->path));
411 TALLOC_FREE(listel);
412 if (notify_rec == NULL) {
413 return NT_STATUS_INTERNAL_DB_CORRUPTION;
415 status = notify_del_entry(notify_rec, &pid, private_data);
416 DEBUG(10, ("del_entry returned %s\n", nt_errstr(status)));
417 TALLOC_FREE(notify_rec);
418 return status;
421 static NTSTATUS notify_del_entry(struct db_record *rec,
422 const struct server_id *pid,
423 void *private_data)
425 TDB_DATA value = dbwrap_record_get_value(rec);
426 struct notify_db_entry *entries;
427 size_t i, num_entries;
428 time_t now;
430 DEBUG(10, ("del_entry called for %s %p\n", procid_str_static(pid),
431 private_data));
433 if ((value.dsize % sizeof(struct notify_db_entry)) != 0) {
434 DEBUG(1, ("Invalid value.dsize = %u\n",
435 (unsigned)value.dsize));
436 return NT_STATUS_INTERNAL_DB_CORRUPTION;
438 num_entries = value.dsize / sizeof(struct notify_db_entry);
439 entries = (struct notify_db_entry *)value.dptr;
441 for (i=0; i<num_entries; i++) {
442 struct notify_db_entry *e = &entries[i];
444 if (DEBUGLEVEL >= 10) {
445 NDR_PRINT_DEBUG(notify_db_entry, e);
448 if (e->private_data != private_data) {
449 continue;
451 if (procid_equal(&e->server, pid)) {
452 break;
455 if (i == num_entries) {
456 return NT_STATUS_NOT_FOUND;
458 entries[i] = entries[num_entries-1];
459 value.dsize -= sizeof(struct notify_db_entry);
461 if (value.dsize == 0) {
462 now = time(NULL);
463 value.dptr = (uint8_t *)&now;
464 value.dsize = sizeof(now);
466 return dbwrap_record_store(rec, value, 0);
469 struct notify_trigger_index_state {
470 TALLOC_CTX *mem_ctx;
471 uint32_t *vnns;
472 uint32_t my_vnn;
473 bool found_my_vnn;
476 static void notify_trigger_index_parser(TDB_DATA key, TDB_DATA data,
477 void *private_data)
479 struct notify_trigger_index_state *state =
480 (struct notify_trigger_index_state *)private_data;
481 uint32_t *new_vnns;
482 size_t i, num_vnns, num_new_vnns;
484 if ((data.dsize % sizeof(uint32_t)) != 0) {
485 DEBUG(1, ("Invalid record size in notify index db: %u\n",
486 (unsigned)data.dsize));
487 return;
489 new_vnns = (uint32_t *)data.dptr;
490 num_new_vnns = data.dsize / sizeof(uint32_t);
492 num_vnns = talloc_array_length(state->vnns);
494 for (i=0; i<num_new_vnns; i++) {
495 if (new_vnns[i] == state->my_vnn) {
496 state->found_my_vnn = true;
500 state->vnns = talloc_realloc(state->mem_ctx, state->vnns, uint32_t,
501 num_vnns + num_new_vnns);
502 if ((num_vnns + num_new_vnns != 0) && (state->vnns == NULL)) {
503 DEBUG(1, ("talloc_realloc failed\n"));
504 return;
506 memcpy(&state->vnns[num_vnns], data.dptr, data.dsize);
509 static int vnn_cmp(const void *p1, const void *p2)
511 uint32_t *vnn1 = (uint32_t *)p1;
512 uint32_t *vnn2 = (uint32_t *)p2;
514 if (*vnn1 < *vnn2) {
515 return -1;
517 if (*vnn1 == *vnn2) {
518 return 0;
520 return 1;
523 static bool notify_push_remote_blob(TALLOC_CTX *mem_ctx, uint32_t action,
524 uint32_t filter, const char *path,
525 uint8_t **pblob, size_t *pblob_len)
527 struct notify_remote_event ev;
528 DATA_BLOB data;
529 enum ndr_err_code ndr_err;
531 ev.action = action;
532 ev.filter = filter;
533 ev.path = path;
535 if (DEBUGLEVEL >= 10) {
536 NDR_PRINT_DEBUG(notify_remote_event, &ev);
539 ndr_err = ndr_push_struct_blob(
540 &data, mem_ctx, &ev,
541 (ndr_push_flags_fn_t)ndr_push_notify_remote_event);
542 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
543 return false;
545 *pblob = data.data;
546 *pblob_len = data.length;
547 return true;
550 static bool notify_pull_remote_blob(TALLOC_CTX *mem_ctx,
551 const uint8_t *blob, size_t blob_len,
552 uint32_t *paction, uint32_t *pfilter,
553 char **path)
555 struct notify_remote_event *ev;
556 enum ndr_err_code ndr_err;
557 DATA_BLOB data;
559 data.data = discard_const_p(uint8_t, blob);
560 data.length = blob_len;
562 ev = talloc(mem_ctx, struct notify_remote_event);
563 if (ev == NULL) {
564 return false;
567 ndr_err = ndr_pull_struct_blob(
568 &data, ev, ev,
569 (ndr_pull_flags_fn_t)ndr_pull_notify_remote_event);
570 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
571 TALLOC_FREE(ev);
572 return false;
574 if (DEBUGLEVEL >= 10) {
575 NDR_PRINT_DEBUG(notify_remote_event, ev);
577 *paction = ev->action;
578 *pfilter = ev->filter;
579 *path = talloc_move(mem_ctx, (char **)&ev->path);
581 TALLOC_FREE(ev);
582 return true;
585 void notify_trigger(struct notify_context *notify,
586 uint32_t action, uint32_t filter, const char *path)
588 struct ctdbd_connection *ctdbd_conn;
589 struct notify_trigger_index_state idx_state;
590 const char *p, *next_p;
591 size_t i, num_vnns;
592 uint32_t last_vnn;
593 uint8_t *remote_blob = NULL;
594 size_t remote_blob_len = 0;
596 DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, "
597 "path=%s\n", (unsigned)action, (unsigned)filter, path));
599 /* see if change notify is enabled at all */
600 if (notify == NULL) {
601 return;
604 idx_state.mem_ctx = talloc_tos();
605 idx_state.vnns = NULL;
606 idx_state.my_vnn = get_my_vnn();
608 for (p = path; p != NULL; p = next_p) {
609 ptrdiff_t path_len = p - path;
610 bool recursive;
612 next_p = strchr(p+1, '/');
613 recursive = (next_p != NULL);
615 idx_state.found_my_vnn = false;
617 dbwrap_parse_record(
618 notify->db_index,
619 make_tdb_data((uint8_t *)path, path_len),
620 notify_trigger_index_parser, &idx_state);
622 if (!idx_state.found_my_vnn) {
623 continue;
625 notify_trigger_local(notify, action, filter,
626 path, path_len, recursive);
629 ctdbd_conn = messaging_ctdbd_connection();
630 if (ctdbd_conn == NULL) {
631 goto done;
634 num_vnns = talloc_array_length(idx_state.vnns);
635 qsort(idx_state.vnns, num_vnns, sizeof(uint32_t), vnn_cmp);
637 last_vnn = 0xffffffff;
638 remote_blob = NULL;
640 for (i=0; i<num_vnns; i++) {
641 uint32_t vnn = idx_state.vnns[i];
642 NTSTATUS status;
644 if (vnn == last_vnn) {
645 continue;
647 if (vnn == idx_state.my_vnn) {
648 continue;
650 if ((remote_blob == NULL) &&
651 !notify_push_remote_blob(
652 talloc_tos(), action, filter,
653 path, &remote_blob, &remote_blob_len)) {
654 break;
657 status = ctdbd_messaging_send_blob(
658 ctdbd_conn, vnn, CTDB_SRVID_SAMBA_NOTIFY_PROXY,
659 remote_blob, remote_blob_len);
660 if (!NT_STATUS_IS_OK(status)) {
661 DEBUG(10, ("ctdbd_messaging_send_blob to vnn %d "
662 "returned %s, ignoring\n", (int)vnn,
663 nt_errstr(status)));
666 last_vnn = vnn;
669 done:
670 TALLOC_FREE(remote_blob);
671 TALLOC_FREE(idx_state.vnns);
674 static void notify_trigger_local(struct notify_context *notify,
675 uint32_t action, uint32_t filter,
676 const char *path, size_t path_len,
677 bool recursive)
679 TDB_DATA data;
680 struct notify_db_entry *entries;
681 size_t i, num_entries;
682 NTSTATUS status;
684 DEBUG(10, ("notify_trigger_local called for %*s, path_len=%d, "
685 "filter=%d\n", (int)path_len, path, (int)path_len,
686 (int)filter));
688 status = dbwrap_fetch(
689 notify->db_notify, talloc_tos(),
690 make_tdb_data((uint8_t *)path, path_len), &data);
691 if (!NT_STATUS_IS_OK(status)) {
692 DEBUG(10, ("dbwrap_fetch returned %s\n",
693 nt_errstr(status)));
694 return;
696 if (data.dsize == sizeof(time_t)) {
697 DEBUG(10, ("Got deleted record\n"));
698 goto done;
700 if ((data.dsize % sizeof(struct notify_db_entry)) != 0) {
701 DEBUG(1, ("Invalid data.dsize = %u\n",
702 (unsigned)data.dsize));
703 goto done;
706 entries = (struct notify_db_entry *)data.dptr;
707 num_entries = data.dsize / sizeof(struct notify_db_entry);
709 DEBUG(10, ("recursive = %s pathlen=%d (%c)\n",
710 recursive ? "true" : "false", (int)path_len,
711 path[path_len]));
713 for (i=0; i<num_entries; i++) {
714 struct notify_db_entry *e = &entries[i];
715 uint32_t e_filter;
717 if (DEBUGLEVEL >= 10) {
718 NDR_PRINT_DEBUG(notify_db_entry, e);
721 e_filter = recursive ? e->subdir_filter : e->filter;
723 if ((filter & e_filter) == 0) {
724 continue;
727 if (!procid_is_local(&e->server)) {
728 DEBUG(1, ("internal error: Non-local pid %s in "
729 "notify.tdb\n",
730 procid_str_static(&e->server)));
731 continue;
734 status = notify_send(notify, &e->server, path + path_len + 1,
735 action, e->private_data);
736 if (!NT_STATUS_IS_OK(status)) {
737 DEBUG(10, ("notify_send returned %s\n",
738 nt_errstr(status)));
742 done:
743 TALLOC_FREE(data.dptr);
746 static NTSTATUS notify_send(struct notify_context *notify,
747 struct server_id *pid,
748 const char *path, uint32_t action,
749 void *private_data)
751 struct notify_event ev;
752 DATA_BLOB data;
753 NTSTATUS status;
754 enum ndr_err_code ndr_err;
756 ev.action = action;
757 ev.path = path;
758 ev.private_data = private_data;
760 ndr_err = ndr_push_struct_blob(
761 &data, talloc_tos(), &ev,
762 (ndr_push_flags_fn_t)ndr_push_notify_event);
763 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
764 return ndr_map_error2ntstatus(ndr_err);
766 status = messaging_send(notify->msg, *pid, MSG_PVFS_NOTIFY,
767 &data);
768 TALLOC_FREE(data.data);
769 return status;
772 static void notify_handler(struct messaging_context *msg_ctx,
773 void *private_data, uint32_t msg_type,
774 struct server_id server_id, DATA_BLOB *data)
776 struct notify_context *notify = talloc_get_type_abort(
777 private_data, struct notify_context);
778 enum ndr_err_code ndr_err;
779 struct notify_event *n;
780 struct notify_list *listel;
782 n = talloc(talloc_tos(), struct notify_event);
783 if (n == NULL) {
784 DEBUG(1, ("talloc failed\n"));
785 return;
788 ndr_err = ndr_pull_struct_blob(
789 data, n, n, (ndr_pull_flags_fn_t)ndr_pull_notify_event);
790 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
791 TALLOC_FREE(n);
792 return;
794 if (DEBUGLEVEL >= 10) {
795 NDR_PRINT_DEBUG(notify_event, n);
798 for (listel=notify->list;listel;listel=listel->next) {
799 if (listel->private_data == n->private_data) {
800 listel->callback(listel->private_data, n);
801 break;
804 TALLOC_FREE(n);
807 struct notify_walk_idx_state {
808 void (*fn)(const char *path,
809 uint32_t *vnns, size_t num_vnns,
810 void *private_data);
811 void *private_data;
814 static int notify_walk_idx_fn(struct db_record *rec, void *private_data)
816 struct notify_walk_idx_state *state =
817 (struct notify_walk_idx_state *)private_data;
818 TDB_DATA key, value;
819 char *path;
821 key = dbwrap_record_get_key(rec);
822 value = dbwrap_record_get_value(rec);
824 if ((value.dsize % sizeof(uint32_t)) != 0) {
825 DEBUG(1, ("invalid value size in notify index db: %u\n",
826 (unsigned)(value.dsize)));
827 return 0;
830 path = talloc_strndup(talloc_tos(), (char *)key.dptr, key.dsize);
831 if (path == NULL) {
832 DEBUG(1, ("talloc_strndup failed\n"));
833 return 0;
835 state->fn(path, (uint32_t *)value.dptr, value.dsize/sizeof(uint32_t),
836 state->private_data);
837 TALLOC_FREE(path);
838 return 0;
841 void notify_walk_idx(struct notify_context *notify,
842 void (*fn)(const char *path,
843 uint32_t *vnns, size_t num_vnns,
844 void *private_data),
845 void *private_data)
847 struct notify_walk_idx_state state;
848 state.fn = fn;
849 state.private_data = private_data;
850 dbwrap_traverse_read(notify->db_index, notify_walk_idx_fn, &state,
851 NULL);
854 struct notify_walk_state {
855 void (*fn)(const char *path,
856 struct notify_db_entry *entries, size_t num_entries,
857 time_t deleted_time, void *private_data);
858 void *private_data;
861 static int notify_walk_fn(struct db_record *rec, void *private_data)
863 struct notify_walk_state *state =
864 (struct notify_walk_state *)private_data;
865 TDB_DATA key, value;
866 struct notify_db_entry *entries;
867 size_t num_entries;
868 time_t deleted_time;
869 char *path;
871 key = dbwrap_record_get_key(rec);
872 value = dbwrap_record_get_value(rec);
874 if (value.dsize == sizeof(deleted_time)) {
875 memcpy(&deleted_time, value.dptr, sizeof(deleted_time));
876 entries = NULL;
877 num_entries = 0;
878 } else {
879 if ((value.dsize % sizeof(struct notify_db_entry)) != 0) {
880 DEBUG(1, ("invalid value size in notify db: %u\n",
881 (unsigned)(value.dsize)));
882 return 0;
884 entries = (struct notify_db_entry *)value.dptr;
885 num_entries = value.dsize / sizeof(struct notify_db_entry);
886 deleted_time = 0;
889 path = talloc_strndup(talloc_tos(), (char *)key.dptr, key.dsize);
890 if (path == NULL) {
891 DEBUG(1, ("talloc_strndup failed\n"));
892 return 0;
894 state->fn(path, entries, num_entries, deleted_time,
895 state->private_data);
896 TALLOC_FREE(path);
897 return 0;
900 void notify_walk(struct notify_context *notify,
901 void (*fn)(const char *path,
902 struct notify_db_entry *entries,
903 size_t num_entries,
904 time_t deleted_time, void *private_data),
905 void *private_data)
907 struct notify_walk_state state;
908 state.fn = fn;
909 state.private_data = private_data;
910 dbwrap_traverse_read(notify->db_notify, notify_walk_fn, &state,
911 NULL);
914 struct notify_cleanup_state {
915 TALLOC_CTX *mem_ctx;
916 time_t delete_before;
917 ssize_t array_size;
918 uint32_t num_paths;
919 char **paths;
922 static void notify_cleanup_collect(
923 const char *path, struct notify_db_entry *entries, size_t num_entries,
924 time_t deleted_time, void *private_data)
926 struct notify_cleanup_state *state =
927 (struct notify_cleanup_state *)private_data;
928 char *p;
930 if (num_entries != 0) {
931 return;
933 if (deleted_time >= state->delete_before) {
934 return;
937 p = talloc_strdup(state->mem_ctx, path);
938 if (p == NULL) {
939 DEBUG(1, ("talloc_strdup failed\n"));
940 return;
942 add_to_large_array(state->mem_ctx, sizeof(p), (void *)&p,
943 &state->paths, &state->num_paths,
944 &state->array_size);
945 if (state->array_size == -1) {
946 TALLOC_FREE(p);
950 static bool notify_cleanup_path(struct notify_context *notify,
951 const char *path, time_t delete_before);
953 void notify_cleanup(struct notify_context *notify)
955 struct notify_cleanup_state state;
956 uint32_t failure_pool;
958 ZERO_STRUCT(state);
959 state.mem_ctx = talloc_stackframe();
961 state.delete_before = time(NULL)
962 - lp_parm_int(-1, "smbd", "notify cleanup interval", 60);
964 notify_walk(notify, notify_cleanup_collect, &state);
966 failure_pool = state.num_paths;
968 while (state.num_paths != 0) {
969 size_t idx;
972 * This loop is designed to be as kind as possible to
973 * ctdb. ctdb does not like it if many smbds hammer on a
974 * single record. If on many nodes the cleanup process starts
975 * running, it can happen that all of them need to clean up
976 * records in the same order. This would generate a ctdb
977 * migrate storm on these records. Randomizing the load across
978 * multiple records reduces the load on the individual record.
981 generate_random_buffer((uint8_t *)&idx, sizeof(idx));
982 idx = idx % state.num_paths;
984 if (!notify_cleanup_path(notify, state.paths[idx],
985 state.delete_before)) {
987 * notify_cleanup_path failed, the most likely reason
988 * is that dbwrap_try_fetch_locked failed due to
989 * contention. We allow one failed attempt per deleted
990 * path on average before we give up.
992 failure_pool -= 1;
993 if (failure_pool == 0) {
995 * Too many failures. We will come back here,
996 * maybe next time there is less contention.
998 break;
1002 TALLOC_FREE(state.paths[idx]);
1003 state.paths[idx] = state.paths[state.num_paths-1];
1004 state.num_paths -= 1;
1006 TALLOC_FREE(state.mem_ctx);
1009 static bool notify_cleanup_path(struct notify_context *notify,
1010 const char *path, time_t delete_before)
1012 struct db_record *notify_rec = NULL;
1013 struct db_record *idx_rec = NULL;
1014 TDB_DATA key = string_tdb_data(path);
1015 TDB_DATA value;
1016 time_t deleted;
1017 NTSTATUS status;
1019 notify_rec = dbwrap_fetch_locked(notify->db_notify, talloc_tos(), key);
1020 if (notify_rec == NULL) {
1021 DEBUG(10, ("Could not fetch notify_rec\n"));
1022 return false;
1024 value = dbwrap_record_get_value(notify_rec);
1026 if (value.dsize != sizeof(deleted)) {
1027 DEBUG(10, ("record %s has been re-used\n", path));
1028 goto done;
1030 memcpy(&deleted, value.dptr, sizeof(deleted));
1032 if (deleted >= delete_before) {
1033 DEBUG(10, ("record %s too young\n", path));
1034 goto done;
1038 * Be kind to ctdb and only try one dmaster migration at most.
1040 idx_rec = dbwrap_try_fetch_locked(notify->db_index, talloc_tos(), key);
1041 if (idx_rec == NULL) {
1042 DEBUG(10, ("Could not fetch idx_rec\n"));
1043 goto done;
1046 status = dbwrap_record_delete(notify_rec);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 DEBUG(10, ("Could not delete notify_rec: %s\n",
1049 nt_errstr(status)));
1052 status = notify_del_idx(idx_rec, get_my_vnn());
1053 if (!NT_STATUS_IS_OK(status)) {
1054 DEBUG(10, ("Could not delete idx_rec: %s\n",
1055 nt_errstr(status)));
1058 done:
1059 TALLOC_FREE(idx_rec);
1060 TALLOC_FREE(notify_rec);
1061 return true;
1064 static NTSTATUS notify_del_idx(struct db_record *rec, uint32_t vnn)
1066 TDB_DATA value = dbwrap_record_get_value(rec);
1067 uint32_t *vnns;
1068 size_t i, num_vnns;
1070 if ((value.dsize % sizeof(uint32_t)) != 0) {
1071 DEBUG(1, ("Invalid value.dsize = %u\n",
1072 (unsigned)value.dsize));
1073 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1075 num_vnns = value.dsize / sizeof(uint32_t);
1076 vnns = (uint32_t *)value.dptr;
1078 for (i=0; i<num_vnns; i++) {
1079 if (vnns[i] == vnn) {
1080 break;
1084 if (i == num_vnns) {
1086 * Not found. Should not happen, but okay...
1088 return NT_STATUS_OK;
1091 memmove(&vnns[i], &vnns[i+1], sizeof(uint32_t) * (num_vnns - i - 1));
1092 value.dsize -= sizeof(uint32_t);
1094 if (value.dsize == 0) {
1095 return dbwrap_record_delete(rec);
1097 return dbwrap_record_store(rec, value, 0);
1100 struct notify_cluster_proxy_state {
1101 struct tevent_context *ev;
1102 struct notify_context *notify;
1103 struct ctdb_msg_channel *chan;
1106 static void notify_cluster_proxy_got_chan(struct tevent_req *subreq);
1107 static void notify_cluster_proxy_got_msg(struct tevent_req *subreq);
1108 static void notify_cluster_proxy_trigger(struct notify_context *notify,
1109 uint32_t action, uint32_t filter,
1110 char *path);
1112 struct tevent_req *notify_cluster_proxy_send(
1113 TALLOC_CTX *mem_ctx, struct tevent_context *ev,
1114 struct notify_context *notify)
1116 struct tevent_req *req, *subreq;
1117 struct notify_cluster_proxy_state *state;
1119 req = tevent_req_create(mem_ctx, &state,
1120 struct notify_cluster_proxy_state);
1121 if (req == NULL) {
1122 return NULL;
1124 state->ev = ev;
1125 state->notify = notify;
1127 subreq = ctdb_msg_channel_init_send(
1128 state, state->ev, lp_ctdbd_socket(),
1129 CTDB_SRVID_SAMBA_NOTIFY_PROXY);
1130 if (tevent_req_nomem(subreq, req)) {
1131 return tevent_req_post(req, ev);
1133 tevent_req_set_callback(subreq, notify_cluster_proxy_got_chan, req);
1134 return req;
1137 static void notify_cluster_proxy_got_chan(struct tevent_req *subreq)
1139 struct tevent_req *req = tevent_req_callback_data(
1140 subreq, struct tevent_req);
1141 struct notify_cluster_proxy_state *state = tevent_req_data(
1142 req, struct notify_cluster_proxy_state);
1143 int ret;
1145 ret = ctdb_msg_channel_init_recv(subreq, state, &state->chan);
1146 TALLOC_FREE(subreq);
1147 if (ret != 0) {
1148 tevent_req_error(req, ret);
1149 return;
1151 subreq = ctdb_msg_read_send(state, state->ev, state->chan);
1152 if (tevent_req_nomem(subreq, req)) {
1153 return;
1155 tevent_req_set_callback(subreq, notify_cluster_proxy_got_msg, req);
1158 static void notify_cluster_proxy_got_msg(struct tevent_req *subreq)
1160 struct tevent_req *req = tevent_req_callback_data(
1161 subreq, struct tevent_req);
1162 struct notify_cluster_proxy_state *state = tevent_req_data(
1163 req, struct notify_cluster_proxy_state);
1164 uint8_t *msg;
1165 size_t msg_len;
1166 uint32_t action, filter;
1167 char *path;
1168 int ret;
1169 bool res;
1171 ret = ctdb_msg_read_recv(subreq, talloc_tos(), &msg, &msg_len);
1172 TALLOC_FREE(subreq);
1173 if (ret != 0) {
1174 tevent_req_error(req, ret);
1175 return;
1178 res = notify_pull_remote_blob(talloc_tos(), msg, msg_len,
1179 &action, &filter, &path);
1180 TALLOC_FREE(msg);
1181 if (!res) {
1182 tevent_req_error(req, EIO);
1183 return;
1185 notify_cluster_proxy_trigger(state->notify, action, filter, path);
1186 TALLOC_FREE(path);
1188 subreq = ctdb_msg_read_send(state, state->ev, state->chan);
1189 if (tevent_req_nomem(subreq, req)) {
1190 return;
1192 tevent_req_set_callback(subreq, notify_cluster_proxy_got_msg, req);
1195 static void notify_cluster_proxy_trigger(struct notify_context *notify,
1196 uint32_t action, uint32_t filter,
1197 char *path)
1199 const char *p, *next_p;
1201 for (p = path; p != NULL; p = next_p) {
1202 ptrdiff_t path_len = p - path;
1203 bool recursive;
1205 next_p = strchr(p+1, '/');
1206 recursive = (next_p != NULL);
1208 notify_trigger_local(notify, action, filter,
1209 path, path_len, recursive);
1213 int notify_cluster_proxy_recv(struct tevent_req *req)
1215 int err;
1217 if (tevent_req_is_unix_error(req, &err)) {
1218 return err;
1220 return 0;