Bugzilla – Attachment 1483 Details for
Bug 1090
Increase MAX_SESSIONS?
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Make sessions array dynamic, audit server for leaks and fatal errors on fd table full conditions
sessions-unlimit3.diff (text/plain), 32.27 KB, created by
Damien Miller
on 2008-04-24 14:34:19 AEST
(
hide
)
Description:
Make sessions array dynamic, audit server for leaks and fatal errors on fd table full conditions
Filename:
MIME Type:
Creator:
Damien Miller
Created:
2008-04-24 14:34:19 AEST
Size:
32.27 KB
patch
obsolete
>Index: clientloop.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/clientloop.c,v >retrieving revision 1.188 >diff -u -p -r1.188 clientloop.c >--- clientloop.c 22 Feb 2008 20:44:02 -0000 1.188 >+++ clientloop.c 24 Apr 2008 04:30:57 -0000 >@@ -164,6 +164,11 @@ struct confirm_ctx { > char **env; > }; > >+struct channel_reply_ctx { >+ const char *request_type; >+ int do_close; >+}; >+ > /*XXX*/ > extern Kex *xxx_kex; > >@@ -636,10 +641,11 @@ client_process_net_input(fd_set *readset > } > > static void >-client_subsystem_reply(int type, u_int32_t seq, void *ctxt) >+client_handle_reply(int type, u_int32_t seq, void *ctxt, void *ex_ctx) > { > int id; > Channel *c; >+ struct channel_reply_ctx *cr = (struct channel_reply_ctx *)ex_ctx; > > id = packet_get_int(); > packet_check_eom(); >@@ -649,12 +655,30 @@ client_subsystem_reply(int type, u_int32 > return; > } > >- if (type == SSH2_MSG_CHANNEL_SUCCESS) >- debug2("Request suceeded on channel %d", id); >- else if (type == SSH2_MSG_CHANNEL_FAILURE) { >- error("Request failed on channel %d", id); >- channel_free(c); >+ if (type == SSH2_MSG_CHANNEL_SUCCESS) { >+ debug2("%s request accepted on channel %d", >+ cr->request_type, id); >+ } else if (type == SSH2_MSG_CHANNEL_FAILURE) { >+ error("%s request failed on channel %d", >+ cr->request_type, id); >+ /* XXX return a nice error message to mux clients */ >+ if (cr->do_close) { >+ chan_read_failed(c); >+ chan_write_failed(c); >+ } > } >+ xfree(cr); >+} >+ >+static void >+client_expect_channel_reply(const char *request, int do_close) >+{ >+ struct channel_reply_ctx *cr = xmalloc(sizeof(*cr)); >+ >+ cr->request_type = request; >+ cr->do_close = do_close; >+ dispatch_expect_range(SSH2_MSG_CHANNEL_SUCCESS, >+ SSH2_MSG_CHANNEL_FAILURE, client_handle_reply, (void *)cr); > } > > static void >@@ -690,7 +714,7 @@ client_extra_session2_setup(int id, void > > client_session2_setup(id, cctx->want_tty, cctx->want_subsys, > cctx->term, &cctx->tio, c->rfd, &cctx->cmd, cctx->env, >- client_subsystem_reply); >+ client_handle_reply); > > c->confirm_ctx = NULL; > buffer_free(&cctx->cmd); >@@ -1947,7 +1971,7 @@ client_input_global_request(int type, u_ > void > client_session2_setup(int id, int want_tty, int want_subsystem, > const char *term, struct termios *tiop, int in_fd, Buffer *cmd, char **env, >- dispatch_fn *subsys_repl) >+ dispatch_ex_fn *subsys_repl) > { > int len; > Channel *c = NULL; >@@ -1965,7 +1989,8 @@ client_session2_setup(int id, int want_t > if (ioctl(in_fd, TIOCGWINSZ, &ws) < 0) > memset(&ws, 0, sizeof(ws)); > >- channel_request_start(id, "pty-req", 0); >+ channel_request_start(id, "pty-req", 1); >+ client_expect_channel_reply("PTY allocation", 0); > packet_put_cstring(term != NULL ? term : ""); > packet_put_int((u_int)ws.ws_col); > packet_put_int((u_int)ws.ws_row); >@@ -2021,21 +2046,20 @@ client_session2_setup(int id, int want_t > len = 900; > if (want_subsystem) { > debug("Sending subsystem: %.*s", len, (u_char*)buffer_ptr(cmd)); >- channel_request_start(id, "subsystem", subsys_repl != NULL); >- if (subsys_repl != NULL) { >- /* register callback for reply */ >- /* XXX we assume that client_loop has already been called */ >- dispatch_set(SSH2_MSG_CHANNEL_FAILURE, subsys_repl); >- dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, subsys_repl); >- } >+ channel_request_start(id, "subsystem", >+ subsys_repl != NULL); >+ if (subsys_repl != NULL) >+ client_expect_channel_reply("subsystem", 1); > } else { > debug("Sending command: %.*s", len, (u_char*)buffer_ptr(cmd)); >- channel_request_start(id, "exec", 0); >+ channel_request_start(id, "exec", 1); >+ client_expect_channel_reply("exec", 1); > } > packet_put_string(buffer_ptr(cmd), buffer_len(cmd)); > packet_send(); > } else { >- channel_request_start(id, "shell", 0); >+ channel_request_start(id, "shell", 1); >+ client_expect_channel_reply("shell", 1); > packet_send(); > } > } >Index: clientloop.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/clientloop.h,v >retrieving revision 1.17 >diff -u -p -r1.17 clientloop.h >--- clientloop.h 7 Aug 2007 07:32:53 -0000 1.17 >+++ clientloop.h 24 Apr 2008 04:30:57 -0000 >@@ -43,7 +43,7 @@ void client_x11_get_proto(const char *, > char **, char **); > void client_global_request_reply_fwd(int, u_int32_t, void *); > void client_session2_setup(int, int, int, const char *, struct termios *, >- int, Buffer *, char **, dispatch_fn *); >+ int, Buffer *, char **, dispatch_ex_fn *); > int client_request_tun_fwd(int, int, int); > > /* Multiplexing protocol version */ >Index: dispatch.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/dispatch.c,v >retrieving revision 1.21 >diff -u -p -r1.21 dispatch.c >--- dispatch.c 3 Aug 2006 03:34:42 -0000 1.21 >+++ dispatch.c 24 Apr 2008 04:30:57 -0000 >@@ -24,22 +24,36 @@ > */ > > #include <sys/types.h> >+#include <sys/queue.h> > > #include <signal.h> > #include <stdarg.h> >+#include <stdlib.h> >+#include <string.h> > > #include "ssh1.h" > #include "ssh2.h" > #include "log.h" > #include "dispatch.h" > #include "packet.h" >+#include "xmalloc.h" > #include "compat.h" > > #define DISPATCH_MIN 0 > #define DISPATCH_MAX 255 > >+struct dispatch_expectation { >+ int id_low, id_high; >+ dispatch_ex_fn *cb; >+ void *ex_ctx; >+ TAILQ_ENTRY(dispatch_expectation) entry; >+}; >+TAILQ_HEAD(dispatch_expectations, dispatch_expectation); >+ > dispatch_fn *dispatch[DISPATCH_MAX]; >+struct dispatch_expectations expected = TAILQ_HEAD_INITIALIZER(expected); > >+/* ARGSUSED */ > void > dispatch_protocol_error(int type, u_int32_t seq, void *ctxt) > { >@@ -51,6 +65,8 @@ dispatch_protocol_error(int type, u_int3 > packet_send(); > packet_write_wait(); > } >+ >+/* ARGSUSED */ > void > dispatch_protocol_ignore(int type, u_int32_t seq, void *ctxt) > { >@@ -79,9 +95,33 @@ dispatch_set(int type, dispatch_fn *fn) > { > dispatch[type] = fn; > } >+ >+void >+dispatch_expect_range(int id_low, int id_high, dispatch_ex_fn *cb, void *ex_ctx) >+{ >+ struct dispatch_expectation *de; >+ >+ if (id_low > id_high) >+ fatal("%s: id_low > id_high", __func__); >+ de = xmalloc(sizeof(*de)); >+ de->id_low = id_low; >+ de->id_high = id_high; >+ de->cb = cb; >+ de->ex_ctx = cb != NULL ? ex_ctx : NULL; >+ TAILQ_INSERT_TAIL(&expected, de, entry); >+} >+ >+void >+dispatch_expect(int id, dispatch_ex_fn *cb, void *ex_ctx) >+{ >+ dispatch_expect_range(id, id, cb, ex_ctx); >+} >+ > void > dispatch_run(int mode, volatile sig_atomic_t *done, void *ctxt) > { >+ struct dispatch_expectation *de; >+ > for (;;) { > int type; > u_int32_t seqnr; >@@ -93,7 +133,16 @@ dispatch_run(int mode, volatile sig_atom > if (type == SSH_MSG_NONE) > return; > } >- if (type > 0 && type < DISPATCH_MAX && dispatch[type] != NULL) >+ /* Run any specific expected packets first */ >+ de = TAILQ_FIRST(&expected); >+ if (de != NULL && de->id_low <= type && de->id_high >= type) { >+ if (de->cb != NULL) >+ de->cb(type, seqnr, ctxt, de->ex_ctx); >+ TAILQ_REMOVE(&expected, de, entry); >+ bzero(de, sizeof(*de)); >+ free(de); >+ } else if (type > 0 && type < DISPATCH_MAX && >+ dispatch[type] != NULL) > (*dispatch[type])(type, seqnr, ctxt); > else > packet_disconnect("protocol error: rcvd type %d", type); >Index: dispatch.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/dispatch.h,v >retrieving revision 1.11 >diff -u -p -r1.11 dispatch.h >--- dispatch.h 20 Apr 2006 09:27:09 -0000 1.11 >+++ dispatch.h 24 Apr 2008 04:30:57 -0000 >@@ -29,10 +29,13 @@ enum { > }; > > typedef void dispatch_fn(int, u_int32_t, void *); >+typedef void dispatch_ex_fn(int, u_int32_t, void *, void *); > > void dispatch_init(dispatch_fn *); > void dispatch_set(int, dispatch_fn *); > void dispatch_range(u_int, u_int, dispatch_fn *); >+void dispatch_expect_range(int, int, dispatch_ex_fn *, void *); >+void dispatch_expect(int, dispatch_ex_fn *, void *); > void dispatch_run(int, volatile sig_atomic_t *, void *); > void dispatch_protocol_error(int, u_int32_t, void *); > void dispatch_protocol_ignore(int, u_int32_t, void *); >Index: monitor.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/monitor.c,v >retrieving revision 1.94 >diff -u -p -r1.94 monitor.c >--- monitor.c 29 Oct 2007 04:08:08 -0000 1.94 >+++ monitor.c 24 Apr 2008 04:30:57 -0000 >@@ -999,7 +999,7 @@ mm_session_close(Session *s) > debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); > session_pty_cleanup2(s); > } >- s->used = 0; >+ session_unused(s->self); > } > > int >Index: monitor_wrap.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/monitor_wrap.c,v >retrieving revision 1.60 >diff -u -p -r1.60 monitor_wrap.c >--- monitor_wrap.c 29 Oct 2007 04:08:08 -0000 1.60 >+++ monitor_wrap.c 24 Apr 2008 04:30:57 -0000 >@@ -653,7 +653,18 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, > { > Buffer m; > 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__); >+ close(tmp1); >+ close(tmp2); >+ return 0; >+ } >+ close(tmp1); >+ close(tmp2); > > buffer_init(&m); > mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m); >@@ -698,8 +709,9 @@ mm_session_pty_cleanup2(Session *s) > buffer_free(&m); > > /* closed dup'ed master */ >- if (close(s->ptymaster) < 0) >- error("close(s->ptymaster): %s", strerror(errno)); >+ if (s->ptymaster != -1 && close(s->ptymaster) < 0) >+ error("close(s->ptymaster/%d): %s", >+ s->ptymaster, strerror(errno)); > > /* unlink pty from session */ > s->ttyfd = -1; >Index: servconf.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/servconf.c,v >retrieving revision 1.177 >diff -u -p -r1.177 servconf.c >--- servconf.c 10 Feb 2008 10:54:28 -0000 1.177 >+++ servconf.c 24 Apr 2008 04:30:57 -0000 >@@ -105,6 +105,7 @@ initialize_server_options(ServerOptions > options->max_startups_rate = -1; > options->max_startups = -1; > options->max_authtries = -1; >+ options->max_sessions = -1; > options->banner = NULL; > options->use_dns = -1; > options->client_alive_interval = -1; >@@ -221,6 +222,8 @@ fill_default_server_options(ServerOption > options->max_startups_begin = options->max_startups; > if (options->max_authtries == -1) > options->max_authtries = DEFAULT_AUTH_FAIL_MAX; >+ if (options->max_sessions == -1) >+ options->max_sessions = DEFAULT_SESSIONS_MAX; > if (options->use_dns == -1) > options->use_dns = 1; > if (options->client_alive_interval == -1) >@@ -262,7 +265,7 @@ typedef enum { > sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, > sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, > sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, >- sMaxStartups, sMaxAuthTries, >+ sMaxStartups, sMaxAuthTries, sMaxSessions, > sBanner, sUseDNS, sHostbasedAuthentication, > sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, > sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, >@@ -353,6 +356,7 @@ static struct { > { "subsystem", sSubsystem, SSHCFG_GLOBAL }, > { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, > { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL }, >+ { "maxsessions", sMaxSessions, SSHCFG_ALL }, > { "banner", sBanner, SSHCFG_ALL }, > { "usedns", sUseDNS, SSHCFG_GLOBAL }, > { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, >@@ -647,7 +651,7 @@ process_server_config_line(ServerOptions > > case sServerKeyBits: > intptr = &options->server_key_bits; >-parse_int: >+ parse_int: > arg = strdelim(&cp); > if (!arg || *arg == '\0') > fatal("%s line %d: missing integer value.", >@@ -659,7 +663,7 @@ parse_int: > > case sLoginGraceTime: > intptr = &options->login_grace_time; >-parse_time: >+ parse_time: > arg = strdelim(&cp); > if (!arg || *arg == '\0') > fatal("%s line %d: missing time value.", >@@ -728,7 +732,7 @@ parse_time: > fatal("%s line %d: too many host keys specified (max %d).", > filename, linenum, MAX_HOSTKEYS); > charptr = &options->host_key_files[*intptr]; >-parse_filename: >+ parse_filename: > arg = strdelim(&cp); > if (!arg || *arg == '\0') > fatal("%s line %d: missing file name.", >@@ -771,7 +775,7 @@ parse_filename: > > case sIgnoreRhosts: > intptr = &options->ignore_rhosts; >-parse_flag: >+ parse_flag: > arg = strdelim(&cp); > if (!arg || *arg == '\0') > fatal("%s line %d: missing yes/no argument.", >@@ -1103,6 +1107,10 @@ parse_flag: > intptr = &options->max_authtries; > goto parse_int; > >+ case sMaxSessions: >+ intptr = &options->max_sessions; >+ goto parse_int; >+ > case sBanner: > charptr = &options->banner; > goto parse_filename; >@@ -1329,6 +1337,7 @@ copy_set_server_options(ServerOptions *d > M_CP_INTOPT(x11_display_offset); > M_CP_INTOPT(x11_forwarding); > M_CP_INTOPT(x11_use_localhost); >+ M_CP_INTOPT(max_sessions); > > M_CP_STROPT(banner); > if (preauth) >Index: servconf.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/servconf.h,v >retrieving revision 1.82 >diff -u -p -r1.82 servconf.h >--- servconf.h 13 Feb 2008 22:38:17 -0000 1.82 >+++ servconf.h 24 Apr 2008 04:30:57 -0000 >@@ -35,6 +35,7 @@ > #define PERMIT_YES 3 > > #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ >+#define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ > > /* Magic name for internal sftp-server */ > #define INTERNAL_SFTP_NAME "internal-sftp" >@@ -122,6 +123,7 @@ typedef struct { > int max_startups_rate; > int max_startups; > int max_authtries; >+ int max_sessions; > char *banner; /* SSH-2 banner message */ > int use_dns; > int client_alive_interval; /* >Index: session.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/session.c,v >retrieving revision 1.234 >diff -u -p -r1.234 session.c >--- session.c 18 Apr 2008 22:01:33 -0000 1.234 >+++ session.c 24 Apr 2008 04:30:58 -0000 >@@ -93,9 +93,9 @@ void session_set_fds(Session *, int, int > void session_pty_cleanup(Session *); > void session_proctitle(Session *); > int session_setup_x11fwd(Session *); >-void do_exec_pty(Session *, const char *); >-void do_exec_no_pty(Session *, const char *); >-void do_exec(Session *, const char *); >+int do_exec_pty(Session *, const char *); >+int do_exec_no_pty(Session *, const char *); >+int do_exec(Session *, const char *); > void do_login(Session *, const char *); > void do_child(Session *, const char *); > void do_motd(void); >@@ -120,8 +120,9 @@ extern Buffer loginmsg; > const char *original_command = NULL; > > /* data */ >-#define MAX_SESSIONS 10 >-Session sessions[MAX_SESSIONS]; >+static int sessions_first_unused = -1; >+static int sessions_nalloc = 0; >+static Session *sessions = NULL; > > #define SUBSYSTEM_NONE 0 > #define SUBSYSTEM_EXT 1 >@@ -153,7 +154,7 @@ static int > auth_input_request_forwarding(struct passwd * pw) > { > Channel *nc; >- int sock; >+ int sock = -1; > struct sockaddr_un sunaddr; > > if (auth_sock_name != NULL) { >@@ -165,43 +166,49 @@ auth_input_request_forwarding(struct pas > temporarily_use_uid(pw); > > /* Allocate a buffer for the socket name, and format the name. */ >- auth_sock_name = xmalloc(MAXPATHLEN); >- auth_sock_dir = xmalloc(MAXPATHLEN); >- strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); >+ auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); > > /* Create private directory for socket */ > if (mkdtemp(auth_sock_dir) == NULL) { > packet_send_debug("Agent forwarding disabled: " > "mkdtemp() failed: %.100s", strerror(errno)); > restore_uid(); >- xfree(auth_sock_name); > xfree(auth_sock_dir); >- auth_sock_name = NULL; > auth_sock_dir = NULL; >- return 0; >+ goto authsock_err; > } >- snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", >- auth_sock_dir, (long) getpid()); >+ >+ auth_sock_name = xmalloc(MAXPATHLEN); >+ xasprintf(&auth_sock_name, "%s/agent.%ld", >+ auth_sock_dir, (long) getpid()); > > /* Create the socket. */ > sock = socket(AF_UNIX, SOCK_STREAM, 0); >- if (sock < 0) >- packet_disconnect("socket: %.100s", strerror(errno)); >+ if (sock < 0) { >+ error("socket: %.100s", strerror(errno)); >+ restore_uid(); >+ goto authsock_err; >+ } > > /* Bind it to the name. */ > memset(&sunaddr, 0, sizeof(sunaddr)); > sunaddr.sun_family = AF_UNIX; > strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); > >- if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) >- packet_disconnect("bind: %.100s", strerror(errno)); >+ if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { >+ error("bind: %.100s", strerror(errno)); >+ restore_uid(); >+ goto authsock_err; >+ } > > /* Restore the privileged uid. */ > restore_uid(); > > /* Start listening on the socket. */ >- if (listen(sock, SSH_LISTEN_BACKLOG) < 0) >- packet_disconnect("listen: %.100s", strerror(errno)); >+ if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { >+ error("listen: %.100s", strerror(errno)); >+ goto authsock_err; >+ } > > /* Allocate a channel for the authentication agent socket. */ > nc = channel_new("auth socket", >@@ -210,6 +217,19 @@ auth_input_request_forwarding(struct pas > 0, "auth socket", 1); > strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); > 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 >@@ -358,7 +378,8 @@ do_authenticated1(Authctxt *authctxt) > if (type == SSH_CMSG_EXEC_CMD) { > command = packet_get_string(&dlen); > debug("Exec command '%.500s'", command); >- do_exec(s, command); >+ if (do_exec(s, command) != 0) >+ cleanup_exit(255); > xfree(command); > } else { > do_exec(s, NULL); >@@ -391,28 +412,44 @@ do_authenticated1(Authctxt *authctxt) > * will call do_child from the child, and server_loop from the parent after > * setting up file descriptors and such. > */ >-void >+int > do_exec_no_pty(Session *s, const char *command) > { > pid_t pid; >- > int inout[2], err[2]; >+ > /* Uses socket pairs to communicate with the program. */ >- if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || >- socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) >- packet_disconnect("Could not create socket pairs: %.100s", >- strerror(errno)); >+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { >+ error("%s: socketpair #1: %.100s", __func__, strerror(errno)); >+ return -1; >+ } >+ 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; >+ } >+ > if (s == NULL) > fatal("do_exec_no_pty: no session"); > > session_proctitle(s); > > /* Fork the child. */ >- if ((pid = fork()) == 0) { >+ switch ((pid = fork())) { >+ case -1: >+ error("%s: fork: %.100s", __func__, strerror(errno)); >+ close(inout[0]); >+ close(inout[1]); >+ close(err[0]); >+ close(err[1]); >+ return -1; >+ case 0: > is_child = 1; > > /* 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 >@@ -430,7 +467,7 @@ do_exec_no_pty(Session *s, const char *c > close(err[1]); > if (dup2(inout[0], 0) < 0) /* 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"); > if (dup2(err[0], 2) < 0) /* stderr */ > perror("dup2 stderr"); >@@ -438,9 +475,10 @@ do_exec_no_pty(Session *s, const char *c > /* Do processing for the child (exec command etc). */ > do_child(s, command); > /* NOTREACHED */ >+ default: >+ break; > } >- if (pid < 0) >- packet_disconnect("fork failed: %.100s", strerror(errno)); >+ > s->pid = pid; > /* Set interactive/non-interactive mode. */ > packet_set_interactive(s->display != NULL); >@@ -454,11 +492,15 @@ do_exec_no_pty(Session *s, const char *c > * handle the case that fdin and fdout are the same. > */ > 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 { > server_loop(pid, inout[1], inout[1], err[1]); > /* server_loop has closed inout[1] and err[1]. */ > } >+ return 0; > } > > /* >@@ -467,7 +509,7 @@ do_exec_no_pty(Session *s, const char *c > * setting up file descriptors, controlling tty, updating wtmp, utmp, > * lastlog, and other such operations. > */ >-void >+int > do_exec_pty(Session *s, const char *command) > { > int fdout, ptyfd, ttyfd, ptymaster; >@@ -478,12 +520,46 @@ do_exec_pty(Session *s, const char *comm > ptyfd = s->ptyfd; > 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. */ >- 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; > >+ close(fdout); >+ close(ptymaster); >+ > /* 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(ptyfd); > >@@ -505,33 +581,22 @@ do_exec_pty(Session *s, const char *comm > if (!(options.use_login && command == NULL)) > do_login(s, command); > >- /* Do common processing for the child, such as execing the command. */ >+ /* >+ * Do common processing for the child, such as execing >+ * the command. >+ */ > do_child(s, command); > /* NOTREACHED */ >+ default: >+ break; > } >- if (pid < 0) >- packet_disconnect("fork failed: %.100s", strerror(errno)); > s->pid = pid; > > /* Parent. Close the slave side of the pseudo tty. */ > 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. */ >+ s->ptymaster = ptymaster; > packet_set_interactive(1); > if (compat20) { > session_set_fds(s, ptyfd, fdout, -1); >@@ -539,15 +604,18 @@ do_exec_pty(Session *s, const char *comm > server_loop(pid, ptyfd, fdout, -1); > /* server_loop _has_ closed ptyfd and fdout. */ > } >+ return 0; > } > > /* > * This is called to fork and execute a command. If another command is > * to be forced, execute that instead. > */ >-void >+int > do_exec(Session *s, const char *command) > { >+ int ret; >+ > if (options.adm_forced_command) { > original_command = command; > command = options.adm_forced_command; >@@ -574,9 +642,9 @@ do_exec(Session *s, const char *command) > } > #endif > if (s->ttyfd != -1) >- do_exec_pty(s, command); >+ ret = do_exec_pty(s, command); > else >- do_exec_no_pty(s, command); >+ ret = do_exec_no_pty(s, command); > > original_command = NULL; > >@@ -586,6 +654,8 @@ do_exec(Session *s, const char *command) > * multiple copies of the login messages. > */ > buffer_clear(&loginmsg); >+ >+ return ret; > } > > >@@ -1291,43 +1361,79 @@ do_child(Session *s, const char *command > 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_new(void) > { >- int i; >- static int did_init = 0; >- if (!did_init) { >- debug("session_new: init"); >- for (i = 0; i < MAX_SESSIONS; i++) { >- sessions[i].used = 0; >- } >- did_init = 1; >- } >- for (i = 0; i < MAX_SESSIONS; i++) { >- Session *s = &sessions[i]; >- if (! s->used) { >- memset(s, 0, sizeof(*s)); >- s->chanid = -1; >- s->ptyfd = -1; >- s->ttyfd = -1; >- s->used = 1; >- s->self = i; >- s->x11_chanids = NULL; >- debug("session_new: session %d", i); >- return s; >- } >- } >- return NULL; >+ Session *s, *tmp; >+ >+ if (sessions_first_unused == -1) { >+ if (sessions_nalloc >= options.max_sessions) >+ return NULL; >+ 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; >+ } >+ sessions = tmp; >+ session_unused(sessions_nalloc++); >+ } >+ >+ if (sessions_first_unused >= sessions_nalloc || >+ sessions_first_unused < 0) { >+ fatal("%s: insane first_unused %d max %d nalloc %d", >+ __func__, sessions_first_unused, options.max_sessions, >+ sessions_nalloc); >+ } >+ >+ 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 > session_dump(void) > { > int i; >- for (i = 0; i < MAX_SESSIONS; i++) { >+ for (i = 0; i < sessions_nalloc; 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->next_unused, > s->self, > s, > s->chanid, >@@ -1357,7 +1463,7 @@ Session * > session_by_tty(char *tty) > { > int i; >- for (i = 0; i < MAX_SESSIONS; i++) { >+ for (i = 0; i < sessions_nalloc; i++) { > Session *s = &sessions[i]; > if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { > debug("session_by_tty: session %d tty %s", i, tty); >@@ -1373,10 +1479,11 @@ static Session * > session_by_channel(int id) > { > int i; >- for (i = 0; i < MAX_SESSIONS; i++) { >+ for (i = 0; i < sessions_nalloc; i++) { > Session *s = &sessions[i]; > 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; > } > } >@@ -1390,7 +1497,7 @@ session_by_x11_channel(int id) > { > int i, j; > >- for (i = 0; i < MAX_SESSIONS; i++) { >+ for (i = 0; i < sessions_nalloc; i++) { > Session *s = &sessions[i]; > > if (s->x11_chanids == NULL || !s->used) >@@ -1413,7 +1520,7 @@ session_by_pid(pid_t pid) > { > int i; > 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]; > if (s->used && s->pid == pid) > return s; >@@ -1469,7 +1576,8 @@ session_pty_req(Session *s) > > /* Allocate a pty and open it. */ > 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) > xfree(s->term); > s->term = NULL; >@@ -1522,8 +1630,7 @@ session_subsystem_req(Session *s) > s->is_subsystem = SUBSYSTEM_EXT; > } > debug("subsystem: exec() %s", cmd); >- do_exec(s, cmd); >- success = 1; >+ success = do_exec(s, cmd) == 0; > break; > } > } >@@ -1566,19 +1673,19 @@ static int > session_shell_req(Session *s) > { > packet_check_eom(); >- do_exec(s, NULL); >- return 1; >+ return do_exec(s, NULL) == 0; > } > > static int > session_exec_req(Session *s) > { >- u_int len; >+ u_int len, success; >+ > char *command = packet_get_string(&len); > packet_check_eom(); >- do_exec(s, command); >+ success = do_exec(s, command) == 0; > xfree(command); >- return 1; >+ return success; > } > > static int >@@ -1588,8 +1695,7 @@ session_break_req(Session *s) > packet_get_int(); /* ignored */ > packet_check_eom(); > >- if (s->ttyfd == -1 || >- tcsendbreak(s->ttyfd, 0) < 0) >+ if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0) > return 0; > return 1; > } >@@ -1736,8 +1842,9 @@ session_pty_cleanup2(Session *s) > * the pty cleanup, so that another process doesn't get this pty > * while we're still cleaning up. > */ >- if (close(s->ptymaster) < 0) >- error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); >+ if (s->ptymaster != -1 && close(s->ptymaster) < 0) >+ error("close(s->ptymaster/%d): %s", >+ s->ptymaster, strerror(errno)); > > /* unlink pty from session */ > s->ttyfd = -1; >@@ -1893,7 +2000,6 @@ session_close(Session *s) > xfree(s->auth_data); > if (s->auth_proto) > xfree(s->auth_proto); >- s->used = 0; > if (s->env != NULL) { > for (i = 0; i < s->num_env; i++) { > xfree(s->env[i].name); >@@ -1902,6 +2008,7 @@ session_close(Session *s) > xfree(s->env); > } > session_proctitle(s); >+ session_unused(s->self); > } > > void >@@ -1965,7 +2072,7 @@ void > session_destroy_all(void (*closefunc)(Session *)) > { > int i; >- for (i = 0; i < MAX_SESSIONS; i++) { >+ for (i = 0; i < sessions_nalloc; i++) { > Session *s = &sessions[i]; > if (s->used) { > if (closefunc != NULL) >@@ -1982,7 +2089,7 @@ session_tty_list(void) > static char buf[1024]; > int i; > buf[0] = '\0'; >- for (i = 0; i < MAX_SESSIONS; i++) { >+ for (i = 0; i < sessions_nalloc; i++) { > Session *s = &sessions[i]; > if (s->used && s->ttyfd != -1) { > if (buf[0] != '\0') >Index: session.h >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/session.h,v >retrieving revision 1.29 >diff -u -p -r1.29 session.h >--- session.h 3 Aug 2006 03:34:42 -0000 1.29 >+++ session.h 24 Apr 2008 04:30:58 -0000 >@@ -31,6 +31,7 @@ typedef struct Session Session; > struct Session { > int used; > int self; >+ int next_unused; > struct passwd *pw; > Authctxt *authctxt; > pid_t pid; >@@ -65,6 +66,7 @@ void do_authenticated(Authctxt *); > void do_cleanup(Authctxt *); > > int session_open(Authctxt *, int); >+void session_unused(int); > int session_input_channel_req(Channel *, const char *); > void session_close_by_pid(pid_t, int); > void session_close_by_channel(int, void *); >Index: ssh.c >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/ssh.c,v >retrieving revision 1.309 >diff -u -p -r1.309 ssh.c >--- ssh.c 19 Jan 2008 20:51:26 -0000 1.309 >+++ ssh.c 24 Apr 2008 04:30:58 -0000 >@@ -1019,7 +1019,7 @@ ssh_session(void) > } > > static void >-ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt) >+ssh_subsystem_reply(int type, u_int32_t seq, void *ctxt, void *ex_ctx) > { > int id, len; > >Index: sshd_config >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sshd_config,v >retrieving revision 1.77 >diff -u -p -r1.77 sshd_config >--- sshd_config 8 Feb 2008 23:24:07 -0000 1.77 >+++ sshd_config 24 Apr 2008 04:30:58 -0000 >@@ -39,6 +39,7 @@ Protocol 2 > #PermitRootLogin yes > #StrictModes yes > #MaxAuthTries 6 >+#MaxSessions 10 > > #RSAAuthentication yes > #PubkeyAuthentication yes >Index: sshd_config.5 >=================================================================== >RCS file: /cvs/src/usr.bin/ssh/sshd_config.5,v >retrieving revision 1.87 >diff -u -p -r1.87 sshd_config.5 >--- sshd_config.5 5 Apr 2008 02:46:02 -0000 1.87 >+++ sshd_config.5 24 Apr 2008 04:30:58 -0000 >@@ -585,6 +585,9 @@ connection. > Once the number of failures reaches half this value, > additional failures are logged. > 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 > Specifies the maximum number of concurrent unauthenticated connections to the > SSH daemon.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 1090
:
963
|
979
|
1473
| 1483