[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