diff --git a/runopts.h b/runopts.h index 8c44b52..50c51df 100644 --- a/runopts.h +++ b/runopts.h @@ -79,8 +79,9 @@ typedef struct svr_runopts { char *addresses[DROPBEAR_MAX_PORTS]; int inetdmode; - /* Hidden "-2" flag indicates it's re-executing itself */ - int reexec_child; + /* Hidden "-2 childpipe_fd" flag indicates it's re-executing itself, + stores the childpipe preauth file descriptor. Set to -1 otherwise. */ + int reexec_childpipe; /* Flags indicating whether to use ipv4 and ipv6 */ /* not used yet diff --git a/svr-main.c b/svr-main.c index a9f8a57..be69e39 100644 --- a/svr-main.c +++ b/svr-main.c @@ -71,7 +71,7 @@ int main(int argc, char ** argv) #endif #if DROPBEAR_DO_REEXEC - if (svr_opts.reexec_child) { + if (svr_opts.reexec_childpipe >= 0) { #ifdef PR_SET_NAME /* Fix the "Name:" in /proc/pid/status, otherwise it's a FD number from fexecve. @@ -102,7 +102,7 @@ static void main_inetd() { seedrandom(); - if (!svr_opts.reexec_child) { + if (svr_opts.reexec_childpipe < 0) { /* In case our inetd was lax in logging source addresses */ get_socket_address(0, NULL, NULL, &host, &port, 0); dropbear_log(LOG_INFO, "Child connection from %s:%s", host, port); @@ -115,10 +115,8 @@ static void main_inetd() { setsid(); } - /* Start service program - * -1 is a dummy childpipe, just something we can close() without - * mattering. */ - svr_session(0, -1); + /* -1 for childpipe in the inetd case is discarded */ + svr_session(0, svr_opts.reexec_childpipe); /* notreached */ } @@ -347,9 +345,10 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) { if (execfd >= 0) { #if DROPBEAR_DO_REEXEC - /* Add "-2" to the args and re-execute ourself. */ - char **new_argv = m_malloc(sizeof(char*) * (argc+3)); - int pos0 = 0, new_argc = argc+1; + /* Add "-2 childpipe[1]" to the args and re-execute ourself. */ + char **new_argv = m_malloc(sizeof(char*) * (argc+4)); + char buf[10]; + int pos0 = 0, new_argc = argc+2; /* We need to specially handle "dropbearmulti dropbear". */ if (multipath) { @@ -359,7 +358,9 @@ static void main_noinetd(int argc, char ** argv, const char* multipath) { } memcpy(&new_argv[pos0], argv, sizeof(char*) * argc); - new_argv[new_argc-1] = "-2"; + new_argv[new_argc-2] = "-2"; + snprintf(buf, sizeof(buf), "%d", childpipe[1]); + new_argv[new_argc-1] = buf; new_argv[new_argc] = NULL; if ((dup2(childsock, STDIN_FILENO) < 0)) { diff --git a/svr-runopts.c b/svr-runopts.c index 9f40089..c15f23b 100644 --- a/svr-runopts.c +++ b/svr-runopts.c @@ -138,6 +138,7 @@ void svr_getopts(int argc, char ** argv) { char* keepalive_arg = NULL; char* idle_timeout_arg = NULL; char* maxauthtries_arg = NULL; + char* reexec_fd_arg = NULL; char* keyfile = NULL; char c; #if DROPBEAR_PLUGIN @@ -175,6 +176,7 @@ void svr_getopts(int argc, char ** argv) { svr_opts.pubkey_plugin_options = NULL; #endif svr_opts.pass_on_env = 0; + svr_opts.reexec_childpipe = -1; #ifndef DISABLE_ZLIB opts.compress_mode = DROPBEAR_COMPRESS_DELAYED; @@ -250,12 +252,12 @@ void svr_getopts(int argc, char ** argv) { #if DROPBEAR_DO_REEXEC && NON_INETD_MODE /* For internal use by re-exec */ case '2': - svr_opts.reexec_child = 1; + next = &reexec_fd_arg; break; #endif case 'p': - nextisport = 1; - break; + nextisport = 1; + break; case 'P': next = &svr_opts.pidfile; break; @@ -426,6 +428,13 @@ void svr_getopts(int argc, char ** argv) { dropbear_log(LOG_INFO, "Forced command set to '%s'", svr_opts.forced_command); } + if (reexec_fd_arg) { + if (m_str_to_uint(reexec_fd_arg, &svr_opts.reexec_childpipe) == DROPBEAR_FAILURE + || svr_opts.reexec_childpipe < 0) { + dropbear_exit("Bad -2"); + } + } + #if INETD_MODE if (svr_opts.inetdmode && ( opts.usingsyslog == 0