diff options
-rw-r--r-- | ChangeLog | 17 | ||||
-rw-r--r-- | monitor.c | 4 | ||||
-rw-r--r-- | monitor_wrap.c | 22 | ||||
-rw-r--r-- | servconf.c | 21 | ||||
-rw-r--r-- | servconf.h | 4 | ||||
-rw-r--r-- | session.c | 382 | ||||
-rw-r--r-- | session.h | 4 | ||||
-rw-r--r-- | sshd_config | 3 | ||||
-rw-r--r-- | sshd_config.5 | 7 |
9 files changed, 326 insertions, 138 deletions
@@ -77,6 +77,21 @@ | |||
77 | shouldn't happen in compliant implementations, but it could be | 77 | shouldn't happen in compliant implementations, but it could be |
78 | abused to leak memory. | 78 | abused to leak memory. |
79 | ok markus@ (as part of a larger diff) | 79 | ok markus@ (as part of a larger diff) |
80 | - djm@cvs.openbsd.org 2008/05/08 12:21:16 | ||
81 | [monitor.c monitor_wrap.c session.h servconf.c servconf.h session.c] | ||
82 | [sshd_config sshd_config.5] | ||
83 | Make the maximum number of sessions run-time controllable via | ||
84 | a sshd_config MaxSessions knob. This is useful for disabling | ||
85 | login/shell/subsystem access while leaving port-forwarding working | ||
86 | (MaxSessions 0), disabling connection multiplexing (MaxSessions 1) or | ||
87 | simply increasing the number of allows multiplexed sessions. | ||
88 | Because some bozos are sure to configure MaxSessions in excess of the | ||
89 | number of available file descriptors in sshd (which, at peak, might be | ||
90 | as many as 9*MaxSessions), audit sshd to ensure that it doesn't leak fds | ||
91 | on error paths, and make it fail gracefully on out-of-fd conditions - | ||
92 | sending channel errors instead of than exiting with fatal(). | ||
93 | bz#1090; MaxSessions config bits and manpage from junyer AT gmail.com | ||
94 | ok markus@ | ||
80 | 95 | ||
81 | 20080403 | 96 | 20080403 |
82 | - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- | 97 | - (djm) [openbsd-compat/bsd-poll.c] Include stdlib.h to avoid compile- |
@@ -3937,4 +3952,4 @@ | |||
3937 | OpenServer 6 and add osr5bigcrypt support so when someone migrates | 3952 | OpenServer 6 and add osr5bigcrypt support so when someone migrates |
3938 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ | 3953 | passwords between UnixWare and OpenServer they will still work. OK dtucker@ |
3939 | 3954 | ||
3940 | $Id: ChangeLog,v 1.4922 2008/05/19 05:28:35 djm Exp $ | 3955 | $Id: ChangeLog,v 1.4923 2008/05/19 05:34:50 djm Exp $ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor.c,v 1.95 2008/05/08 12:02:23 djm Exp $ */ | 1 | /* $OpenBSD: monitor.c,v 1.96 2008/05/08 12:21:16 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -1273,7 +1273,7 @@ mm_session_close(Session *s) | |||
1273 | debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); | 1273 | debug3("%s: tty %s ptyfd %d", __func__, s->tty, s->ptyfd); |
1274 | session_pty_cleanup2(s); | 1274 | session_pty_cleanup2(s); |
1275 | } | 1275 | } |
1276 | s->used = 0; | 1276 | session_unused(s->self); |
1277 | } | 1277 | } |
1278 | 1278 | ||
1279 | int | 1279 | int |
diff --git a/monitor_wrap.c b/monitor_wrap.c index 72fd5c83c..e65fb1279 100644 --- a/monitor_wrap.c +++ b/monitor_wrap.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: monitor_wrap.c,v 1.61 2008/05/08 12:02:23 djm Exp $ */ | 1 | /* $OpenBSD: monitor_wrap.c,v 1.62 2008/05/08 12:21:16 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> | 3 | * Copyright 2002 Niels Provos <provos@citi.umich.edu> |
4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> | 4 | * Copyright 2002 Markus Friedl <markus@openbsd.org> |
@@ -666,7 +666,20 @@ mm_pty_allocate(int *ptyfd, int *ttyfd, char *namebuf, size_t namebuflen) | |||
666 | { | 666 | { |
667 | Buffer m; | 667 | Buffer m; |
668 | char *p, *msg; | 668 | char *p, *msg; |
669 | int success = 0; | 669 | int success = 0, tmp1 = -1, tmp2 = -1; |
670 | |||
671 | /* Kludge: ensure there are fds free to receive the pty/tty */ | ||
672 | if ((tmp1 = dup(pmonitor->m_recvfd)) == -1 || | ||
673 | (tmp2 = dup(pmonitor->m_recvfd)) == -1) { | ||
674 | error("%s: cannot allocate fds for pty", __func__); | ||
675 | if (tmp1 > 0) | ||
676 | close(tmp1); | ||
677 | if (tmp2 > 0) | ||
678 | close(tmp2); | ||
679 | return 0; | ||
680 | } | ||
681 | close(tmp1); | ||
682 | close(tmp2); | ||
670 | 683 | ||
671 | buffer_init(&m); | 684 | buffer_init(&m); |
672 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m); | 685 | mm_request_send(pmonitor->m_recvfd, MONITOR_REQ_PTY, &m); |
@@ -711,8 +724,9 @@ mm_session_pty_cleanup2(Session *s) | |||
711 | buffer_free(&m); | 724 | buffer_free(&m); |
712 | 725 | ||
713 | /* closed dup'ed master */ | 726 | /* closed dup'ed master */ |
714 | if (close(s->ptymaster) < 0) | 727 | if (s->ptymaster != -1 && close(s->ptymaster) < 0) |
715 | error("close(s->ptymaster): %s", strerror(errno)); | 728 | error("close(s->ptymaster/%d): %s", |
729 | s->ptymaster, strerror(errno)); | ||
716 | 730 | ||
717 | /* unlink pty from session */ | 731 | /* unlink pty from session */ |
718 | s->ttyfd = -1; | 732 | s->ttyfd = -1; |
diff --git a/servconf.c b/servconf.c index b8a968aa3..94dff1fd6 100644 --- a/servconf.c +++ b/servconf.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.c,v 1.179 2008/05/08 12:02:23 djm Exp $ */ | 1 | /* $OpenBSD: servconf.c,v 1.180 2008/05/08 12:21:16 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -114,6 +114,7 @@ initialize_server_options(ServerOptions *options) | |||
114 | options->max_startups_rate = -1; | 114 | options->max_startups_rate = -1; |
115 | options->max_startups = -1; | 115 | options->max_startups = -1; |
116 | options->max_authtries = -1; | 116 | options->max_authtries = -1; |
117 | options->max_sessions = -1; | ||
117 | options->banner = NULL; | 118 | options->banner = NULL; |
118 | options->use_dns = -1; | 119 | options->use_dns = -1; |
119 | options->client_alive_interval = -1; | 120 | options->client_alive_interval = -1; |
@@ -237,6 +238,8 @@ fill_default_server_options(ServerOptions *options) | |||
237 | options->max_startups_begin = options->max_startups; | 238 | options->max_startups_begin = options->max_startups; |
238 | if (options->max_authtries == -1) | 239 | if (options->max_authtries == -1) |
239 | options->max_authtries = DEFAULT_AUTH_FAIL_MAX; | 240 | options->max_authtries = DEFAULT_AUTH_FAIL_MAX; |
241 | if (options->max_sessions == -1) | ||
242 | options->max_sessions = DEFAULT_SESSIONS_MAX; | ||
240 | if (options->use_dns == -1) | 243 | if (options->use_dns == -1) |
241 | options->use_dns = 1; | 244 | options->use_dns = 1; |
242 | if (options->client_alive_interval == -1) | 245 | if (options->client_alive_interval == -1) |
@@ -291,7 +294,7 @@ typedef enum { | |||
291 | sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, | 294 | sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups, |
292 | sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, | 295 | sIgnoreUserKnownHosts, sCiphers, sMacs, sProtocol, sPidFile, |
293 | sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, | 296 | sGatewayPorts, sPubkeyAuthentication, sXAuthLocation, sSubsystem, |
294 | sMaxStartups, sMaxAuthTries, | 297 | sMaxStartups, sMaxAuthTries, sMaxSessions, |
295 | sBanner, sUseDNS, sHostbasedAuthentication, | 298 | sBanner, sUseDNS, sHostbasedAuthentication, |
296 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, | 299 | sHostbasedUsesNameFromPacketOnly, sClientAliveInterval, |
297 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, | 300 | sClientAliveCountMax, sAuthorizedKeysFile, sAuthorizedKeysFile2, |
@@ -395,6 +398,7 @@ static struct { | |||
395 | { "subsystem", sSubsystem, SSHCFG_GLOBAL }, | 398 | { "subsystem", sSubsystem, SSHCFG_GLOBAL }, |
396 | { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, | 399 | { "maxstartups", sMaxStartups, SSHCFG_GLOBAL }, |
397 | { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL }, | 400 | { "maxauthtries", sMaxAuthTries, SSHCFG_GLOBAL }, |
401 | { "maxsessions", sMaxSessions, SSHCFG_ALL }, | ||
398 | { "banner", sBanner, SSHCFG_ALL }, | 402 | { "banner", sBanner, SSHCFG_ALL }, |
399 | { "usedns", sUseDNS, SSHCFG_GLOBAL }, | 403 | { "usedns", sUseDNS, SSHCFG_GLOBAL }, |
400 | { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, | 404 | { "verifyreversemapping", sDeprecated, SSHCFG_GLOBAL }, |
@@ -695,7 +699,7 @@ process_server_config_line(ServerOptions *options, char *line, | |||
695 | 699 | ||
696 | case sServerKeyBits: | 700 | case sServerKeyBits: |
697 | intptr = &options->server_key_bits; | 701 | intptr = &options->server_key_bits; |
698 | parse_int: | 702 | parse_int: |
699 | arg = strdelim(&cp); | 703 | arg = strdelim(&cp); |
700 | if (!arg || *arg == '\0') | 704 | if (!arg || *arg == '\0') |
701 | fatal("%s line %d: missing integer value.", | 705 | fatal("%s line %d: missing integer value.", |
@@ -707,7 +711,7 @@ parse_int: | |||
707 | 711 | ||
708 | case sLoginGraceTime: | 712 | case sLoginGraceTime: |
709 | intptr = &options->login_grace_time; | 713 | intptr = &options->login_grace_time; |
710 | parse_time: | 714 | parse_time: |
711 | arg = strdelim(&cp); | 715 | arg = strdelim(&cp); |
712 | if (!arg || *arg == '\0') | 716 | if (!arg || *arg == '\0') |
713 | fatal("%s line %d: missing time value.", | 717 | fatal("%s line %d: missing time value.", |
@@ -776,7 +780,7 @@ parse_time: | |||
776 | fatal("%s line %d: too many host keys specified (max %d).", | 780 | fatal("%s line %d: too many host keys specified (max %d).", |
777 | filename, linenum, MAX_HOSTKEYS); | 781 | filename, linenum, MAX_HOSTKEYS); |
778 | charptr = &options->host_key_files[*intptr]; | 782 | charptr = &options->host_key_files[*intptr]; |
779 | parse_filename: | 783 | parse_filename: |
780 | arg = strdelim(&cp); | 784 | arg = strdelim(&cp); |
781 | if (!arg || *arg == '\0') | 785 | if (!arg || *arg == '\0') |
782 | fatal("%s line %d: missing file name.", | 786 | fatal("%s line %d: missing file name.", |
@@ -819,7 +823,7 @@ parse_filename: | |||
819 | 823 | ||
820 | case sIgnoreRhosts: | 824 | case sIgnoreRhosts: |
821 | intptr = &options->ignore_rhosts; | 825 | intptr = &options->ignore_rhosts; |
822 | parse_flag: | 826 | parse_flag: |
823 | arg = strdelim(&cp); | 827 | arg = strdelim(&cp); |
824 | if (!arg || *arg == '\0') | 828 | if (!arg || *arg == '\0') |
825 | fatal("%s line %d: missing yes/no argument.", | 829 | fatal("%s line %d: missing yes/no argument.", |
@@ -1155,6 +1159,10 @@ parse_flag: | |||
1155 | intptr = &options->max_authtries; | 1159 | intptr = &options->max_authtries; |
1156 | goto parse_int; | 1160 | goto parse_int; |
1157 | 1161 | ||
1162 | case sMaxSessions: | ||
1163 | intptr = &options->max_sessions; | ||
1164 | goto parse_int; | ||
1165 | |||
1158 | case sBanner: | 1166 | case sBanner: |
1159 | charptr = &options->banner; | 1167 | charptr = &options->banner; |
1160 | goto parse_filename; | 1168 | goto parse_filename; |
@@ -1382,6 +1390,7 @@ copy_set_server_options(ServerOptions *dst, ServerOptions *src, int preauth) | |||
1382 | M_CP_INTOPT(x11_display_offset); | 1390 | M_CP_INTOPT(x11_display_offset); |
1383 | M_CP_INTOPT(x11_forwarding); | 1391 | M_CP_INTOPT(x11_forwarding); |
1384 | M_CP_INTOPT(x11_use_localhost); | 1392 | M_CP_INTOPT(x11_use_localhost); |
1393 | M_CP_INTOPT(max_sessions); | ||
1385 | 1394 | ||
1386 | M_CP_STROPT(banner); | 1395 | M_CP_STROPT(banner); |
1387 | if (preauth) | 1396 | if (preauth) |
diff --git a/servconf.h b/servconf.h index aaf87cd18..819a028c8 100644 --- a/servconf.h +++ b/servconf.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: servconf.h,v 1.83 2008/05/07 05:49:37 pyr Exp $ */ | 1 | /* $OpenBSD: servconf.h,v 1.84 2008/05/08 12:21:16 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -35,6 +35,7 @@ | |||
35 | #define PERMIT_YES 3 | 35 | #define PERMIT_YES 3 |
36 | 36 | ||
37 | #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ | 37 | #define DEFAULT_AUTH_FAIL_MAX 6 /* Default for MaxAuthTries */ |
38 | #define DEFAULT_SESSIONS_MAX 10 /* Default for MaxSessions */ | ||
38 | 39 | ||
39 | /* Magic name for internal sftp-server */ | 40 | /* Magic name for internal sftp-server */ |
40 | #define INTERNAL_SFTP_NAME "internal-sftp" | 41 | #define INTERNAL_SFTP_NAME "internal-sftp" |
@@ -123,6 +124,7 @@ typedef struct { | |||
123 | int max_startups_rate; | 124 | int max_startups_rate; |
124 | int max_startups; | 125 | int max_startups; |
125 | int max_authtries; | 126 | int max_authtries; |
127 | int max_sessions; | ||
126 | char *banner; /* SSH-2 banner message */ | 128 | char *banner; /* SSH-2 banner message */ |
127 | int use_dns; | 129 | int use_dns; |
128 | int client_alive_interval; /* | 130 | int client_alive_interval; /* |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.c,v 1.236 2008/05/08 12:02:23 djm Exp $ */ | 1 | /* $OpenBSD: session.c,v 1.237 2008/05/08 12:21:16 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
4 | * All rights reserved | 4 | * All rights reserved |
@@ -102,9 +102,9 @@ void session_set_fds(Session *, int, int, int); | |||
102 | void session_pty_cleanup(Session *); | 102 | void session_pty_cleanup(Session *); |
103 | void session_proctitle(Session *); | 103 | void session_proctitle(Session *); |
104 | int session_setup_x11fwd(Session *); | 104 | int session_setup_x11fwd(Session *); |
105 | void do_exec_pty(Session *, const char *); | 105 | int do_exec_pty(Session *, const char *); |
106 | void do_exec_no_pty(Session *, const char *); | 106 | int do_exec_no_pty(Session *, const char *); |
107 | void do_exec(Session *, const char *); | 107 | int do_exec(Session *, const char *); |
108 | void do_login(Session *, const char *); | 108 | void do_login(Session *, const char *); |
109 | #ifdef LOGIN_NEEDS_UTMPX | 109 | #ifdef LOGIN_NEEDS_UTMPX |
110 | static void do_pre_login(Session *s); | 110 | static void do_pre_login(Session *s); |
@@ -132,8 +132,9 @@ extern Buffer loginmsg; | |||
132 | const char *original_command = NULL; | 132 | const char *original_command = NULL; |
133 | 133 | ||
134 | /* data */ | 134 | /* data */ |
135 | #define MAX_SESSIONS 20 | 135 | static int sessions_first_unused = -1; |
136 | Session sessions[MAX_SESSIONS]; | 136 | static int sessions_nalloc = 0; |
137 | static Session *sessions = NULL; | ||
137 | 138 | ||
138 | #define SUBSYSTEM_NONE 0 | 139 | #define SUBSYSTEM_NONE 0 |
139 | #define SUBSYSTEM_EXT 1 | 140 | #define SUBSYSTEM_EXT 1 |
@@ -167,7 +168,7 @@ static int | |||
167 | auth_input_request_forwarding(struct passwd * pw) | 168 | auth_input_request_forwarding(struct passwd * pw) |
168 | { | 169 | { |
169 | Channel *nc; | 170 | Channel *nc; |
170 | int sock; | 171 | int sock = -1; |
171 | struct sockaddr_un sunaddr; | 172 | struct sockaddr_un sunaddr; |
172 | 173 | ||
173 | if (auth_sock_name != NULL) { | 174 | if (auth_sock_name != NULL) { |
@@ -179,43 +180,48 @@ auth_input_request_forwarding(struct passwd * pw) | |||
179 | temporarily_use_uid(pw); | 180 | temporarily_use_uid(pw); |
180 | 181 | ||
181 | /* Allocate a buffer for the socket name, and format the name. */ | 182 | /* Allocate a buffer for the socket name, and format the name. */ |
182 | auth_sock_name = xmalloc(MAXPATHLEN); | 183 | auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX"); |
183 | auth_sock_dir = xmalloc(MAXPATHLEN); | ||
184 | strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN); | ||
185 | 184 | ||
186 | /* Create private directory for socket */ | 185 | /* Create private directory for socket */ |
187 | if (mkdtemp(auth_sock_dir) == NULL) { | 186 | if (mkdtemp(auth_sock_dir) == NULL) { |
188 | packet_send_debug("Agent forwarding disabled: " | 187 | packet_send_debug("Agent forwarding disabled: " |
189 | "mkdtemp() failed: %.100s", strerror(errno)); | 188 | "mkdtemp() failed: %.100s", strerror(errno)); |
190 | restore_uid(); | 189 | restore_uid(); |
191 | xfree(auth_sock_name); | ||
192 | xfree(auth_sock_dir); | 190 | xfree(auth_sock_dir); |
193 | auth_sock_name = NULL; | ||
194 | auth_sock_dir = NULL; | 191 | auth_sock_dir = NULL; |
195 | return 0; | 192 | goto authsock_err; |
196 | } | 193 | } |
197 | snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", | 194 | |
198 | auth_sock_dir, (long) getpid()); | 195 | xasprintf(&auth_sock_name, "%s/agent.%ld", |
196 | auth_sock_dir, (long) getpid()); | ||
199 | 197 | ||
200 | /* Create the socket. */ | 198 | /* Create the socket. */ |
201 | sock = socket(AF_UNIX, SOCK_STREAM, 0); | 199 | sock = socket(AF_UNIX, SOCK_STREAM, 0); |
202 | if (sock < 0) | 200 | if (sock < 0) { |
203 | packet_disconnect("socket: %.100s", strerror(errno)); | 201 | error("socket: %.100s", strerror(errno)); |
202 | restore_uid(); | ||
203 | goto authsock_err; | ||
204 | } | ||
204 | 205 | ||
205 | /* Bind it to the name. */ | 206 | /* Bind it to the name. */ |
206 | memset(&sunaddr, 0, sizeof(sunaddr)); | 207 | memset(&sunaddr, 0, sizeof(sunaddr)); |
207 | sunaddr.sun_family = AF_UNIX; | 208 | sunaddr.sun_family = AF_UNIX; |
208 | strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); | 209 | strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); |
209 | 210 | ||
210 | if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) | 211 | if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) { |
211 | packet_disconnect("bind: %.100s", strerror(errno)); | 212 | error("bind: %.100s", strerror(errno)); |
213 | restore_uid(); | ||
214 | goto authsock_err; | ||
215 | } | ||
212 | 216 | ||
213 | /* Restore the privileged uid. */ | 217 | /* Restore the privileged uid. */ |
214 | restore_uid(); | 218 | restore_uid(); |
215 | 219 | ||
216 | /* Start listening on the socket. */ | 220 | /* Start listening on the socket. */ |
217 | if (listen(sock, SSH_LISTEN_BACKLOG) < 0) | 221 | if (listen(sock, SSH_LISTEN_BACKLOG) < 0) { |
218 | packet_disconnect("listen: %.100s", strerror(errno)); | 222 | error("listen: %.100s", strerror(errno)); |
223 | goto authsock_err; | ||
224 | } | ||
219 | 225 | ||
220 | /* Allocate a channel for the authentication agent socket. */ | 226 | /* Allocate a channel for the authentication agent socket. */ |
221 | nc = channel_new("auth socket", | 227 | nc = channel_new("auth socket", |
@@ -224,6 +230,19 @@ auth_input_request_forwarding(struct passwd * pw) | |||
224 | 0, "auth socket", 1); | 230 | 0, "auth socket", 1); |
225 | strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); | 231 | strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); |
226 | return 1; | 232 | return 1; |
233 | |||
234 | authsock_err: | ||
235 | if (auth_sock_name != NULL) | ||
236 | xfree(auth_sock_name); | ||
237 | if (auth_sock_dir != NULL) { | ||
238 | rmdir(auth_sock_dir); | ||
239 | xfree(auth_sock_dir); | ||
240 | } | ||
241 | if (sock != -1) | ||
242 | close(sock); | ||
243 | auth_sock_name = NULL; | ||
244 | auth_sock_dir = NULL; | ||
245 | return 0; | ||
227 | } | 246 | } |
228 | 247 | ||
229 | static void | 248 | static void |
@@ -373,10 +392,14 @@ do_authenticated1(Authctxt *authctxt) | |||
373 | if (type == SSH_CMSG_EXEC_CMD) { | 392 | if (type == SSH_CMSG_EXEC_CMD) { |
374 | command = packet_get_string(&dlen); | 393 | command = packet_get_string(&dlen); |
375 | debug("Exec command '%.500s'", command); | 394 | debug("Exec command '%.500s'", command); |
376 | do_exec(s, command); | 395 | if (do_exec(s, command) != 0) |
396 | packet_disconnect( | ||
397 | "command execution failed"); | ||
377 | xfree(command); | 398 | xfree(command); |
378 | } else { | 399 | } else { |
379 | do_exec(s, NULL); | 400 | if (do_exec(s, NULL) != 0) |
401 | packet_disconnect( | ||
402 | "shell execution failed"); | ||
380 | } | 403 | } |
381 | packet_check_eom(); | 404 | packet_check_eom(); |
382 | session_close(s); | 405 | session_close(s); |
@@ -401,41 +424,84 @@ do_authenticated1(Authctxt *authctxt) | |||
401 | } | 424 | } |
402 | } | 425 | } |
403 | 426 | ||
427 | #define USE_PIPES | ||
404 | /* | 428 | /* |
405 | * This is called to fork and execute a command when we have no tty. This | 429 | * This is called to fork and execute a command when we have no tty. This |
406 | * will call do_child from the child, and server_loop from the parent after | 430 | * will call do_child from the child, and server_loop from the parent after |
407 | * setting up file descriptors and such. | 431 | * setting up file descriptors and such. |
408 | */ | 432 | */ |
409 | void | 433 | int |
410 | do_exec_no_pty(Session *s, const char *command) | 434 | do_exec_no_pty(Session *s, const char *command) |
411 | { | 435 | { |
412 | pid_t pid; | 436 | pid_t pid; |
413 | 437 | ||
414 | #ifdef USE_PIPES | 438 | #ifdef USE_PIPES |
415 | int pin[2], pout[2], perr[2]; | 439 | int pin[2], pout[2], perr[2]; |
440 | |||
416 | /* Allocate pipes for communicating with the program. */ | 441 | /* Allocate pipes for communicating with the program. */ |
417 | if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) | 442 | if (pipe(pin) < 0) { |
418 | packet_disconnect("Could not create pipes: %.100s", | 443 | error("%s: pipe in: %.100s", __func__, strerror(errno)); |
419 | strerror(errno)); | 444 | return -1; |
420 | #else /* USE_PIPES */ | 445 | } |
446 | if (pipe(pout) < 0) { | ||
447 | error("%s: pipe out: %.100s", __func__, strerror(errno)); | ||
448 | close(pin[0]); | ||
449 | close(pin[1]); | ||
450 | return -1; | ||
451 | } | ||
452 | if (pipe(perr) < 0) { | ||
453 | error("%s: pipe err: %.100s", __func__, strerror(errno)); | ||
454 | close(pin[0]); | ||
455 | close(pin[1]); | ||
456 | close(pout[0]); | ||
457 | close(pout[1]); | ||
458 | return -1; | ||
459 | } | ||
460 | #else | ||
421 | int inout[2], err[2]; | 461 | int inout[2], err[2]; |
462 | |||
422 | /* Uses socket pairs to communicate with the program. */ | 463 | /* Uses socket pairs to communicate with the program. */ |
423 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || | 464 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) { |
424 | socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) | 465 | error("%s: socketpair #1: %.100s", __func__, strerror(errno)); |
425 | packet_disconnect("Could not create socket pairs: %.100s", | 466 | return -1; |
426 | strerror(errno)); | 467 | } |
427 | #endif /* USE_PIPES */ | 468 | if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) { |
469 | error("%s: socketpair #2: %.100s", __func__, strerror(errno)); | ||
470 | close(inout[0]); | ||
471 | close(inout[1]); | ||
472 | return -1; | ||
473 | } | ||
474 | #endif | ||
475 | |||
428 | if (s == NULL) | 476 | if (s == NULL) |
429 | fatal("do_exec_no_pty: no session"); | 477 | fatal("do_exec_no_pty: no session"); |
430 | 478 | ||
431 | session_proctitle(s); | 479 | session_proctitle(s); |
432 | 480 | ||
433 | /* Fork the child. */ | 481 | /* Fork the child. */ |
434 | if ((pid = fork()) == 0) { | 482 | switch ((pid = fork())) { |
483 | case -1: | ||
484 | error("%s: fork: %.100s", __func__, strerror(errno)); | ||
485 | #ifdef USE_PIPES | ||
486 | close(pin[0]); | ||
487 | close(pin[1]); | ||
488 | close(pout[0]); | ||
489 | close(pout[1]); | ||
490 | close(perr[0]); | ||
491 | close(perr[1]); | ||
492 | #else | ||
493 | close(inout[0]); | ||
494 | close(inout[1]); | ||
495 | close(err[0]); | ||
496 | close(err[1]); | ||
497 | #endif | ||
498 | return -1; | ||
499 | case 0: | ||
435 | is_child = 1; | 500 | is_child = 1; |
436 | 501 | ||
437 | /* Child. Reinitialize the log since the pid has changed. */ | 502 | /* Child. Reinitialize the log since the pid has changed. */ |
438 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | 503 | log_init(__progname, options.log_level, |
504 | options.log_facility, log_stderr); | ||
439 | 505 | ||
440 | /* | 506 | /* |
441 | * Create a new session and process group since the 4.4BSD | 507 | * Create a new session and process group since the 4.4BSD |
@@ -465,7 +531,7 @@ do_exec_no_pty(Session *s, const char *command) | |||
465 | if (dup2(perr[1], 2) < 0) | 531 | if (dup2(perr[1], 2) < 0) |
466 | perror("dup2 stderr"); | 532 | perror("dup2 stderr"); |
467 | close(perr[1]); | 533 | close(perr[1]); |
468 | #else /* USE_PIPES */ | 534 | #else |
469 | /* | 535 | /* |
470 | * Redirect stdin, stdout, and stderr. Stdin and stdout will | 536 | * Redirect stdin, stdout, and stderr. Stdin and stdout will |
471 | * use the same socket, as some programs (particularly rdist) | 537 | * use the same socket, as some programs (particularly rdist) |
@@ -475,11 +541,14 @@ do_exec_no_pty(Session *s, const char *command) | |||
475 | close(err[1]); | 541 | close(err[1]); |
476 | if (dup2(inout[0], 0) < 0) /* stdin */ | 542 | if (dup2(inout[0], 0) < 0) /* stdin */ |
477 | perror("dup2 stdin"); | 543 | perror("dup2 stdin"); |
478 | if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ | 544 | if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */ |
479 | perror("dup2 stdout"); | 545 | perror("dup2 stdout"); |
546 | close(inout[0]); | ||
480 | if (dup2(err[0], 2) < 0) /* stderr */ | 547 | if (dup2(err[0], 2) < 0) /* stderr */ |
481 | perror("dup2 stderr"); | 548 | perror("dup2 stderr"); |
482 | #endif /* USE_PIPES */ | 549 | close(err[0]); |
550 | #endif | ||
551 | |||
483 | 552 | ||
484 | #ifdef _UNICOS | 553 | #ifdef _UNICOS |
485 | cray_init_job(s->pw); /* set up cray jid and tmpdir */ | 554 | cray_init_job(s->pw); /* set up cray jid and tmpdir */ |
@@ -488,7 +557,10 @@ do_exec_no_pty(Session *s, const char *command) | |||
488 | /* Do processing for the child (exec command etc). */ | 557 | /* Do processing for the child (exec command etc). */ |
489 | do_child(s, command); | 558 | do_child(s, command); |
490 | /* NOTREACHED */ | 559 | /* NOTREACHED */ |
560 | default: | ||
561 | break; | ||
491 | } | 562 | } |
563 | |||
492 | #ifdef _UNICOS | 564 | #ifdef _UNICOS |
493 | signal(WJSIGNAL, cray_job_termination_handler); | 565 | signal(WJSIGNAL, cray_job_termination_handler); |
494 | #endif /* _UNICOS */ | 566 | #endif /* _UNICOS */ |
@@ -496,11 +568,18 @@ do_exec_no_pty(Session *s, const char *command) | |||
496 | if (is_winnt) | 568 | if (is_winnt) |
497 | cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); | 569 | cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); |
498 | #endif | 570 | #endif |
499 | if (pid < 0) | 571 | |
500 | packet_disconnect("fork failed: %.100s", strerror(errno)); | ||
501 | s->pid = pid; | 572 | s->pid = pid; |
502 | /* Set interactive/non-interactive mode. */ | 573 | /* Set interactive/non-interactive mode. */ |
503 | packet_set_interactive(s->display != NULL); | 574 | packet_set_interactive(s->display != NULL); |
575 | |||
576 | /* | ||
577 | * Clear loginmsg, since it's the child's responsibility to display | ||
578 | * it to the user, otherwise multiple sessions may accumulate | ||
579 | * multiple copies of the login messages. | ||
580 | */ | ||
581 | buffer_clear(&loginmsg); | ||
582 | |||
504 | #ifdef USE_PIPES | 583 | #ifdef USE_PIPES |
505 | /* We are the parent. Close the child sides of the pipes. */ | 584 | /* We are the parent. Close the child sides of the pipes. */ |
506 | close(pin[0]); | 585 | close(pin[0]); |
@@ -518,29 +597,26 @@ do_exec_no_pty(Session *s, const char *command) | |||
518 | server_loop(pid, pin[1], pout[0], perr[0]); | 597 | server_loop(pid, pin[1], pout[0], perr[0]); |
519 | /* server_loop has closed pin[1], pout[0], and perr[0]. */ | 598 | /* server_loop has closed pin[1], pout[0], and perr[0]. */ |
520 | } | 599 | } |
521 | #else /* USE_PIPES */ | 600 | #else |
522 | /* We are the parent. Close the child sides of the socket pairs. */ | 601 | /* We are the parent. Close the child sides of the socket pairs. */ |
523 | close(inout[0]); | 602 | close(inout[0]); |
524 | close(err[0]); | 603 | close(err[0]); |
525 | 604 | ||
526 | /* | 605 | /* |
527 | * Clear loginmsg, since it's the child's responsibility to display | ||
528 | * it to the user, otherwise multiple sessions may accumulate | ||
529 | * multiple copies of the login messages. | ||
530 | */ | ||
531 | buffer_clear(&loginmsg); | ||
532 | |||
533 | /* | ||
534 | * Enter the interactive session. Note: server_loop must be able to | 606 | * Enter the interactive session. Note: server_loop must be able to |
535 | * handle the case that fdin and fdout are the same. | 607 | * handle the case that fdin and fdout are the same. |
536 | */ | 608 | */ |
537 | if (compat20) { | 609 | if (compat20) { |
538 | session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]); | 610 | session_set_fds(s, inout[1], inout[1], |
611 | s->is_subsystem ? -1 : err[1]); | ||
612 | if (s->is_subsystem) | ||
613 | close(err[1]); | ||
539 | } else { | 614 | } else { |
540 | server_loop(pid, inout[1], inout[1], err[1]); | 615 | server_loop(pid, inout[1], inout[1], err[1]); |
541 | /* server_loop has closed inout[1] and err[1]. */ | 616 | /* server_loop has closed inout[1] and err[1]. */ |
542 | } | 617 | } |
543 | #endif /* USE_PIPES */ | 618 | #endif |
619 | return 0; | ||
544 | } | 620 | } |
545 | 621 | ||
546 | /* | 622 | /* |
@@ -549,7 +625,7 @@ do_exec_no_pty(Session *s, const char *command) | |||
549 | * setting up file descriptors, controlling tty, updating wtmp, utmp, | 625 | * setting up file descriptors, controlling tty, updating wtmp, utmp, |
550 | * lastlog, and other such operations. | 626 | * lastlog, and other such operations. |
551 | */ | 627 | */ |
552 | void | 628 | int |
553 | do_exec_pty(Session *s, const char *command) | 629 | do_exec_pty(Session *s, const char *command) |
554 | { | 630 | { |
555 | int fdout, ptyfd, ttyfd, ptymaster; | 631 | int fdout, ptyfd, ttyfd, ptymaster; |
@@ -560,12 +636,46 @@ do_exec_pty(Session *s, const char *command) | |||
560 | ptyfd = s->ptyfd; | 636 | ptyfd = s->ptyfd; |
561 | ttyfd = s->ttyfd; | 637 | ttyfd = s->ttyfd; |
562 | 638 | ||
639 | /* | ||
640 | * Create another descriptor of the pty master side for use as the | ||
641 | * standard input. We could use the original descriptor, but this | ||
642 | * simplifies code in server_loop. The descriptor is bidirectional. | ||
643 | * Do this before forking (and cleanup in the child) so as to | ||
644 | * detect and gracefully fail out-of-fd conditions. | ||
645 | */ | ||
646 | if ((fdout = dup(ptyfd)) < 0) { | ||
647 | error("%s: dup #1: %s", __func__, strerror(errno)); | ||
648 | close(ttyfd); | ||
649 | close(ptyfd); | ||
650 | return -1; | ||
651 | } | ||
652 | /* we keep a reference to the pty master */ | ||
653 | if ((ptymaster = dup(ptyfd)) < 0) { | ||
654 | error("%s: dup #2: %s", __func__, strerror(errno)); | ||
655 | close(ttyfd); | ||
656 | close(ptyfd); | ||
657 | close(fdout); | ||
658 | return -1; | ||
659 | } | ||
660 | |||
563 | /* Fork the child. */ | 661 | /* Fork the child. */ |
564 | if ((pid = fork()) == 0) { | 662 | switch ((pid = fork())) { |
663 | case -1: | ||
664 | error("%s: fork: %.100s", __func__, strerror(errno)); | ||
665 | close(fdout); | ||
666 | close(ptymaster); | ||
667 | close(ttyfd); | ||
668 | close(ptyfd); | ||
669 | return -1; | ||
670 | case 0: | ||
565 | is_child = 1; | 671 | is_child = 1; |
566 | 672 | ||
673 | close(fdout); | ||
674 | close(ptymaster); | ||
675 | |||
567 | /* Child. Reinitialize the log because the pid has changed. */ | 676 | /* Child. Reinitialize the log because the pid has changed. */ |
568 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | 677 | log_init(__progname, options.log_level, |
678 | options.log_facility, log_stderr); | ||
569 | /* Close the master side of the pseudo tty. */ | 679 | /* Close the master side of the pseudo tty. */ |
570 | close(ptyfd); | 680 | close(ptyfd); |
571 | 681 | ||
@@ -596,11 +706,16 @@ do_exec_pty(Session *s, const char *command) | |||
596 | do_pre_login(s); | 706 | do_pre_login(s); |
597 | # endif | 707 | # endif |
598 | #endif | 708 | #endif |
599 | 709 | /* | |
600 | /* Do common processing for the child, such as execing the command. */ | 710 | * Do common processing for the child, such as execing |
601 | do_child(s, command); | 711 | * the command. |
602 | /* NOTREACHED */ | 712 | */ |
713 | do_child(s, command); | ||
714 | /* NOTREACHED */ | ||
715 | default: | ||
716 | break; | ||
603 | } | 717 | } |
718 | |||
604 | #ifdef _UNICOS | 719 | #ifdef _UNICOS |
605 | signal(WJSIGNAL, cray_job_termination_handler); | 720 | signal(WJSIGNAL, cray_job_termination_handler); |
606 | #endif /* _UNICOS */ | 721 | #endif /* _UNICOS */ |
@@ -608,29 +723,14 @@ do_exec_pty(Session *s, const char *command) | |||
608 | if (is_winnt) | 723 | if (is_winnt) |
609 | cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); | 724 | cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); |
610 | #endif | 725 | #endif |
611 | if (pid < 0) | 726 | |
612 | packet_disconnect("fork failed: %.100s", strerror(errno)); | ||
613 | s->pid = pid; | 727 | s->pid = pid; |
614 | 728 | ||
615 | /* Parent. Close the slave side of the pseudo tty. */ | 729 | /* Parent. Close the slave side of the pseudo tty. */ |
616 | close(ttyfd); | 730 | close(ttyfd); |
617 | 731 | ||
618 | /* | ||
619 | * Create another descriptor of the pty master side for use as the | ||
620 | * standard input. We could use the original descriptor, but this | ||
621 | * simplifies code in server_loop. The descriptor is bidirectional. | ||
622 | */ | ||
623 | fdout = dup(ptyfd); | ||
624 | if (fdout < 0) | ||
625 | packet_disconnect("dup #1 failed: %.100s", strerror(errno)); | ||
626 | |||
627 | /* we keep a reference to the pty master */ | ||
628 | ptymaster = dup(ptyfd); | ||
629 | if (ptymaster < 0) | ||
630 | packet_disconnect("dup #2 failed: %.100s", strerror(errno)); | ||
631 | s->ptymaster = ptymaster; | ||
632 | |||
633 | /* Enter interactive session. */ | 732 | /* Enter interactive session. */ |
733 | s->ptymaster = ptymaster; | ||
634 | packet_set_interactive(1); | 734 | packet_set_interactive(1); |
635 | if (compat20) { | 735 | if (compat20) { |
636 | session_set_fds(s, ptyfd, fdout, -1); | 736 | session_set_fds(s, ptyfd, fdout, -1); |
@@ -638,6 +738,7 @@ do_exec_pty(Session *s, const char *command) | |||
638 | server_loop(pid, ptyfd, fdout, -1); | 738 | server_loop(pid, ptyfd, fdout, -1); |
639 | /* server_loop _has_ closed ptyfd and fdout. */ | 739 | /* server_loop _has_ closed ptyfd and fdout. */ |
640 | } | 740 | } |
741 | return 0; | ||
641 | } | 742 | } |
642 | 743 | ||
643 | #ifdef LOGIN_NEEDS_UTMPX | 744 | #ifdef LOGIN_NEEDS_UTMPX |
@@ -672,9 +773,11 @@ do_pre_login(Session *s) | |||
672 | * This is called to fork and execute a command. If another command is | 773 | * This is called to fork and execute a command. If another command is |
673 | * to be forced, execute that instead. | 774 | * to be forced, execute that instead. |
674 | */ | 775 | */ |
675 | void | 776 | int |
676 | do_exec(Session *s, const char *command) | 777 | do_exec(Session *s, const char *command) |
677 | { | 778 | { |
779 | int ret; | ||
780 | |||
678 | if (options.adm_forced_command) { | 781 | if (options.adm_forced_command) { |
679 | original_command = command; | 782 | original_command = command; |
680 | command = options.adm_forced_command; | 783 | command = options.adm_forced_command; |
@@ -705,9 +808,9 @@ do_exec(Session *s, const char *command) | |||
705 | } | 808 | } |
706 | #endif | 809 | #endif |
707 | if (s->ttyfd != -1) | 810 | if (s->ttyfd != -1) |
708 | do_exec_pty(s, command); | 811 | ret = do_exec_pty(s, command); |
709 | else | 812 | else |
710 | do_exec_no_pty(s, command); | 813 | ret = do_exec_no_pty(s, command); |
711 | 814 | ||
712 | original_command = NULL; | 815 | original_command = NULL; |
713 | 816 | ||
@@ -717,6 +820,8 @@ do_exec(Session *s, const char *command) | |||
717 | * multiple copies of the login messages. | 820 | * multiple copies of the login messages. |
718 | */ | 821 | */ |
719 | buffer_clear(&loginmsg); | 822 | buffer_clear(&loginmsg); |
823 | |||
824 | return ret; | ||
720 | } | 825 | } |
721 | 826 | ||
722 | /* administrative, login(1)-like work */ | 827 | /* administrative, login(1)-like work */ |
@@ -1740,43 +1845,79 @@ do_child(Session *s, const char *command) | |||
1740 | exit(1); | 1845 | exit(1); |
1741 | } | 1846 | } |
1742 | 1847 | ||
1848 | void | ||
1849 | session_unused(int id) | ||
1850 | { | ||
1851 | debug3("%s: session id %d unused", __func__, id); | ||
1852 | if (id >= options.max_sessions || | ||
1853 | id >= sessions_nalloc) { | ||
1854 | fatal("%s: insane session id %d (max %d nalloc %d)", | ||
1855 | __func__, id, options.max_sessions, sessions_nalloc); | ||
1856 | } | ||
1857 | bzero(&sessions[id], sizeof(*sessions)); | ||
1858 | sessions[id].self = id; | ||
1859 | sessions[id].used = 0; | ||
1860 | sessions[id].chanid = -1; | ||
1861 | sessions[id].ptyfd = -1; | ||
1862 | sessions[id].ttyfd = -1; | ||
1863 | sessions[id].ptymaster = -1; | ||
1864 | sessions[id].x11_chanids = NULL; | ||
1865 | sessions[id].next_unused = sessions_first_unused; | ||
1866 | sessions_first_unused = id; | ||
1867 | } | ||
1868 | |||
1743 | Session * | 1869 | Session * |
1744 | session_new(void) | 1870 | session_new(void) |
1745 | { | 1871 | { |
1746 | int i; | 1872 | Session *s, *tmp; |
1747 | static int did_init = 0; | 1873 | |
1748 | if (!did_init) { | 1874 | if (sessions_first_unused == -1) { |
1749 | debug("session_new: init"); | 1875 | if (sessions_nalloc >= options.max_sessions) |
1750 | for (i = 0; i < MAX_SESSIONS; i++) { | 1876 | return NULL; |
1751 | sessions[i].used = 0; | 1877 | debug2("%s: allocate (allocated %d max %d)", |
1878 | __func__, sessions_nalloc, options.max_sessions); | ||
1879 | tmp = xrealloc(sessions, sessions_nalloc + 1, | ||
1880 | sizeof(*sessions)); | ||
1881 | if (tmp == NULL) { | ||
1882 | error("%s: cannot allocate %d sessions", | ||
1883 | __func__, sessions_nalloc + 1); | ||
1884 | return NULL; | ||
1752 | } | 1885 | } |
1753 | did_init = 1; | 1886 | sessions = tmp; |
1887 | session_unused(sessions_nalloc++); | ||
1754 | } | 1888 | } |
1755 | for (i = 0; i < MAX_SESSIONS; i++) { | 1889 | |
1756 | Session *s = &sessions[i]; | 1890 | if (sessions_first_unused >= sessions_nalloc || |
1757 | if (! s->used) { | 1891 | sessions_first_unused < 0) { |
1758 | memset(s, 0, sizeof(*s)); | 1892 | fatal("%s: insane first_unused %d max %d nalloc %d", |
1759 | s->chanid = -1; | 1893 | __func__, sessions_first_unused, options.max_sessions, |
1760 | s->ptyfd = -1; | 1894 | sessions_nalloc); |
1761 | s->ttyfd = -1; | ||
1762 | s->used = 1; | ||
1763 | s->self = i; | ||
1764 | s->x11_chanids = NULL; | ||
1765 | debug("session_new: session %d", i); | ||
1766 | return s; | ||
1767 | } | ||
1768 | } | 1895 | } |
1769 | return NULL; | 1896 | |
1897 | s = &sessions[sessions_first_unused]; | ||
1898 | if (s->used) { | ||
1899 | fatal("%s: session %d already used", | ||
1900 | __func__, sessions_first_unused); | ||
1901 | } | ||
1902 | sessions_first_unused = s->next_unused; | ||
1903 | s->used = 1; | ||
1904 | s->next_unused = -1; | ||
1905 | debug("session_new: session %d", s->self); | ||
1906 | |||
1907 | return s; | ||
1770 | } | 1908 | } |
1771 | 1909 | ||
1772 | static void | 1910 | static void |
1773 | session_dump(void) | 1911 | session_dump(void) |
1774 | { | 1912 | { |
1775 | int i; | 1913 | int i; |
1776 | for (i = 0; i < MAX_SESSIONS; i++) { | 1914 | for (i = 0; i < sessions_nalloc; i++) { |
1777 | Session *s = &sessions[i]; | 1915 | Session *s = &sessions[i]; |
1778 | debug("dump: used %d session %d %p channel %d pid %ld", | 1916 | |
1917 | debug("dump: used %d next_unused %d session %d %p " | ||
1918 | "channel %d pid %ld", | ||
1779 | s->used, | 1919 | s->used, |
1920 | s->next_unused, | ||
1780 | s->self, | 1921 | s->self, |
1781 | s, | 1922 | s, |
1782 | s->chanid, | 1923 | s->chanid, |
@@ -1806,7 +1947,7 @@ Session * | |||
1806 | session_by_tty(char *tty) | 1947 | session_by_tty(char *tty) |
1807 | { | 1948 | { |
1808 | int i; | 1949 | int i; |
1809 | for (i = 0; i < MAX_SESSIONS; i++) { | 1950 | for (i = 0; i < sessions_nalloc; i++) { |
1810 | Session *s = &sessions[i]; | 1951 | Session *s = &sessions[i]; |
1811 | if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { | 1952 | if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { |
1812 | debug("session_by_tty: session %d tty %s", i, tty); | 1953 | debug("session_by_tty: session %d tty %s", i, tty); |
@@ -1822,10 +1963,11 @@ static Session * | |||
1822 | session_by_channel(int id) | 1963 | session_by_channel(int id) |
1823 | { | 1964 | { |
1824 | int i; | 1965 | int i; |
1825 | for (i = 0; i < MAX_SESSIONS; i++) { | 1966 | for (i = 0; i < sessions_nalloc; i++) { |
1826 | Session *s = &sessions[i]; | 1967 | Session *s = &sessions[i]; |
1827 | if (s->used && s->chanid == id) { | 1968 | if (s->used && s->chanid == id) { |
1828 | debug("session_by_channel: session %d channel %d", i, id); | 1969 | debug("session_by_channel: session %d channel %d", |
1970 | i, id); | ||
1829 | return s; | 1971 | return s; |
1830 | } | 1972 | } |
1831 | } | 1973 | } |
@@ -1839,7 +1981,7 @@ session_by_x11_channel(int id) | |||
1839 | { | 1981 | { |
1840 | int i, j; | 1982 | int i, j; |
1841 | 1983 | ||
1842 | for (i = 0; i < MAX_SESSIONS; i++) { | 1984 | for (i = 0; i < sessions_nalloc; i++) { |
1843 | Session *s = &sessions[i]; | 1985 | Session *s = &sessions[i]; |
1844 | 1986 | ||
1845 | if (s->x11_chanids == NULL || !s->used) | 1987 | if (s->x11_chanids == NULL || !s->used) |
@@ -1862,7 +2004,7 @@ session_by_pid(pid_t pid) | |||
1862 | { | 2004 | { |
1863 | int i; | 2005 | int i; |
1864 | debug("session_by_pid: pid %ld", (long)pid); | 2006 | debug("session_by_pid: pid %ld", (long)pid); |
1865 | for (i = 0; i < MAX_SESSIONS; i++) { | 2007 | for (i = 0; i < sessions_nalloc; i++) { |
1866 | Session *s = &sessions[i]; | 2008 | Session *s = &sessions[i]; |
1867 | if (s->used && s->pid == pid) | 2009 | if (s->used && s->pid == pid) |
1868 | return s; | 2010 | return s; |
@@ -1918,7 +2060,8 @@ session_pty_req(Session *s) | |||
1918 | 2060 | ||
1919 | /* Allocate a pty and open it. */ | 2061 | /* Allocate a pty and open it. */ |
1920 | debug("Allocating pty."); | 2062 | debug("Allocating pty."); |
1921 | if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { | 2063 | if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, |
2064 | sizeof(s->tty)))) { | ||
1922 | if (s->term) | 2065 | if (s->term) |
1923 | xfree(s->term); | 2066 | xfree(s->term); |
1924 | s->term = NULL; | 2067 | s->term = NULL; |
@@ -1971,8 +2114,7 @@ session_subsystem_req(Session *s) | |||
1971 | s->is_subsystem = SUBSYSTEM_EXT; | 2114 | s->is_subsystem = SUBSYSTEM_EXT; |
1972 | } | 2115 | } |
1973 | debug("subsystem: exec() %s", cmd); | 2116 | debug("subsystem: exec() %s", cmd); |
1974 | do_exec(s, cmd); | 2117 | success = do_exec(s, cmd) == 0; |
1975 | success = 1; | ||
1976 | break; | 2118 | break; |
1977 | } | 2119 | } |
1978 | } | 2120 | } |
@@ -2015,19 +2157,19 @@ static int | |||
2015 | session_shell_req(Session *s) | 2157 | session_shell_req(Session *s) |
2016 | { | 2158 | { |
2017 | packet_check_eom(); | 2159 | packet_check_eom(); |
2018 | do_exec(s, NULL); | 2160 | return do_exec(s, NULL) == 0; |
2019 | return 1; | ||
2020 | } | 2161 | } |
2021 | 2162 | ||
2022 | static int | 2163 | static int |
2023 | session_exec_req(Session *s) | 2164 | session_exec_req(Session *s) |
2024 | { | 2165 | { |
2025 | u_int len; | 2166 | u_int len, success; |
2167 | |||
2026 | char *command = packet_get_string(&len); | 2168 | char *command = packet_get_string(&len); |
2027 | packet_check_eom(); | 2169 | packet_check_eom(); |
2028 | do_exec(s, command); | 2170 | success = do_exec(s, command) == 0; |
2029 | xfree(command); | 2171 | xfree(command); |
2030 | return 1; | 2172 | return success; |
2031 | } | 2173 | } |
2032 | 2174 | ||
2033 | static int | 2175 | static int |
@@ -2037,8 +2179,7 @@ session_break_req(Session *s) | |||
2037 | packet_get_int(); /* ignored */ | 2179 | packet_get_int(); /* ignored */ |
2038 | packet_check_eom(); | 2180 | packet_check_eom(); |
2039 | 2181 | ||
2040 | if (s->ttyfd == -1 || | 2182 | if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0) |
2041 | tcsendbreak(s->ttyfd, 0) < 0) | ||
2042 | return 0; | 2183 | return 0; |
2043 | return 1; | 2184 | return 1; |
2044 | } | 2185 | } |
@@ -2185,8 +2326,9 @@ session_pty_cleanup2(Session *s) | |||
2185 | * the pty cleanup, so that another process doesn't get this pty | 2326 | * the pty cleanup, so that another process doesn't get this pty |
2186 | * while we're still cleaning up. | 2327 | * while we're still cleaning up. |
2187 | */ | 2328 | */ |
2188 | if (close(s->ptymaster) < 0) | 2329 | if (s->ptymaster != -1 && close(s->ptymaster) < 0) |
2189 | error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); | 2330 | error("close(s->ptymaster/%d): %s", |
2331 | s->ptymaster, strerror(errno)); | ||
2190 | 2332 | ||
2191 | /* unlink pty from session */ | 2333 | /* unlink pty from session */ |
2192 | s->ttyfd = -1; | 2334 | s->ttyfd = -1; |
@@ -2346,7 +2488,6 @@ session_close(Session *s) | |||
2346 | xfree(s->auth_data); | 2488 | xfree(s->auth_data); |
2347 | if (s->auth_proto) | 2489 | if (s->auth_proto) |
2348 | xfree(s->auth_proto); | 2490 | xfree(s->auth_proto); |
2349 | s->used = 0; | ||
2350 | if (s->env != NULL) { | 2491 | if (s->env != NULL) { |
2351 | for (i = 0; i < s->num_env; i++) { | 2492 | for (i = 0; i < s->num_env; i++) { |
2352 | xfree(s->env[i].name); | 2493 | xfree(s->env[i].name); |
@@ -2355,6 +2496,7 @@ session_close(Session *s) | |||
2355 | xfree(s->env); | 2496 | xfree(s->env); |
2356 | } | 2497 | } |
2357 | session_proctitle(s); | 2498 | session_proctitle(s); |
2499 | session_unused(s->self); | ||
2358 | } | 2500 | } |
2359 | 2501 | ||
2360 | void | 2502 | void |
@@ -2418,7 +2560,7 @@ void | |||
2418 | session_destroy_all(void (*closefunc)(Session *)) | 2560 | session_destroy_all(void (*closefunc)(Session *)) |
2419 | { | 2561 | { |
2420 | int i; | 2562 | int i; |
2421 | for (i = 0; i < MAX_SESSIONS; i++) { | 2563 | for (i = 0; i < sessions_nalloc; i++) { |
2422 | Session *s = &sessions[i]; | 2564 | Session *s = &sessions[i]; |
2423 | if (s->used) { | 2565 | if (s->used) { |
2424 | if (closefunc != NULL) | 2566 | if (closefunc != NULL) |
@@ -2437,7 +2579,7 @@ session_tty_list(void) | |||
2437 | char *cp; | 2579 | char *cp; |
2438 | 2580 | ||
2439 | buf[0] = '\0'; | 2581 | buf[0] = '\0'; |
2440 | for (i = 0; i < MAX_SESSIONS; i++) { | 2582 | for (i = 0; i < sessions_nalloc; i++) { |
2441 | Session *s = &sessions[i]; | 2583 | Session *s = &sessions[i]; |
2442 | if (s->used && s->ttyfd != -1) { | 2584 | if (s->used && s->ttyfd != -1) { |
2443 | 2585 | ||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: session.h,v 1.29 2006/08/03 03:34:42 deraadt Exp $ */ | 1 | /* $OpenBSD: session.h,v 1.30 2008/05/08 12:21:16 djm Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. | 4 | * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. |
@@ -31,6 +31,7 @@ typedef struct Session Session; | |||
31 | struct Session { | 31 | struct Session { |
32 | int used; | 32 | int used; |
33 | int self; | 33 | int self; |
34 | int next_unused; | ||
34 | struct passwd *pw; | 35 | struct passwd *pw; |
35 | Authctxt *authctxt; | 36 | Authctxt *authctxt; |
36 | pid_t pid; | 37 | pid_t pid; |
@@ -65,6 +66,7 @@ void do_authenticated(Authctxt *); | |||
65 | void do_cleanup(Authctxt *); | 66 | void do_cleanup(Authctxt *); |
66 | 67 | ||
67 | int session_open(Authctxt *, int); | 68 | int session_open(Authctxt *, int); |
69 | void session_unused(int); | ||
68 | int session_input_channel_req(Channel *, const char *); | 70 | int session_input_channel_req(Channel *, const char *); |
69 | void session_close_by_pid(pid_t, int); | 71 | void session_close_by_pid(pid_t, int); |
70 | void session_close_by_channel(int, void *); | 72 | void session_close_by_channel(int, void *); |
diff --git a/sshd_config b/sshd_config index 1f97a9dcc..c5ee7c8a4 100644 --- a/sshd_config +++ b/sshd_config | |||
@@ -1,4 +1,4 @@ | |||
1 | # $OpenBSD: sshd_config,v 1.78 2008/05/07 06:43:35 pyr Exp $ | 1 | # $OpenBSD: sshd_config,v 1.79 2008/05/08 12:21:16 djm Exp $ |
2 | 2 | ||
3 | # This is the sshd server system-wide configuration file. See | 3 | # This is the sshd server system-wide configuration file. See |
4 | # sshd_config(5) for more information. | 4 | # sshd_config(5) for more information. |
@@ -41,6 +41,7 @@ Protocol 2 | |||
41 | #PermitRootLogin yes | 41 | #PermitRootLogin yes |
42 | #StrictModes yes | 42 | #StrictModes yes |
43 | #MaxAuthTries 6 | 43 | #MaxAuthTries 6 |
44 | #MaxSessions 10 | ||
44 | 45 | ||
45 | #RSAAuthentication yes | 46 | #RSAAuthentication yes |
46 | #PubkeyAuthentication yes | 47 | #PubkeyAuthentication yes |
diff --git a/sshd_config.5 b/sshd_config.5 index 99b5621e7..0d8c140bf 100644 --- a/sshd_config.5 +++ b/sshd_config.5 | |||
@@ -34,8 +34,8 @@ | |||
34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 34 | .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 35 | .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
36 | .\" | 36 | .\" |
37 | .\" $OpenBSD: sshd_config.5,v 1.89 2008/05/07 08:00:14 jmc Exp $ | 37 | .\" $OpenBSD: sshd_config.5,v 1.90 2008/05/08 12:21:16 djm Exp $ |
38 | .Dd $Mdocdate: May 19 2008 $ | 38 | .Dd $Mdocdate: May 8 2008 $ |
39 | .Dt SSHD_CONFIG 5 | 39 | .Dt SSHD_CONFIG 5 |
40 | .Os | 40 | .Os |
41 | .Sh NAME | 41 | .Sh NAME |
@@ -594,6 +594,9 @@ connection. | |||
594 | Once the number of failures reaches half this value, | 594 | Once the number of failures reaches half this value, |
595 | additional failures are logged. | 595 | additional failures are logged. |
596 | The default is 6. | 596 | The default is 6. |
597 | .It Cm MaxSessions | ||
598 | Specifies the maximum number of open sessions permitted per network connection. | ||
599 | The default is 10. | ||
597 | .It Cm MaxStartups | 600 | .It Cm MaxStartups |
598 | Specifies the maximum number of concurrent unauthenticated connections to the | 601 | Specifies the maximum number of concurrent unauthenticated connections to the |
599 | SSH daemon. | 602 | SSH daemon. |