- djm@cvs.openbsd.org 2008/05/08 12:21:16
[monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c] [sshd_config sshd_config.5] Make the maximum number of sessions run-time controllable via a sshd_config MaxSessions knob. This is useful for disabling login/shell/subsystem access while leaving port-forwarding working (MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or simply increasing the number of allows multiplexed sessions. Because some bozos are sure to configure MaxSessions in excess of the number of available file descriptors in sshd (which, at peak, might be as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds on error paths, and make it fail gracefully on out-of-fd conditions - sending channel errors instead of than exiting with fatal(). bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com ok markus@
This commit is contained in:
parent
9417831ece
commit
7207f64a23
17
ChangeLog
17
ChangeLog
|
@ -77,6 +77,21 @@
|
||||||
shouldn't happen in compliant implementations, but it could be
|
shouldn't happen in compliant implementations, but it could be
|
||||||
abused to leak memory.
|
abused to leak memory.
|
||||||
ok markus@ (as part of a larger diff)
|
ok markus@ (as part of a larger diff)
|
||||||
|
- djm@cvs.openbsd.org 2008/05/08 12:21:16
|
||||||
|
[monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c]
|
||||||
|
[sshd_config sshd_config.5]
|
||||||
|
Make the maximum number of sessions run-time controllable via
|
||||||
|
a sshd_config MaxSessions knob. This is useful for disabling
|
||||||
|
login/shell/subsystem access while leaving port-forwarding working
|
||||||
|
(MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or
|
||||||
|
simply increasing the number of allows multiplexed sessions.
|
||||||
|
Because some bozos are sure to configure MaxSessions in excess of the
|
||||||
|
number of available file descriptors in sshd (which, at peak, might be
|
||||||
|
as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds
|
||||||
|
on error paths, and make it fail gracefully on out-of-fd conditions -
|
||||||
|
sending channel errors instead of than exiting with fatal().
|
||||||
|
bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com
|
||||||
|
ok markus@
|
||||||
|
|
||||||
20080403
|
20080403
|
||||||
- (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
|
- (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile-
|
||||||
|
@ -3937,4 +3952,4 @@
|
||||||
OpenServer 6 and add osr5bigcrypt support so when someone migrates
|
OpenServer 6 and add osr5bigcrypt support so when someone migrates
|
||||||
passwords between UnixWare and OpenServer they will still work. OK dtucker@
|
passwords between UnixWare and OpenServer they will still work. OK dtucker@
|
||||||
|
|
||||||
$Id: ChangeLog,v 1.4922 2008/05/19 05:28:35 djm Exp $
|
$Id: ChangeLog,v 1.4923 2008/05/19 05:34:50 djm Exp $
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: monitor.c,v 1.95 2008/05/08 12:02:23 djm Exp $ */
|
/* $OpenBSD: monitor.c,v 1.96 2008/05/08 12:21:16 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||||
|
@ -1273,7 +1273,7 @@ mm_session_close(Session *s)
|
||||||
debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
|
debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd);
|
||||||
session_pty_cleanup2(s);
|
session_pty_cleanup2(s);
|
||||||
}
|
}
|
||||||
s->used = 0;
|
session_unused(s->self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: monitor_wrap.c,v 1.61 2008/05/08 12:02:23 djm Exp $ */
|
/* $OpenBSD: monitor_wrap.c,v 1.62 2008/05/08 12:21:16 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
* Copyright 2002 Niels Provos <provos@citi.umich.edu>
|
||||||
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
* Copyright 2002 Markus Friedl <markus@openbsd.org>
|
||||||
|
@ -666,7 +666,20 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen)
|
||||||
{
|
{
|
||||||
Buffer m;
|
Buffer m;
|
||||||
char *p, *msg;
|
char *p, *msg;
|
||||||
int success = 0;
|
int success = 0, tmp1 = -1, tmp2 = -1;
|
||||||
|
|
||||||
|
/* Kludge: ensure there are fds free to receive the pty/tty */
|
||||||
|
if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 ||
|
||||||
|
(tmp2 = dup(pmonitor->m_recvfd)) == -1) {
|
||||||
|
error("%s: cannot allocate fds for pty", __func__);
|
||||||
|
if (tmp1 > 0)
|
||||||
|
close(tmp1);
|
||||||
|
if (tmp2 > 0)
|
||||||
|
close(tmp2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
close(tmp1);
|
||||||
|
close(tmp2);
|
||||||
|
|
||||||
buffer_init(&m);
|
buffer_init(&m);
|
||||||
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m);
|
mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m);
|
||||||
|
@ -711,8 +724,9 @@ mm_session_pty_cleanup2(Session *s)
|
||||||
buffer_free(&m);
|
buffer_free(&m);
|
||||||
|
|
||||||
/* closed dup'ed master */
|
/* closed dup'ed master */
|
||||||
if (close(s->ptymaster) < 0)
|
if (s->ptymaster != -1 && close(s->ptymaster) < 0)
|
||||||
error("close(s->ptymaster): %s", strerror(errno));
|
error("close(s->ptymaster/%d): %s",
|
||||||
|
s->ptymaster, strerror(errno));
|
||||||
|
|
||||||
/* unlink pty from session */
|
/* unlink pty from session */
|
||||||
s->ttyfd = -1;
|
s->ttyfd = -1;
|
||||||
|
|
21
servconf.c
21
servconf.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: servconf.c,v 1.179 2008/05/08 12:02:23 djm Exp $ */
|
/* $OpenBSD: servconf.c,v 1.180 2008/05/08 12:21:16 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
|
@ -114,6 +114,7 @@ initialize_server_options(ServerOptions *options)
|
||||||
options->max_startups_rate = -1;
|
options->max_startups_rate = -1;
|
||||||
options->max_startups = -1;
|
options->max_startups = -1;
|
||||||
options->max_authtries = -1;
|
options->max_authtries = -1;
|
||||||
|
options->max_sessions = -1;
|
||||||
options->banner = NULL;
|
options->banner = NULL;
|
||||||
options->use_dns = -1;
|
options->use_dns = -1;
|
||||||
options->client_alive_interval = -1;
|
options->client_alive_interval = -1;
|
||||||
|
@ -237,6 +238,8 @@ fill_default_server_options(ServerOptions *options)
|
||||||
options->max_startups_begin = options->max_startups;
|
options->max_startups_begin = options->max_startups;
|
||||||
if (options->max_authtries == -1)
|
if (options->max_authtries == -1)
|
||||||
options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
|
options->max_authtries = DEFAULT_AUTH_FAIL_MAX;
|
||||||
|
if (options->max_sessions == -1)
|
||||||
|
options->max_sessions = DEFAULT_SESSIONS_MAX;
|
||||||
if (options->use_dns == -1)
|
if (options->use_dns == -1)
|
||||||
options->use_dns = 1;
|
options->use_dns = 1;
|
||||||
if (options->client_alive_interval == -1)
|
if (options->client_alive_interval == -1)
|
||||||
|
@ -291,7 +294,7 @@ typedef enum {
|
||||||
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
|
||||||
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
|
sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile,
|
||||||
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
|
sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem,
|
||||||
sMaxStartups, sMaxAuthTries,
|
sMaxStartups, sMaxAuthTries, sMaxSessions,
|
||||||
sBanner, sUseDNS, sHostbasedAuthentication,
|
sBanner, sUseDNS, sHostbasedAuthentication,
|
||||||
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
|
sHostbasedUsesNameFromPacketOnly, sClientAliveInterval,
|
||||||
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
|
sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2,
|
||||||
|
@ -395,6 +398,7 @@ static struct {
|
||||||
{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
|
{ "subsystem", sSubsystem, SSHCFG_GLOBAL },
|
||||||
{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
|
{ "maxstartups", sMaxStartups, SSHCFG_GLOBAL },
|
||||||
{ "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
|
{ "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL },
|
||||||
|
{ "maxsessions", sMaxSessions, SSHCFG_ALL },
|
||||||
{ "banner", sBanner, SSHCFG_ALL },
|
{ "banner", sBanner, SSHCFG_ALL },
|
||||||
{ "usedns", sUseDNS, SSHCFG_GLOBAL },
|
{ "usedns", sUseDNS, SSHCFG_GLOBAL },
|
||||||
{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
|
{ "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL },
|
||||||
|
@ -695,7 +699,7 @@ process_server_config_line(ServerOptions *options, char *line,
|
||||||
|
|
||||||
case sServerKeyBits:
|
case sServerKeyBits:
|
||||||
intptr = &options->server_key_bits;
|
intptr = &options->server_key_bits;
|
||||||
parse_int:
|
parse_int:
|
||||||
arg = strdelim(&cp);
|
arg = strdelim(&cp);
|
||||||
if (!arg || *arg == '\0')
|
if (!arg || *arg == '\0')
|
||||||
fatal("%s line %d: missing integer value.",
|
fatal("%s line %d: missing integer value.",
|
||||||
|
@ -707,7 +711,7 @@ parse_int:
|
||||||
|
|
||||||
case sLoginGraceTime:
|
case sLoginGraceTime:
|
||||||
intptr = &options->login_grace_time;
|
intptr = &options->login_grace_time;
|
||||||
parse_time:
|
parse_time:
|
||||||
arg = strdelim(&cp);
|
arg = strdelim(&cp);
|
||||||
if (!arg || *arg == '\0')
|
if (!arg || *arg == '\0')
|
||||||
fatal("%s line %d: missing time value.",
|
fatal("%s line %d: missing time value.",
|
||||||
|
@ -776,7 +780,7 @@ parse_time:
|
||||||
fatal("%s line %d: too many host keys specified (max %d).",
|
fatal("%s line %d: too many host keys specified (max %d).",
|
||||||
filename, linenum, MAX_HOSTKEYS);
|
filename, linenum, MAX_HOSTKEYS);
|
||||||
charptr = &options->host_key_files[*intptr];
|
charptr = &options->host_key_files[*intptr];
|
||||||
parse_filename:
|
parse_filename:
|
||||||
arg = strdelim(&cp);
|
arg = strdelim(&cp);
|
||||||
if (!arg || *arg == '\0')
|
if (!arg || *arg == '\0')
|
||||||
fatal("%s line %d: missing file name.",
|
fatal("%s line %d: missing file name.",
|
||||||
|
@ -819,7 +823,7 @@ parse_filename:
|
||||||
|
|
||||||
case sIgnoreRhosts:
|
case sIgnoreRhosts:
|
||||||
intptr = &options->ignore_rhosts;
|
intptr = &options->ignore_rhosts;
|
||||||
parse_flag:
|
parse_flag:
|
||||||
arg = strdelim(&cp);
|
arg = strdelim(&cp);
|
||||||
if (!arg || *arg == '\0')
|
if (!arg || *arg == '\0')
|
||||||
fatal("%s line %d: missing yes/no argument.",
|
fatal("%s line %d: missing yes/no argument.",
|
||||||
|
@ -1155,6 +1159,10 @@ parse_flag:
|
||||||
intptr = &options->max_authtries;
|
intptr = &options->max_authtries;
|
||||||
goto parse_int;
|
goto parse_int;
|
||||||
|
|
||||||
|
case sMaxSessions:
|
||||||
|
intptr = &options->max_sessions;
|
||||||
|
goto parse_int;
|
||||||
|
|
||||||
case sBanner:
|
case sBanner:
|
||||||
charptr = &options->banner;
|
charptr = &options->banner;
|
||||||
goto parse_filename;
|
goto parse_filename;
|
||||||
|
@ -1382,6 +1390,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth)
|
||||||
M_CP_INTOPT(x11_display_offset);
|
M_CP_INTOPT(x11_display_offset);
|
||||||
M_CP_INTOPT(x11_forwarding);
|
M_CP_INTOPT(x11_forwarding);
|
||||||
M_CP_INTOPT(x11_use_localhost);
|
M_CP_INTOPT(x11_use_localhost);
|
||||||
|
M_CP_INTOPT(max_sessions);
|
||||||
|
|
||||||
M_CP_STROPT(banner);
|
M_CP_STROPT(banner);
|
||||||
if (preauth)
|
if (preauth)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: servconf.h,v 1.83 2008/05/07 05:49:37 pyr Exp $ */
|
/* $OpenBSD: servconf.h,v 1.84 2008/05/08 12:21:16 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
* Author: Tatu Ylonen <ylo@cs.hut.fi>
|
||||||
|
@ -35,6 +35,7 @@
|
||||||
#define PERMIT_YES 3
|
#define PERMIT_YES 3
|
||||||
|
|
||||||
#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */
|
#define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */
|
||||||
|
#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */
|
||||||
|
|
||||||
/* Magic name for internal sftp-server */
|
/* Magic name for internal sftp-server */
|
||||||
#define INTERNAL_SFTP_NAME "internal-sftp"
|
#define INTERNAL_SFTP_NAME "internal-sftp"
|
||||||
|
@ -123,6 +124,7 @@ typedef struct {
|
||||||
int max_startups_rate;
|
int max_startups_rate;
|
||||||
int max_startups;
|
int max_startups;
|
||||||
int max_authtries;
|
int max_authtries;
|
||||||
|
int max_sessions;
|
||||||
char *banner; /* SSH-2 banner message */
|
char *banner; /* SSH-2 banner message */
|
||||||
int use_dns;
|
int use_dns;
|
||||||
int client_alive_interval; /*
|
int client_alive_interval; /*
|
||||||
|
|
382
session.c
382
session.c
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: session.c,v 1.236 2008/05/08 12:02:23 djm Exp $ */
|
/* $OpenBSD: session.c,v 1.237 2008/05/08 12:21:16 djm Exp $ */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
|
||||||
* All rights reserved
|
* All rights reserved
|
||||||
|
@ -102,9 +102,9 @@ void session_set_fds(Session *, int, int, int);
|
||||||
void session_pty_cleanup(Session *);
|
void session_pty_cleanup(Session *);
|
||||||
void session_proctitle(Session *);
|
void session_proctitle(Session *);
|
||||||
int session_setup_x11fwd(Session *);
|
int session_setup_x11fwd(Session *);
|
||||||
void do_exec_pty(Session *, const char *);
|
int do_exec_pty(Session *, const char *);
|
||||||
void do_exec_no_pty(Session *, const char *);
|
int do_exec_no_pty(Session *, const char *);
|
||||||
void do_exec(Session *, const char *);
|
int do_exec(Session *, const char *);
|
||||||
void do_login(Session *, const char *);
|
void do_login(Session *, const char *);
|
||||||
#ifdef LOGIN_NEEDS_UTMPX
|
#ifdef LOGIN_NEEDS_UTMPX
|
||||||
static void do_pre_login(Session *s);
|
static void do_pre_login(Session *s);
|
||||||
|
@ -132,8 +132,9 @@ extern Buffer loginmsg;
|
||||||
const char *original_command = NULL;
|
const char *original_command = NULL;
|
||||||
|
|
||||||
/* data */
|
/* data */
|
||||||
#define MAX_SESSIONS 20
|
static int sessions_first_unused = -1;
|
||||||
Session sessions[MAX_SESSIONS];
|
static int sessions_nalloc = 0;
|
||||||
|
static Session *sessions = NULL;
|
||||||
|
|
||||||
#define SUBSYSTEM_NONE 0
|
#define SUBSYSTEM_NONE 0
|
||||||
#define SUBSYSTEM_EXT 1
|
#define SUBSYSTEM_EXT 1
|
||||||
|
@ -167,7 +168,7 @@ static int
|
||||||
auth_input_request_forwarding(struct passwd * pw)
|
auth_input_request_forwarding(struct passwd * pw)
|
||||||
{
|
{
|
||||||
Channel *nc;
|
Channel *nc;
|
||||||
int sock;
|
int sock = -1;
|
||||||
struct sockaddr_un sunaddr;
|
struct sockaddr_un sunaddr;
|
||||||
|
|
||||||
if (auth_sock_name != NULL) {
|
if (auth_sock_name != NULL) {
|
||||||
|
@ -179,43 +180,48 @@ auth_input_request_forwarding(struct passwd * pw)
|
||||||
temporarily_use_uid(pw);
|
temporarily_use_uid(pw);
|
||||||
|
|
||||||
/* Allocate a buffer for the socket name, and format the name. */
|
/* Allocate a buffer for the socket name, and format the name. */
|
||||||
auth_sock_name = xmalloc(MAXPATHLEN);
|
auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
|
||||||
auth_sock_dir = xmalloc(MAXPATHLEN);
|
|
||||||
strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
|
|
||||||
|
|
||||||
/* Create private directory for socket */
|
/* Create private directory for socket */
|
||||||
if (mkdtemp(auth_sock_dir) == NULL) {
|
if (mkdtemp(auth_sock_dir) == NULL) {
|
||||||
packet_send_debug("Agent forwarding disabled: "
|
packet_send_debug("Agent forwarding disabled: "
|
||||||
"mkdtemp() failed: %.100s", strerror(errno));
|
"mkdtemp() failed: %.100s", strerror(errno));
|
||||||
restore_uid();
|
restore_uid();
|
||||||
xfree(auth_sock_name);
|
|
||||||
xfree(auth_sock_dir);
|
xfree(auth_sock_dir);
|
||||||
auth_sock_name = NULL;
|
|
||||||
auth_sock_dir = NULL;
|
auth_sock_dir = NULL;
|
||||||
return 0;
|
goto authsock_err;
|
||||||
}
|
}
|
||||||
snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",
|
|
||||||
auth_sock_dir, (long) getpid());
|
xasprintf(&auth_sock_name, "%s/agent.%ld",
|
||||||
|
auth_sock_dir, (long) getpid());
|
||||||
|
|
||||||
/* Create the socket. */
|
/* Create the socket. */
|
||||||
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
if (sock < 0)
|
if (sock < 0) {
|
||||||
packet_disconnect("socket: %.100s", strerror(errno));
|
error("socket: %.100s", strerror(errno));
|
||||||
|
restore_uid();
|
||||||
|
goto authsock_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Bind it to the name. */
|
/* Bind it to the name. */
|
||||||
memset(&sunaddr, 0, sizeof(sunaddr));
|
memset(&sunaddr, 0, sizeof(sunaddr));
|
||||||
sunaddr.sun_family = AF_UNIX;
|
sunaddr.sun_family = AF_UNIX;
|
||||||
strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
|
strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
|
||||||
|
|
||||||
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
|
if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
|
||||||
packet_disconnect("bind: %.100s", strerror(errno));
|
error("bind: %.100s", strerror(errno));
|
||||||
|
restore_uid();
|
||||||
|
goto authsock_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Restore the privileged uid. */
|
/* Restore the privileged uid. */
|
||||||
restore_uid();
|
restore_uid();
|
||||||
|
|
||||||
/* Start listening on the socket. */
|
/* Start listening on the socket. */
|
||||||
if (listen(sock, SSH_LISTEN_BACKLOG) < 0)
|
if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
|
||||||
packet_disconnect("listen: %.100s", strerror(errno));
|
error("listen: %.100s", strerror(errno));
|
||||||
|
goto authsock_err;
|
||||||
|
}
|
||||||
|
|
||||||
/* Allocate a channel for the authentication agent socket. */
|
/* Allocate a channel for the authentication agent socket. */
|
||||||
nc = channel_new("auth socket",
|
nc = channel_new("auth socket",
|
||||||
|
@ -224,6 +230,19 @@ auth_input_request_forwarding(struct passwd * pw)
|
||||||
0, "auth socket", 1);
|
0, "auth socket", 1);
|
||||||
strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
|
strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
|
authsock_err:
|
||||||
|
if (auth_sock_name != NULL)
|
||||||
|
xfree(auth_sock_name);
|
||||||
|
if (auth_sock_dir != NULL) {
|
||||||
|
rmdir(auth_sock_dir);
|
||||||
|
xfree(auth_sock_dir);
|
||||||
|
}
|
||||||
|
if (sock != -1)
|
||||||
|
close(sock);
|
||||||
|
auth_sock_name = NULL;
|
||||||
|
auth_sock_dir = NULL;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -373,10 +392,14 @@ do_authenticated1(Authctxt *authctxt)
|
||||||
if (type == SSH_CMSG_EXEC_CMD) {
|
if (type == SSH_CMSG_EXEC_CMD) {
|
||||||
command = packet_get_string(&dlen);
|
command = packet_get_string(&dlen);
|
||||||
debug("Exec command '%.500s'", command);
|
debug("Exec command '%.500s'", command);
|
||||||
do_exec(s, command);
|
if (do_exec(s, command) != 0)
|
||||||
|
packet_disconnect(
|
||||||
|
"command execution failed");
|
||||||
xfree(command);
|
xfree(command);
|
||||||
} else {
|
} else {
|
||||||
do_exec(s, NULL);
|
if (do_exec(s, NULL) != 0)
|
||||||
|
packet_disconnect(
|
||||||
|
"shell execution failed");
|
||||||
}
|
}
|
||||||
packet_check_eom();
|
packet_check_eom();
|
||||||
session_close(s);
|
session_close(s);
|
||||||
|
@ -401,41 +424,84 @@ do_authenticated1(Authctxt *authctxt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define USE_PIPES
|
||||||
/*
|
/*
|
||||||
* This is called to fork and execute a command when we have no tty. This
|
* This is called to fork and execute a command when we have no tty. This
|
||||||
* will call do_child from the child, and server_loop from the parent after
|
* will call do_child from the child, and server_loop from the parent after
|
||||||
* setting up file descriptors and such.
|
* setting up file descriptors and such.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
do_exec_no_pty(Session *s, const char *command)
|
do_exec_no_pty(Session *s, const char *command)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
#ifdef USE_PIPES
|
#ifdef USE_PIPES
|
||||||
int pin[2], pout[2], perr[2];
|
int pin[2], pout[2], perr[2];
|
||||||
|
|
||||||
/* Allocate pipes for communicating with the program. */
|
/* Allocate pipes for communicating with the program. */
|
||||||
if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)
|
if (pipe(pin) < 0) {
|
||||||
packet_disconnect("Could not create pipes: %.100s",
|
error("%s: pipe in: %.100s", __func__, strerror(errno));
|
||||||
strerror(errno));
|
return -1;
|
||||||
#else /* USE_PIPES */
|
}
|
||||||
|
if (pipe(pout) < 0) {
|
||||||
|
error("%s: pipe out: %.100s", __func__, strerror(errno));
|
||||||
|
close(pin[0]);
|
||||||
|
close(pin[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (pipe(perr) < 0) {
|
||||||
|
error("%s: pipe err: %.100s", __func__, strerror(errno));
|
||||||
|
close(pin[0]);
|
||||||
|
close(pin[1]);
|
||||||
|
close(pout[0]);
|
||||||
|
close(pout[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#else
|
||||||
int inout[2], err[2];
|
int inout[2], err[2];
|
||||||
|
|
||||||
/* Uses socket pairs to communicate with the program. */
|
/* Uses socket pairs to communicate with the program. */
|
||||||
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
|
||||||
socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)
|
error("%s: socketpair #1: %.100s", __func__, strerror(errno));
|
||||||
packet_disconnect("Could not create socket pairs: %.100s",
|
return -1;
|
||||||
strerror(errno));
|
}
|
||||||
#endif /* USE_PIPES */
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
|
||||||
|
error("%s: socketpair #2: %.100s", __func__, strerror(errno));
|
||||||
|
close(inout[0]);
|
||||||
|
close(inout[1]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (s == NULL)
|
if (s == NULL)
|
||||||
fatal("do_exec_no_pty: no session");
|
fatal("do_exec_no_pty: no session");
|
||||||
|
|
||||||
session_proctitle(s);
|
session_proctitle(s);
|
||||||
|
|
||||||
/* Fork the child. */
|
/* Fork the child. */
|
||||||
if ((pid = fork()) == 0) {
|
switch ((pid = fork())) {
|
||||||
|
case -1:
|
||||||
|
error("%s: fork: %.100s", __func__, strerror(errno));
|
||||||
|
#ifdef USE_PIPES
|
||||||
|
close(pin[0]);
|
||||||
|
close(pin[1]);
|
||||||
|
close(pout[0]);
|
||||||
|
close(pout[1]);
|
||||||
|
close(perr[0]);
|
||||||
|
close(perr[1]);
|
||||||
|
#else
|
||||||
|
close(inout[0]);
|
||||||
|
close(inout[1]);
|
||||||
|
close(err[0]);
|
||||||
|
close(err[1]);
|
||||||
|
#endif
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
is_child = 1;
|
is_child = 1;
|
||||||
|
|
||||||
/* Child. Reinitialize the log since the pid has changed. */
|
/* Child. Reinitialize the log since the pid has changed. */
|
||||||
log_init(__progname, options.log_level, options.log_facility, log_stderr);
|
log_init(__progname, options.log_level,
|
||||||
|
options.log_facility, log_stderr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new session and process group since the 4.4BSD
|
* Create a new session and process group since the 4.4BSD
|
||||||
|
@ -465,7 +531,7 @@ do_exec_no_pty(Session *s, const char *command)
|
||||||
if (dup2(perr[1], 2) < 0)
|
if (dup2(perr[1], 2) < 0)
|
||||||
perror("dup2 stderr");
|
perror("dup2 stderr");
|
||||||
close(perr[1]);
|
close(perr[1]);
|
||||||
#else /* USE_PIPES */
|
#else
|
||||||
/*
|
/*
|
||||||
* Redirect stdin, stdout, and stderr. Stdin and stdout will
|
* Redirect stdin, stdout, and stderr. Stdin and stdout will
|
||||||
* use the same socket, as some programs (particularly rdist)
|
* use the same socket, as some programs (particularly rdist)
|
||||||
|
@ -475,11 +541,14 @@ do_exec_no_pty(Session *s, const char *command)
|
||||||
close(err[1]);
|
close(err[1]);
|
||||||
if (dup2(inout[0], 0) < 0) /* stdin */
|
if (dup2(inout[0], 0) < 0) /* stdin */
|
||||||
perror("dup2 stdin");
|
perror("dup2 stdin");
|
||||||
if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */
|
if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */
|
||||||
perror("dup2 stdout");
|
perror("dup2 stdout");
|
||||||
|
close(inout[0]);
|
||||||
if (dup2(err[0], 2) < 0) /* stderr */
|
if (dup2(err[0], 2) < 0) /* stderr */
|
||||||
perror("dup2 stderr");
|
perror("dup2 stderr");
|
||||||
#endif /* USE_PIPES */
|
close(err[0]);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#ifdef _UNICOS
|
#ifdef _UNICOS
|
||||||
cray_init_job(s->pw); /* set up cray jid and tmpdir */
|
cray_init_job(s->pw); /* set up cray jid and tmpdir */
|
||||||
|
@ -488,7 +557,10 @@ do_exec_no_pty(Session *s, const char *command)
|
||||||
/* Do processing for the child (exec command etc). */
|
/* Do processing for the child (exec command etc). */
|
||||||
do_child(s, command);
|
do_child(s, command);
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _UNICOS
|
#ifdef _UNICOS
|
||||||
signal(WJSIGNAL, cray_job_termination_handler);
|
signal(WJSIGNAL, cray_job_termination_handler);
|
||||||
#endif /* _UNICOS */
|
#endif /* _UNICOS */
|
||||||
|
@ -496,11 +568,18 @@ do_exec_no_pty(Session *s, const char *command)
|
||||||
if (is_winnt)
|
if (is_winnt)
|
||||||
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
|
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
|
||||||
#endif
|
#endif
|
||||||
if (pid < 0)
|
|
||||||
packet_disconnect("fork failed: %.100s", strerror(errno));
|
|
||||||
s->pid = pid;
|
s->pid = pid;
|
||||||
/* Set interactive/non-interactive mode. */
|
/* Set interactive/non-interactive mode. */
|
||||||
packet_set_interactive(s->display != NULL);
|
packet_set_interactive(s->display != NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Clear loginmsg, since it's the child's responsibility to display
|
||||||
|
* it to the user, otherwise multiple sessions may accumulate
|
||||||
|
* multiple copies of the login messages.
|
||||||
|
*/
|
||||||
|
buffer_clear(&loginmsg);
|
||||||
|
|
||||||
#ifdef USE_PIPES
|
#ifdef USE_PIPES
|
||||||
/* We are the parent. Close the child sides of the pipes. */
|
/* We are the parent. Close the child sides of the pipes. */
|
||||||
close(pin[0]);
|
close(pin[0]);
|
||||||
|
@ -518,29 +597,26 @@ do_exec_no_pty(Session *s, const char *command)
|
||||||
server_loop(pid, pin[1], pout[0], perr[0]);
|
server_loop(pid, pin[1], pout[0], perr[0]);
|
||||||
/* server_loop has closed pin[1], pout[0], and perr[0]. */
|
/* server_loop has closed pin[1], pout[0], and perr[0]. */
|
||||||
}
|
}
|
||||||
#else /* USE_PIPES */
|
#else
|
||||||
/* We are the parent. Close the child sides of the socket pairs. */
|
/* We are the parent. Close the child sides of the socket pairs. */
|
||||||
close(inout[0]);
|
close(inout[0]);
|
||||||
close(err[0]);
|
close(err[0]);
|
||||||
|
|
||||||
/*
|
|
||||||
* Clear loginmsg, since it's the child's responsibility to display
|
|
||||||
* it to the user, otherwise multiple sessions may accumulate
|
|
||||||
* multiple copies of the login messages.
|
|
||||||
*/
|
|
||||||
buffer_clear(&loginmsg);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enter the interactive session. Note: server_loop must be able to
|
* Enter the interactive session. Note: server_loop must be able to
|
||||||
* handle the case that fdin and fdout are the same.
|
* handle the case that fdin and fdout are the same.
|
||||||
*/
|
*/
|
||||||
if (compat20) {
|
if (compat20) {
|
||||||
session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);
|
session_set_fds(s, inout[1], inout[1],
|
||||||
|
s->is_subsystem ? -1 : err[1]);
|
||||||
|
if (s->is_subsystem)
|
||||||
|
close(err[1]);
|
||||||
} else {
|
} else {
|
||||||
server_loop(pid, inout[1], inout[1], err[1]);
|
server_loop(pid, inout[1], inout[1], err[1]);
|
||||||
/* server_loop has closed inout[1] and err[1]. */
|
/* server_loop has closed inout[1] and err[1]. */
|
||||||
}
|
}
|
||||||
#endif /* USE_PIPES */
|
#endif
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -549,7 +625,7 @@ do_exec_no_pty(Session *s, const char *command)
|
||||||
* setting up file descriptors, controlling tty, updating wtmp, utmp,
|
* setting up file descriptors, controlling tty, updating wtmp, utmp,
|
||||||
* lastlog, and other such operations.
|
* lastlog, and other such operations.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
do_exec_pty(Session *s, const char *command)
|
do_exec_pty(Session *s, const char *command)
|
||||||
{
|
{
|
||||||
int fdout, ptyfd, ttyfd, ptymaster;
|
int fdout, ptyfd, ttyfd, ptymaster;
|
||||||
|
@ -560,12 +636,46 @@ do_exec_pty(Session *s, const char *command)
|
||||||
ptyfd = s->ptyfd;
|
ptyfd = s->ptyfd;
|
||||||
ttyfd = s->ttyfd;
|
ttyfd = s->ttyfd;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create another descriptor of the pty master side for use as the
|
||||||
|
* standard input. We could use the original descriptor, but this
|
||||||
|
* simplifies code in server_loop. The descriptor is bidirectional.
|
||||||
|
* Do this before forking (and cleanup in the child) so as to
|
||||||
|
* detect and gracefully fail out-of-fd conditions.
|
||||||
|
*/
|
||||||
|
if ((fdout = dup(ptyfd)) < 0) {
|
||||||
|
error("%s: dup #1: %s", __func__, strerror(errno));
|
||||||
|
close(ttyfd);
|
||||||
|
close(ptyfd);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* we keep a reference to the pty master */
|
||||||
|
if ((ptymaster = dup(ptyfd)) < 0) {
|
||||||
|
error("%s: dup #2: %s", __func__, strerror(errno));
|
||||||
|
close(ttyfd);
|
||||||
|
close(ptyfd);
|
||||||
|
close(fdout);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Fork the child. */
|
/* Fork the child. */
|
||||||
if ((pid = fork()) == 0) {
|
switch ((pid = fork())) {
|
||||||
|
case -1:
|
||||||
|
error("%s: fork: %.100s", __func__, strerror(errno));
|
||||||
|
close(fdout);
|
||||||
|
close(ptymaster);
|
||||||
|
close(ttyfd);
|
||||||
|
close(ptyfd);
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
is_child = 1;
|
is_child = 1;
|
||||||
|
|
||||||
|
close(fdout);
|
||||||
|
close(ptymaster);
|
||||||
|
|
||||||
/* Child. Reinitialize the log because the pid has changed. */
|
/* Child. Reinitialize the log because the pid has changed. */
|
||||||
log_init(__progname, options.log_level, options.log_facility, log_stderr);
|
log_init(__progname, options.log_level,
|
||||||
|
options.log_facility, log_stderr);
|
||||||
/* Close the master side of the pseudo tty. */
|
/* Close the master side of the pseudo tty. */
|
||||||
close(ptyfd);
|
close(ptyfd);
|
||||||
|
|
||||||
|
@ -596,11 +706,16 @@ do_exec_pty(Session *s, const char *command)
|
||||||
do_pre_login(s);
|
do_pre_login(s);
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
/* Do common processing for the child, such as execing the command. */
|
* Do common processing for the child, such as execing
|
||||||
do_child(s, command);
|
* the command.
|
||||||
/* NOTREACHED */
|
*/
|
||||||
|
do_child(s, command);
|
||||||
|
/* NOTREACHED */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _UNICOS
|
#ifdef _UNICOS
|
||||||
signal(WJSIGNAL, cray_job_termination_handler);
|
signal(WJSIGNAL, cray_job_termination_handler);
|
||||||
#endif /* _UNICOS */
|
#endif /* _UNICOS */
|
||||||
|
@ -608,29 +723,14 @@ do_exec_pty(Session *s, const char *command)
|
||||||
if (is_winnt)
|
if (is_winnt)
|
||||||
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
|
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
|
||||||
#endif
|
#endif
|
||||||
if (pid < 0)
|
|
||||||
packet_disconnect("fork failed: %.100s", strerror(errno));
|
|
||||||
s->pid = pid;
|
s->pid = pid;
|
||||||
|
|
||||||
/* Parent. Close the slave side of the pseudo tty. */
|
/* Parent. Close the slave side of the pseudo tty. */
|
||||||
close(ttyfd);
|
close(ttyfd);
|
||||||
|
|
||||||
/*
|
|
||||||
* Create another descriptor of the pty master side for use as the
|
|
||||||
* standard input. We could use the original descriptor, but this
|
|
||||||
* simplifies code in server_loop. The descriptor is bidirectional.
|
|
||||||
*/
|
|
||||||
fdout = dup(ptyfd);
|
|
||||||
if (fdout < 0)
|
|
||||||
packet_disconnect("dup #1 failed: %.100s", strerror(errno));
|
|
||||||
|
|
||||||
/* we keep a reference to the pty master */
|
|
||||||
ptymaster = dup(ptyfd);
|
|
||||||
if (ptymaster < 0)
|
|
||||||
packet_disconnect("dup #2 failed: %.100s", strerror(errno));
|
|
||||||
s->ptymaster = ptymaster;
|
|
||||||
|
|
||||||
/* Enter interactive session. */
|
/* Enter interactive session. */
|
||||||
|
s->ptymaster = ptymaster;
|
||||||
packet_set_interactive(1);
|
packet_set_interactive(1);
|
||||||
if (compat20) {
|
if (compat20) {
|
||||||
session_set_fds(s, ptyfd, fdout, -1);
|
session_set_fds(s, ptyfd, fdout, -1);
|
||||||
|
@ -638,6 +738,7 @@ do_exec_pty(Session *s, const char *command)
|
||||||
server_loop(pid, ptyfd, fdout, -1);
|
server_loop(pid, ptyfd, fdout, -1);
|
||||||
/* server_loop _has_ closed ptyfd and fdout. */
|
/* server_loop _has_ closed ptyfd and fdout. */
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOGIN_NEEDS_UTMPX
|
#ifdef LOGIN_NEEDS_UTMPX
|
||||||
|
@ -672,9 +773,11 @@ do_pre_login(Session *s)
|
||||||
* This is called to fork and execute a command. If another command is
|
* This is called to fork and execute a command. If another command is
|
||||||
* to be forced, execute that instead.
|
* to be forced, execute that instead.
|
||||||
*/
|
*/
|
||||||
void
|
int
|
||||||
do_exec(Session *s, const char *command)
|
do_exec(Session *s, const char *command)
|
||||||
{
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (options.adm_forced_command) {
|
if (options.adm_forced_command) {
|
||||||
original_command = command;
|
original_command = command;
|
||||||
command = options.adm_forced_command;
|
command = options.adm_forced_command;
|
||||||
|
@ -705,9 +808,9 @@ do_exec(Session *s, const char *command)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (s->ttyfd != -1)
|
if (s->ttyfd != -1)
|
||||||
do_exec_pty(s, command);
|
ret = do_exec_pty(s, command);
|
||||||
else
|
else
|
||||||
do_exec_no_pty(s, command);
|
ret = do_exec_no_pty(s, command);
|
||||||
|
|
||||||
original_command = NULL;
|
original_command = NULL;
|
||||||
|
|
||||||
|
@ -717,6 +820,8 @@ do_exec(Session *s, const char *command)
|
||||||
* multiple copies of the login messages.
|
* multiple copies of the login messages.
|
||||||
*/
|
*/
|
||||||
buffer_clear(&loginmsg);
|
buffer_clear(&loginmsg);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* administrative, login(1)-like work */
|
/* administrative, login(1)-like work */
|
||||||
|
@ -1740,43 +1845,79 @@ do_child(Session *s, const char *command)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
session_unused(int id)
|
||||||
|
{
|
||||||
|
debug3("%s: session id %d unused", __func__, id);
|
||||||
|
if (id >= options.max_sessions ||
|
||||||
|
id >= sessions_nalloc) {
|
||||||
|
fatal("%s: insane session id %d (max %d nalloc %d)",
|
||||||
|
__func__, id, options.max_sessions, sessions_nalloc);
|
||||||
|
}
|
||||||
|
bzero(&sessions[id], sizeof(*sessions));
|
||||||
|
sessions[id].self = id;
|
||||||
|
sessions[id].used = 0;
|
||||||
|
sessions[id].chanid = -1;
|
||||||
|
sessions[id].ptyfd = -1;
|
||||||
|
sessions[id].ttyfd = -1;
|
||||||
|
sessions[id].ptymaster = -1;
|
||||||
|
sessions[id].x11_chanids = NULL;
|
||||||
|
sessions[id].next_unused = sessions_first_unused;
|
||||||
|
sessions_first_unused = id;
|
||||||
|
}
|
||||||
|
|
||||||
Session *
|
Session *
|
||||||
session_new(void)
|
session_new(void)
|
||||||
{
|
{
|
||||||
int i;
|
Session *s, *tmp;
|
||||||
static int did_init = 0;
|
|
||||||
if (!did_init) {
|
if (sessions_first_unused == -1) {
|
||||||
debug("session_new: init");
|
if (sessions_nalloc >= options.max_sessions)
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
return NULL;
|
||||||
sessions[i].used = 0;
|
debug2("%s: allocate (allocated %d max %d)",
|
||||||
|
__func__, sessions_nalloc, options.max_sessions);
|
||||||
|
tmp = xrealloc(sessions, sessions_nalloc + 1,
|
||||||
|
sizeof(*sessions));
|
||||||
|
if (tmp == NULL) {
|
||||||
|
error("%s: cannot allocate %d sessions",
|
||||||
|
__func__, sessions_nalloc + 1);
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
did_init = 1;
|
sessions = tmp;
|
||||||
|
session_unused(sessions_nalloc++);
|
||||||
}
|
}
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
|
||||||
Session *s = &sessions[i];
|
if (sessions_first_unused >= sessions_nalloc ||
|
||||||
if (! s->used) {
|
sessions_first_unused < 0) {
|
||||||
memset(s, 0, sizeof(*s));
|
fatal("%s: insane first_unused %d max %d nalloc %d",
|
||||||
s->chanid = -1;
|
__func__, sessions_first_unused, options.max_sessions,
|
||||||
s->ptyfd = -1;
|
sessions_nalloc);
|
||||||
s->ttyfd = -1;
|
|
||||||
s->used = 1;
|
|
||||||
s->self = i;
|
|
||||||
s->x11_chanids = NULL;
|
|
||||||
debug("session_new: session %d", i);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return NULL;
|
|
||||||
|
s = &sessions[sessions_first_unused];
|
||||||
|
if (s->used) {
|
||||||
|
fatal("%s: session %d already used",
|
||||||
|
__func__, sessions_first_unused);
|
||||||
|
}
|
||||||
|
sessions_first_unused = s->next_unused;
|
||||||
|
s->used = 1;
|
||||||
|
s->next_unused = -1;
|
||||||
|
debug("session_new: session %d", s->self);
|
||||||
|
|
||||||
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
session_dump(void)
|
session_dump(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
debug("dump: used %d session %d %p channel %d pid %ld",
|
|
||||||
|
debug("dump: used %d next_unused %d session %d %p "
|
||||||
|
"channel %d pid %ld",
|
||||||
s->used,
|
s->used,
|
||||||
|
s->next_unused,
|
||||||
s->self,
|
s->self,
|
||||||
s,
|
s,
|
||||||
s->chanid,
|
s->chanid,
|
||||||
|
@ -1806,7 +1947,7 @@ Session *
|
||||||
session_by_tty(char *tty)
|
session_by_tty(char *tty)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
|
if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
|
||||||
debug("session_by_tty: session %d tty %s", i, tty);
|
debug("session_by_tty: session %d tty %s", i, tty);
|
||||||
|
@ -1822,10 +1963,11 @@ static Session *
|
||||||
session_by_channel(int id)
|
session_by_channel(int id)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
if (s->used && s->chanid == id) {
|
if (s->used && s->chanid == id) {
|
||||||
debug("session_by_channel: session %d channel %d", i, id);
|
debug("session_by_channel: session %d channel %d",
|
||||||
|
i, id);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1839,7 +1981,7 @@ session_by_x11_channel(int id)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
|
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
|
|
||||||
if (s->x11_chanids == NULL || !s->used)
|
if (s->x11_chanids == NULL || !s->used)
|
||||||
|
@ -1862,7 +2004,7 @@ session_by_pid(pid_t pid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
debug("session_by_pid: pid %ld", (long)pid);
|
debug("session_by_pid: pid %ld", (long)pid);
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
if (s->used && s->pid == pid)
|
if (s->used && s->pid == pid)
|
||||||
return s;
|
return s;
|
||||||
|
@ -1918,7 +2060,8 @@ session_pty_req(Session *s)
|
||||||
|
|
||||||
/* Allocate a pty and open it. */
|
/* Allocate a pty and open it. */
|
||||||
debug("Allocating pty.");
|
debug("Allocating pty.");
|
||||||
if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) {
|
if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
|
||||||
|
sizeof(s->tty)))) {
|
||||||
if (s->term)
|
if (s->term)
|
||||||
xfree(s->term);
|
xfree(s->term);
|
||||||
s->term = NULL;
|
s->term = NULL;
|
||||||
|
@ -1971,8 +2114,7 @@ session_subsystem_req(Session *s)
|
||||||
s->is_subsystem = SUBSYSTEM_EXT;
|
s->is_subsystem = SUBSYSTEM_EXT;
|
||||||
}
|
}
|
||||||
debug("subsystem: exec() %s", cmd);
|
debug("subsystem: exec() %s", cmd);
|
||||||
do_exec(s, cmd);
|
success = do_exec(s, cmd) == 0;
|
||||||
success = 1;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2015,19 +2157,19 @@ static int
|
||||||
session_shell_req(Session *s)
|
session_shell_req(Session *s)
|
||||||
{
|
{
|
||||||
packet_check_eom();
|
packet_check_eom();
|
||||||
do_exec(s, NULL);
|
return do_exec(s, NULL) == 0;
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
session_exec_req(Session *s)
|
session_exec_req(Session *s)
|
||||||
{
|
{
|
||||||
u_int len;
|
u_int len, success;
|
||||||
|
|
||||||
char *command = packet_get_string(&len);
|
char *command = packet_get_string(&len);
|
||||||
packet_check_eom();
|
packet_check_eom();
|
||||||
do_exec(s, command);
|
success = do_exec(s, command) == 0;
|
||||||
xfree(command);
|
xfree(command);
|
||||||
return 1;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -2037,8 +2179,7 @@ session_break_req(Session *s)
|
||||||
packet_get_int(); /* ignored */
|
packet_get_int(); /* ignored */
|
||||||
packet_check_eom();
|
packet_check_eom();
|
||||||
|
|
||||||
if (s->ttyfd == -1 ||
|
if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
|
||||||
tcsendbreak(s->ttyfd, 0) < 0)
|
|
||||||
return 0;
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2185,8 +2326,9 @@ session_pty_cleanup2(Session *s)
|
||||||
* the pty cleanup, so that another process doesn't get this pty
|
* the pty cleanup, so that another process doesn't get this pty
|
||||||
* while we're still cleaning up.
|
* while we're still cleaning up.
|
||||||
*/
|
*/
|
||||||
if (close(s->ptymaster) < 0)
|
if (s->ptymaster != -1 && close(s->ptymaster) < 0)
|
||||||
error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno));
|
error("close(s->ptymaster/%d): %s",
|
||||||
|
s->ptymaster, strerror(errno));
|
||||||
|
|
||||||
/* unlink pty from session */
|
/* unlink pty from session */
|
||||||
s->ttyfd = -1;
|
s->ttyfd = -1;
|
||||||
|
@ -2346,7 +2488,6 @@ session_close(Session *s)
|
||||||
xfree(s->auth_data);
|
xfree(s->auth_data);
|
||||||
if (s->auth_proto)
|
if (s->auth_proto)
|
||||||
xfree(s->auth_proto);
|
xfree(s->auth_proto);
|
||||||
s->used = 0;
|
|
||||||
if (s->env != NULL) {
|
if (s->env != NULL) {
|
||||||
for (i = 0; i < s->num_env; i++) {
|
for (i = 0; i < s->num_env; i++) {
|
||||||
xfree(s->env[i].name);
|
xfree(s->env[i].name);
|
||||||
|
@ -2355,6 +2496,7 @@ session_close(Session *s)
|
||||||
xfree(s->env);
|
xfree(s->env);
|
||||||
}
|
}
|
||||||
session_proctitle(s);
|
session_proctitle(s);
|
||||||
|
session_unused(s->self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -2418,7 +2560,7 @@ void
|
||||||
session_destroy_all(void (*closefunc)(Session *))
|
session_destroy_all(void (*closefunc)(Session *))
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
if (s->used) {
|
if (s->used) {
|
||||||
if (closefunc != NULL)
|
if (closefunc != NULL)
|
||||||
|
@ -2437,7 +2579,7 @@ session_tty_list(void)
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
for (i = 0; i < MAX_SESSIONS; i++) {
|
for (i = 0; i < sessions_nalloc; i++) {
|
||||||
Session *s = &sessions[i];
|
Session *s = &sessions[i];
|
||||||
if (s->used && s->ttyfd != -1) {
|
if (s->used && s->ttyfd != -1) {
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $OpenBSD: session.h,v 1.29 2006/08/03 03:34:42 deraadt Exp $ */
|
/* $OpenBSD: session.h,v 1.30 2008/05/08 12:21:16 djm Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
* Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
|
||||||
|
@ -31,6 +31,7 @@ typedef struct Session Session;
|
||||||
struct Session {
|
struct Session {
|
||||||
int used;
|
int used;
|
||||||
int self;
|
int self;
|
||||||
|
int next_unused;
|
||||||
struct passwd *pw;
|
struct passwd *pw;
|
||||||
Authctxt *authctxt;
|
Authctxt *authctxt;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
@ -65,6 +66,7 @@ void do_authenticated(Authctxt *);
|
||||||
void do_cleanup(Authctxt *);
|
void do_cleanup(Authctxt *);
|
||||||
|
|
||||||
int session_open(Authctxt *, int);
|
int session_open(Authctxt *, int);
|
||||||
|
void session_unused(int);
|
||||||
int session_input_channel_req(Channel *, const char *);
|
int session_input_channel_req(Channel *, const char *);
|
||||||
void session_close_by_pid(pid_t, int);
|
void session_close_by_pid(pid_t, int);
|
||||||
void session_close_by_channel(int, void *);
|
void session_close_by_channel(int, void *);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $OpenBSD: sshd_config,v 1.78 2008/05/07 06:43:35 pyr Exp $
|
# $OpenBSD: sshd_config,v 1.79 2008/05/08 12:21:16 djm Exp $
|
||||||
|
|
||||||
# This is the sshd server system-wide configuration file. See
|
# This is the sshd server system-wide configuration file. See
|
||||||
# sshd_config(5) for more information.
|
# sshd_config(5) for more information.
|
||||||
|
@ -41,6 +41,7 @@ Protocol 2
|
||||||
#PermitRootLogin yes
|
#PermitRootLogin yes
|
||||||
#StrictModes yes
|
#StrictModes yes
|
||||||
#MaxAuthTries 6
|
#MaxAuthTries 6
|
||||||
|
#MaxSessions 10
|
||||||
|
|
||||||
#RSAAuthentication yes
|
#RSAAuthentication yes
|
||||||
#PubkeyAuthentication yes
|
#PubkeyAuthentication yes
|
||||||
|
|
|
@ -34,8 +34,8 @@
|
||||||
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
.\"
|
.\"
|
||||||
.\" $OpenBSD: sshd_config.5,v 1.89 2008/05/07 08:00:14 jmc Exp $
|
.\" $OpenBSD: sshd_config.5,v 1.90 2008/05/08 12:21:16 djm Exp $
|
||||||
.Dd $Mdocdate: May 19 2008 $
|
.Dd $Mdocdate: May 8 2008 $
|
||||||
.Dt SSHD_CONFIG 5
|
.Dt SSHD_CONFIG 5
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -594,6 +594,9 @@ connection.
|
||||||
Once the number of failures reaches half this value,
|
Once the number of failures reaches half this value,
|
||||||
additional failures are logged.
|
additional failures are logged.
|
||||||
The default is 6.
|
The default is 6.
|
||||||
|
.It Cm MaxSessions
|
||||||
|
Specifies the maximum number of open sessions permitted per network connection.
|
||||||
|
The default is 10.
|
||||||
.It Cm MaxStartups
|
.It Cm MaxStartups
|
||||||
Specifies the maximum number of concurrent unauthenticated connections to the
|
Specifies the maximum number of concurrent unauthenticated connections to the
|
||||||
SSH daemon.
|
SSH daemon.
|
||||||
|
|
Loading…
Reference in New Issue