aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/sshd.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/sshd.c')
-rw-r--r--crypto/openssh/sshd.c402
1 files changed, 261 insertions, 141 deletions
diff --git a/crypto/openssh/sshd.c b/crypto/openssh/sshd.c
index fd48835ebd2a..14b6ce5d10a1 100644
--- a/crypto/openssh/sshd.c
+++ b/crypto/openssh/sshd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sshd.c,v 1.612 2024/09/15 01:11:26 djm Exp $ */
+/* $OpenBSD: sshd.c,v 1.617 2025/04/07 08:12:22 dtucker Exp $ */
/*
* Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved.
* Copyright (c) 2002 Niels Provos. All rights reserved.
@@ -39,6 +39,7 @@
#include "openbsd-compat/sys-tree.h"
#include "openbsd-compat/sys-queue.h"
#include <sys/wait.h>
+#include <sys/utsname.h>
#include <errno.h>
#include <fcntl.h>
@@ -53,6 +54,7 @@
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
+#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -101,6 +103,7 @@
#include "sk-api.h"
#include "addr.h"
#include "srclimit.h"
+#include "atomicio.h"
#ifdef LIBWRAP
#include <tcpd.h>
@@ -109,9 +112,8 @@
/* Re-exec fds */
#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1)
-#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2)
-#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3)
-#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4)
+#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 2)
+#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 3)
extern char *__progname;
@@ -196,13 +198,15 @@ struct early_child {
struct xaddr addr;
int have_addr;
int status, have_status;
+ struct sshbuf *config;
+ struct sshbuf *keys;
};
static struct early_child *children;
static int children_active;
-static int startup_pipe = -1; /* in child */
/* sshd_config buffer */
struct sshbuf *cfg;
+struct sshbuf *config; /* packed */
/* Included files from the configuration file */
struct include_list includes = TAILQ_HEAD_INITIALIZER(includes);
@@ -253,7 +257,10 @@ child_register(int pipefd, int sockfd)
struct sockaddr *sa = (struct sockaddr *)&addr;
for (i = 0; i < options.max_startups; i++) {
- if (children[i].pipefd != -1 || children[i].pid > 0)
+ if (children[i].pipefd != -1 ||
+ children[i].config != NULL ||
+ children[i].keys != NULL ||
+ children[i].pid > 0)
continue;
child = &(children[i]);
break;
@@ -264,6 +271,8 @@ child_register(int pipefd, int sockfd)
}
child->pipefd = pipefd;
child->early = 1;
+ if ((child->config = sshbuf_fromb(config)) == NULL)
+ fatal_f("sshbuf_fromb failed");
/* record peer address, if available */
if (getpeername(sockfd, sa, &addrlen) == 0 &&
addr_sa_to_xaddr(sa, addrlen, &child->addr) == 0)
@@ -297,6 +306,8 @@ child_finish(struct early_child *child)
fatal_f("internal error: children_active underflow");
if (child->pipefd != -1)
close(child->pipefd);
+ sshbuf_free(child->config);
+ sshbuf_free(child->keys);
free(child->id);
memset(child, '\0', sizeof(*child));
child->pipefd = -1;
@@ -350,6 +361,16 @@ child_reap(struct early_child *child)
{
LogLevel level = SYSLOG_LEVEL_DEBUG1;
int was_crash, penalty_type = SRCLIMIT_PENALTY_NONE;
+ const char *child_status;
+
+ if (child->config)
+ child_status = " (sending config)";
+ else if (child->keys)
+ child_status = " (sending keys)";
+ else if (child->early)
+ child_status = " (early)";
+ else
+ child_status = "";
/* Log exit information */
if (WIFSIGNALED(child->status)) {
@@ -361,54 +382,50 @@ child_reap(struct early_child *child)
level = SYSLOG_LEVEL_ERROR;
do_log2(level, "session process %ld for %s killed by "
"signal %d%s", (long)child->pid, child->id,
- WTERMSIG(child->status), child->early ? " (early)" : "");
+ WTERMSIG(child->status), child_status);
if (was_crash)
penalty_type = SRCLIMIT_PENALTY_CRASH;
} else if (!WIFEXITED(child->status)) {
penalty_type = SRCLIMIT_PENALTY_CRASH;
error("session process %ld for %s terminated abnormally, "
"status=0x%x%s", (long)child->pid, child->id, child->status,
- child->early ? " (early)" : "");
+ child_status);
} else {
/* Normal exit. We care about the status */
switch (WEXITSTATUS(child->status)) {
case 0:
debug3_f("preauth child %ld for %s completed "
- "normally %s", (long)child->pid, child->id,
- child->early ? " (early)" : "");
+ "normally%s", (long)child->pid, child->id,
+ child_status);
break;
case EXIT_LOGIN_GRACE:
penalty_type = SRCLIMIT_PENALTY_GRACE_EXCEEDED;
logit("Timeout before authentication for %s, "
"pid = %ld%s", child->id, (long)child->pid,
- child->early ? " (early)" : "");
+ child_status);
break;
case EXIT_CHILD_CRASH:
penalty_type = SRCLIMIT_PENALTY_CRASH;
logit("Session process %ld unpriv child crash for %s%s",
- (long)child->pid, child->id,
- child->early ? " (early)" : "");
+ (long)child->pid, child->id, child_status);
break;
case EXIT_AUTH_ATTEMPTED:
penalty_type = SRCLIMIT_PENALTY_AUTHFAIL;
debug_f("preauth child %ld for %s exited "
- "after unsuccessful auth attempt %s",
- (long)child->pid, child->id,
- child->early ? " (early)" : "");
+ "after unsuccessful auth attempt%s",
+ (long)child->pid, child->id, child_status);
break;
case EXIT_CONFIG_REFUSED:
penalty_type = SRCLIMIT_PENALTY_REFUSECONNECTION;
debug_f("preauth child %ld for %s prohibited by"
- "RefuseConnection %s",
- (long)child->pid, child->id,
- child->early ? " (early)" : "");
+ "RefuseConnection%s",
+ (long)child->pid, child->id, child_status);
break;
default:
penalty_type = SRCLIMIT_PENALTY_NOAUTH;
debug_f("preauth child %ld for %s exited "
"with status %d%s", (long)child->pid, child->id,
- WEXITSTATUS(child->status),
- child->early ? " (early)" : "");
+ WEXITSTATUS(child->status), child_status);
break;
}
}
@@ -471,6 +488,7 @@ static void
show_info(void)
{
int i;
+ const char *child_status;
/* XXX print listening sockets here too */
if (children == NULL)
@@ -479,9 +497,16 @@ show_info(void)
for (i = 0; i < options.max_startups; i++) {
if (children[i].pipefd == -1 && children[i].pid <= 0)
continue;
+ if (children[i].config)
+ child_status = " (sending config)";
+ else if (children[i].keys)
+ child_status = " (sending keys)";
+ else if (children[i].early)
+ child_status = " (early)";
+ else
+ child_status = "";
logit("child %d: fd=%d pid=%ld %s%s", i, children[i].pipefd,
- (long)children[i].pid, children[i].id,
- children[i].early ? " (early)" : "");
+ (long)children[i].pid, children[i].id, child_status);
}
srclimit_penalty_info();
}
@@ -579,59 +604,51 @@ should_drop_connection(int startups)
static int
drop_connection(int sock, int startups, int notify_pipe)
{
+ static struct log_ratelimit_ctx ratelimit_maxstartups;
+ static struct log_ratelimit_ctx ratelimit_penalty;
+ static int init_done;
char *laddr, *raddr;
- const char *reason = NULL, msg[] = "Not allowed at this time\r\n";
- static time_t last_drop, first_drop;
- static u_int ndropped;
- LogLevel drop_level = SYSLOG_LEVEL_VERBOSE;
- time_t now;
-
- if (!srclimit_penalty_check_allow(sock, &reason)) {
- drop_level = SYSLOG_LEVEL_INFO;
- goto handle;
- }
-
- now = monotime();
- if (!should_drop_connection(startups) &&
- srclimit_check_allow(sock, notify_pipe) == 1) {
- if (last_drop != 0 &&
- startups < options.max_startups_begin - 1) {
- /* XXX maybe need better hysteresis here */
- logit("exited MaxStartups throttling after %s, "
- "%u connections dropped",
- fmt_timeframe(now - first_drop), ndropped);
- last_drop = 0;
- }
- return 0;
+ const char *reason = NULL, *subreason = NULL;
+ const char msg[] = "Not allowed at this time\r\n";
+ struct log_ratelimit_ctx *rl = NULL;
+ int ratelimited;
+ u_int ndropped;
+
+ if (!init_done) {
+ init_done = 1;
+ log_ratelimit_init(&ratelimit_maxstartups, 4, 60, 20, 5*60);
+ log_ratelimit_init(&ratelimit_penalty, 8, 60, 30, 2*60);
}
-#define SSHD_MAXSTARTUPS_LOG_INTERVAL (5 * 60)
- if (last_drop == 0) {
- error("beginning MaxStartups throttling");
- drop_level = SYSLOG_LEVEL_INFO;
- first_drop = now;
- ndropped = 0;
- } else if (last_drop + SSHD_MAXSTARTUPS_LOG_INTERVAL < now) {
- /* Periodic logs */
- error("in MaxStartups throttling for %s, "
- "%u connections dropped",
- fmt_timeframe(now - first_drop), ndropped + 1);
- drop_level = SYSLOG_LEVEL_INFO;
+ /* PerSourcePenalties */
+ if (!srclimit_penalty_check_allow(sock, &subreason)) {
+ reason = "PerSourcePenalties";
+ rl = &ratelimit_penalty;
+ } else {
+ /* MaxStartups */
+ if (!should_drop_connection(startups) &&
+ srclimit_check_allow(sock, notify_pipe) == 1)
+ return 0;
+ reason = "Maxstartups";
+ rl = &ratelimit_maxstartups;
}
- last_drop = now;
- ndropped++;
- reason = "past Maxstartups";
- handle:
laddr = get_local_ipaddr(sock);
raddr = get_peer_ipaddr(sock);
- do_log2(drop_level, "drop connection #%d from [%s]:%d on [%s]:%d %s",
+ ratelimited = log_ratelimit(rl, time(NULL), NULL, &ndropped);
+ do_log2(ratelimited ? SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_INFO,
+ "drop connection #%d from [%s]:%d on [%s]:%d %s",
startups,
raddr, get_peer_port(sock),
laddr, get_local_port(sock),
- reason);
+ subreason != NULL ? subreason : reason);
free(laddr);
free(raddr);
+ if (ndropped != 0) {
+ logit("%s logging rate-limited: additional %u connections "
+ "dropped", reason, ndropped);
+ }
+
/* best-effort notification to client */
(void)write(sock, msg, sizeof(msg) - 1);
return 1;
@@ -659,11 +676,13 @@ usage(void)
static struct sshbuf *
pack_hostkeys(void)
{
- struct sshbuf *keybuf = NULL, *hostkeys = NULL;
+ struct sshbuf *m = NULL, *keybuf = NULL, *hostkeys = NULL;
int r;
u_int i;
+ size_t len;
- if ((keybuf = sshbuf_new()) == NULL ||
+ if ((m = sshbuf_new()) == NULL ||
+ (keybuf = sshbuf_new()) == NULL ||
(hostkeys = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
@@ -698,19 +717,28 @@ pack_hostkeys(void)
}
}
+ if ((r = sshbuf_put_u32(m, 0)) != 0 ||
+ (r = sshbuf_put_u8(m, 0)) != 0 ||
+ (r = sshbuf_put_stringb(m, hostkeys)) != 0)
+ fatal_fr(r, "compose message");
+ if ((len = sshbuf_len(m)) < 5 || len > 0xffffffff)
+ fatal_f("bad length %zu", len);
+ POKE_U32(sshbuf_mutable_ptr(m), len - 4);
+
sshbuf_free(keybuf);
- return hostkeys;
+ sshbuf_free(hostkeys);
+ return m;
}
-static void
-send_rexec_state(int fd, struct sshbuf *conf)
+static struct sshbuf *
+pack_config(struct sshbuf *conf)
{
- struct sshbuf *m = NULL, *inc = NULL, *hostkeys = NULL;
+ struct sshbuf *m = NULL, *inc = NULL;
struct include_item *item = NULL;
- int r, sz;
+ size_t len;
+ int r;
- debug3_f("entering fd = %d config len %zu", fd,
- sshbuf_len(conf));
+ debug3_f("d config len %zu", sshbuf_len(conf));
if ((m = sshbuf_new()) == NULL ||
(inc = sshbuf_new()) == NULL)
@@ -724,42 +752,76 @@ send_rexec_state(int fd, struct sshbuf *conf)
fatal_fr(r, "compose includes");
}
- hostkeys = pack_hostkeys();
-
- /*
- * Protocol from reexec master to child:
- * string configuration
- * uint64 timing_secret
- * string host_keys[] {
- * string private_key
- * string public_key
- * string certificate
- * }
- * string included_files[] {
- * string selector
- * string filename
- * string contents
- * }
- */
- if ((r = sshbuf_put_stringb(m, conf)) != 0 ||
+ if ((r = sshbuf_put_u32(m, 0)) != 0 ||
+ (r = sshbuf_put_u8(m, 0)) != 0 ||
+ (r = sshbuf_put_stringb(m, conf)) != 0 ||
(r = sshbuf_put_u64(m, options.timing_secret)) != 0 ||
- (r = sshbuf_put_stringb(m, hostkeys)) != 0 ||
(r = sshbuf_put_stringb(m, inc)) != 0)
fatal_fr(r, "compose config");
- /* We need to fit the entire message inside the socket send buffer */
- sz = ROUNDUP(sshbuf_len(m) + 5, 16*1024);
- if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sz, sizeof sz) == -1)
- fatal_f("setsockopt SO_SNDBUF: %s", strerror(errno));
-
- if (ssh_msg_send(fd, 0, m) == -1)
- error_f("ssh_msg_send failed");
+ if ((len = sshbuf_len(m)) < 5 || len > 0xffffffff)
+ fatal_f("bad length %zu", len);
+ POKE_U32(sshbuf_mutable_ptr(m), len - 4);
- sshbuf_free(m);
sshbuf_free(inc);
- sshbuf_free(hostkeys);
debug3_f("done");
+ return m;
+}
+
+/*
+ * Protocol from reexec master to child:
+ * uint32 size
+ * uint8 type (ignored)
+ * string configuration
+ * uint64 timing_secret
+ * string included_files[] {
+ * string selector
+ * string filename
+ * string contents
+ * }
+ * Second message
+ * uint32 size
+ * uint8 type (ignored)
+ * string host_keys[] {
+ * string private_key
+ * string public_key
+ * string certificate
+ * }
+ */
+/*
+ * This function is used only if inet_flag or debug_flag is set,
+ * otherwise the data is sent from the main poll loop.
+ * It sends the config from a child process back to the parent.
+ * The parent will read the config after exec.
+ */
+static void
+send_rexec_state(int fd)
+{
+ struct sshbuf *keys;
+ u_int mlen;
+ pid_t pid;
+
+ if ((pid = fork()) == -1)
+ fatal_f("fork failed: %s", strerror(errno));
+ if (pid != 0)
+ return;
+
+ debug3_f("entering fd = %d config len %zu", fd,
+ sshbuf_len(config));
+
+ mlen = sshbuf_len(config);
+ if (atomicio(vwrite, fd, sshbuf_mutable_ptr(config), mlen) != mlen)
+ error_f("write: %s", strerror(errno));
+
+ keys = pack_hostkeys();
+ mlen = sshbuf_len(keys);
+ if (atomicio(vwrite, fd, sshbuf_mutable_ptr(keys), mlen) != mlen)
+ error_f("write: %s", strerror(errno));
+
+ sshbuf_free(keys);
+ debug3_f("done");
+ exit(0);
}
/*
@@ -874,12 +936,15 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
int log_stderr)
{
struct pollfd *pfd = NULL;
- int i, ret, npfd;
+ int i, ret, npfd, r;
int oactive = -1, listening = 0, lameduck = 0;
- int startup_p[2] = { -1 , -1 }, *startup_pollfd;
+ int *startup_pollfd;
+ ssize_t len;
+ const u_char *ptr;
char c = 0;
struct sockaddr_storage from;
struct early_child *child;
+ struct sshbuf *buf;
socklen_t fromlen;
u_char rnd[256];
sigset_t nsigset, osigset;
@@ -962,6 +1027,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
if (children[i].pipefd != -1) {
pfd[npfd].fd = children[i].pipefd;
pfd[npfd].events = POLLIN;
+ if (children[i].config != NULL ||
+ children[i].keys != NULL)
+ pfd[npfd].events |= POLLOUT;
startup_pollfd[i] = npfd++;
}
}
@@ -980,6 +1048,50 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
for (i = 0; i < options.max_startups; i++) {
if (children[i].pipefd == -1 ||
startup_pollfd[i] == -1 ||
+ !(pfd[startup_pollfd[i]].revents & POLLOUT))
+ continue;
+ if (children[i].config)
+ buf = children[i].config;
+ else if (children[i].keys)
+ buf = children[i].keys;
+ else {
+ error_f("no buffer to send");
+ continue;
+ }
+ ptr = sshbuf_ptr(buf);
+ len = sshbuf_len(buf);
+ ret = write(children[i].pipefd, ptr, len);
+ if (ret == -1 && (errno == EINTR || errno == EAGAIN))
+ continue;
+ if (ret <= 0) {
+ if (children[i].early)
+ listening--;
+ srclimit_done(children[i].pipefd);
+ child_close(&(children[i]), 0, 0);
+ continue;
+ }
+ if (ret == len) {
+ /* finished sending buffer */
+ sshbuf_free(buf);
+ if (children[i].config == buf) {
+ /* sent config, now send keys */
+ children[i].config = NULL;
+ children[i].keys = pack_hostkeys();
+ } else if (children[i].keys == buf) {
+ /* sent both config and keys */
+ children[i].keys = NULL;
+ } else {
+ fatal("config buf not set");
+ }
+
+ } else {
+ if ((r = sshbuf_consume(buf, ret)) != 0)
+ fatal_fr(r, "config buf inconsistent");
+ }
+ }
+ for (i = 0; i < options.max_startups; i++) {
+ if (children[i].pipefd == -1 ||
+ startup_pollfd[i] == -1 ||
!(pfd[startup_pollfd[i]].revents & (POLLIN|POLLHUP)))
continue;
switch (read(children[i].pipefd, &c, sizeof(c))) {
@@ -1000,6 +1112,17 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
child_close(&(children[i]), 0, 0);
break;
case 1:
+ if (children[i].config) {
+ error_f("startup pipe %d (fd=%d)"
+ " early read", i, children[i].pipefd);
+ if (children[i].early)
+ listening--;
+ if (children[i].pid > 0)
+ kill(children[i].pid, SIGTERM);
+ srclimit_done(children[i].pipefd);
+ child_close(&(children[i]), 0, 0);
+ break;
+ }
if (children[i].early && c == '\0') {
/* child has finished preliminaries */
listening--;
@@ -1077,26 +1200,18 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
close(*newsock);
continue;
}
- if (pipe(startup_p) == -1) {
- error_f("pipe(startup_p): %s", strerror(errno));
- close(*newsock);
- continue;
- }
- if (drop_connection(*newsock,
- children_active, startup_p[0])) {
- close(*newsock);
- close(startup_p[0]);
- close(startup_p[1]);
- continue;
- }
-
if (socketpair(AF_UNIX,
SOCK_STREAM, 0, config_s) == -1) {
error("reexec socketpair: %s",
strerror(errno));
close(*newsock);
- close(startup_p[0]);
- close(startup_p[1]);
+ continue;
+ }
+ if (drop_connection(*newsock,
+ children_active, config_s[0])) {
+ close(*newsock);
+ close(config_s[0]);
+ close(config_s[1]);
continue;
}
@@ -1114,10 +1229,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
close_listen_socks();
*sock_in = *newsock;
*sock_out = *newsock;
- close(startup_p[0]);
- close(startup_p[1]);
- startup_pipe = -1;
- send_rexec_state(config_s[0], cfg);
+ send_rexec_state(config_s[0]);
close(config_s[0]);
free(pfd);
return;
@@ -1129,8 +1241,9 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
* parent continues listening.
*/
platform_pre_fork();
+ set_nonblock(config_s[0]);
listening++;
- child = child_register(startup_p[0], *newsock);
+ child = child_register(config_s[0], *newsock);
if ((child->pid = fork()) == 0) {
/*
* Child. Close the listening and
@@ -1141,7 +1254,6 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
* the connection.
*/
platform_post_fork_child();
- startup_pipe = startup_p[1];
close_startup_pipes();
close_listen_socks();
*sock_in = *newsock;
@@ -1162,11 +1274,7 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s,
else
debug("Forked child %ld.", (long)child->pid);
- close(startup_p[1]);
-
close(config_s[1]);
- send_rexec_state(config_s[0], cfg);
- close(config_s[0]);
close(*newsock);
/*
@@ -1256,13 +1364,14 @@ main(int ac, char **av)
int sock_in = -1, sock_out = -1, newsock = -1, rexec_argc = 0;
int devnull, config_s[2] = { -1 , -1 }, have_connection_info = 0;
int need_chroot = 1;
- char *fp, *line, *logfile = NULL, **rexec_argv = NULL;
+ char *args, *fp, *line, *logfile = NULL, **rexec_argv = NULL;
struct stat sb;
u_int i, j;
mode_t new_umask;
struct sshkey *key;
struct sshkey *pubkey;
struct connection_info connection_info;
+ struct utsname utsname;
sigset_t sigmask;
memset(&connection_info, 0, sizeof(connection_info));
@@ -1298,6 +1407,7 @@ main(int ac, char **av)
initialize_server_options(&options);
/* Parse command-line arguments. */
+ args = argv_assemble(ac, av); /* logged later */
while ((opt = getopt(ac, av,
"C:E:b:c:f:g:h:k:o:p:u:46DGQRTdeiqrtV")) != -1) {
switch (opt) {
@@ -1467,6 +1577,16 @@ main(int ac, char **av)
fatal("Config test connection parameter (-C) provided without "
"test mode (-T)");
+ debug("sshd version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION);
+ if (uname(&utsname) != 0) {
+ memset(&utsname, 0, sizeof(utsname));
+ strlcpy(utsname.sysname, "UNKNOWN", sizeof(utsname.sysname));
+ }
+ debug3("Running on %s %s %s %s", utsname.sysname, utsname.release,
+ utsname.version, utsname.machine);
+ debug3("Started with: %s", args);
+ free(args);
+
/* Fetch our configuration */
if ((cfg = sshbuf_new()) == NULL)
fatal("sshbuf_new config failed");
@@ -1514,8 +1634,6 @@ main(int ac, char **av)
exit(1);
}
- debug("sshd version %s, %s", SSH_VERSION, SSH_OPENSSL_VERSION);
-
if (do_dump_cfg)
print_config(&connection_info);
@@ -1727,6 +1845,13 @@ main(int ac, char **av)
fatal("%s does not exist or is not executable", rexec_argv[0]);
debug3("using %s for re-exec", rexec_argv[0]);
+ /* Ensure that the privsep binary exists now too. */
+ if (stat(options.sshd_auth_path, &sb) != 0 ||
+ !(sb.st_mode & (S_IXOTH|S_IXUSR))) {
+ fatal("%s does not exist or is not executable",
+ options.sshd_auth_path);
+ }
+
listener_proctitle = prepare_proctitle(ac, av);
/* Ensure that umask disallows at least group and world write */
@@ -1771,12 +1896,14 @@ main(int ac, char **av)
/* ignore SIGPIPE */
ssh_signal(SIGPIPE, SIG_IGN);
+ config = pack_config(cfg);
+
/* Get a connection, either from inetd or a listening TCP socket */
if (inetd_flag) {
/* Send configuration to ancestor sshd-session process */
if (socketpair(AF_UNIX, SOCK_STREAM, 0, config_s) == -1)
fatal("socketpair: %s", strerror(errno));
- send_rexec_state(config_s[0], cfg);
+ send_rexec_state(config_s[0]);
close(config_s[0]);
} else {
platform_pre_listen();
@@ -1824,8 +1951,8 @@ main(int ac, char **av)
if (!debug_flag && !inetd_flag && setsid() == -1)
error("setsid: %.100s", strerror(errno));
- debug("rexec start in %d out %d newsock %d pipe %d sock %d/%d",
- sock_in, sock_out, newsock, startup_pipe, config_s[0], config_s[1]);
+ debug("rexec start in %d out %d newsock %d config_s %d/%d",
+ sock_in, sock_out, newsock, config_s[0], config_s[1]);
if (!inetd_flag) {
if (dup2(newsock, STDIN_FILENO) == -1)
fatal("dup2 stdin: %s", strerror(errno));
@@ -1839,13 +1966,6 @@ main(int ac, char **av)
fatal("dup2 config_s: %s", strerror(errno));
close(config_s[1]);
}
- if (startup_pipe == -1)
- close(REEXEC_STARTUP_PIPE_FD);
- else if (startup_pipe != REEXEC_STARTUP_PIPE_FD) {
- if (dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD) == -1)
- fatal("dup2 startup_p: %s", strerror(errno));
- close(startup_pipe);
- }
log_redirect_stderr_to(NULL);
closefrom(REEXEC_MIN_FREE_FD);