1
0
mirror of https://github.com/samba-team/samba.git synced 2025-08-03 04:22:09 +03:00

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>
This commit is contained in:
Michael Adam
2012-03-15 16:29:27 +01:00
parent e5ebe67e38
commit c80f70390c
5 changed files with 92 additions and 0 deletions

View File

@ -484,6 +484,7 @@ char *unix_clean_name(TALLOC_CTX *ctx, const char *s);
char *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); 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); int set_blocking(int fd, bool set);
NTSTATUS init_before_fork(void);
NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx, NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
struct event_context *ev_ctx, struct event_context *ev_ctx,
bool parent_longlived); bool parent_longlived);

View File

@ -356,6 +356,46 @@ ssize_t write_data_at_offset(int fd, const char *buffer, size_t N, SMB_OFF_T pos
#endif #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, NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
struct event_context *ev_ctx, struct event_context *ev_ctx,
@ -363,6 +403,11 @@ NTSTATUS reinit_after_fork(struct messaging_context *msg_ctx,
{ {
NTSTATUS status = NT_STATUS_OK; 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 /* Reset the state of the random
* number generation system, so * number generation system, so
* children do not get the same random * 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"); 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) { if (msg_ctx) {
/* /*
* For clustering, we need to re-init our ctdbd connection after the * For clustering, we need to re-init our ctdbd connection after the

View File

@ -951,6 +951,17 @@ static bool open_sockets(bool isdaemon, int port)
exit(1); 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)) if (!nmbd_setup_sig_term_handler(msg))
exit(1); exit(1);
if (!nmbd_setup_stdin_handler(msg, !Fork)) if (!nmbd_setup_stdin_handler(msg, !Fork))

View File

@ -57,6 +57,8 @@ struct smbd_parent_context {
/* the list of current child processes */ /* the list of current child processes */
struct smbd_child_pid *children; struct smbd_child_pid *children;
size_t num_children; size_t num_children;
/* pipe for detecting death of parent process in child: */
int child_pipe[2];
struct timed_event *cleanup_te; struct timed_event *cleanup_te;
}; };
@ -1231,6 +1233,17 @@ extern void build_options(bool screen);
exit(1); 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; smbd_server_conn->msg_ctx = msg_ctx;
parent = talloc_zero(ev_ctx, struct smbd_parent_context); parent = talloc_zero(ev_ctx, struct smbd_parent_context);

View File

@ -1461,6 +1461,17 @@ int main(int argc, char **argv, char **envp)
exit(1); 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); winbindd_register_handlers(!Fork);
status = init_system_info(); status = init_system_info();