[PATCH] s3: Dynamic share permission detection, part2.
Bo Yang
boyang at samba.org
Sun Nov 29 02:53:00 MST 2009
Signed-off-by: Bo Yang <boyang at samba.org>
---
source3/include/proto.h | 1 +
source3/include/smb.h | 5 +
source3/smbd/notify_inotify.c | 4 +-
source3/smbd/process.c | 194 +++++++++++++++++++++++++++++++++++++++++
source3/smbd/server.c | 43 +++++++++
5 files changed, 246 insertions(+), 1 deletions(-)
diff --git a/source3/include/proto.h b/source3/include/proto.h
index 81c1322..0b6ddc3 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -6803,6 +6803,7 @@ void chain_reply(struct smb_request *req);
bool req_is_in_chain(struct smb_request *req);
void check_reload(time_t t);
void smbd_process(void);
+void smbd_watch_share_permissions(void);
/* The following definitions come from smbd/quotas.c */
diff --git a/source3/include/smb.h b/source3/include/smb.h
index 0968984..30e91e7 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -1434,6 +1434,11 @@ struct bitmap {
#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200
#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400
#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800
+#define FILE_NOTIFY_CHANGE_FILE_CONTENT \
+ (FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME \
+ | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE \
+ | FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_EA \
+ | FILE_NOTIFY_CHANGE_SECURITY)
#define FILE_NOTIFY_CHANGE_NAME \
(FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME)
diff --git a/source3/smbd/notify_inotify.c b/source3/smbd/notify_inotify.c
index 6159945..a9b4437 100644
--- a/source3/smbd/notify_inotify.c
+++ b/source3/smbd/notify_inotify.c
@@ -322,7 +322,9 @@ static const struct {
{FILE_NOTIFY_CHANGE_LAST_WRITE, IN_ATTRIB},
{FILE_NOTIFY_CHANGE_LAST_ACCESS, IN_ATTRIB},
{FILE_NOTIFY_CHANGE_EA, IN_ATTRIB},
- {FILE_NOTIFY_CHANGE_SECURITY, IN_ATTRIB}
+ {FILE_NOTIFY_CHANGE_SECURITY, IN_ATTRIB},
+ {FILE_NOTIFY_CHANGE_FILE_CONTENT, IN_MODIFY|IN_DELETE|IN_CREATE|IN_DELETE_SELF
+ |IN_MOVE_SELF|IN_MOVED_FROM|IN_MOVED_TO},
};
static uint32_t inotify_map(struct notify_entry *e)
diff --git a/source3/smbd/process.c b/source3/smbd/process.c
index 9abfd36..965928e 100644
--- a/source3/smbd/process.c
+++ b/source3/smbd/process.c
@@ -2291,6 +2291,200 @@ void smbd_process(void)
exit_server_cleanly(NULL);
}
+#ifdef HAVE_INOTIFY
+struct notify_context {
+ struct db_context *db_recursive;
+ struct db_context *db_onelevel;
+ struct server_id server;
+ struct messaging_context *messaging_ctx;
+ struct notify_list *list;
+ struct notify_array *array;
+ int seqnum;
+ struct sys_notify_context *sys_notify_ctx;
+ TDB_DATA key;
+};
+
+static void smbd_share_permission_changed_handler(struct sys_notify_context *ctx,
+ void *ptr, struct notify_event *ev)
+{
+ struct messaging_context *msg_ctx = talloc_get_type(ptr, struct messaging_context);
+ bool retval = false;
+ int len, sent;
+ len = strlen(ev->path) + 1;
+ retval = message_send_all(msg_ctx, MSG_SMB_REEVALUATE_SHARE, ev->path, len, &sent);
+ if (!retval) {
+ DEBUG(10, ("smbd_share_permission_changed_handler: "
+ "Send message to all smbd failed!\n"));
+ }
+ return;
+}
+
+static NTSTATUS smbd_watch_directory(TALLOC_CTX *mem_ctx,
+ struct sys_notify_context *sys_ctx,
+ const char *path)
+{
+ struct notify_entry e;
+ struct inotify_watch_context *w = NULL;
+ NTSTATUS status;
+ if (!sys_ctx) {
+ DEBUG(1, ("smbd_watch_directory: out of memory!!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ ZERO_STRUCT(e);
+ /* Add directory to the watch list. */
+ e.path = talloc_strdup(mem_ctx, path);
+ if (!e.path) {
+ DEBUG(1, ("smbd_watch_directory: out of memory!\n"));
+ return NT_STATUS_NO_MEMORY;
+ }
+ e.path_len = strlen(e.path);
+ e.filter = FILE_NOTIFY_CHANGE_FILE_CONTENT;
+ status = inotify_watch(sys_ctx, &e, smbd_share_permission_changed_handler,
+ (void *)smbd_messaging_context(), (void *)&w);
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(1, ("smbd_watch_directory: add inotify for directory [%s] failed!\n", path));
+ return status;
+ }
+ return NT_STATUS_OK;
+}
+
+static NTSTATUS smbd_notify_init(void)
+{
+ struct notify_context *notify;
+ struct sys_notify_context *sys_ctx = NULL;
+ NTSTATUS status;
+
+ notify = talloc(NULL, struct notify_context);
+ if (notify == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ notify->server = server_id_self();
+ notify->messaging_ctx = smbd_messaging_context();
+ notify->list = NULL;
+ notify->array = NULL;
+
+ notify->sys_notify_ctx = sys_notify_context_create(NULL, notify, smbd_event_context());
+ sys_ctx = notify->sys_notify_ctx;
+ /* Adding usershare to the watch list. */
+ status = smbd_watch_directory(notify, sys_ctx, lp_usershare_path());
+ if (NT_STATUS_IS_ERR(status)) {
+ DEBUG(1, ("add inotify for usershare permission failed!\n"));
+ return status;
+ }
+
+ /* Watch on other directories here. configure files, etc.*/
+
+ return NT_STATUS_OK;
+}
+#endif
+
+void smbd_watch_share_permissions(void)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+
+ reload_services(true);
+
+ static_init_rpc;
+
+ init_modules();
+
+ smb_perfcount_init();
+
+ if (!init_account_policy()) {
+ exit_server("Could not open account policy tdb.\n");
+ }
+
+ if (*lp_rootdir()) {
+ if (chroot(lp_rootdir()) != 0) {
+ DEBUG(0,("Failed to change root to %s\n", lp_rootdir()));
+ exit_server("Failed to chroot()");
+ }
+ if (chdir("/") == -1) {
+ DEBUG(0,("Failed to chdir to / on chroot to %s\n", lp_rootdir()));
+ exit_server("Failed to chroot()");
+ }
+ DEBUG(0,("Changed root to %s\n", lp_rootdir()));
+ }
+
+ /*
+ * Use the default MSG_DEBUG handler to avoid rebroadcasting
+ * MSGs to all child processes
+ */
+ messaging_deregister(smbd_messaging_context(),
+ MSG_DEBUG, NULL);
+ messaging_register(smbd_messaging_context(), NULL,
+ MSG_DEBUG, debug_message);
+
+#ifdef CLUSTER_SUPPORT
+
+ if (lp_clustering()) {
+ /*
+ * We need to tell ctdb about our client's TCP
+ * connection, so that for failover ctdbd can send
+ * tickle acks, triggering a reconnection by the
+ * client.
+ */
+
+ struct sockaddr_storage srv, clnt;
+
+ if (client_get_tcp_info(&srv, &clnt) == 0) {
+
+ NTSTATUS status;
+
+ status = ctdbd_register_ips(
+ messaging_ctdbd_connection(),
+ &srv, &clnt, release_ip, NULL);
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("ctdbd_register_ips failed: %s\n",
+ nt_errstr(status)));
+ }
+ } else
+ {
+ DEBUG(0,("Unable to get tcp info for "
+ "CTDB_CONTROL_TCP_CLIENT: %s\n",
+ strerror(errno)));
+ }
+ }
+
+#endif
+
+#if 0
+ smbd_file_list_init();
+#endif
+#ifdef HAVE_INOTIFY
+ status = smbd_notify_init();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("smbd_watch_share_permissions: inotify init failed!\n"));
+ exit_server_cleanly(NULL);
+ }
+#else
+ exit_server_cleanly(NULL);
+#endif
+
+ TALLOC_FREE(frame);
+
+ while (True) {
+ frame = talloc_stackframe_pool(8192);
+
+ errno = 0;
+
+ status = smbd_server_connection_loop_once(NULL);
+ if (!NT_STATUS_EQUAL(status, NT_STATUS_RETRY) &&
+ !NT_STATUS_IS_OK(status)) {
+ DEBUG(3, ("smbd_server_connection_loop_once failed: %s,"
+ " exiting\n", nt_errstr(status)));
+ break;
+ }
+
+ TALLOC_FREE(frame);
+ }
+
+ exit_server_cleanly(NULL);
+}
+
bool req_is_in_chain(struct smb_request *req)
{
if (req->vwv != (uint16_t *)(req->inbuf+smb_vwv)) {
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index 09ad8d8..956d6c0 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -1268,6 +1268,49 @@ extern void build_options(bool screen);
}
parent->interactive = interactive;
+ {
+ /* fork a child here to watch on share permissions. */
+ pid_t pid;
+ pid = sys_fork();
+ if (!pid) {
+ /* child process. */
+ NTSTATUS status = NT_STATUS_OK;
+ /* Child code ... */
+ am_parent = 0;
+
+ /* Stop zombies, the parent explicitly handles
+ * them, counting worker smbds. */
+ CatchChild();
+
+ /* close our standard file
+ * descriptors */
+ close_low_fds(False);
+
+ /*
+ * Can't use TALLOC_FREE here. Nulling out the argument to it
+ * would overwrite memory we've just freed.
+ */
+
+ status = reinit_after_fork(smbd_messaging_context(),
+ smbd_event_context(), true);
+ if (!NT_STATUS_IS_OK(status)) {
+ if (NT_STATUS_EQUAL(status,
+ NT_STATUS_TOO_MANY_OPENED_FILES)) {
+ DEBUG(0,("child process cannot initialize "
+ "because too many files are open\n"));
+ exit_server_cleanly(NULL);
+ }
+ DEBUG(0,("reinit_after_fork() failed\n"));
+ smb_panic("reinit_after_fork() failed");
+ }
+
+ smbd_setup_sig_term_handler();
+ smbd_setup_sig_hup_handler();
+ smbd_watch_share_permissions();
+ exit_server_cleanly(NULL);
+ }
+ }
+
if (!open_sockets_smbd(parent, ports))
exit_server("open_sockets_smbd() failed");
--
1.5.3
--------------020706050703070905050801
Content-Type: text/x-patch;
name*0="dynamic-share-permission-master-part-3-normal-share-mbox.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename*0="dynamic-share-permission-master-part-3-normal-share-mbox.dif";
filename*1="f"
More information about the samba-technical
mailing list