ssh -f and -O ControlPersist=yes, ControlMaster=yes leaves stderr open

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

 



Hi


I'm trying to wrap ssh in an application using glib. For now, I'm launching the
ssh client in master mode and want it to detach, keeping the control socket around.

I figured I could do that using the -f flag and the usual Control* options to
force ssh to daemonize (ideally without executing any command), but it turns out
that glib doesn't recognize the daemonized process as exited, since its...
(grand-?) child process stderr pipe keeps connected (hereditary) to the original
stderr pipe, which, in my tests, happens to be the stderr pipe of my shell.


Now, that's not a tragedy per se, but I wonder if this is considered a feature
or rather a bug.

I usually expect a daemonizing process to close its file descriptors - at least
in children. The OpenSSH client does not do that in some cases...


From current master's ssh.c:

------------------------------------>snip<------------------------------------
static int ssh_session2(struct ssh *ssh, struct passwd *pw) {
[...]
	if (options.control_persist && muxserver_sock != -1) {
		[...]
		if (!fork_after_authentication_flag)
			need_controlpersist_detach = 1;
		fork_after_authentication_flag = 1;
	}
------------------------------------>snip<------------------------------------

Note how need_controlpersist_detach is only set to 1 if
fork_after_authentication_flag is not set (i.e., -f has not been passed). This
probably makes sense to not fork twice, but let's look further:

------------------------------------>snip<------------------------------------
/* Do fork() after authentication. Used by "ssh -f" */
static void fork_postauth(void) {
	if (need_controlpersist_detach)
		control_persist_detach();
	[...]
	if (daemon(1, 1) == -1)
------------------------------------>snip<------------------------------------

No closing of FDs through daemon()... and since need_controlpersist_detach will
not be true if fork_after_authentication_flag is, the code that closes the other
FDs will not run.


I wonder if that (not closing stderr) is generally a sane idea, not just in my,
admittedly, advanced use case. stdin and stdout will be closed, which makes
sense, but stderr is kept connected. That *might* be useful because stderr is
the default logging place (and you wouldn't be able to get error messages from
the backgrounded child otherwise) *and* the documentation doesn't talk about
daemonizing, but merely "backgrounding" (is this nitpicking). It feels odd, though.


And it's especially odd in my use case, because the control-persist feature
explicitly includes this code (if -f has not been passed):

------------------------------------>snip<------------------------------------
static void control_persist_detach(void) {
[...]
	switch ((pid = fork())) {
	[...]
	case 0:
		/* Child: master process continues mainloop */
		break;
	default:
		/* Parent: set up mux slave to connect to backgrounded master */
		[...]
		/* muxclient() doesn't return on success. */
		fatal("Failed to connect to new control master");
	}
	[...]
		keep_stderr = log_is_on_stderr() && debug_flag;
		if (dup2(devnull, STDIN_FILENO) == -1 ||
		    dup2(devnull, STDOUT_FILENO) == -1 ||
		    (!keep_stderr && dup2(devnull, STDERR_FILENO) == -1))
		[...]
	daemon(1, 1);
------------------------------------>snip<------------------------------------

Note how stderr is explicitly to be closed by the master (child) process UNLESS
debugging is turned on, which sounds like an okay consideration for debugging
things.


What's your opinion? Is this a bug or an intended feature?



Mihai

Attachment: signature.asc
Description: OpenPGP digital signature

_______________________________________________
openssh-unix-dev mailing list
openssh-unix-dev@xxxxxxxxxxx
https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev

[Date Prev] [Date Next] [Thread Prev] [Thread Next] [Date Index] [Thread Index]

[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux