summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Adam <obnox@samba.org>2012-03-15 16:29:27 +0100
committerMichael Adam <obnox@samba.org>2012-03-15 18:41:37 +0100
commitc80f70390c3763d5d7248979db9542cd05b7cb44 (patch)
treea0f96da41205705839cec1dead1fc1762051a2e5
parente5ebe67e3837cf4da0ae2c3d00c72a244b8f202f (diff)
downloadsamba-c80f70390c3763d5d7248979db9542cd05b7cb44.tar.gz
samba-c80f70390c3763d5d7248979db9542cd05b7cb44.tar.bz2
samba-c80f70390c3763d5d7248979db9542cd05b7cb44.zip
s3:smbd: let smbd/nmbd/winbindd child processes terminate if the parent process died.
This applies to all child processes making use of reinit_after_fork(). It is implemented by establishing a pipe between parent and child. The child watches for EOF on the read end of the pipe, indidcating an exited parent. Pair-Programmed-With: Stefan Metzmacher <metze@samba.org>
-rw-r--r--source3/include/proto.h1
-rw-r--r--source3/lib/util.c56
-rw-r--r--source3/nmbd/nmbd.c11
-rw-r--r--source3/smbd/server.c13
-rw-r--r--source3/winbindd/winbindd.c11
5 files changed, 92 insertions, 0 deletions
diff --git a/source3/include/proto.h b/source3/include/proto.h
index e0d9f3117e..e8a0d42b3c 100644
--- a/source3/include/proto.h
+++ b/source3/include/proto.h
@@ -484,6 +484,7 @@ char *unix_clean_name(TALLOC_CTX *ctx, const char *s);
char *clean_name(TALLOC_CTX *ctx, const char *s);
ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos);
int set_blocking(int fd, bool set);
+NTSTATUS init_before_fork(void);
NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
struct event_context *ev_ctx,
bool parent_longlived);
diff --git a/source3/lib/util.c b/source3/lib/util.c
index 822db43fef..fa2cc9fd83 100644
--- a/source3/lib/util.c
+++ b/source3/lib/util.c
@@ -356,6 +356,46 @@ ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos
#endif
}
+static int reinit_after_fork_pipe[2] = { -1, -1 };
+
+NTSTATUS init_before_fork(void)
+{
+ int ret;
+
+ ret = pipe(reinit_after_fork_pipe);
+ if (ret == -1) {
+ NTSTATUS status;
+
+ status = map_nt_error_from_unix_common(errno);
+
+ DEBUG(0, ("Error creating child_pipe: %s\n",
+ nt_errstr(status)));
+
+ return status;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/**
+ * Detect died parent by detecting EOF on the pipe
+ */
+static void reinit_after_fork_pipe_handler(struct tevent_context *ev,
+ struct tevent_fd *fde,
+ uint16_t flags,
+ void *private_data)
+{
+ char c;
+
+ if (read(reinit_after_fork_pipe[0], &c, 1) != 1) {
+ /*
+ * we have reached EOF on stdin, which means the
+ * parent has exited. Shutdown the server
+ */
+ (void)kill(getpid(), SIGTERM);
+ }
+}
+
NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
struct event_context *ev_ctx,
@@ -363,6 +403,11 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
{
NTSTATUS status = NT_STATUS_OK;
+ if (reinit_after_fork_pipe[1] != -1) {
+ close(reinit_after_fork_pipe[1]);
+ reinit_after_fork_pipe[1] = -1;
+ }
+
/* Reset the state of the random
* number generation system, so
* children do not get the same random
@@ -380,6 +425,17 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
smb_panic(__location__ ": Failed to re-initialise event context");
}
+ if (reinit_after_fork_pipe[0] != -1) {
+ struct tevent_fd *fde;
+
+ fde = tevent_add_fd(ev_ctx, ev_ctx /* TALLOC_CTX */,
+ reinit_after_fork_pipe[0], TEVENT_FD_READ,
+ reinit_after_fork_pipe_handler, NULL);
+ if (fde == NULL) {
+ smb_panic(__location__ ": Failed to add reinit_after_fork pipe event");
+ }
+ }
+
if (msg_ctx) {
/*
* For clustering, we need to re-init our ctdbd connection after the
diff --git a/source3/nmbd/nmbd.c b/source3/nmbd/nmbd.c
index 52d7ed9e4e..eff1eca2f1 100644
--- a/source3/nmbd/nmbd.c
+++ b/source3/nmbd/nmbd.c
@@ -951,6 +951,17 @@ static bool open_sockets(bool isdaemon, int port)
exit(1);
}
+ /*
+ * Do not initialize the parent-child-pipe before becoming
+ * a daemon: this is used to detect a died parent in the child
+ * process.
+ */
+ status = init_before_fork();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+ exit(1);
+ }
+
if (!nmbd_setup_sig_term_handler(msg))
exit(1);
if (!nmbd_setup_stdin_handler(msg, !Fork))
diff --git a/source3/smbd/server.c b/source3/smbd/server.c
index aa3da1f743..851b4608a7 100644
--- a/source3/smbd/server.c
+++ b/source3/smbd/server.c
@@ -57,6 +57,8 @@ struct smbd_parent_context {
/* the list of current child processes */
struct smbd_child_pid *children;
size_t num_children;
+ /* pipe for detecting death of parent process in child: */
+ int child_pipe[2];
struct timed_event *cleanup_te;
};
@@ -1231,6 +1233,17 @@ extern void build_options(bool screen);
exit(1);
}
+ /*
+ * Do not initialize the parent-child-pipe before becoming
+ * a daemon: this is used to detect a died parent in the child
+ * process.
+ */
+ status = init_before_fork();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+ exit(1);
+ }
+
smbd_server_conn->msg_ctx = msg_ctx;
parent = talloc_zero(ev_ctx, struct smbd_parent_context);
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index d1d36fd007..66e53d9cae 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -1461,6 +1461,17 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
+ /*
+ * Do not initialize the parent-child-pipe before becoming
+ * a daemon: this is used to detect a died parent in the child
+ * process.
+ */
+ status = init_before_fork();
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("init_before_fork failed: %s\n", nt_errstr(status)));
+ exit(1);
+ }
+
winbindd_register_handlers(!Fork);
status = init_system_info();