summaryrefslogtreecommitdiff
path: root/session.c
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
committerColin Watson <cjwatson@debian.org>2008-07-22 19:45:18 +0000
commit137d76ba65883aa8143af1fcad83b57e7badef0c (patch)
treef426e804bb5248ceafedfab7bb78ae6e6752942c /session.c
parentdac7d049dad31f5f84d421d4eb628a7e13f977d7 (diff)
parentef94e5613d37bcbf880f21ee6094e4b1c7683a4c (diff)
* New upstream release (closes: #474301). Important changes not previously
backported to 4.7p1: - 4.9/4.9p1 (http://www.openssh.com/txt/release-4.9): + Added chroot(2) support for sshd(8), controlled by a new option "ChrootDirectory" (closes: #139047, LP: #24777). + Linked sftp-server(8) into sshd(8). The internal sftp server is used when the command "internal-sftp" is specified in a Subsystem or ForceCommand declaration. When used with ChrootDirectory, the internal sftp server requires no special configuration of files inside the chroot environment. + Added a protocol extension method "posix-rename@openssh.com" for sftp-server(8) to perform POSIX atomic rename() operations; sftp(1) prefers this if available (closes: #308561). + Removed the fixed limit of 100 file handles in sftp-server(8). + ssh(8) will now skip generation of SSH protocol 1 ephemeral server keys when in inetd mode and protocol 2 connections are negotiated. This speeds up protocol 2 connections to inetd-mode servers that also allow Protocol 1. + Accept the PermitRootLogin directive in a sshd_config(5) Match block. Allows for, e.g. permitting root only from the local network. + Reworked sftp(1) argument splitting and escaping to be more internally consistent (i.e. between sftp commands) and more consistent with sh(1). Please note that this will change the interpretation of some quoted strings, especially those with embedded backslash escape sequences. + Support "Banner=none" in sshd_config(5) to disable sending of a pre-login banner (e.g. in a Match block). + ssh(1) ProxyCommands are now executed with $SHELL rather than /bin/sh. + ssh(1)'s ConnectTimeout option is now applied to both the TCP connection and the SSH banner exchange (previously it just covered the TCP connection). This allows callers of ssh(1) to better detect and deal with stuck servers that accept a TCP connection but don't progress the protocol, and also makes ConnectTimeout useful for connections via a ProxyCommand. + scp(1) incorrectly reported "stalled" on slow copies (closes: #140828). + scp(1) date underflow for timestamps before epoch. + ssh(1) used the obsolete SIG DNS RRtype for host keys in DNS, instead of the current standard RRSIG. + Correctly drain ACKs when a sftp(1) upload write fails midway, avoids a fatal() exit from what should be a recoverable condition. + Fixed ssh-keygen(1) selective host key hashing (i.e. "ssh-keygen -HF hostname") to not include any IP address in the data to be hashed. + Make ssh(1) skip listening on the IPv6 wildcard address when a binding address of 0.0.0.0 is used against an old SSH server that does not support the RFC4254 syntax for wildcard bind addresses. + Enable IPV6_V6ONLY socket option on sshd(8) listen socket, as is already done for X11/TCP forwarding sockets (closes: #439661). + Fix FD leak that could hang a ssh(1) connection multiplexing master. + Make ssh(1) -q option documentation consistent with reality. + Fixed sshd(8) PAM support not calling pam_session_close(), or failing to call it with root privileges (closes: #372680). + Fix activation of OpenSSL engine support when requested in configure (LP: #119295). - 5.1/5.1p1 (http://www.openssh.com/txt/release-5.1): + Introduce experimental SSH Fingerprint ASCII Visualisation to ssh(1) and ssh-keygen(1). Visual fingerprint display is controlled by a new ssh_config(5) option "VisualHostKey". The intent is to render SSH host keys in a visual form that is amenable to easy recall and rejection of changed host keys. + sshd_config(5) now supports CIDR address/masklen matching in "Match address" blocks, with a fallback to classic wildcard matching. + sshd(8) now supports CIDR matching in ~/.ssh/authorized_keys from="..." restrictions, also with a fallback to classic wildcard matching. + Added an extended test mode (-T) to sshd(8) to request that it write its effective configuration to stdout and exit. Extended test mode also supports the specification of connection parameters (username, source address and hostname) to test the application of sshd_config(5) Match rules. + ssh(1) now prints the number of bytes transferred and the overall connection throughput for SSH protocol 2 sessions when in verbose mode (previously these statistics were displayed for protocol 1 connections only). + sftp-server(8) now supports extension methods statvfs@openssh.com and fstatvfs@openssh.com that implement statvfs(2)-like operations. + sftp(1) now has a "df" command to the sftp client that uses the statvfs@openssh.com to produce a df(1)-like display of filesystem space and inode utilisation (requires statvfs@openssh.com support on the server). + Added a MaxSessions option to sshd_config(5) to allow control of the number of multiplexed sessions supported over a single TCP connection. This allows increasing the number of allowed sessions above the previous default of 10, disabling connection multiplexing (MaxSessions=1) or disallowing login/shell/subsystem sessions entirely (MaxSessions=0). + Added a no-more-sessions@openssh.com global request extension that is sent from ssh(1) to sshd(8) when the client knows that it will never request another session (i.e. when session multiplexing is disabled). This allows a server to disallow further session requests and terminate the session in cases where the client has been hijacked. + ssh-keygen(1) now supports the use of the -l option in combination with -F to search for a host in ~/.ssh/known_hosts and display its fingerprint. + ssh-keyscan(1) now defaults to "rsa" (protocol 2) keys, instead of "rsa1". + Added an AllowAgentForwarding option to sshd_config(8) to control whether authentication agent forwarding is permitted. Note that this is a loose control, as a client may install their own unofficial forwarder. + ssh(1) and sshd(8): avoid unnecessary malloc/copy/free when receiving network data, resulting in a ~10% speedup. + ssh(1) and sshd(8) will now try additional addresses when connecting to a port forward destination whose DNS name resolves to more than one address. The previous behaviour was to try the only first address and give up if that failed. + ssh(1) and sshd(8) now support signalling that channels are half-closed for writing, through a channel protocol extension notification "eow@openssh.com". This allows propagation of closed file descriptors, so that commands such as "ssh -2 localhost od /bin/ls | true" do not send unnecessary data over the wire. + sshd(8): increased the default size of ssh protocol 1 ephemeral keys from 768 to 1024 bits. + When ssh(1) has been requested to fork after authentication ("ssh -f") with ExitOnForwardFailure enabled, delay the fork until after replies for any -R forwards have been seen. Allows for robust detection of -R forward failure when using -f. + "Match group" blocks in sshd_config(5) now support negation of groups. E.g. "Match group staff,!guests". + sftp(1) and sftp-server(8) now allow chmod-like operations to set set[ug]id/sticky bits. + The MaxAuthTries option is now permitted in sshd_config(5) match blocks. + Multiplexed ssh(1) sessions now support a subset of the ~ escapes that are available to a primary connection. + ssh(1) connection multiplexing will now fall back to creating a new connection in most error cases (closes: #352830). + Make ssh(1) deal more gracefully with channel requests that fail. Previously it would optimistically assume that requests would always succeed, which could cause hangs if they did not (e.g. when the server runs out of file descriptors). + ssh(1) now reports multiplexing errors via the multiplex slave's stderr where possible (subject to LogLevel in the mux master). + Prevent sshd(8) from erroneously applying public key restrictions leaned from ~/.ssh/authorized_keys to other authentication methods when public key authentication subsequently fails (LP: #161047). + Fixed an UMAC alignment problem that manifested on Itanium platforms.
Diffstat (limited to 'session.c')
-rw-r--r--session.c578
1 files changed, 407 insertions, 171 deletions
diff --git a/session.c b/session.c
index 997ee5fa9..93babf957 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: session.c,v 1.221 2007/01/21 01:41:54 stevesk Exp $ */ 1/* $OpenBSD: session.c,v 1.241 2008/06/16 13:22:53 dtucker 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
@@ -59,6 +59,7 @@
59#include <string.h> 59#include <string.h>
60#include <unistd.h> 60#include <unistd.h>
61 61
62#include "openbsd-compat/sys-queue.h"
62#include "xmalloc.h" 63#include "xmalloc.h"
63#include "ssh.h" 64#include "ssh.h"
64#include "ssh1.h" 65#include "ssh1.h"
@@ -84,9 +85,11 @@
84#include "sshlogin.h" 85#include "sshlogin.h"
85#include "serverloop.h" 86#include "serverloop.h"
86#include "canohost.h" 87#include "canohost.h"
88#include "misc.h"
87#include "session.h" 89#include "session.h"
88#include "kex.h" 90#include "kex.h"
89#include "monitor_wrap.h" 91#include "monitor_wrap.h"
92#include "sftp.h"
90 93
91#if defined(KRB5) && defined(USE_AFS) 94#if defined(KRB5) && defined(USE_AFS)
92#include <kafs.h> 95#include <kafs.h>
@@ -95,13 +98,13 @@
95/* func */ 98/* func */
96 99
97Session *session_new(void); 100Session *session_new(void);
98void session_set_fds(Session *, int, int, int); 101void session_set_fds(Session *, int, int, int, int);
99void session_pty_cleanup(Session *); 102void session_pty_cleanup(Session *);
100void session_proctitle(Session *); 103void session_proctitle(Session *);
101int session_setup_x11fwd(Session *); 104int session_setup_x11fwd(Session *);
102void do_exec_pty(Session *, const char *); 105int do_exec_pty(Session *, const char *);
103void do_exec_no_pty(Session *, const char *); 106int do_exec_no_pty(Session *, const char *);
104void do_exec(Session *, const char *); 107int do_exec(Session *, const char *);
105void do_login(Session *, const char *); 108void do_login(Session *, const char *);
106#ifdef LOGIN_NEEDS_UTMPX 109#ifdef LOGIN_NEEDS_UTMPX
107static void do_pre_login(Session *s); 110static void do_pre_login(Session *s);
@@ -129,8 +132,13 @@ extern Buffer loginmsg;
129const char *original_command = NULL; 132const char *original_command = NULL;
130 133
131/* data */ 134/* data */
132#define MAX_SESSIONS 64 135static int sessions_first_unused = -1;
133Session sessions[MAX_SESSIONS]; 136static int sessions_nalloc = 0;
137static Session *sessions = NULL;
138
139#define SUBSYSTEM_NONE 0
140#define SUBSYSTEM_EXT 1
141#define SUBSYSTEM_INT_SFTP 2
134 142
135#ifdef HAVE_LOGIN_CAP 143#ifdef HAVE_LOGIN_CAP
136login_cap_t *lc; 144login_cap_t *lc;
@@ -160,7 +168,7 @@ static int
160auth_input_request_forwarding(struct passwd * pw) 168auth_input_request_forwarding(struct passwd * pw)
161{ 169{
162 Channel *nc; 170 Channel *nc;
163 int sock; 171 int sock = -1;
164 struct sockaddr_un sunaddr; 172 struct sockaddr_un sunaddr;
165 173
166 if (auth_sock_name != NULL) { 174 if (auth_sock_name != NULL) {
@@ -172,43 +180,48 @@ auth_input_request_forwarding(struct passwd * pw)
172 temporarily_use_uid(pw); 180 temporarily_use_uid(pw);
173 181
174 /* Allocate a buffer for the socket name, and format the name. */ 182 /* Allocate a buffer for the socket name, and format the name. */
175 auth_sock_name = xmalloc(MAXPATHLEN); 183 auth_sock_dir = xstrdup("/tmp/ssh-XXXXXXXXXX");
176 auth_sock_dir = xmalloc(MAXPATHLEN);
177 strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);
178 184
179 /* Create private directory for socket */ 185 /* Create private directory for socket */
180 if (mkdtemp(auth_sock_dir) == NULL) { 186 if (mkdtemp(auth_sock_dir) == NULL) {
181 packet_send_debug("Agent forwarding disabled: " 187 packet_send_debug("Agent forwarding disabled: "
182 "mkdtemp() failed: %.100s", strerror(errno)); 188 "mkdtemp() failed: %.100s", strerror(errno));
183 restore_uid(); 189 restore_uid();
184 xfree(auth_sock_name);
185 xfree(auth_sock_dir); 190 xfree(auth_sock_dir);
186 auth_sock_name = NULL;
187 auth_sock_dir = NULL; 191 auth_sock_dir = NULL;
188 return 0; 192 goto authsock_err;
189 } 193 }
190 snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld", 194
191 auth_sock_dir, (long) getpid()); 195 xasprintf(&auth_sock_name, "%s/agent.%ld",
196 auth_sock_dir, (long) getpid());
192 197
193 /* Create the socket. */ 198 /* Create the socket. */
194 sock = socket(AF_UNIX, SOCK_STREAM, 0); 199 sock = socket(AF_UNIX, SOCK_STREAM, 0);
195 if (sock < 0) 200 if (sock < 0) {
196 packet_disconnect("socket: %.100s", strerror(errno)); 201 error("socket: %.100s", strerror(errno));
202 restore_uid();
203 goto authsock_err;
204 }
197 205
198 /* Bind it to the name. */ 206 /* Bind it to the name. */
199 memset(&sunaddr, 0, sizeof(sunaddr)); 207 memset(&sunaddr, 0, sizeof(sunaddr));
200 sunaddr.sun_family = AF_UNIX; 208 sunaddr.sun_family = AF_UNIX;
201 strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path)); 209 strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));
202 210
203 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) 211 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
204 packet_disconnect("bind: %.100s", strerror(errno)); 212 error("bind: %.100s", strerror(errno));
213 restore_uid();
214 goto authsock_err;
215 }
205 216
206 /* Restore the privileged uid. */ 217 /* Restore the privileged uid. */
207 restore_uid(); 218 restore_uid();
208 219
209 /* Start listening on the socket. */ 220 /* Start listening on the socket. */
210 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) 221 if (listen(sock, SSH_LISTEN_BACKLOG) < 0) {
211 packet_disconnect("listen: %.100s", strerror(errno)); 222 error("listen: %.100s", strerror(errno));
223 goto authsock_err;
224 }
212 225
213 /* Allocate a channel for the authentication agent socket. */ 226 /* Allocate a channel for the authentication agent socket. */
214 nc = channel_new("auth socket", 227 nc = channel_new("auth socket",
@@ -217,6 +230,19 @@ auth_input_request_forwarding(struct passwd * pw)
217 0, "auth socket", 1); 230 0, "auth socket", 1);
218 strlcpy(nc->path, auth_sock_name, sizeof(nc->path)); 231 strlcpy(nc->path, auth_sock_name, sizeof(nc->path));
219 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;
220} 246}
221 247
222static void 248static void
@@ -329,7 +355,8 @@ do_authenticated1(Authctxt *authctxt)
329 break; 355 break;
330 356
331 case SSH_CMSG_AGENT_REQUEST_FORWARDING: 357 case SSH_CMSG_AGENT_REQUEST_FORWARDING:
332 if (no_agent_forwarding_flag || compat13) { 358 if (!options.allow_agent_forwarding ||
359 no_agent_forwarding_flag || compat13) {
333 debug("Authentication agent forwarding not permitted for this authentication."); 360 debug("Authentication agent forwarding not permitted for this authentication.");
334 break; 361 break;
335 } 362 }
@@ -365,10 +392,14 @@ do_authenticated1(Authctxt *authctxt)
365 if (type == SSH_CMSG_EXEC_CMD) { 392 if (type == SSH_CMSG_EXEC_CMD) {
366 command = packet_get_string(&dlen); 393 command = packet_get_string(&dlen);
367 debug("Exec command '%.500s'", command); 394 debug("Exec command '%.500s'", command);
368 do_exec(s, command); 395 if (do_exec(s, command) != 0)
396 packet_disconnect(
397 "command execution failed");
369 xfree(command); 398 xfree(command);
370 } else { 399 } else {
371 do_exec(s, NULL); 400 if (do_exec(s, NULL) != 0)
401 packet_disconnect(
402 "shell execution failed");
372 } 403 }
373 packet_check_eom(); 404 packet_check_eom();
374 session_close(s); 405 session_close(s);
@@ -393,46 +424,84 @@ do_authenticated1(Authctxt *authctxt)
393 } 424 }
394} 425}
395 426
427#define USE_PIPES
396/* 428/*
397 * 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
398 * 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
399 * setting up file descriptors and such. 431 * setting up file descriptors and such.
400 */ 432 */
401void 433int
402do_exec_no_pty(Session *s, const char *command) 434do_exec_no_pty(Session *s, const char *command)
403{ 435{
404 pid_t pid; 436 pid_t pid;
405 437
406#ifdef USE_PIPES 438#ifdef USE_PIPES
407 int pin[2], pout[2], perr[2]; 439 int pin[2], pout[2], perr[2];
440
408 /* Allocate pipes for communicating with the program. */ 441 /* Allocate pipes for communicating with the program. */
409 if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0) 442 if (pipe(pin) < 0) {
410 packet_disconnect("Could not create pipes: %.100s", 443 error("%s: pipe in: %.100s", __func__, strerror(errno));
411 strerror(errno)); 444 return -1;
412#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
413 int inout[2], err[2]; 461 int inout[2], err[2];
462
414 /* Uses socket pairs to communicate with the program. */ 463 /* Uses socket pairs to communicate with the program. */
415 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 || 464 if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
416 socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) 465 error("%s: socketpair #1: %.100s", __func__, strerror(errno));
417 packet_disconnect("Could not create socket pairs: %.100s", 466 return -1;
418 strerror(errno)); 467 }
419#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
420 if (s == NULL) 476 if (s == NULL)
421 fatal("do_exec_no_pty: no session"); 477 fatal("do_exec_no_pty: no session");
422 478
423 session_proctitle(s); 479 session_proctitle(s);
424 480
425#if defined(USE_PAM)
426 if (options.use_pam && !use_privsep)
427 do_pam_setcred(1);
428#endif /* USE_PAM */
429
430 /* Fork the child. */ 481 /* Fork the child. */
431 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:
432 is_child = 1; 500 is_child = 1;
433 501
434 /* Child. Reinitialize the log since the pid has changed. */ 502 /* Child. Reinitialize the log since the pid has changed. */
435 log_init(__progname, options.log_level, options.log_facility, log_stderr); 503 log_init(__progname, options.log_level,
504 options.log_facility, log_stderr);
436 505
437 /* 506 /*
438 * Create a new session and process group since the 4.4BSD 507 * Create a new session and process group since the 4.4BSD
@@ -462,7 +531,7 @@ do_exec_no_pty(Session *s, const char *command)
462 if (dup2(perr[1], 2) < 0) 531 if (dup2(perr[1], 2) < 0)
463 perror("dup2 stderr"); 532 perror("dup2 stderr");
464 close(perr[1]); 533 close(perr[1]);
465#else /* USE_PIPES */ 534#else
466 /* 535 /*
467 * Redirect stdin, stdout, and stderr. Stdin and stdout will 536 * Redirect stdin, stdout, and stderr. Stdin and stdout will
468 * use the same socket, as some programs (particularly rdist) 537 * use the same socket, as some programs (particularly rdist)
@@ -472,11 +541,14 @@ do_exec_no_pty(Session *s, const char *command)
472 close(err[1]); 541 close(err[1]);
473 if (dup2(inout[0], 0) < 0) /* stdin */ 542 if (dup2(inout[0], 0) < 0) /* stdin */
474 perror("dup2 stdin"); 543 perror("dup2 stdin");
475 if (dup2(inout[0], 1) < 0) /* stdout. Note: same socket as stdin. */ 544 if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */
476 perror("dup2 stdout"); 545 perror("dup2 stdout");
546 close(inout[0]);
477 if (dup2(err[0], 2) < 0) /* stderr */ 547 if (dup2(err[0], 2) < 0) /* stderr */
478 perror("dup2 stderr"); 548 perror("dup2 stderr");
479#endif /* USE_PIPES */ 549 close(err[0]);
550#endif
551
480 552
481#ifdef _UNICOS 553#ifdef _UNICOS
482 cray_init_job(s->pw); /* set up cray jid and tmpdir */ 554 cray_init_job(s->pw); /* set up cray jid and tmpdir */
@@ -485,7 +557,10 @@ do_exec_no_pty(Session *s, const char *command)
485 /* Do processing for the child (exec command etc). */ 557 /* Do processing for the child (exec command etc). */
486 do_child(s, command); 558 do_child(s, command);
487 /* NOTREACHED */ 559 /* NOTREACHED */
560 default:
561 break;
488 } 562 }
563
489#ifdef _UNICOS 564#ifdef _UNICOS
490 signal(WJSIGNAL, cray_job_termination_handler); 565 signal(WJSIGNAL, cray_job_termination_handler);
491#endif /* _UNICOS */ 566#endif /* _UNICOS */
@@ -493,11 +568,18 @@ do_exec_no_pty(Session *s, const char *command)
493 if (is_winnt) 568 if (is_winnt)
494 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 569 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
495#endif 570#endif
496 if (pid < 0) 571
497 packet_disconnect("fork failed: %.100s", strerror(errno));
498 s->pid = pid; 572 s->pid = pid;
499 /* Set interactive/non-interactive mode. */ 573 /* Set interactive/non-interactive mode. */
500 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
501#ifdef USE_PIPES 583#ifdef USE_PIPES
502 /* We are the parent. Close the child sides of the pipes. */ 584 /* We are the parent. Close the child sides of the pipes. */
503 close(pin[0]); 585 close(pin[0]);
@@ -509,35 +591,32 @@ do_exec_no_pty(Session *s, const char *command)
509 close(perr[0]); 591 close(perr[0]);
510 perr[0] = -1; 592 perr[0] = -1;
511 } 593 }
512 session_set_fds(s, pin[1], pout[0], perr[0]); 594 session_set_fds(s, pin[1], pout[0], perr[0], 0);
513 } else { 595 } else {
514 /* Enter the interactive session. */ 596 /* Enter the interactive session. */
515 server_loop(pid, pin[1], pout[0], perr[0]); 597 server_loop(pid, pin[1], pout[0], perr[0]);
516 /* server_loop has closed pin[1], pout[0], and perr[0]. */ 598 /* server_loop has closed pin[1], pout[0], and perr[0]. */
517 } 599 }
518#else /* USE_PIPES */ 600#else
519 /* 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. */
520 close(inout[0]); 602 close(inout[0]);
521 close(err[0]); 603 close(err[0]);
522 604
523 /* 605 /*
524 * Clear loginmsg, since it's the child's responsibility to display
525 * it to the user, otherwise multiple sessions may accumulate
526 * multiple copies of the login messages.
527 */
528 buffer_clear(&loginmsg);
529
530 /*
531 * Enter the interactive session. Note: server_loop must be able to 606 * Enter the interactive session. Note: server_loop must be able to
532 * handle the case that fdin and fdout are the same. 607 * handle the case that fdin and fdout are the same.
533 */ 608 */
534 if (compat20) { 609 if (compat20) {
535 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], 0);
612 if (s->is_subsystem)
613 close(err[1]);
536 } else { 614 } else {
537 server_loop(pid, inout[1], inout[1], err[1]); 615 server_loop(pid, inout[1], inout[1], err[1]);
538 /* server_loop has closed inout[1] and err[1]. */ 616 /* server_loop has closed inout[1] and err[1]. */
539 } 617 }
540#endif /* USE_PIPES */ 618#endif
619 return 0;
541} 620}
542 621
543/* 622/*
@@ -546,7 +625,7 @@ do_exec_no_pty(Session *s, const char *command)
546 * setting up file descriptors, controlling tty, updating wtmp, utmp, 625 * setting up file descriptors, controlling tty, updating wtmp, utmp,
547 * lastlog, and other such operations. 626 * lastlog, and other such operations.
548 */ 627 */
549void 628int
550do_exec_pty(Session *s, const char *command) 629do_exec_pty(Session *s, const char *command)
551{ 630{
552 int fdout, ptyfd, ttyfd, ptymaster; 631 int fdout, ptyfd, ttyfd, ptymaster;
@@ -557,20 +636,46 @@ do_exec_pty(Session *s, const char *command)
557 ptyfd = s->ptyfd; 636 ptyfd = s->ptyfd;
558 ttyfd = s->ttyfd; 637 ttyfd = s->ttyfd;
559 638
560#if defined(USE_PAM) 639 /*
561 if (options.use_pam) { 640 * Create another descriptor of the pty master side for use as the
562 do_pam_set_tty(s->tty); 641 * standard input. We could use the original descriptor, but this
563 if (!use_privsep) 642 * simplifies code in server_loop. The descriptor is bidirectional.
564 do_pam_setcred(1); 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;
565 } 659 }
566#endif
567 660
568 /* Fork the child. */ 661 /* Fork the child. */
569 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:
570 is_child = 1; 671 is_child = 1;
571 672
673 close(fdout);
674 close(ptymaster);
675
572 /* Child. Reinitialize the log because the pid has changed. */ 676 /* Child. Reinitialize the log because the pid has changed. */
573 log_init(__progname, options.log_level, options.log_facility, log_stderr); 677 log_init(__progname, options.log_level,
678 options.log_facility, log_stderr);
574 /* Close the master side of the pseudo tty. */ 679 /* Close the master side of the pseudo tty. */
575 close(ptyfd); 680 close(ptyfd);
576 681
@@ -601,11 +706,16 @@ do_exec_pty(Session *s, const char *command)
601 do_pre_login(s); 706 do_pre_login(s);
602# endif 707# endif
603#endif 708#endif
604 709 /*
605 /* Do common processing for the child, such as execing the command. */ 710 * Do common processing for the child, such as execing
606 do_child(s, command); 711 * the command.
607 /* NOTREACHED */ 712 */
713 do_child(s, command);
714 /* NOTREACHED */
715 default:
716 break;
608 } 717 }
718
609#ifdef _UNICOS 719#ifdef _UNICOS
610 signal(WJSIGNAL, cray_job_termination_handler); 720 signal(WJSIGNAL, cray_job_termination_handler);
611#endif /* _UNICOS */ 721#endif /* _UNICOS */
@@ -613,36 +723,22 @@ do_exec_pty(Session *s, const char *command)
613 if (is_winnt) 723 if (is_winnt)
614 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE); 724 cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
615#endif 725#endif
616 if (pid < 0) 726
617 packet_disconnect("fork failed: %.100s", strerror(errno));
618 s->pid = pid; 727 s->pid = pid;
619 728
620 /* Parent. Close the slave side of the pseudo tty. */ 729 /* Parent. Close the slave side of the pseudo tty. */
621 close(ttyfd); 730 close(ttyfd);
622 731
623 /*
624 * Create another descriptor of the pty master side for use as the
625 * standard input. We could use the original descriptor, but this
626 * simplifies code in server_loop. The descriptor is bidirectional.
627 */
628 fdout = dup(ptyfd);
629 if (fdout < 0)
630 packet_disconnect("dup #1 failed: %.100s", strerror(errno));
631
632 /* we keep a reference to the pty master */
633 ptymaster = dup(ptyfd);
634 if (ptymaster < 0)
635 packet_disconnect("dup #2 failed: %.100s", strerror(errno));
636 s->ptymaster = ptymaster;
637
638 /* Enter interactive session. */ 732 /* Enter interactive session. */
733 s->ptymaster = ptymaster;
639 packet_set_interactive(1); 734 packet_set_interactive(1);
640 if (compat20) { 735 if (compat20) {
641 session_set_fds(s, ptyfd, fdout, -1); 736 session_set_fds(s, ptyfd, fdout, -1, 1);
642 } else { 737 } else {
643 server_loop(pid, ptyfd, fdout, -1); 738 server_loop(pid, ptyfd, fdout, -1);
644 /* server_loop _has_ closed ptyfd and fdout. */ 739 /* server_loop _has_ closed ptyfd and fdout. */
645 } 740 }
741 return 0;
646} 742}
647 743
648#ifdef LOGIN_NEEDS_UTMPX 744#ifdef LOGIN_NEEDS_UTMPX
@@ -677,16 +773,26 @@ do_pre_login(Session *s)
677 * 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
678 * to be forced, execute that instead. 774 * to be forced, execute that instead.
679 */ 775 */
680void 776int
681do_exec(Session *s, const char *command) 777do_exec(Session *s, const char *command)
682{ 778{
779 int ret;
780
683 if (options.adm_forced_command) { 781 if (options.adm_forced_command) {
684 original_command = command; 782 original_command = command;
685 command = options.adm_forced_command; 783 command = options.adm_forced_command;
784 if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
785 s->is_subsystem = SUBSYSTEM_INT_SFTP;
786 else if (s->is_subsystem)
787 s->is_subsystem = SUBSYSTEM_EXT;
686 debug("Forced command (config) '%.900s'", command); 788 debug("Forced command (config) '%.900s'", command);
687 } else if (forced_command) { 789 } else if (forced_command) {
688 original_command = command; 790 original_command = command;
689 command = forced_command; 791 command = forced_command;
792 if (strcmp(INTERNAL_SFTP_NAME, command) == 0)
793 s->is_subsystem = SUBSYSTEM_INT_SFTP;
794 else if (s->is_subsystem)
795 s->is_subsystem = SUBSYSTEM_EXT;
690 debug("Forced command (key option) '%.900s'", command); 796 debug("Forced command (key option) '%.900s'", command);
691 } 797 }
692 798
@@ -701,11 +807,10 @@ do_exec(Session *s, const char *command)
701 PRIVSEP(audit_run_command(shell)); 807 PRIVSEP(audit_run_command(shell));
702 } 808 }
703#endif 809#endif
704
705 if (s->ttyfd != -1) 810 if (s->ttyfd != -1)
706 do_exec_pty(s, command); 811 ret = do_exec_pty(s, command);
707 else 812 else
708 do_exec_no_pty(s, command); 813 ret = do_exec_no_pty(s, command);
709 814
710 original_command = NULL; 815 original_command = NULL;
711 816
@@ -715,6 +820,8 @@ do_exec(Session *s, const char *command)
715 * multiple copies of the login messages. 820 * multiple copies of the login messages.
716 */ 821 */
717 buffer_clear(&loginmsg); 822 buffer_clear(&loginmsg);
823
824 return ret;
718} 825}
719 826
720/* administrative, login(1)-like work */ 827/* administrative, login(1)-like work */
@@ -897,8 +1004,9 @@ read_environment_file(char ***env, u_int *envsize,
897 ; 1004 ;
898 if (!*cp || *cp == '#' || *cp == '\n') 1005 if (!*cp || *cp == '#' || *cp == '\n')
899 continue; 1006 continue;
900 if (strchr(cp, '\n')) 1007
901 *strchr(cp, '\n') = '\0'; 1008 cp[strcspn(cp, "\n")] = '\0';
1009
902 value = strchr(cp, '='); 1010 value = strchr(cp, '=');
903 if (value == NULL) { 1011 if (value == NULL) {
904 fprintf(stderr, "Bad line %u in %.100s\n", lineno, 1012 fprintf(stderr, "Bad line %u in %.100s\n", lineno,
@@ -1203,7 +1311,7 @@ do_rc_files(Session *s, const char *shell)
1203 1311
1204 /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */ 1312 /* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
1205 if (!s->is_subsystem && options.adm_forced_command == NULL && 1313 if (!s->is_subsystem && options.adm_forced_command == NULL &&
1206 !no_user_rc && (stat(_PATH_SSH_USER_RC, &st) >= 0)) { 1314 !no_user_rc && stat(_PATH_SSH_USER_RC, &st) >= 0) {
1207 snprintf(cmd, sizeof cmd, "%s -c '%s %s'", 1315 snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
1208 shell, _PATH_BSHELL, _PATH_SSH_USER_RC); 1316 shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
1209 if (debug_flag) 1317 if (debug_flag)
@@ -1284,10 +1392,72 @@ do_nologin(struct passwd *pw)
1284 } 1392 }
1285} 1393}
1286 1394
1395/*
1396 * Chroot into a directory after checking it for safety: all path components
1397 * must be root-owned directories with strict permissions.
1398 */
1399static void
1400safely_chroot(const char *path, uid_t uid)
1401{
1402 const char *cp;
1403 char component[MAXPATHLEN];
1404 struct stat st;
1405
1406 if (*path != '/')
1407 fatal("chroot path does not begin at root");
1408 if (strlen(path) >= sizeof(component))
1409 fatal("chroot path too long");
1410
1411 /*
1412 * Descend the path, checking that each component is a
1413 * root-owned directory with strict permissions.
1414 */
1415 for (cp = path; cp != NULL;) {
1416 if ((cp = strchr(cp, '/')) == NULL)
1417 strlcpy(component, path, sizeof(component));
1418 else {
1419 cp++;
1420 memcpy(component, path, cp - path);
1421 component[cp - path] = '\0';
1422 }
1423
1424 debug3("%s: checking '%s'", __func__, component);
1425
1426 if (stat(component, &st) != 0)
1427 fatal("%s: stat(\"%s\"): %s", __func__,
1428 component, strerror(errno));
1429 if (st.st_uid != 0 || (st.st_mode & 022) != 0)
1430 fatal("bad ownership or modes for chroot "
1431 "directory %s\"%s\"",
1432 cp == NULL ? "" : "component ", component);
1433 if (!S_ISDIR(st.st_mode))
1434 fatal("chroot path %s\"%s\" is not a directory",
1435 cp == NULL ? "" : "component ", component);
1436
1437 }
1438
1439 if (chdir(path) == -1)
1440 fatal("Unable to chdir to chroot path \"%s\": "
1441 "%s", path, strerror(errno));
1442 if (chroot(path) == -1)
1443 fatal("chroot(\"%s\"): %s", path, strerror(errno));
1444 if (chdir("/") == -1)
1445 fatal("%s: chdir(/) after chroot: %s",
1446 __func__, strerror(errno));
1447 verbose("Changed root directory to \"%s\"", path);
1448}
1449
1287/* Set login name, uid, gid, and groups. */ 1450/* Set login name, uid, gid, and groups. */
1288void 1451void
1289do_setusercontext(struct passwd *pw) 1452do_setusercontext(struct passwd *pw)
1290{ 1453{
1454 char *chroot_path, *tmp;
1455
1456#ifdef WITH_SELINUX
1457 /* Cache selinux status for later use */
1458 (void)ssh_selinux_enabled();
1459#endif
1460
1291#ifndef HAVE_CYGWIN 1461#ifndef HAVE_CYGWIN
1292 if (getuid() == 0 || geteuid() == 0) 1462 if (getuid() == 0 || geteuid() == 0)
1293#endif /* HAVE_CYGWIN */ 1463#endif /* HAVE_CYGWIN */
@@ -1301,21 +1471,13 @@ do_setusercontext(struct passwd *pw)
1301# ifdef __bsdi__ 1471# ifdef __bsdi__
1302 setpgid(0, 0); 1472 setpgid(0, 0);
1303# endif 1473# endif
1304#ifdef GSSAPI
1305 if (options.gss_authentication) {
1306 temporarily_use_uid(pw);
1307 ssh_gssapi_storecreds();
1308 restore_uid();
1309 }
1310#endif
1311# ifdef USE_PAM 1474# ifdef USE_PAM
1312 if (options.use_pam) { 1475 if (options.use_pam) {
1313 do_pam_session();
1314 do_pam_setcred(use_privsep); 1476 do_pam_setcred(use_privsep);
1315 } 1477 }
1316# endif /* USE_PAM */ 1478# endif /* USE_PAM */
1317 if (setusercontext(lc, pw, pw->pw_uid, 1479 if (setusercontext(lc, pw, pw->pw_uid,
1318 (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { 1480 (LOGIN_SETALL & ~(LOGIN_SETPATH|LOGIN_SETUSER))) < 0) {
1319 perror("unable to set user context"); 1481 perror("unable to set user context");
1320 exit(1); 1482 exit(1);
1321 } 1483 }
@@ -1338,13 +1500,6 @@ do_setusercontext(struct passwd *pw)
1338 exit(1); 1500 exit(1);
1339 } 1501 }
1340 endgrent(); 1502 endgrent();
1341#ifdef GSSAPI
1342 if (options.gss_authentication) {
1343 temporarily_use_uid(pw);
1344 ssh_gssapi_storecreds();
1345 restore_uid();
1346 }
1347#endif
1348# ifdef USE_PAM 1503# ifdef USE_PAM
1349 /* 1504 /*
1350 * PAM credentials may take the form of supplementary groups. 1505 * PAM credentials may take the form of supplementary groups.
@@ -1352,21 +1507,39 @@ do_setusercontext(struct passwd *pw)
1352 * Reestablish them here. 1507 * Reestablish them here.
1353 */ 1508 */
1354 if (options.use_pam) { 1509 if (options.use_pam) {
1355 do_pam_session();
1356 do_pam_setcred(use_privsep); 1510 do_pam_setcred(use_privsep);
1357 } 1511 }
1358# endif /* USE_PAM */ 1512# endif /* USE_PAM */
1359# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) 1513# if defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY)
1360 irix_setusercontext(pw); 1514 irix_setusercontext(pw);
1361# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */ 1515# endif /* defined(WITH_IRIX_PROJECT) || defined(WITH_IRIX_JOBS) || defined(WITH_IRIX_ARRAY) */
1362# ifdef _AIX 1516# ifdef _AIX
1363 aix_usrinfo(pw); 1517 aix_usrinfo(pw);
1364# endif /* _AIX */ 1518# endif /* _AIX */
1365#ifdef USE_LIBIAF 1519# ifdef USE_LIBIAF
1366 if (set_id(pw->pw_name) != 0) { 1520 if (set_id(pw->pw_name) != 0) {
1367 exit(1); 1521 exit(1);
1368 } 1522 }
1369#endif /* USE_LIBIAF */ 1523# endif /* USE_LIBIAF */
1524#endif
1525
1526 if (options.chroot_directory != NULL &&
1527 strcasecmp(options.chroot_directory, "none") != 0) {
1528 tmp = tilde_expand_filename(options.chroot_directory,
1529 pw->pw_uid);
1530 chroot_path = percent_expand(tmp, "h", pw->pw_dir,
1531 "u", pw->pw_name, (char *)NULL);
1532 safely_chroot(chroot_path, pw->pw_uid);
1533 free(tmp);
1534 free(chroot_path);
1535 }
1536
1537#ifdef HAVE_LOGIN_CAP
1538 if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUSER) < 0) {
1539 perror("unable to set user context (setuser)");
1540 exit(1);
1541 }
1542#else
1370 /* Permanently switch to the desired uid. */ 1543 /* Permanently switch to the desired uid. */
1371 permanently_set_uid(pw); 1544 permanently_set_uid(pw);
1372#endif 1545#endif
@@ -1465,14 +1638,16 @@ child_close_fds(void)
1465 * environment, closing extra file descriptors, setting the user and group 1638 * environment, closing extra file descriptors, setting the user and group
1466 * ids, and executing the command or shell. 1639 * ids, and executing the command or shell.
1467 */ 1640 */
1641#define ARGV_MAX 10
1468void 1642void
1469do_child(Session *s, const char *command) 1643do_child(Session *s, const char *command)
1470{ 1644{
1471 extern char **environ; 1645 extern char **environ;
1472 char **env; 1646 char **env;
1473 char *argv[10]; 1647 char *argv[ARGV_MAX];
1474 const char *shell, *shell0, *hostname = NULL; 1648 const char *shell, *shell0, *hostname = NULL;
1475 struct passwd *pw = s->pw; 1649 struct passwd *pw = s->pw;
1650 int r = 0;
1476 1651
1477 /* remove hostkey from the child's memory */ 1652 /* remove hostkey from the child's memory */
1478 destroy_sensitive_data(); 1653 destroy_sensitive_data();
@@ -1588,20 +1763,42 @@ do_child(Session *s, const char *command)
1588 1763
1589 /* Change current directory to the user's home directory. */ 1764 /* Change current directory to the user's home directory. */
1590 if (chdir(pw->pw_dir) < 0) { 1765 if (chdir(pw->pw_dir) < 0) {
1591 fprintf(stderr, "Could not chdir to home directory %s: %s\n", 1766 /* Suppress missing homedir warning for chroot case */
1592 pw->pw_dir, strerror(errno));
1593#ifdef HAVE_LOGIN_CAP 1767#ifdef HAVE_LOGIN_CAP
1594 if (login_getcapbool(lc, "requirehome", 0)) 1768 r = login_getcapbool(lc, "requirehome", 0);
1595 exit(1);
1596#endif 1769#endif
1770 if (r || options.chroot_directory == NULL)
1771 fprintf(stderr, "Could not chdir to home "
1772 "directory %s: %s\n", pw->pw_dir,
1773 strerror(errno));
1774 if (r)
1775 exit(1);
1597 } 1776 }
1598 1777
1778 closefrom(STDERR_FILENO + 1);
1779
1599 if (!options.use_login) 1780 if (!options.use_login)
1600 do_rc_files(s, shell); 1781 do_rc_files(s, shell);
1601 1782
1602 /* restore SIGPIPE for child */ 1783 /* restore SIGPIPE for child */
1603 signal(SIGPIPE, SIG_DFL); 1784 signal(SIGPIPE, SIG_DFL);
1604 1785
1786 if (s->is_subsystem == SUBSYSTEM_INT_SFTP) {
1787 extern int optind, optreset;
1788 int i;
1789 char *p, *args;
1790
1791 setproctitle("%s@internal-sftp-server", s->pw->pw_name);
1792 args = strdup(command ? command : "sftp-server");
1793 for (i = 0, (p = strtok(args, " ")); p; (p = strtok(NULL, " ")))
1794 if (i < ARGV_MAX - 1)
1795 argv[i++] = p;
1796 argv[i] = NULL;
1797 optind = optreset = 1;
1798 __progname = argv[0];
1799 exit(sftp_server_main(i, argv, s->pw));
1800 }
1801
1605 if (options.use_login) { 1802 if (options.use_login) {
1606 launch_login(pw, hostname); 1803 launch_login(pw, hostname);
1607 /* NEVERREACHED */ 1804 /* NEVERREACHED */
@@ -1653,43 +1850,79 @@ do_child(Session *s, const char *command)
1653 exit(1); 1850 exit(1);
1654} 1851}
1655 1852
1853void
1854session_unused(int id)
1855{
1856 debug3("%s: session id %d unused", __func__, id);
1857 if (id >= options.max_sessions ||
1858 id >= sessions_nalloc) {
1859 fatal("%s: insane session id %d (max %d nalloc %d)",
1860 __func__, id, options.max_sessions, sessions_nalloc);
1861 }
1862 bzero(&sessions[id], sizeof(*sessions));
1863 sessions[id].self = id;
1864 sessions[id].used = 0;
1865 sessions[id].chanid = -1;
1866 sessions[id].ptyfd = -1;
1867 sessions[id].ttyfd = -1;
1868 sessions[id].ptymaster = -1;
1869 sessions[id].x11_chanids = NULL;
1870 sessions[id].next_unused = sessions_first_unused;
1871 sessions_first_unused = id;
1872}
1873
1656Session * 1874Session *
1657session_new(void) 1875session_new(void)
1658{ 1876{
1659 int i; 1877 Session *s, *tmp;
1660 static int did_init = 0; 1878
1661 if (!did_init) { 1879 if (sessions_first_unused == -1) {
1662 debug("session_new: init"); 1880 if (sessions_nalloc >= options.max_sessions)
1663 for (i = 0; i < MAX_SESSIONS; i++) { 1881 return NULL;
1664 sessions[i].used = 0; 1882 debug2("%s: allocate (allocated %d max %d)",
1883 __func__, sessions_nalloc, options.max_sessions);
1884 tmp = xrealloc(sessions, sessions_nalloc + 1,
1885 sizeof(*sessions));
1886 if (tmp == NULL) {
1887 error("%s: cannot allocate %d sessions",
1888 __func__, sessions_nalloc + 1);
1889 return NULL;
1665 } 1890 }
1666 did_init = 1; 1891 sessions = tmp;
1892 session_unused(sessions_nalloc++);
1667 } 1893 }
1668 for (i = 0; i < MAX_SESSIONS; i++) { 1894
1669 Session *s = &sessions[i]; 1895 if (sessions_first_unused >= sessions_nalloc ||
1670 if (! s->used) { 1896 sessions_first_unused < 0) {
1671 memset(s, 0, sizeof(*s)); 1897 fatal("%s: insane first_unused %d max %d nalloc %d",
1672 s->chanid = -1; 1898 __func__, sessions_first_unused, options.max_sessions,
1673 s->ptyfd = -1; 1899 sessions_nalloc);
1674 s->ttyfd = -1;
1675 s->used = 1;
1676 s->self = i;
1677 s->x11_chanids = NULL;
1678 debug("session_new: session %d", i);
1679 return s;
1680 }
1681 } 1900 }
1682 return NULL; 1901
1902 s = &sessions[sessions_first_unused];
1903 if (s->used) {
1904 fatal("%s: session %d already used",
1905 __func__, sessions_first_unused);
1906 }
1907 sessions_first_unused = s->next_unused;
1908 s->used = 1;
1909 s->next_unused = -1;
1910 debug("session_new: session %d", s->self);
1911
1912 return s;
1683} 1913}
1684 1914
1685static void 1915static void
1686session_dump(void) 1916session_dump(void)
1687{ 1917{
1688 int i; 1918 int i;
1689 for (i = 0; i < MAX_SESSIONS; i++) { 1919 for (i = 0; i < sessions_nalloc; i++) {
1690 Session *s = &sessions[i]; 1920 Session *s = &sessions[i];
1691 debug("dump: used %d session %d %p channel %d pid %ld", 1921
1922 debug("dump: used %d next_unused %d session %d %p "
1923 "channel %d pid %ld",
1692 s->used, 1924 s->used,
1925 s->next_unused,
1693 s->self, 1926 s->self,
1694 s, 1927 s,
1695 s->chanid, 1928 s->chanid,
@@ -1719,7 +1952,7 @@ Session *
1719session_by_tty(char *tty) 1952session_by_tty(char *tty)
1720{ 1953{
1721 int i; 1954 int i;
1722 for (i = 0; i < MAX_SESSIONS; i++) { 1955 for (i = 0; i < sessions_nalloc; i++) {
1723 Session *s = &sessions[i]; 1956 Session *s = &sessions[i];
1724 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) { 1957 if (s->used && s->ttyfd != -1 && strcmp(s->tty, tty) == 0) {
1725 debug("session_by_tty: session %d tty %s", i, tty); 1958 debug("session_by_tty: session %d tty %s", i, tty);
@@ -1735,10 +1968,11 @@ static Session *
1735session_by_channel(int id) 1968session_by_channel(int id)
1736{ 1969{
1737 int i; 1970 int i;
1738 for (i = 0; i < MAX_SESSIONS; i++) { 1971 for (i = 0; i < sessions_nalloc; i++) {
1739 Session *s = &sessions[i]; 1972 Session *s = &sessions[i];
1740 if (s->used && s->chanid == id) { 1973 if (s->used && s->chanid == id) {
1741 debug("session_by_channel: session %d channel %d", i, id); 1974 debug("session_by_channel: session %d channel %d",
1975 i, id);
1742 return s; 1976 return s;
1743 } 1977 }
1744 } 1978 }
@@ -1752,7 +1986,7 @@ session_by_x11_channel(int id)
1752{ 1986{
1753 int i, j; 1987 int i, j;
1754 1988
1755 for (i = 0; i < MAX_SESSIONS; i++) { 1989 for (i = 0; i < sessions_nalloc; i++) {
1756 Session *s = &sessions[i]; 1990 Session *s = &sessions[i];
1757 1991
1758 if (s->x11_chanids == NULL || !s->used) 1992 if (s->x11_chanids == NULL || !s->used)
@@ -1775,7 +2009,7 @@ session_by_pid(pid_t pid)
1775{ 2009{
1776 int i; 2010 int i;
1777 debug("session_by_pid: pid %ld", (long)pid); 2011 debug("session_by_pid: pid %ld", (long)pid);
1778 for (i = 0; i < MAX_SESSIONS; i++) { 2012 for (i = 0; i < sessions_nalloc; i++) {
1779 Session *s = &sessions[i]; 2013 Session *s = &sessions[i];
1780 if (s->used && s->pid == pid) 2014 if (s->used && s->pid == pid)
1781 return s; 2015 return s;
@@ -1831,7 +2065,8 @@ session_pty_req(Session *s)
1831 2065
1832 /* Allocate a pty and open it. */ 2066 /* Allocate a pty and open it. */
1833 debug("Allocating pty."); 2067 debug("Allocating pty.");
1834 if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty, sizeof(s->tty)))) { 2068 if (!PRIVSEP(pty_allocate(&s->ptyfd, &s->ttyfd, s->tty,
2069 sizeof(s->tty)))) {
1835 if (s->term) 2070 if (s->term)
1836 xfree(s->term); 2071 xfree(s->term);
1837 s->term = NULL; 2072 s->term = NULL;
@@ -1874,15 +2109,17 @@ session_subsystem_req(Session *s)
1874 if (strcmp(subsys, options.subsystem_name[i]) == 0) { 2109 if (strcmp(subsys, options.subsystem_name[i]) == 0) {
1875 prog = options.subsystem_command[i]; 2110 prog = options.subsystem_command[i];
1876 cmd = options.subsystem_args[i]; 2111 cmd = options.subsystem_args[i];
1877 if (stat(prog, &st) < 0) { 2112 if (!strcmp(INTERNAL_SFTP_NAME, prog)) {
2113 s->is_subsystem = SUBSYSTEM_INT_SFTP;
2114 } else if (stat(prog, &st) < 0) {
1878 error("subsystem: cannot stat %s: %s", prog, 2115 error("subsystem: cannot stat %s: %s", prog,
1879 strerror(errno)); 2116 strerror(errno));
1880 break; 2117 break;
2118 } else {
2119 s->is_subsystem = SUBSYSTEM_EXT;
1881 } 2120 }
1882 debug("subsystem: exec() %s", cmd); 2121 debug("subsystem: exec() %s", cmd);
1883 s->is_subsystem = 1; 2122 success = do_exec(s, cmd) == 0;
1884 do_exec(s, cmd);
1885 success = 1;
1886 break; 2123 break;
1887 } 2124 }
1888 } 2125 }
@@ -1925,19 +2162,19 @@ static int
1925session_shell_req(Session *s) 2162session_shell_req(Session *s)
1926{ 2163{
1927 packet_check_eom(); 2164 packet_check_eom();
1928 do_exec(s, NULL); 2165 return do_exec(s, NULL) == 0;
1929 return 1;
1930} 2166}
1931 2167
1932static int 2168static int
1933session_exec_req(Session *s) 2169session_exec_req(Session *s)
1934{ 2170{
1935 u_int len; 2171 u_int len, success;
2172
1936 char *command = packet_get_string(&len); 2173 char *command = packet_get_string(&len);
1937 packet_check_eom(); 2174 packet_check_eom();
1938 do_exec(s, command); 2175 success = do_exec(s, command) == 0;
1939 xfree(command); 2176 xfree(command);
1940 return 1; 2177 return success;
1941} 2178}
1942 2179
1943static int 2180static int
@@ -1947,8 +2184,7 @@ session_break_req(Session *s)
1947 packet_get_int(); /* ignored */ 2184 packet_get_int(); /* ignored */
1948 packet_check_eom(); 2185 packet_check_eom();
1949 2186
1950 if (s->ttyfd == -1 || 2187 if (s->ttyfd == -1 || tcsendbreak(s->ttyfd, 0) < 0)
1951 tcsendbreak(s->ttyfd, 0) < 0)
1952 return 0; 2188 return 0;
1953 return 1; 2189 return 1;
1954} 2190}
@@ -1993,7 +2229,7 @@ session_auth_agent_req(Session *s)
1993{ 2229{
1994 static int called = 0; 2230 static int called = 0;
1995 packet_check_eom(); 2231 packet_check_eom();
1996 if (no_agent_forwarding_flag) { 2232 if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
1997 debug("session_auth_agent_req: no_agent_forwarding_flag"); 2233 debug("session_auth_agent_req: no_agent_forwarding_flag");
1998 return 0; 2234 return 0;
1999 } 2235 }
@@ -2049,7 +2285,7 @@ session_input_channel_req(Channel *c, const char *rtype)
2049} 2285}
2050 2286
2051void 2287void
2052session_set_fds(Session *s, int fdin, int fdout, int fderr) 2288session_set_fds(Session *s, int fdin, int fdout, int fderr, int is_tty)
2053{ 2289{
2054 if (!compat20) 2290 if (!compat20)
2055 fatal("session_set_fds: called for proto != 2.0"); 2291 fatal("session_set_fds: called for proto != 2.0");
@@ -2062,8 +2298,7 @@ session_set_fds(Session *s, int fdin, int fdout, int fderr)
2062 channel_set_fds(s->chanid, 2298 channel_set_fds(s->chanid,
2063 fdout, fdin, fderr, 2299 fdout, fdin, fderr,
2064 fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ, 2300 fderr == -1 ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
2065 1, 2301 1, is_tty, CHAN_SES_WINDOW_DEFAULT);
2066 CHAN_SES_WINDOW_DEFAULT);
2067} 2302}
2068 2303
2069/* 2304/*
@@ -2095,8 +2330,9 @@ session_pty_cleanup2(Session *s)
2095 * the pty cleanup, so that another process doesn't get this pty 2330 * the pty cleanup, so that another process doesn't get this pty
2096 * while we're still cleaning up. 2331 * while we're still cleaning up.
2097 */ 2332 */
2098 if (close(s->ptymaster) < 0) 2333 if (s->ptymaster != -1 && close(s->ptymaster) < 0)
2099 error("close(s->ptymaster/%d): %s", s->ptymaster, strerror(errno)); 2334 error("close(s->ptymaster/%d): %s",
2335 s->ptymaster, strerror(errno));
2100 2336
2101 /* unlink pty from session */ 2337 /* unlink pty from session */
2102 s->ttyfd = -1; 2338 s->ttyfd = -1;
@@ -2204,7 +2440,7 @@ session_exit_message(Session *s, int status)
2204 channel_request_start(s->chanid, "exit-signal", 0); 2440 channel_request_start(s->chanid, "exit-signal", 0);
2205 packet_put_cstring(sig2name(WTERMSIG(status))); 2441 packet_put_cstring(sig2name(WTERMSIG(status)));
2206#ifdef WCOREDUMP 2442#ifdef WCOREDUMP
2207 packet_put_char(WCOREDUMP(status)); 2443 packet_put_char(WCOREDUMP(status)? 1 : 0);
2208#else /* WCOREDUMP */ 2444#else /* WCOREDUMP */
2209 packet_put_char(0); 2445 packet_put_char(0);
2210#endif /* WCOREDUMP */ 2446#endif /* WCOREDUMP */
@@ -2256,7 +2492,6 @@ session_close(Session *s)
2256 xfree(s->auth_data); 2492 xfree(s->auth_data);
2257 if (s->auth_proto) 2493 if (s->auth_proto)
2258 xfree(s->auth_proto); 2494 xfree(s->auth_proto);
2259 s->used = 0;
2260 if (s->env != NULL) { 2495 if (s->env != NULL) {
2261 for (i = 0; i < s->num_env; i++) { 2496 for (i = 0; i < s->num_env; i++) {
2262 xfree(s->env[i].name); 2497 xfree(s->env[i].name);
@@ -2265,6 +2500,7 @@ session_close(Session *s)
2265 xfree(s->env); 2500 xfree(s->env);
2266 } 2501 }
2267 session_proctitle(s); 2502 session_proctitle(s);
2503 session_unused(s->self);
2268} 2504}
2269 2505
2270void 2506void
@@ -2328,7 +2564,7 @@ void
2328session_destroy_all(void (*closefunc)(Session *)) 2564session_destroy_all(void (*closefunc)(Session *))
2329{ 2565{
2330 int i; 2566 int i;
2331 for (i = 0; i < MAX_SESSIONS; i++) { 2567 for (i = 0; i < sessions_nalloc; i++) {
2332 Session *s = &sessions[i]; 2568 Session *s = &sessions[i];
2333 if (s->used) { 2569 if (s->used) {
2334 if (closefunc != NULL) 2570 if (closefunc != NULL)
@@ -2347,7 +2583,7 @@ session_tty_list(void)
2347 char *cp; 2583 char *cp;
2348 2584
2349 buf[0] = '\0'; 2585 buf[0] = '\0';
2350 for (i = 0; i < MAX_SESSIONS; i++) { 2586 for (i = 0; i < sessions_nalloc; i++) {
2351 Session *s = &sessions[i]; 2587 Session *s = &sessions[i];
2352 if (s->used && s->ttyfd != -1) { 2588 if (s->used && s->ttyfd != -1) {
2353 2589