diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:47:29 +0000 |
commit | 4f5791ebd03eaec1c7da0865a383175b05102712 (patch) | |
tree | 8ce7b00f7a76baa386372422adebbe64510812d4 /source3/smbd/notify_msg.c | |
parent | Initial commit. (diff) | |
download | samba-upstream.tar.xz samba-upstream.zip |
Adding upstream version 2:4.17.12+dfsg.upstream/2%4.17.12+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'source3/smbd/notify_msg.c')
-rw-r--r-- | source3/smbd/notify_msg.c | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/source3/smbd/notify_msg.c b/source3/smbd/notify_msg.c new file mode 100644 index 0000000..0ea992c --- /dev/null +++ b/source3/smbd/notify_msg.c @@ -0,0 +1,247 @@ +/* + * Unix SMB/CIFS implementation. + * + * Copyright (C) Volker Lendecke 2014 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "includes.h" +#include "librpc/gen_ndr/notify.h" +#include "librpc/gen_ndr/messaging.h" +#include "lib/dbwrap/dbwrap.h" +#include "lib/dbwrap/dbwrap_rbt.h" +#include "lib/util/server_id.h" +#include "messages.h" +#include "proto.h" +#include "globals.h" +#include "tdb.h" +#include "util_tdb.h" +#include "lib/util/server_id_db.h" +#include "smbd/notifyd/notifyd.h" + +struct notify_context { + struct server_id notifyd; + struct messaging_context *msg_ctx; + + struct smbd_server_connection *sconn; + void (*callback)(struct smbd_server_connection *sconn, + void *private_data, struct timespec when, + const struct notify_event *ctx); +}; + +static void notify_handler(struct messaging_context *msg, void *private_data, + uint32_t msg_type, struct server_id src, + DATA_BLOB *data); +static int notify_context_destructor(struct notify_context *ctx); + +struct notify_context *notify_init( + TALLOC_CTX *mem_ctx, struct messaging_context *msg, + struct smbd_server_connection *sconn, + void (*callback)(struct smbd_server_connection *sconn, + void *, struct timespec, + const struct notify_event *)) +{ + struct server_id_db *names_db; + struct notify_context *ctx; + NTSTATUS status; + + ctx = talloc(mem_ctx, struct notify_context); + if (ctx == NULL) { + return NULL; + } + ctx->msg_ctx = msg; + + ctx->sconn = sconn; + ctx->callback = callback; + + names_db = messaging_names_db(msg); + if (!server_id_db_lookup_one(names_db, "notify-daemon", + &ctx->notifyd)) { + DBG_WARNING("No notify daemon around\n"); + TALLOC_FREE(ctx); + return NULL; + } + + { + struct server_id_buf tmp; + DBG_DEBUG("notifyd=%s\n", + server_id_str_buf(ctx->notifyd, &tmp)); + } + + if (callback != NULL) { + status = messaging_register(msg, ctx, MSG_PVFS_NOTIFY, + notify_handler); + if (!NT_STATUS_IS_OK(status)) { + DBG_WARNING("messaging_register failed: %s\n", + nt_errstr(status)); + TALLOC_FREE(ctx); + return NULL; + } + } + + talloc_set_destructor(ctx, notify_context_destructor); + + return ctx; +} + +static int notify_context_destructor(struct notify_context *ctx) +{ + if (ctx->callback != NULL) { + messaging_deregister(ctx->msg_ctx, MSG_PVFS_NOTIFY, ctx); + } + + return 0; +} + +static void notify_handler(struct messaging_context *msg, void *private_data, + uint32_t msg_type, struct server_id src, + DATA_BLOB *data) +{ + struct notify_context *ctx = talloc_get_type_abort( + private_data, struct notify_context); + struct notify_event_msg *event_msg; + struct notify_event event; + + if (data->length < offsetof(struct notify_event_msg, path) + 1) { + DBG_WARNING("message too short: %zu\n", data->length); + return; + } + if (data->data[data->length-1] != 0) { + DBG_WARNING("path not 0-terminated\n"); + return; + } + + event_msg = (struct notify_event_msg *)data->data; + + event.action = event_msg->action; + event.path = event_msg->path; + event.private_data = event_msg->private_data; + + DBG_DEBUG("Got notify_event action=%"PRIu32", private_data=%p, " + "path=%s\n", + event.action, + event.private_data, + event.path); + + ctx->callback(ctx->sconn, event.private_data, event_msg->when, &event); +} + +NTSTATUS notify_add(struct notify_context *ctx, + const char *path, uint32_t filter, uint32_t subdir_filter, + void *private_data) +{ + struct notify_rec_change_msg msg = {}; + struct iovec iov[2]; + size_t pathlen; + NTSTATUS status; + + if (ctx == NULL) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + DBG_DEBUG("path=[%s], filter=%"PRIu32", subdir_filter=%"PRIu32", " + "private_data=%p\n", + path, + filter, + subdir_filter, + private_data); + + pathlen = strlen(path)+1; + + clock_gettime_mono(&msg.instance.creation_time); + msg.instance.filter = filter; + msg.instance.subdir_filter = subdir_filter; + msg.instance.private_data = private_data; + + iov[0].iov_base = &msg; + iov[0].iov_len = offsetof(struct notify_rec_change_msg, path); + iov[1].iov_base = discard_const_p(char, path); + iov[1].iov_len = pathlen; + + status = messaging_send_iov( + ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE, + iov, ARRAY_SIZE(iov), NULL, 0); + + if (!NT_STATUS_IS_OK(status)) { + DBG_DEBUG("messaging_send_iov returned %s\n", + nt_errstr(status)); + return status; + } + + return NT_STATUS_OK; +} + +NTSTATUS notify_remove(struct notify_context *ctx, void *private_data, + char *path) +{ + struct notify_rec_change_msg msg = {}; + struct iovec iov[2]; + NTSTATUS status; + + /* see if change notify is enabled at all */ + if (ctx == NULL) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + msg.instance.private_data = private_data; + + iov[0].iov_base = &msg; + iov[0].iov_len = offsetof(struct notify_rec_change_msg, path); + iov[1].iov_base = path; + iov[1].iov_len = strlen(path)+1; + + status = messaging_send_iov( + ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_REC_CHANGE, + iov, ARRAY_SIZE(iov), NULL, 0); + + return status; +} + +void notify_trigger(struct notify_context *ctx, + uint32_t action, uint32_t filter, + const char *dir, const char *name) +{ + struct notify_trigger_msg msg; + struct iovec iov[4]; + char slash = '/'; + + DBG_DEBUG("notify_trigger called action=0x%"PRIx32", " + "filter=0x%"PRIx32", dir=%s, name=%s\n", + action, + filter, + dir, + name); + + if (ctx == NULL) { + return; + } + + msg.when = timespec_current(); + msg.action = action; + msg.filter = filter; + + iov[0].iov_base = &msg; + iov[0].iov_len = offsetof(struct notify_trigger_msg, path); + iov[1].iov_base = discard_const_p(char, dir); + iov[1].iov_len = strlen(dir); + iov[2].iov_base = &slash; + iov[2].iov_len = 1; + iov[3].iov_base = discard_const_p(char, name); + iov[3].iov_len = strlen(name)+1; + + messaging_send_iov( + ctx->msg_ctx, ctx->notifyd, MSG_SMB_NOTIFY_TRIGGER, + iov, ARRAY_SIZE(iov), NULL, 0); +} |