summaryrefslogtreecommitdiff
path: root/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'session.c')
-rw-r--r--session.c1393
1 files changed, 670 insertions, 723 deletions
diff --git a/session.c b/session.c
index 9a153846..449b84c5 100644
--- a/session.c
+++ b/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.277 2015/01/16 06:40:12 deraadt Exp $ */
+/* $OpenBSD: session.c,v 1.319 2020/03/13 03:17:07 djm Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -46,6 +46,7 @@
#include <arpa/inet.h>
+#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
@@ -55,26 +56,26 @@
#endif
#include <pwd.h>
#include <signal.h>
-#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdarg.h>
#include <unistd.h>
#include <limits.h>
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
-#include "ssh1.h"
#include "ssh2.h"
#include "sshpty.h"
#include "packet.h"
-#include "buffer.h"
+#include "sshbuf.h"
+#include "ssherr.h"
#include "match.h"
#include "uidswap.h"
#include "compat.h"
#include "channels.h"
-#include "key.h"
+#include "sshkey.h"
#include "cipher.h"
#ifdef GSSAPI
#include "ssh-gss.h"
@@ -94,6 +95,7 @@
#include "kex.h"
#include "monitor_wrap.h"
#include "sftp.h"
+#include "atomicio.h"
#if defined(KRB5) && defined(USE_AFS)
#include <kafs.h>
@@ -112,35 +114,32 @@
/* func */
Session *session_new(void);
-void session_set_fds(Session *, int, int, int, int, int);
+void session_set_fds(struct ssh *, Session *, int, int, int, int, int);
void session_pty_cleanup(Session *);
void session_proctitle(Session *);
-int session_setup_x11fwd(Session *);
-int do_exec_pty(Session *, const char *);
-int do_exec_no_pty(Session *, const char *);
-int do_exec(Session *, const char *);
-void do_login(Session *, const char *);
-#ifdef LOGIN_NEEDS_UTMPX
-static void do_pre_login(Session *s);
-#endif
-void do_child(Session *, const char *);
+int session_setup_x11fwd(struct ssh *, Session *);
+int do_exec_pty(struct ssh *, Session *, const char *);
+int do_exec_no_pty(struct ssh *, Session *, const char *);
+int do_exec(struct ssh *, Session *, const char *);
+void do_login(struct ssh *, Session *, const char *);
+void do_child(struct ssh *, Session *, const char *);
void do_motd(void);
int check_quietlogin(Session *, const char *);
-static void do_authenticated1(Authctxt *);
-static void do_authenticated2(Authctxt *);
+static void do_authenticated2(struct ssh *, Authctxt *);
-static int session_pty_req(Session *);
+static int session_pty_req(struct ssh *, Session *);
/* import */
extern ServerOptions options;
extern char *__progname;
-extern int log_stderr;
extern int debug_flag;
extern u_int utmp_len;
extern int startup_pipe;
extern void destroy_sensitive_data(void);
-extern Buffer loginmsg;
+extern struct sshbuf *loginmsg;
+extern struct sshauthopt *auth_opts;
+extern char *tun_fwd_ifnames; /* serverloop.c */
/* original command from peer. */
const char *original_command = NULL;
@@ -160,6 +159,10 @@ login_cap_t *lc;
#endif
static int is_child = 0;
+static int in_chroot = 0;
+
+/* File containing userauth info, if ExposeAuthInfo set */
+static char *auth_info_file = NULL;
/* Name and directory of socket for authentication agent forwarding. */
static char *auth_sock_name = NULL;
@@ -180,7 +183,7 @@ auth_sock_cleanup_proc(struct passwd *pw)
}
static int
-auth_input_request_forwarding(struct passwd * pw)
+auth_input_request_forwarding(struct ssh *ssh, struct passwd * pw)
{
Channel *nc;
int sock = -1;
@@ -198,7 +201,7 @@ auth_input_request_forwarding(struct passwd * pw)
/* Create private directory for socket */
if (mkdtemp(auth_sock_dir) == NULL) {
- packet_send_debug("Agent forwarding disabled: "
+ ssh_packet_send_debug(ssh, "Agent forwarding disabled: "
"mkdtemp() failed: %.100s", strerror(errno));
restore_uid();
free(auth_sock_dir);
@@ -220,7 +223,7 @@ auth_input_request_forwarding(struct passwd * pw)
goto authsock_err;
/* Allocate a channel for the authentication agent socket. */
- nc = channel_new("auth socket",
+ nc = channel_new(ssh, "auth socket",
SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,
CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,
0, "auth socket", 1);
@@ -230,7 +233,9 @@ auth_input_request_forwarding(struct passwd * pw)
authsock_err:
free(auth_sock_name);
if (auth_sock_dir != NULL) {
+ temporarily_use_uid(pw);
rmdir(auth_sock_dir);
+ restore_uid();
free(auth_sock_dir);
}
if (sock != -1)
@@ -243,186 +248,138 @@ auth_input_request_forwarding(struct passwd * pw)
static void
display_loginmsg(void)
{
- if (buffer_len(&loginmsg) > 0) {
- buffer_append(&loginmsg, "\0", 1);
- printf("%s", (char *)buffer_ptr(&loginmsg));
- buffer_clear(&loginmsg);
- }
+ int r;
+
+ if (sshbuf_len(loginmsg) == 0)
+ return;
+ if ((r = sshbuf_put_u8(loginmsg, 0)) != 0)
+ fatal("%s: buffer error: %s", __func__, ssh_err(r));
+ printf("%s", (char *)sshbuf_ptr(loginmsg));
+ sshbuf_reset(loginmsg);
}
-void
-do_authenticated(Authctxt *authctxt)
+static void
+prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
{
- setproctitle("%s", authctxt->pw->pw_name);
+ int fd = -1, success = 0;
- /* setup the channel layer */
- /* XXX - streamlocal? */
- if (no_port_forwarding_flag ||
- (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
- channel_disable_adm_local_opens();
- else
- channel_permit_all_opens();
-
- auth_debug_send();
-
- if (compat20)
- do_authenticated2(authctxt);
- else
- do_authenticated1(authctxt);
+ if (!options.expose_userauth_info || info == NULL)
+ return;
- do_cleanup(authctxt);
+ temporarily_use_uid(pw);
+ auth_info_file = xstrdup("/tmp/sshauth.XXXXXXXXXXXXXXX");
+ if ((fd = mkstemp(auth_info_file)) == -1) {
+ error("%s: mkstemp: %s", __func__, strerror(errno));
+ goto out;
+ }
+ if (atomicio(vwrite, fd, sshbuf_mutable_ptr(info),
+ sshbuf_len(info)) != sshbuf_len(info)) {
+ error("%s: write: %s", __func__, strerror(errno));
+ goto out;
+ }
+ if (close(fd) != 0) {
+ error("%s: close: %s", __func__, strerror(errno));
+ goto out;
+ }
+ success = 1;
+ out:
+ if (!success) {
+ if (fd != -1)
+ close(fd);
+ free(auth_info_file);
+ auth_info_file = NULL;
+ }
+ restore_uid();
}
-/*
- * Prepares for an interactive session. This is called after the user has
- * been successfully authenticated. During this message exchange, pseudo
- * terminals are allocated, X11, TCP/IP, and authentication agent forwardings
- * are requested, etc.
- */
static void
-do_authenticated1(Authctxt *authctxt)
+set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
{
- Session *s;
- char *command;
- int success, type, screen_flag;
- int enable_compression_after_reply = 0;
- u_int proto_len, data_len, dlen, compression_level = 0;
-
- s = session_new();
- if (s == NULL) {
- error("no more sessions");
- return;
+ char *tmp, *cp, *host;
+ int port;
+ size_t i;
+
+ if ((options.allow_tcp_forwarding & FORWARD_LOCAL) != 0) {
+ channel_clear_permission(ssh, FORWARD_USER, FORWARD_LOCAL);
+ for (i = 0; i < auth_opts->npermitopen; i++) {
+ tmp = cp = xstrdup(auth_opts->permitopen[i]);
+ /* This shouldn't fail as it has already been checked */
+ if ((host = hpdelim(&cp)) == NULL)
+ fatal("%s: internal error: hpdelim", __func__);
+ host = cleanhostname(host);
+ if (cp == NULL || (port = permitopen_port(cp)) < 0)
+ fatal("%s: internal error: permitopen port",
+ __func__);
+ channel_add_permission(ssh,
+ FORWARD_USER, FORWARD_LOCAL, host, port);
+ free(tmp);
+ }
}
- s->authctxt = authctxt;
- s->pw = authctxt->pw;
-
- /*
- * We stay in this loop until the client requests to execute a shell
- * or a command.
- */
- for (;;) {
- success = 0;
+ if ((options.allow_tcp_forwarding & FORWARD_REMOTE) != 0) {
+ channel_clear_permission(ssh, FORWARD_USER, FORWARD_REMOTE);
+ for (i = 0; i < auth_opts->npermitlisten; i++) {
+ tmp = cp = xstrdup(auth_opts->permitlisten[i]);
+ /* This shouldn't fail as it has already been checked */
+ if ((host = hpdelim(&cp)) == NULL)
+ fatal("%s: internal error: hpdelim", __func__);
+ host = cleanhostname(host);
+ if (cp == NULL || (port = permitopen_port(cp)) < 0)
+ fatal("%s: internal error: permitlisten port",
+ __func__);
+ channel_add_permission(ssh,
+ FORWARD_USER, FORWARD_REMOTE, host, port);
+ free(tmp);
+ }
+ }
+}
- /* Get a packet from the client. */
- type = packet_read();
-
- /* Process the packet. */
- switch (type) {
- case SSH_CMSG_REQUEST_COMPRESSION:
- compression_level = packet_get_int();
- packet_check_eom();
- if (compression_level < 1 || compression_level > 9) {
- packet_send_debug("Received invalid compression level %d.",
- compression_level);
- break;
- }
- if (options.compression == COMP_NONE) {
- debug2("compression disabled");
- break;
- }
- /* Enable compression after we have responded with SUCCESS. */
- enable_compression_after_reply = 1;
- success = 1;
- break;
+void
+do_authenticated(struct ssh *ssh, Authctxt *authctxt)
+{
+ setproctitle("%s", authctxt->pw->pw_name);
- case SSH_CMSG_REQUEST_PTY:
- success = session_pty_req(s);
- break;
+ auth_log_authopts("active", auth_opts, 0);
- case SSH_CMSG_X11_REQUEST_FORWARDING:
- s->auth_proto = packet_get_string(&proto_len);
- s->auth_data = packet_get_string(&data_len);
+ /* setup the channel layer */
+ /* XXX - streamlocal? */
+ set_fwdpermit_from_authopts(ssh, auth_opts);
- screen_flag = packet_get_protocol_flags() &
- SSH_PROTOFLAG_SCREEN_NUMBER;
- debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);
+ if (!auth_opts->permit_port_forwarding_flag ||
+ options.disable_forwarding) {
+ channel_disable_admin(ssh, FORWARD_LOCAL);
+ channel_disable_admin(ssh, FORWARD_REMOTE);
+ } else {
+ if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
+ channel_disable_admin(ssh, FORWARD_LOCAL);
+ else
+ channel_permit_all(ssh, FORWARD_LOCAL);
+ if ((options.allow_tcp_forwarding & FORWARD_REMOTE) == 0)
+ channel_disable_admin(ssh, FORWARD_REMOTE);
+ else
+ channel_permit_all(ssh, FORWARD_REMOTE);
+ }
+ auth_debug_send(ssh);
- if (packet_remaining() == 4) {
- if (!screen_flag)
- debug2("Buggy client: "
- "X11 screen flag missing");
- s->screen = packet_get_int();
- } else {
- s->screen = 0;
- }
- packet_check_eom();
- success = session_setup_x11fwd(s);
- if (!success) {
- free(s->auth_proto);
- free(s->auth_data);
- s->auth_proto = NULL;
- s->auth_data = NULL;
- }
- break;
+ prepare_auth_info_file(authctxt->pw, authctxt->session_info);
- case SSH_CMSG_AGENT_REQUEST_FORWARDING:
- if (!options.allow_agent_forwarding ||
- no_agent_forwarding_flag || compat13) {
- debug("Authentication agent forwarding not permitted for this authentication.");
- break;
- }
- debug("Received authentication agent forwarding request.");
- success = auth_input_request_forwarding(s->pw);
- break;
+ do_authenticated2(ssh, authctxt);
- case SSH_CMSG_PORT_FORWARD_REQUEST:
- if (no_port_forwarding_flag) {
- debug("Port forwarding not permitted for this authentication.");
- break;
- }
- if (!(options.allow_tcp_forwarding & FORWARD_REMOTE)) {
- debug("Port forwarding not permitted.");
- break;
- }
- debug("Received TCP/IP port forwarding request.");
- if (channel_input_port_forward_request(s->pw->pw_uid == 0,
- &options.fwd_opts) < 0) {
- debug("Port forwarding failed.");
- break;
- }
- success = 1;
- break;
+ do_cleanup(ssh, authctxt);
+}
- case SSH_CMSG_MAX_PACKET_SIZE:
- if (packet_set_maxsize(packet_get_int()) > 0)
- success = 1;
- break;
+/* Check untrusted xauth strings for metacharacters */
+static int
+xauth_valid_string(const char *s)
+{
+ size_t i;
- case SSH_CMSG_EXEC_SHELL:
- case SSH_CMSG_EXEC_CMD:
- if (type == SSH_CMSG_EXEC_CMD) {
- command = packet_get_string(&dlen);
- debug("Exec command '%.500s'", command);
- if (do_exec(s, command) != 0)
- packet_disconnect(
- "command execution failed");
- free(command);
- } else {
- if (do_exec(s, NULL) != 0)
- packet_disconnect(
- "shell execution failed");
- }
- packet_check_eom();
- session_close(s);
- return;
-
- default:
- /*
- * Any unknown messages in this phase are ignored,
- * and a failure message is returned.
- */
- logit("Unknown packet type received after authentication: %d", type);
- }
- packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
- packet_send();
- packet_write_wait();
-
- /* Enable compression now that we have replied if appropriate. */
- if (enable_compression_after_reply) {
- enable_compression_after_reply = 0;
- packet_start_compression(compression_level);
- }
+ for (i = 0; s[i] != '\0'; i++) {
+ if (!isalnum((u_char)s[i]) &&
+ s[i] != '.' && s[i] != ':' && s[i] != '/' &&
+ s[i] != '-' && s[i] != '_')
+ return 0;
}
+ return 1;
}
#define USE_PIPES 1
@@ -432,10 +389,9 @@ do_authenticated1(Authctxt *authctxt)
* setting up file descriptors and such.
*/
int
-do_exec_no_pty(Session *s, const char *command)
+do_exec_no_pty(struct ssh *ssh, Session *s, const char *command)
{
pid_t pid;
-
#ifdef USE_PIPES
int pin[2], pout[2], perr[2];
@@ -443,17 +399,17 @@ do_exec_no_pty(Session *s, const char *command)
fatal("do_exec_no_pty: no session");
/* Allocate pipes for communicating with the program. */
- if (pipe(pin) < 0) {
+ if (pipe(pin) == -1) {
error("%s: pipe in: %.100s", __func__, strerror(errno));
return -1;
}
- if (pipe(pout) < 0) {
+ if (pipe(pout) == -1) {
error("%s: pipe out: %.100s", __func__, strerror(errno));
close(pin[0]);
close(pin[1]);
return -1;
}
- if (pipe(perr) < 0) {
+ if (pipe(perr) == -1) {
error("%s: pipe err: %.100s", __func__,
strerror(errno));
close(pin[0]);
@@ -469,11 +425,11 @@ do_exec_no_pty(Session *s, const char *command)
fatal("do_exec_no_pty: no session");
/* Uses socket pairs to communicate with the program. */
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) == -1) {
error("%s: socketpair #1: %.100s", __func__, strerror(errno));
return -1;
}
- if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0) {
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, err) == -1) {
error("%s: socketpair #2: %.100s", __func__,
strerror(errno));
close(inout[0]);
@@ -505,15 +461,11 @@ do_exec_no_pty(Session *s, const char *command)
case 0:
is_child = 1;
- /* Child. Reinitialize the log since the pid has changed. */
- log_init(__progname, options.log_level,
- options.log_facility, log_stderr);
-
/*
* Create a new session and process group since the 4.4BSD
* setlogin() affects the entire process group.
*/
- if (setsid() < 0)
+ if (setsid() == -1)
error("setsid failed: %.100s", strerror(errno));
#ifdef USE_PIPES
@@ -522,19 +474,19 @@ do_exec_no_pty(Session *s, const char *command)
* pair, and make the child side the standard input.
*/
close(pin[1]);
- if (dup2(pin[0], 0) < 0)
+ if (dup2(pin[0], 0) == -1)
perror("dup2 stdin");
close(pin[0]);
/* Redirect stdout. */
close(pout[0]);
- if (dup2(pout[1], 1) < 0)
+ if (dup2(pout[1], 1) == -1)
perror("dup2 stdout");
close(pout[1]);
/* Redirect stderr. */
close(perr[0]);
- if (dup2(perr[1], 2) < 0)
+ if (dup2(perr[1], 2) == -1)
perror("dup2 stderr");
close(perr[1]);
#else
@@ -545,38 +497,30 @@ do_exec_no_pty(Session *s, const char *command)
*/
close(inout[1]);
close(err[1]);
- if (dup2(inout[0], 0) < 0) /* stdin */
+ if (dup2(inout[0], 0) == -1) /* stdin */
perror("dup2 stdin");
- if (dup2(inout[0], 1) < 0) /* stdout (same as stdin) */
+ if (dup2(inout[0], 1) == -1) /* stdout (same as stdin) */
perror("dup2 stdout");
close(inout[0]);
- if (dup2(err[0], 2) < 0) /* stderr */
+ if (dup2(err[0], 2) == -1) /* stderr */
perror("dup2 stderr");
close(err[0]);
#endif
-
-#ifdef _UNICOS
- cray_init_job(s->pw); /* set up cray jid and tmpdir */
-#endif
-
/* Do processing for the child (exec command etc). */
- do_child(s, command);
+ do_child(ssh, s, command);
/* NOTREACHED */
default:
break;
}
-#ifdef _UNICOS
- signal(WJSIGNAL, cray_job_termination_handler);
-#endif /* _UNICOS */
#ifdef HAVE_CYGWIN
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
s->pid = pid;
/* Set interactive/non-interactive mode. */
- packet_set_interactive(s->display != NULL,
+ ssh_packet_set_interactive(ssh, s->display != NULL,
options.ip_qos_interactive, options.ip_qos_bulk);
/*
@@ -584,7 +528,7 @@ do_exec_no_pty(Session *s, const char *command)
* it to the user, otherwise multiple sessions may accumulate
* multiple copies of the login messages.
*/
- buffer_clear(&loginmsg);
+ sshbuf_reset(loginmsg);
#ifdef USE_PIPES
/* We are the parent. Close the child sides of the pipes. */
@@ -592,14 +536,8 @@ do_exec_no_pty(Session *s, const char *command)
close(pout[1]);
close(perr[1]);
- if (compat20) {
- session_set_fds(s, pin[1], pout[0], perr[0],
- s->is_subsystem, 0);
- } else {
- /* Enter the interactive session. */
- server_loop(pid, pin[1], pout[0], perr[0]);
- /* server_loop has closed pin[1], pout[0], and perr[0]. */
- }
+ session_set_fds(ssh, s, pin[1], pout[0], perr[0],
+ s->is_subsystem, 0);
#else
/* We are the parent. Close the child sides of the socket pairs. */
close(inout[0]);
@@ -609,13 +547,8 @@ do_exec_no_pty(Session *s, const char *command)
* Enter the interactive session. Note: server_loop must be able to
* handle the case that fdin and fdout are the same.
*/
- if (compat20) {
- session_set_fds(s, inout[1], inout[1], err[1],
- s->is_subsystem, 0);
- } else {
- server_loop(pid, inout[1], inout[1], err[1]);
- /* server_loop has closed inout[1] and err[1]. */
- }
+ session_set_fds(ssh, s, inout[1], inout[1], err[1],
+ s->is_subsystem, 0);
#endif
return 0;
}
@@ -627,7 +560,7 @@ do_exec_no_pty(Session *s, const char *command)
* lastlog, and other such operations.
*/
int
-do_exec_pty(Session *s, const char *command)
+do_exec_pty(struct ssh *ssh, Session *s, const char *command)
{
int fdout, ptyfd, ttyfd, ptymaster;
pid_t pid;
@@ -644,14 +577,14 @@ do_exec_pty(Session *s, const char *command)
* Do this before forking (and cleanup in the child) so as to
* detect and gracefully fail out-of-fd conditions.
*/
- if ((fdout = dup(ptyfd)) < 0) {
+ if ((fdout = dup(ptyfd)) == -1) {
error("%s: dup #1: %s", __func__, strerror(errno));
close(ttyfd);
close(ptyfd);
return -1;
}
/* we keep a reference to the pty master */
- if ((ptymaster = dup(ptyfd)) < 0) {
+ if ((ptymaster = dup(ptyfd)) == -1) {
error("%s: dup #2: %s", __func__, strerror(errno));
close(ttyfd);
close(ptyfd);
@@ -674,9 +607,6 @@ do_exec_pty(Session *s, const char *command)
close(fdout);
close(ptymaster);
- /* Child. Reinitialize the log because the pid has changed. */
- log_init(__progname, options.log_level,
- options.log_facility, log_stderr);
/* Close the master side of the pseudo tty. */
close(ptyfd);
@@ -684,11 +614,11 @@ do_exec_pty(Session *s, const char *command)
pty_make_controlling_tty(&ttyfd, s->tty);
/* Redirect stdin/stdout/stderr from the pseudo tty. */
- if (dup2(ttyfd, 0) < 0)
+ if (dup2(ttyfd, 0) == -1)
error("dup2 stdin: %s", strerror(errno));
- if (dup2(ttyfd, 1) < 0)
+ if (dup2(ttyfd, 1) == -1)
error("dup2 stdout: %s", strerror(errno));
- if (dup2(ttyfd, 2) < 0)
+ if (dup2(ttyfd, 2) == -1)
error("dup2 stderr: %s", strerror(errno));
/* Close the extra descriptor for the pseudo tty. */
@@ -696,30 +626,18 @@ do_exec_pty(Session *s, const char *command)
/* record login, etc. similar to login(1) */
#ifndef HAVE_OSF_SIA
- if (!(options.use_login && command == NULL)) {
-#ifdef _UNICOS
- cray_init_job(s->pw); /* set up cray jid and tmpdir */
-#endif /* _UNICOS */
- do_login(s, command);
- }
-# ifdef LOGIN_NEEDS_UTMPX
- else
- do_pre_login(s);
-# endif
+ do_login(ssh, s, command);
#endif
/*
* Do common processing for the child, such as execing
* the command.
*/
- do_child(s, command);
+ do_child(ssh, s, command);
/* NOTREACHED */
default:
break;
}
-#ifdef _UNICOS
- signal(WJSIGNAL, cray_job_termination_handler);
-#endif /* _UNICOS */
#ifdef HAVE_CYGWIN
cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);
#endif
@@ -731,66 +649,35 @@ do_exec_pty(Session *s, const char *command)
/* Enter interactive session. */
s->ptymaster = ptymaster;
- packet_set_interactive(1,
+ ssh_packet_set_interactive(ssh, 1,
options.ip_qos_interactive, options.ip_qos_bulk);
- if (compat20) {
- session_set_fds(s, ptyfd, fdout, -1, 1, 1);
- } else {
- server_loop(pid, ptyfd, fdout, -1);
- /* server_loop _has_ closed ptyfd and fdout. */
- }
+ session_set_fds(ssh, s, ptyfd, fdout, -1, 1, 1);
return 0;
}
-#ifdef LOGIN_NEEDS_UTMPX
-static void
-do_pre_login(Session *s)
-{
- socklen_t fromlen;
- struct sockaddr_storage from;
- pid_t pid = getpid();
-
- /*
- * Get IP address of client. If the connection is not a socket, let
- * the address be 0.0.0.0.
- */
- memset(&from, 0, sizeof(from));
- fromlen = sizeof(from);
- if (packet_connection_is_on_socket()) {
- if (getpeername(packet_get_connection_in(),
- (struct sockaddr *)&from, &fromlen) < 0) {
- debug("getpeername: %.100s", strerror(errno));
- cleanup_exit(255);
- }
- }
-
- record_utmp_only(pid, s->tty, s->pw->pw_name,
- get_remote_name_or_ip(utmp_len, options.use_dns),
- (struct sockaddr *)&from, fromlen);
-}
-#endif
-
/*
* This is called to fork and execute a command. If another command is
* to be forced, execute that instead.
*/
int
-do_exec(Session *s, const char *command)
+do_exec(struct ssh *ssh, Session *s, const char *command)
{
int ret;
- const char *forced = NULL;
- char session_type[1024], *tty = NULL;
+ const char *forced = NULL, *tty = NULL;
+ char session_type[1024];
if (options.adm_forced_command) {
original_command = command;
command = options.adm_forced_command;
forced = "(config)";
- } else if (forced_command) {
+ } else if (auth_opts->force_command != NULL) {
original_command = command;
- command = forced_command;
+ command = auth_opts->force_command;
forced = "(key-option)";
}
+ s->forced = 0;
if (forced != NULL) {
+ s->forced = 1;
if (IS_INTERNAL_SFTP(command)) {
s->is_subsystem = s->is_subsystem ?
SUBSYSTEM_INT_SFTP : SUBSYSTEM_INT_SFTP_ERROR;
@@ -814,13 +701,14 @@ do_exec(Session *s, const char *command)
tty += 5;
}
- verbose("Starting session: %s%s%s for %s from %.200s port %d",
+ verbose("Starting session: %s%s%s for %s from %.200s port %d id %d",
session_type,
tty == NULL ? "" : " on ",
tty == NULL ? "" : tty,
s->pw->pw_name,
- get_remote_ipaddr(),
- get_remote_port());
+ ssh_remote_ipaddr(ssh),
+ ssh_remote_port(ssh),
+ s->self);
#ifdef SSH_AUDIT_EVENTS
if (command != NULL)
@@ -834,9 +722,9 @@ do_exec(Session *s, const char *command)
}
#endif
if (s->ttyfd != -1)
- ret = do_exec_pty(s, command);
+ ret = do_exec_pty(ssh, s, command);
else
- ret = do_exec_no_pty(s, command);
+ ret = do_exec_no_pty(ssh, s, command);
original_command = NULL;
@@ -845,14 +733,14 @@ do_exec(Session *s, const char *command)
* it to the user, otherwise multiple sessions may accumulate
* multiple copies of the login messages.
*/
- buffer_clear(&loginmsg);
+ sshbuf_reset(loginmsg);
return ret;
}
/* administrative, login(1)-like work */
void
-do_login(Session *s, const char *command)
+do_login(struct ssh *ssh, Session *s, const char *command)
{
socklen_t fromlen;
struct sockaddr_storage from;
@@ -865,9 +753,9 @@ do_login(Session *s, const char *command)
*/
memset(&from, 0, sizeof(from));
fromlen = sizeof(from);
- if (packet_connection_is_on_socket()) {
- if (getpeername(packet_get_connection_in(),
- (struct sockaddr *)&from, &fromlen) < 0) {
+ if (ssh_packet_connection_is_on_socket(ssh)) {
+ if (getpeername(ssh_packet_get_connection_in(ssh),
+ (struct sockaddr *)&from, &fromlen) == -1) {
debug("getpeername: %.100s", strerror(errno));
cleanup_exit(255);
}
@@ -876,7 +764,7 @@ do_login(Session *s, const char *command)
/* Record that there was a login on that tty from the remote host. */
if (!use_privsep)
record_login(pid, s->tty, pw->pw_name, pw->pw_uid,
- get_remote_name_or_ip(utmp_len,
+ session_get_remote_name_or_ip(ssh, utmp_len,
options.use_dns),
(struct sockaddr *)&from, fromlen);
@@ -951,87 +839,30 @@ check_quietlogin(Session *s, const char *command)
}
/*
- * Sets the value of the given variable in the environment. If the variable
- * already exists, its value is overridden.
- */
-void
-child_set_env(char ***envp, u_int *envsizep, const char *name,
- const char *value)
-{
- char **env;
- u_int envsize;
- u_int i, namelen;
-
- if (strchr(name, '=') != NULL) {
- error("Invalid environment variable \"%.100s\"", name);
- return;
- }
-
- /*
- * If we're passed an uninitialized list, allocate a single null
- * entry before continuing.
- */
- if (*envp == NULL && *envsizep == 0) {
- *envp = xmalloc(sizeof(char *));
- *envp[0] = NULL;
- *envsizep = 1;
- }
-
- /*
- * Find the slot where the value should be stored. If the variable
- * already exists, we reuse the slot; otherwise we append a new slot
- * at the end of the array, expanding if necessary.
- */
- env = *envp;
- namelen = strlen(name);
- for (i = 0; env[i]; i++)
- if (strncmp(env[i], name, namelen) == 0 && env[i][namelen] == '=')
- break;
- if (env[i]) {
- /* Reuse the slot. */
- free(env[i]);
- } else {
- /* New variable. Expand if necessary. */
- envsize = *envsizep;
- if (i >= envsize - 1) {
- if (envsize >= 1000)
- fatal("child_set_env: too many env vars");
- envsize += 50;
- env = (*envp) = xrealloc(env, envsize, sizeof(char *));
- *envsizep = envsize;
- }
- /* Need to set the NULL pointer at end of array beyond the new slot. */
- env[i + 1] = NULL;
- }
-
- /* Allocate space and format the variable in the appropriate slot. */
- env[i] = xmalloc(strlen(name) + 1 + strlen(value) + 1);
- snprintf(env[i], strlen(name) + 1 + strlen(value) + 1, "%s=%s", name, value);
-}
-
-/*
* Reads environment variables from the given file and adds/overrides them
* into the environment. If the file does not exist, this does nothing.
* Otherwise, it must consist of empty lines, comments (line starts with '#')
* and assignments of the form name=value. No other forms are allowed.
+ * If whitelist is not NULL, then it is interpreted as a pattern list and
+ * only variable names that match it will be accepted.
*/
static void
read_environment_file(char ***env, u_int *envsize,
- const char *filename)
+ const char *filename, const char *whitelist)
{
FILE *f;
- char buf[4096];
- char *cp, *value;
+ char *line = NULL, *cp, *value;
+ size_t linesize = 0;
u_int lineno = 0;
f = fopen(filename, "r");
if (!f)
return;
- while (fgets(buf, sizeof(buf), f)) {
+ while (getline(&line, &linesize, f) != -1) {
if (++lineno > 1000)
fatal("Too many lines in environment file %s", filename);
- for (cp = buf; *cp == ' ' || *cp == '\t'; cp++)
+ for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
;
if (!*cp || *cp == '#' || *cp == '\n')
continue;
@@ -1050,8 +881,12 @@ read_environment_file(char ***env, u_int *envsize,
*/
*value = '\0';
value++;
+ if (whitelist != NULL &&
+ match_pattern_list(cp, whitelist, 0) != 1)
+ continue;
child_set_env(env, envsize, cp, value);
}
+ free(line);
fclose(f);
}
@@ -1088,7 +923,8 @@ read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
* so we use a temporary environment and copy the variables we're
* interested in.
*/
- read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login");
+ read_environment_file(&tmpenv, &tmpenvsize, "/etc/default/login",
+ options.permit_user_env_whitelist);
if (tmpenv == NULL)
return;
@@ -1110,8 +946,10 @@ read_etc_default_login(char ***env, u_int *envsize, uid_t uid)
}
#endif /* HAVE_ETC_DEFAULT_LOGIN */
-void
-copy_environment(char **source, char ***env, u_int *envsize)
+#if defined(USE_PAM) || defined(HAVE_CYGWIN)
+static void
+copy_environment_blacklist(char **source, char ***env, u_int *envsize,
+ const char *blacklist)
{
char *var_name, *var_val;
int i;
@@ -1127,19 +965,32 @@ copy_environment(char **source, char ***env, u_int *envsize)
}
*var_val++ = '\0';
- debug3("Copy environment: %s=%s", var_name, var_val);
- child_set_env(env, envsize, var_name, var_val);
+ if (blacklist == NULL ||
+ match_pattern_list(var_name, blacklist, 0) != 1) {
+ debug3("Copy environment: %s=%s", var_name, var_val);
+ child_set_env(env, envsize, var_name, var_val);
+ }
free(var_name);
}
}
+#endif /* defined(USE_PAM) || defined(HAVE_CYGWIN) */
+
+#ifdef HAVE_CYGWIN
+static void
+copy_environment(char **source, char ***env, u_int *envsize)
+{
+ copy_environment_blacklist(source, env, envsize, NULL);
+}
+#endif
static char **
-do_setup_env(Session *s, const char *shell)
+do_setup_env(struct ssh *ssh, Session *s, const char *shell)
{
char buf[256];
+ size_t n;
u_int i, envsize;
- char **env, *laddr;
+ char *ocp, *cp, *value, **env, *laddr;
struct passwd *pw = s->pw;
#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
char *path = NULL;
@@ -1166,103 +1017,62 @@ do_setup_env(Session *s, const char *shell)
#ifdef GSSAPI
/* Allow any GSSAPI methods that we've used to alter
- * the childs environment as they see fit
+ * the child's environment as they see fit
*/
ssh_gssapi_do_child(&env, &envsize);
#endif
- if (!options.use_login) {
- /* Set basic environment. */
- for (i = 0; i < s->num_env; i++)
- child_set_env(&env, &envsize, s->env[i].name,
- s->env[i].val);
+ /* Set basic environment. */
+ for (i = 0; i < s->num_env; i++)
+ child_set_env(&env, &envsize, s->env[i].name, s->env[i].val);
- child_set_env(&env, &envsize, "USER", pw->pw_name);
- child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
+ child_set_env(&env, &envsize, "USER", pw->pw_name);
+ child_set_env(&env, &envsize, "LOGNAME", pw->pw_name);
#ifdef _AIX
- child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
+ child_set_env(&env, &envsize, "LOGIN", pw->pw_name);
#endif
- child_set_env(&env, &envsize, "HOME", pw->pw_dir);
+ child_set_env(&env, &envsize, "HOME", pw->pw_dir);
#ifdef HAVE_LOGIN_CAP
- if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
- child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
- else
- child_set_env(&env, &envsize, "PATH", getenv("PATH"));
+ if (setusercontext(lc, pw, pw->pw_uid, LOGIN_SETPATH) < 0)
+ child_set_env(&env, &envsize, "PATH", _PATH_STDPATH);
+ else
+ child_set_env(&env, &envsize, "PATH", getenv("PATH"));
#else /* HAVE_LOGIN_CAP */
# ifndef HAVE_CYGWIN
- /*
- * There's no standard path on Windows. The path contains
- * important components pointing to the system directories,
- * needed for loading shared libraries. So the path better
- * remains intact here.
- */
+ /*
+ * There's no standard path on Windows. The path contains
+ * important components pointing to the system directories,
+ * needed for loading shared libraries. So the path better
+ * remains intact here.
+ */
# ifdef HAVE_ETC_DEFAULT_LOGIN
- read_etc_default_login(&env, &envsize, pw->pw_uid);
- path = child_get_env(env, "PATH");
+ read_etc_default_login(&env, &envsize, pw->pw_uid);
+ path = child_get_env(env, "PATH");
# endif /* HAVE_ETC_DEFAULT_LOGIN */
- if (path == NULL || *path == '\0') {
- child_set_env(&env, &envsize, "PATH",
- s->pw->pw_uid == 0 ?
- SUPERUSER_PATH : _PATH_STDPATH);
- }
+ if (path == NULL || *path == '\0') {
+ child_set_env(&env, &envsize, "PATH",
+ s->pw->pw_uid == 0 ? SUPERUSER_PATH : _PATH_STDPATH);
+ }
# endif /* HAVE_CYGWIN */
#endif /* HAVE_LOGIN_CAP */
-#ifndef ANDROID
+#if !defined(ANDROID)
+ if (!options.use_pam) {
snprintf(buf, sizeof buf, "%.200s/%.50s",
- _PATH_MAILDIR, pw->pw_name);
+ _PATH_MAILDIR, pw->pw_name);
child_set_env(&env, &envsize, "MAIL", buf);
+ }
#endif
- /* Normal systems set SHELL by default. */
- child_set_env(&env, &envsize, "SHELL", shell);
- }
+ /* Normal systems set SHELL by default. */
+ child_set_env(&env, &envsize, "SHELL", shell);
+
if (getenv("TZ"))
child_set_env(&env, &envsize, "TZ", getenv("TZ"));
-
- /* Set custom environment options from RSA authentication. */
- if (!options.use_login) {
- while (custom_environment) {
- struct envstring *ce = custom_environment;
- char *str = ce->s;
-
- for (i = 0; str[i] != '=' && str[i]; i++)
- ;
- if (str[i] == '=') {
- str[i] = 0;
- child_set_env(&env, &envsize, str, str + i + 1);
- }
- custom_environment = ce->next;
- free(ce->s);
- free(ce);
- }
- }
-
- /* SSH_CLIENT deprecated */
- snprintf(buf, sizeof buf, "%.50s %d %d",
- get_remote_ipaddr(), get_remote_port(), get_local_port());
- child_set_env(&env, &envsize, "SSH_CLIENT", buf);
-
- laddr = get_local_ipaddr(packet_get_connection_in());
- snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
- get_remote_ipaddr(), get_remote_port(), laddr, get_local_port());
- free(laddr);
- child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
-
- if (s->ttyfd != -1)
- child_set_env(&env, &envsize, "SSH_TTY", s->tty);
if (s->term)
child_set_env(&env, &envsize, "TERM", s->term);
if (s->display)
child_set_env(&env, &envsize, "DISPLAY", s->display);
- if (original_command)
- child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
- original_command);
-
-#ifdef _UNICOS
- if (cray_tmpdir[0] != '\0')
- child_set_env(&env, &envsize, "TMPDIR", cray_tmpdir);
-#endif /* _UNICOS */
/*
* Since we clear KRB5CCNAME at startup, if it's set now then it
@@ -1282,7 +1092,8 @@ do_setup_env(Session *s, const char *shell)
if ((cp = getenv("AUTHSTATE")) != NULL)
child_set_env(&env, &envsize, "AUTHSTATE", cp);
- read_environment_file(&env, &envsize, "/etc/environment");
+ read_environment_file(&env, &envsize, "/etc/environment",
+ options.permit_user_env_whitelist);
}
#endif
#ifdef KRB5
@@ -1290,6 +1101,37 @@ do_setup_env(Session *s, const char *shell)
child_set_env(&env, &envsize, "KRB5CCNAME",
s->authctxt->krb5_ccname);
#endif
+ if (auth_sock_name != NULL)
+ child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
+ auth_sock_name);
+
+
+ /* Set custom environment options from pubkey authentication. */
+ if (options.permit_user_env) {
+ for (n = 0 ; n < auth_opts->nenv; n++) {
+ ocp = xstrdup(auth_opts->env[n]);
+ cp = strchr(ocp, '=');
+ if (*cp == '=') {
+ *cp = '\0';
+ /* Apply PermitUserEnvironment whitelist */
+ if (options.permit_user_env_whitelist == NULL ||
+ match_pattern_list(ocp,
+ options.permit_user_env_whitelist, 0) == 1)
+ child_set_env(&env, &envsize,
+ ocp, cp + 1);
+ }
+ free(ocp);
+ }
+ }
+
+ /* read $HOME/.ssh/environment. */
+ if (options.permit_user_env) {
+ snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
+ pw->pw_dir);
+ read_environment_file(&env, &envsize, buf,
+ options.permit_user_env_whitelist);
+ }
+
#ifdef USE_PAM
/*
* Pull in any environment variables that may have
@@ -1298,26 +1140,57 @@ do_setup_env(Session *s, const char *shell)
if (options.use_pam) {
char **p;
+ /*
+ * Don't allow PAM-internal env vars to leak
+ * back into the session environment.
+ */
+#define PAM_ENV_BLACKLIST "SSH_AUTH_INFO*,SSH_CONNECTION*"
p = fetch_pam_child_environment();
- copy_environment(p, &env, &envsize);
+ copy_environment_blacklist(p, &env, &envsize,
+ PAM_ENV_BLACKLIST);
free_pam_environment(p);
p = fetch_pam_environment();
- copy_environment(p, &env, &envsize);
+ copy_environment_blacklist(p, &env, &envsize,
+ PAM_ENV_BLACKLIST);
free_pam_environment(p);
}
#endif /* USE_PAM */
- if (auth_sock_name != NULL)
- child_set_env(&env, &envsize, SSH_AUTHSOCKET_ENV_NAME,
- auth_sock_name);
-
- /* read $HOME/.ssh/environment. */
- if (options.permit_user_env && !options.use_login) {
- snprintf(buf, sizeof buf, "%.200s/.ssh/environment",
- strcmp(pw->pw_dir, "/") ? pw->pw_dir : "");
- read_environment_file(&env, &envsize, buf);
+ /* Environment specified by admin */
+ for (i = 0; i < options.num_setenv; i++) {
+ cp = xstrdup(options.setenv[i]);
+ if ((value = strchr(cp, '=')) == NULL) {
+ /* shouldn't happen; vars are checked in servconf.c */
+ fatal("Invalid config SetEnv: %s", options.setenv[i]);
+ }
+ *value++ = '\0';
+ child_set_env(&env, &envsize, cp, value);
}
+
+ /* SSH_CLIENT deprecated */
+ snprintf(buf, sizeof buf, "%.50s %d %d",
+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
+ ssh_local_port(ssh));
+ child_set_env(&env, &envsize, "SSH_CLIENT", buf);
+
+ laddr = get_local_ipaddr(ssh_packet_get_connection_in(ssh));
+ snprintf(buf, sizeof buf, "%.50s %d %.50s %d",
+ ssh_remote_ipaddr(ssh), ssh_remote_port(ssh),
+ laddr, ssh_local_port(ssh));
+ free(laddr);
+ child_set_env(&env, &envsize, "SSH_CONNECTION", buf);
+
+ if (tun_fwd_ifnames != NULL)
+ child_set_env(&env, &envsize, "SSH_TUNNEL", tun_fwd_ifnames);
+ if (auth_info_file != NULL)
+ child_set_env(&env, &envsize, "SSH_USER_AUTH", auth_info_file);
+ if (s->ttyfd != -1)
+ child_set_env(&env, &envsize, "SSH_TTY", s->tty);
+ if (original_command)
+ child_set_env(&env, &envsize, "SSH_ORIGINAL_COMMAND",
+ original_command);
+
if (debug_flag) {
/* dump the environment */
fprintf(stderr, "Environment:\n");
@@ -1332,7 +1205,7 @@ do_setup_env(Session *s, const char *shell)
* first in this order).
*/
static void
-do_rc_files(Session *s, const char *shell)
+do_rc_files(struct ssh *ssh, Session *s, const char *shell)
{
FILE *f = NULL;
char cmd[1024];
@@ -1344,7 +1217,7 @@ do_rc_files(Session *s, const char *shell)
/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
if (!s->is_subsystem && options.adm_forced_command == NULL &&
- !no_user_rc && options.permit_user_rc &&
+ auth_opts->permit_user_rc && options.permit_user_rc &&
stat(_PATH_SSH_USER_RC, &st) >= 0) {
snprintf(cmd, sizeof cmd, "%s -c '%s %s'",
shell, _PATH_BSHELL, _PATH_SSH_USER_RC);
@@ -1425,10 +1298,10 @@ do_nologin(struct passwd *pw)
/* /etc/nologin exists. Print its contents if we can and exit. */
logit("User %.100s not allowed because %s exists", pw->pw_name, nl);
if ((f = fopen(nl, "r")) != NULL) {
- while (fgets(buf, sizeof(buf), f))
- fputs(buf, stderr);
- fclose(f);
- }
+ while (fgets(buf, sizeof(buf), f))
+ fputs(buf, stderr);
+ fclose(f);
+ }
exit(254);
}
@@ -1443,7 +1316,7 @@ safely_chroot(const char *path, uid_t uid)
char component[PATH_MAX];
struct stat st;
- if (*path != '/')
+ if (!path_absolute(path))
fatal("chroot path does not begin at root");
if (strlen(path) >= sizeof(component))
fatal("chroot path too long");
@@ -1468,7 +1341,7 @@ safely_chroot(const char *path, uid_t uid)
component, strerror(errno));
if (st.st_uid != 0 || (st.st_mode & 022) != 0)
fatal("bad ownership or modes for chroot "
- "directory %s\"%s\"",
+ "directory %s\"%s\"",
cp == NULL ? "" : "component ", component);
if (!S_ISDIR(st.st_mode))
fatal("chroot path %s\"%s\" is not a directory",
@@ -1491,10 +1364,7 @@ safely_chroot(const char *path, uid_t uid)
void
do_setusercontext(struct passwd *pw)
{
- char *chroot_path, *tmp;
-#ifdef USE_LIBIAF
- int doing_chroot = 0;
-#endif
+ char uidstr[32], *chroot_path, *tmp;
platform_setusercontext(pw);
@@ -1517,28 +1387,26 @@ do_setusercontext(struct passwd *pw)
perror("initgroups");
exit(1);
}
-#if !defined(ANDROID)
endgrent();
#endif
-#endif
platform_setusercontext_post_groups(pw);
- if (options.chroot_directory != NULL &&
+ if (!in_chroot && options.chroot_directory != NULL &&
strcasecmp(options.chroot_directory, "none") != 0) {
tmp = tilde_expand_filename(options.chroot_directory,
pw->pw_uid);
+ snprintf(uidstr, sizeof(uidstr), "%llu",
+ (unsigned long long)pw->pw_uid);
chroot_path = percent_expand(tmp, "h", pw->pw_dir,
- "u", pw->pw_name, (char *)NULL);
+ "u", pw->pw_name, "U", uidstr, (char *)NULL);
safely_chroot(chroot_path, pw->pw_uid);
free(tmp);
free(chroot_path);
/* Make sure we don't attempt to chroot again */
free(options.chroot_directory);
options.chroot_directory = NULL;
-#ifdef USE_LIBIAF
- doing_chroot = 1;
-#endif
+ in_chroot = 1;
}
#ifdef HAVE_LOGIN_CAP
@@ -1553,16 +1421,16 @@ do_setusercontext(struct passwd *pw)
(void) setusercontext(lc, pw, pw->pw_uid, LOGIN_SETUMASK);
#else
# ifdef USE_LIBIAF
-/* In a chroot environment, the set_id() will always fail; typically
- * because of the lack of necessary authentication services and runtime
- * such as ./usr/lib/libiaf.so, ./usr/lib/libpam.so.1, and ./etc/passwd
- * We skip it in the internal sftp chroot case.
- * We'll lose auditing and ACLs but permanently_set_uid will
- * take care of the rest.
- */
- if ((doing_chroot == 0) && set_id(pw->pw_name) != 0) {
- fatal("set_id(%s) Failed", pw->pw_name);
- }
+ /*
+ * In a chroot environment, the set_id() will always fail;
+ * typically because of the lack of necessary authentication
+ * services and runtime such as ./usr/lib/libiaf.so,
+ * ./usr/lib/libpam.so.1, and ./etc/passwd We skip it in the
+ * internal sftp chroot case. We'll lose auditing and ACLs but
+ * permanently_set_uid will take care of the rest.
+ */
+ if (!in_chroot && set_id(pw->pw_name) != 0)
+ fatal("set_id(%s) Failed", pw->pw_name);
# endif /* USE_LIBIAF */
/* Permanently switch to the desired uid. */
permanently_set_uid(pw);
@@ -1602,28 +1470,7 @@ do_pwchange(Session *s)
}
static void
-launch_login(struct passwd *pw, const char *hostname)
-{
- /* Launch login(1). */
-
- execl(LOGIN_PROGRAM, "login", "-h", hostname,
-#ifdef xxxLOGIN_NEEDS_TERM
- (s->term ? s->term : "unknown"),
-#endif /* LOGIN_NEEDS_TERM */
-#ifdef LOGIN_NO_ENDOPT
- "-p", "-f", pw->pw_name, (char *)NULL);
-#else
- "-p", "-f", "--", pw->pw_name, (char *)NULL);
-#endif
-
- /* Login couldn't be executed, die. */
-
- perror("login");
- exit(1);
-}
-
-static void
-child_close_fds(void)
+child_close_fds(struct ssh *ssh)
{
extern int auth_sock;
@@ -1632,26 +1479,25 @@ child_close_fds(void)
auth_sock = -1;
}
- if (packet_get_connection_in() == packet_get_connection_out())
- close(packet_get_connection_in());
+ if (ssh_packet_get_connection_in(ssh) ==
+ ssh_packet_get_connection_out(ssh))
+ close(ssh_packet_get_connection_in(ssh));
else {
- close(packet_get_connection_in());
- close(packet_get_connection_out());
+ close(ssh_packet_get_connection_in(ssh));
+ close(ssh_packet_get_connection_out(ssh));
}
/*
* Close all descriptors related to channels. They will still remain
* open in the parent.
*/
/* XXX better use close-on-exec? -markus */
- channel_close_all();
+ channel_close_all(ssh);
-#if !defined(ANDROID)
/*
* Close any extra file descriptors. Note that there may still be
* descriptors left by system functions. They will be closed later.
*/
endpwent();
-#endif
/*
* Close any extra open file descriptors so that we don't have them
@@ -1669,60 +1515,52 @@ child_close_fds(void)
*/
#define ARGV_MAX 10
void
-do_child(Session *s, const char *command)
+do_child(struct ssh *ssh, Session *s, const char *command)
{
extern char **environ;
- char **env;
- char *argv[ARGV_MAX];
- const char *shell, *shell0, *hostname = NULL;
+ char **env, *argv[ARGV_MAX], remote_id[512];
+ const char *shell, *shell0;
struct passwd *pw = s->pw;
int r = 0;
+ sshpkt_fmt_connection_id(ssh, remote_id, sizeof(remote_id));
+
/* remove hostkey from the child's memory */
destroy_sensitive_data();
+ ssh_packet_clear_keys(ssh);
/* Force a password change */
if (s->authctxt->force_pwchange) {
do_setusercontext(pw);
- child_close_fds();
+ child_close_fds(ssh);
do_pwchange(s);
exit(1);
}
- /* login(1) is only called if we execute the login shell */
- if (options.use_login && command != NULL)
- options.use_login = 0;
-
-#ifdef _UNICOS
- cray_setup(pw->pw_uid, pw->pw_name, command);
-#endif /* _UNICOS */
-
/*
* Login(1) does this as well, and it needs uid 0 for the "-h"
* switch, so we let login(1) to this for us.
*/
- if (!options.use_login) {
#ifdef HAVE_OSF_SIA
- session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
- if (!check_quietlogin(s, command))
- do_motd();
+ session_setup_sia(pw, s->ttyfd == -1 ? NULL : s->tty);
+ if (!check_quietlogin(s, command))
+ do_motd();
#else /* HAVE_OSF_SIA */
- /* When PAM is enabled we rely on it to do the nologin check */
- if (!options.use_pam)
- do_nologin(pw);
- do_setusercontext(pw);
- /*
- * PAM session modules in do_setusercontext may have
- * generated messages, so if this in an interactive
- * login then display them too.
- */
- if (!check_quietlogin(s, command))
- display_loginmsg();
+ /* When PAM is enabled we rely on it to do the nologin check */
+ if (!options.use_pam)
+ do_nologin(pw);
+ do_setusercontext(pw);
+ /*
+ * PAM session modules in do_setusercontext may have
+ * generated messages, so if this in an interactive
+ * login then display them too.
+ */
+ if (!check_quietlogin(s, command))
+ display_loginmsg();
#endif /* HAVE_OSF_SIA */
- }
#ifdef USE_PAM
- if (options.use_pam && !options.use_login && !is_pam_session_open()) {
+ if (options.use_pam && !is_pam_session_open()) {
debug3("PAM session not opened, exiting");
display_loginmsg();
exit(254);
@@ -1739,24 +1577,20 @@ do_child(Session *s, const char *command)
* Make sure $SHELL points to the shell from the password file,
* even if shell is overridden from login.conf
*/
- env = do_setup_env(s, shell);
+ env = do_setup_env(ssh, s, shell);
#ifdef HAVE_LOGIN_CAP
shell = login_getcapstr(lc, "shell", (char *)shell, (char *)shell);
#endif
- /* we have to stash the hostname before we close our socket. */
- if (options.use_login)
- hostname = get_remote_name_or_ip(utmp_len,
- options.use_dns);
/*
* Close the connection descriptors; note that this is the child, and
* the server will still have the socket open, and it is important
* that we do not shutdown it. Note that the descriptors cannot be
* closed before building the environment, as we call
- * get_remote_ipaddr there.
+ * ssh_remote_ipaddr there.
*/
- child_close_fds();
+ child_close_fds(ssh);
/*
* Must take new environment into use so that .ssh/rc,
@@ -1791,29 +1625,30 @@ do_child(Session *s, const char *command)
#endif
/* Change current directory to the user's home directory. */
- if (chdir(pw->pw_dir) < 0) {
+ if (chdir(pw->pw_dir) == -1) {
/* Suppress missing homedir warning for chroot case */
#ifdef HAVE_LOGIN_CAP
r = login_getcapbool(lc, "requirehome", 0);
#endif
- if (r || options.chroot_directory == NULL ||
- strcasecmp(options.chroot_directory, "none") == 0)
+ if (r || !in_chroot) {
fprintf(stderr, "Could not chdir to home "
"directory %s: %s\n", pw->pw_dir,
strerror(errno));
+ }
if (r)
exit(1);
}
closefrom(STDERR_FILENO + 1);
- if (!options.use_login)
- do_rc_files(s, shell);
+ do_rc_files(ssh, s, shell);
/* restore SIGPIPE for child */
- signal(SIGPIPE, SIG_DFL);
+ ssh_signal(SIGPIPE, SIG_DFL);
if (s->is_subsystem == SUBSYSTEM_INT_SFTP_ERROR) {
+ error("Connection from %s: refusing non-sftp session",
+ remote_id);
printf("This service allows sftp connections only.\n");
fflush(NULL);
exit(1);
@@ -1838,11 +1673,6 @@ do_child(Session *s, const char *command)
fflush(NULL);
- if (options.use_login) {
- launch_login(pw, hostname);
- /* NEVERREACHED */
- }
-
/* Get the last component of the shell name. */
if ((shell0 = strrchr(shell, '/')) != NULL)
shell0++;
@@ -1920,8 +1750,8 @@ session_new(void)
return NULL;
debug2("%s: allocate (allocated %d max %d)",
__func__, sessions_nalloc, options.max_sessions);
- tmp = xrealloc(sessions, sessions_nalloc + 1,
- sizeof(*sessions));
+ tmp = xrecallocarray(sessions, sessions_nalloc,
+ sessions_nalloc + 1, sizeof(*sessions));
if (tmp == NULL) {
error("%s: cannot allocate %d sessions",
__func__, sessions_nalloc + 1);
@@ -2059,43 +1889,40 @@ session_by_pid(pid_t pid)
}
static int
-session_window_change_req(Session *s)
+session_window_change_req(struct ssh *ssh, Session *s)
{
- s->col = packet_get_int();
- s->row = packet_get_int();
- s->xpixel = packet_get_int();
- s->ypixel = packet_get_int();
- packet_check_eom();
+ int r;
+
+ if ((r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
return 1;
}
static int
-session_pty_req(Session *s)
+session_pty_req(struct ssh *ssh, Session *s)
{
- u_int len;
- int n_bytes;
+ int r;
- if (no_pty_flag || !options.permit_tty) {
- debug("Allocating a pty not permitted for this authentication.");
+ if (!auth_opts->permit_pty_flag || !options.permit_tty) {
+ debug("Allocating a pty not permitted for this connection.");
return 0;
}
if (s->ttyfd != -1) {
- packet_disconnect("Protocol error: you already have a pty.");
+ ssh_packet_disconnect(ssh, "Protocol error: you already have a pty.");
return 0;
}
- s->term = packet_get_string(&len);
-
- if (compat20) {
- s->col = packet_get_int();
- s->row = packet_get_int();
- } else {
- s->row = packet_get_int();
- s->col = packet_get_int();
- }
- s->xpixel = packet_get_int();
- s->ypixel = packet_get_int();
+ if ((r = sshpkt_get_cstring(ssh, &s->term, NULL)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->col)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->row)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->xpixel)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->ypixel)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (strcmp(s->term, "") == 0) {
free(s->term);
@@ -2115,10 +1942,10 @@ session_pty_req(Session *s)
}
debug("session_pty_req: session %d alloc %s", s->self, s->tty);
- /* for SSH1 the tty modes length is not given */
- if (!compat20)
- n_bytes = packet_remaining();
- tty_parse_modes(s->ttyfd, &n_bytes);
+ ssh_tty_parse_modes(ssh, s->ttyfd);
+
+ if ((r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
if (!use_privsep)
pty_setowner(s->pw, s->tty);
@@ -2126,22 +1953,21 @@ session_pty_req(Session *s)
/* Set window size from the packet. */
pty_change_window_size(s->ptyfd, s->row, s->col, s->xpixel, s->ypixel);
- packet_check_eom();
session_proctitle(s);
return 1;
}
static int
-session_subsystem_req(Session *s)
+session_subsystem_req(struct ssh *ssh, Session *s)
{
struct stat st;
- u_int len;
- int success = 0;
+ int r, success = 0;
char *prog, *cmd;
u_int i;
- s->subsys = packet_get_string(&len);
- packet_check_eom();
+ if ((r = sshpkt_get_cstring(ssh, &s->subsys, NULL)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
debug2("subsystem request for %.100s by user %s", s->subsys,
s->pw->pw_name);
@@ -2153,13 +1979,13 @@ session_subsystem_req(Session *s)
s->is_subsystem = SUBSYSTEM_INT_SFTP;
debug("subsystem: %s", prog);
} else {
- if (stat(prog, &st) < 0)
+ if (stat(prog, &st) == -1)
debug("subsystem: cannot stat %s: %s",
prog, strerror(errno));
s->is_subsystem = SUBSYSTEM_EXT;
debug("subsystem: exec() %s", cmd);
}
- success = do_exec(s, cmd) == 0;
+ success = do_exec(ssh, s, cmd) == 0;
break;
}
}
@@ -2172,22 +1998,32 @@ session_subsystem_req(Session *s)
}
static int
-session_x11_req(Session *s)
+session_x11_req(struct ssh *ssh, Session *s)
{
- int success;
+ int r, success;
+ u_char single_connection = 0;
if (s->auth_proto != NULL || s->auth_data != NULL) {
error("session_x11_req: session %d: "
"x11 forwarding already active", s->self);
return 0;
}
- s->single_connection = packet_get_char();
- s->auth_proto = packet_get_string(NULL);
- s->auth_data = packet_get_string(NULL);
- s->screen = packet_get_int();
- packet_check_eom();
+ if ((r = sshpkt_get_u8(ssh, &single_connection)) != 0 ||
+ (r = sshpkt_get_cstring(ssh, &s->auth_proto, NULL)) != 0 ||
+ (r = sshpkt_get_cstring(ssh, &s->auth_data, NULL)) != 0 ||
+ (r = sshpkt_get_u32(ssh, &s->screen)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
+
+ s->single_connection = single_connection;
- success = session_setup_x11fwd(s);
+ if (xauth_valid_string(s->auth_proto) &&
+ xauth_valid_string(s->auth_data))
+ success = session_setup_x11fwd(ssh, s);
+ else {
+ success = 0;
+ error("Invalid X11 forwarding data");
+ }
if (!success) {
free(s->auth_proto);
free(s->auth_data);
@@ -2198,45 +2034,56 @@ session_x11_req(Session *s)
}
static int
-session_shell_req(Session *s)
+session_shell_req(struct ssh *ssh, Session *s)
{
- packet_check_eom();
- return do_exec(s, NULL) == 0;
+ int r;
+
+ if ((r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
+ return do_exec(ssh, s, NULL) == 0;
}
static int
-session_exec_req(Session *s)
+session_exec_req(struct ssh *ssh, Session *s)
{
- u_int len, success;
+ u_int success;
+ int r;
+ char *command = NULL;
+
+ if ((r = sshpkt_get_cstring(ssh, &command, NULL)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
- char *command = packet_get_string(&len);
- packet_check_eom();
- success = do_exec(s, command) == 0;
+ success = do_exec(ssh, s, command) == 0;
free(command);
return success;
}
static int
-session_break_req(Session *s)
+session_break_req(struct ssh *ssh, Session *s)
{
+ int r;
- packet_get_int(); /* ignored */
- packet_check_eom();
+ if ((r = sshpkt_get_u32(ssh, NULL)) != 0 || /* ignore */
+ (r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
- if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) < 0)
+ if (s->ptymaster == -1 || tcsendbreak(s->ptymaster, 0) == -1)
return 0;
return 1;
}
static int
-session_env_req(Session *s)
+session_env_req(struct ssh *ssh, Session *s)
{
char *name, *val;
- u_int name_len, val_len, i;
+ u_int i;
+ int r;
- name = packet_get_cstring(&name_len);
- val = packet_get_cstring(&val_len);
- packet_check_eom();
+ if ((r = sshpkt_get_cstring(ssh, &name, NULL)) != 0 ||
+ (r = sshpkt_get_cstring(ssh, &val, NULL)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
/* Don't set too many environment variables */
if (s->num_env > 128) {
@@ -2247,8 +2094,8 @@ session_env_req(Session *s)
for (i = 0; i < options.num_accept_env; i++) {
if (match_pattern(name, options.accept_env[i])) {
debug2("Setting env %d: %s=%s", s->num_env, name, val);
- s->env = xrealloc(s->env, s->num_env + 1,
- sizeof(*s->env));
+ s->env = xrecallocarray(s->env, s->num_env,
+ s->num_env + 1, sizeof(*s->env));
s->env[s->num_env].name = name;
s->env[s->num_env].val = val;
s->num_env++;
@@ -2263,35 +2110,110 @@ session_env_req(Session *s)
return (0);
}
+/*
+ * Conversion of signals from ssh channel request names.
+ * Subset of signals from RFC 4254 section 6.10C, with SIGINFO as
+ * local extension.
+ */
static int
-session_auth_agent_req(Session *s)
+name2sig(char *name)
+{
+#define SSH_SIG(x) if (strcmp(name, #x) == 0) return SIG ## x
+ SSH_SIG(HUP);
+ SSH_SIG(INT);
+ SSH_SIG(KILL);
+ SSH_SIG(QUIT);
+ SSH_SIG(TERM);
+ SSH_SIG(USR1);
+ SSH_SIG(USR2);
+#undef SSH_SIG
+#ifdef SIGINFO
+ if (strcmp(name, "INFO@openssh.com") == 0)
+ return SIGINFO;
+#endif
+ return -1;
+}
+
+static int
+session_signal_req(struct ssh *ssh, Session *s)
+{
+ char *signame = NULL;
+ int r, sig, success = 0;
+
+ if ((r = sshpkt_get_cstring(ssh, &signame, NULL)) != 0 ||
+ (r = sshpkt_get_end(ssh)) != 0) {
+ error("%s: parse packet: %s", __func__, ssh_err(r));
+ goto out;
+ }
+ if ((sig = name2sig(signame)) == -1) {
+ error("%s: unsupported signal \"%s\"", __func__, signame);
+ goto out;
+ }
+ if (s->pid <= 0) {
+ error("%s: no pid for session %d", __func__, s->self);
+ goto out;
+ }
+ if (s->forced || s->is_subsystem) {
+ error("%s: refusing to send signal %s to %s session", __func__,
+ signame, s->forced ? "forced-command" : "subsystem");
+ goto out;
+ }
+ if (!use_privsep || mm_is_monitor()) {
+ error("%s: session signalling requires privilege separation",
+ __func__);
+ goto out;
+ }
+
+ debug("%s: signal %s, killpg(%ld, %d)", __func__, signame,
+ (long)s->pid, sig);
+ temporarily_use_uid(s->pw);
+ r = killpg(s->pid, sig);
+ restore_uid();
+ if (r != 0) {
+ error("%s: killpg(%ld, %d): %s", __func__, (long)s->pid,
+ sig, strerror(errno));
+ goto out;
+ }
+
+ /* success */
+ success = 1;
+ out:
+ free(signame);
+ return success;
+}
+
+static int
+session_auth_agent_req(struct ssh *ssh, Session *s)
{
static int called = 0;
- packet_check_eom();
- if (no_agent_forwarding_flag || !options.allow_agent_forwarding) {
- debug("session_auth_agent_req: no_agent_forwarding_flag");
+ int r;
+
+ if ((r = sshpkt_get_end(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: parse packet", __func__);
+ if (!auth_opts->permit_agent_forwarding_flag ||
+ !options.allow_agent_forwarding) {
+ debug("%s: agent forwarding disabled", __func__);
return 0;
}
if (called) {
return 0;
} else {
called = 1;
- return auth_input_request_forwarding(s->pw);
+ return auth_input_request_forwarding(ssh, s->pw);
}
}
int
-session_input_channel_req(Channel *c, const char *rtype)
+session_input_channel_req(struct ssh *ssh, Channel *c, const char *rtype)
{
int success = 0;
Session *s;
if ((s = session_by_channel(c->self)) == NULL) {
- logit("session_input_channel_req: no session %d req %.100s",
- c->self, rtype);
+ logit("%s: no session %d req %.100s", __func__, c->self, rtype);
return 0;
}
- debug("session_input_channel_req: session %d req %s", s->self, rtype);
+ debug("%s: session %d req %s", __func__, s->self, rtype);
/*
* a session is in LARVAL state until a shell, a command
@@ -2299,43 +2221,43 @@ session_input_channel_req(Channel *c, const char *rtype)
*/
if (c->type == SSH_CHANNEL_LARVAL) {
if (strcmp(rtype, "shell") == 0) {
- success = session_shell_req(s);
+ success = session_shell_req(ssh, s);
} else if (strcmp(rtype, "exec") == 0) {
- success = session_exec_req(s);
+ success = session_exec_req(ssh, s);
} else if (strcmp(rtype, "pty-req") == 0) {
- success = session_pty_req(s);
+ success = session_pty_req(ssh, s);
} else if (strcmp(rtype, "x11-req") == 0) {
- success = session_x11_req(s);
+ success = session_x11_req(ssh, s);
} else if (strcmp(rtype, "auth-agent-req@openssh.com") == 0) {
- success = session_auth_agent_req(s);
+ success = session_auth_agent_req(ssh, s);
} else if (strcmp(rtype, "subsystem") == 0) {
- success = session_subsystem_req(s);
+ success = session_subsystem_req(ssh, s);
} else if (strcmp(rtype, "env") == 0) {
- success = session_env_req(s);
+ success = session_env_req(ssh, s);
}
}
if (strcmp(rtype, "window-change") == 0) {
- success = session_window_change_req(s);
+ success = session_window_change_req(ssh, s);
} else if (strcmp(rtype, "break") == 0) {
- success = session_break_req(s);
+ success = session_break_req(ssh, s);
+ } else if (strcmp(rtype, "signal") == 0) {
+ success = session_signal_req(ssh, s);
}
return success;
}
void
-session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr,
- int is_tty)
+session_set_fds(struct ssh *ssh, Session *s,
+ int fdin, int fdout, int fderr, int ignore_fderr, int is_tty)
{
- if (!compat20)
- fatal("session_set_fds: called for proto != 2.0");
/*
* now that have a child and a pipe to the child,
* we can activate our channel and register the fd's
*/
if (s->chanid == -1)
fatal("no channel for session %d", s->self);
- channel_set_fds(s->chanid,
+ channel_set_fds(ssh, s->chanid,
fdout, fdin, fderr,
ignore_fderr ? CHAN_EXTENDED_IGNORE : CHAN_EXTENDED_READ,
1, is_tty, CHAN_SES_WINDOW_DEFAULT);
@@ -2349,13 +2271,13 @@ void
session_pty_cleanup2(Session *s)
{
if (s == NULL) {
- error("session_pty_cleanup: no session");
+ error("%s: no session", __func__);
return;
}
if (s->ttyfd == -1)
return;
- debug("session_pty_cleanup: session %d release %s", s->self, s->tty);
+ debug("%s: session %d release %s", __func__, s->self, s->tty);
/* Record that the user has logged out. */
if (s->pid != 0)
@@ -2370,7 +2292,7 @@ session_pty_cleanup2(Session *s)
* the pty cleanup, so that another process doesn't get this pty
* while we're still cleaning up.
*/
- if (s->ptymaster != -1 && close(s->ptymaster) < 0)
+ if (s->ptymaster != -1 && close(s->ptymaster) == -1)
error("close(s->ptymaster/%d): %s",
s->ptymaster, strerror(errno));
@@ -2406,40 +2328,40 @@ sig2name(int sig)
}
static void
-session_close_x11(int id)
+session_close_x11(struct ssh *ssh, int id)
{
Channel *c;
- if ((c = channel_by_id(id)) == NULL) {
- debug("session_close_x11: x11 channel %d missing", id);
+ if ((c = channel_by_id(ssh, id)) == NULL) {
+ debug("%s: x11 channel %d missing", __func__, id);
} else {
/* Detach X11 listener */
- debug("session_close_x11: detach x11 channel %d", id);
- channel_cancel_cleanup(id);
+ debug("%s: detach x11 channel %d", __func__, id);
+ channel_cancel_cleanup(ssh, id);
if (c->ostate != CHAN_OUTPUT_CLOSED)
- chan_mark_dead(c);
+ chan_mark_dead(ssh, c);
}
}
static void
-session_close_single_x11(int id, void *arg)
+session_close_single_x11(struct ssh *ssh, int id, void *arg)
{
Session *s;
u_int i;
- debug3("session_close_single_x11: channel %d", id);
- channel_cancel_cleanup(id);
+ debug3("%s: channel %d", __func__, id);
+ channel_cancel_cleanup(ssh, id);
if ((s = session_by_x11_channel(id)) == NULL)
- fatal("session_close_single_x11: no x11 channel %d", id);
+ fatal("%s: no x11 channel %d", __func__, id);
for (i = 0; s->x11_chanids[i] != -1; i++) {
- debug("session_close_single_x11: session %d: "
- "closing channel %d", s->self, s->x11_chanids[i]);
+ debug("%s: session %d: closing channel %d",
+ __func__, s->self, s->x11_chanids[i]);
/*
* The channel "id" is already closing, but make sure we
* close all of its siblings.
*/
if (s->x11_chanids[i] != id)
- session_close_x11(s->x11_chanids[i]);
+ session_close_x11(ssh, s->x11_chanids[i]);
}
free(s->x11_chanids);
s->x11_chanids = NULL;
@@ -2454,45 +2376,47 @@ session_close_single_x11(int id, void *arg)
}
static void
-session_exit_message(Session *s, int status)
+session_exit_message(struct ssh *ssh, Session *s, int status)
{
Channel *c;
+ int r;
- if ((c = channel_lookup(s->chanid)) == NULL)
- fatal("session_exit_message: session %d: no channel %d",
- s->self, s->chanid);
- debug("session_exit_message: session %d channel %d pid %ld",
- s->self, s->chanid, (long)s->pid);
+ if ((c = channel_lookup(ssh, s->chanid)) == NULL)
+ fatal("%s: session %d: no channel %d",
+ __func__, s->self, s->chanid);
+ debug("%s: session %d channel %d pid %ld",
+ __func__, s->self, s->chanid, (long)s->pid);
if (WIFEXITED(status)) {
- channel_request_start(s->chanid, "exit-status", 0);
- packet_put_int(WEXITSTATUS(status));
- packet_send();
+ channel_request_start(ssh, s->chanid, "exit-status", 0);
+ if ((r = sshpkt_put_u32(ssh, WEXITSTATUS(status))) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
} else if (WIFSIGNALED(status)) {
- channel_request_start(s->chanid, "exit-signal", 0);
- packet_put_cstring(sig2name(WTERMSIG(status)));
-#ifdef WCOREDUMP
- packet_put_char(WCOREDUMP(status)? 1 : 0);
-#else /* WCOREDUMP */
- packet_put_char(0);
-#endif /* WCOREDUMP */
- packet_put_cstring("");
- packet_put_cstring("");
- packet_send();
+ channel_request_start(ssh, s->chanid, "exit-signal", 0);
+#ifndef WCOREDUMP
+# define WCOREDUMP(x) (0)
+#endif
+ if ((r = sshpkt_put_cstring(ssh, sig2name(WTERMSIG(status)))) != 0 ||
+ (r = sshpkt_put_u8(ssh, WCOREDUMP(status)? 1 : 0)) != 0 ||
+ (r = sshpkt_put_cstring(ssh, "")) != 0 ||
+ (r = sshpkt_put_cstring(ssh, "")) != 0 ||
+ (r = sshpkt_send(ssh)) != 0)
+ sshpkt_fatal(ssh, r, "%s: exit reply", __func__);
} else {
/* Some weird exit cause. Just exit. */
- packet_disconnect("wait returned status %04x.", status);
+ ssh_packet_disconnect(ssh, "wait returned status %04x.", status);
}
/* disconnect channel */
- debug("session_exit_message: release channel %d", s->chanid);
+ debug("%s: release channel %d", __func__, s->chanid);
/*
* Adjust cleanup callback attachment to send close messages when
* the channel gets EOF. The session will be then be closed
- * by session_close_by_channel when the childs close their fds.
+ * by session_close_by_channel when the child sessions close their fds.
*/
- channel_register_cleanup(c->self, session_close_by_channel, 1);
+ channel_register_cleanup(ssh, c->self, session_close_by_channel, 1);
/*
* emulate a write failure with 'chan_write_failed', nobody will be
@@ -2501,15 +2425,20 @@ session_exit_message(Session *s, int status)
* be some more data waiting in the pipe.
*/
if (c->ostate != CHAN_OUTPUT_CLOSED)
- chan_write_failed(c);
+ chan_write_failed(ssh, c);
}
void
-session_close(Session *s)
+session_close(struct ssh *ssh, Session *s)
{
u_int i;
- debug("session_close: session %d pid %ld", s->self, (long)s->pid);
+ verbose("Close session: user %s from %.200s port %d id %d",
+ s->pw->pw_name,
+ ssh_remote_ipaddr(ssh),
+ ssh_remote_port(ssh),
+ s->self);
+
if (s->ttyfd != -1)
session_pty_cleanup(s);
free(s->term);
@@ -2531,16 +2460,15 @@ session_close(Session *s)
}
void
-session_close_by_pid(pid_t pid, int status)
+session_close_by_pid(struct ssh *ssh, pid_t pid, int status)
{
Session *s = session_by_pid(pid);
if (s == NULL) {
- debug("session_close_by_pid: no session for pid %ld",
- (long)pid);
+ debug("%s: no session for pid %ld", __func__, (long)pid);
return;
}
if (s->chanid != -1)
- session_exit_message(s, status);
+ session_exit_message(ssh, s, status);
if (s->ttyfd != -1)
session_pty_cleanup(s);
s->pid = 0;
@@ -2551,19 +2479,19 @@ session_close_by_pid(pid_t pid, int status)
* the session 'child' itself dies
*/
void
-session_close_by_channel(int id, void *arg)
+session_close_by_channel(struct ssh *ssh, int id, void *arg)
{
Session *s = session_by_channel(id);
u_int i;
if (s == NULL) {
- debug("session_close_by_channel: no session for id %d", id);
+ debug("%s: no session for id %d", __func__, id);
return;
}
- debug("session_close_by_channel: channel %d child %ld",
- id, (long)s->pid);
+ debug("%s: channel %d child %ld", __func__, id, (long)s->pid);
if (s->pid != 0) {
- debug("session_close_by_channel: channel %d: has child", id);
+ debug("%s: channel %d: has child, ttyfd %d",
+ __func__, id, s->ttyfd);
/*
* delay detach of session, but release pty, since
* the fd's to the child are already closed
@@ -2573,22 +2501,22 @@ session_close_by_channel(int id, void *arg)
return;
}
/* detach by removing callback */
- channel_cancel_cleanup(s->chanid);
+ channel_cancel_cleanup(ssh, s->chanid);
/* Close any X11 listeners associated with this session */
if (s->x11_chanids != NULL) {
for (i = 0; s->x11_chanids[i] != -1; i++) {
- session_close_x11(s->x11_chanids[i]);
+ session_close_x11(ssh, s->x11_chanids[i]);
s->x11_chanids[i] = -1;
}
}
s->chanid = -1;
- session_close(s);
+ session_close(ssh, s);
}
void
-session_destroy_all(void (*closefunc)(Session *))
+session_destroy_all(struct ssh *ssh, void (*closefunc)(Session *))
{
int i;
for (i = 0; i < sessions_nalloc; i++) {
@@ -2597,7 +2525,7 @@ session_destroy_all(void (*closefunc)(Session *))
if (closefunc != NULL)
closefunc(s);
else
- session_close(s);
+ session_close(ssh, s);
}
}
}
@@ -2640,15 +2568,15 @@ session_proctitle(Session *s)
}
int
-session_setup_x11fwd(Session *s)
+session_setup_x11fwd(struct ssh *ssh, Session *s)
{
struct stat st;
char display[512], auth_display[512];
char hostname[NI_MAXHOST];
u_int i;
- if (no_x11_forwarding_flag) {
- packet_send_debug("X11 forwarding disabled in user configuration file.");
+ if (!auth_opts->permit_x11_forwarding_flag) {
+ ssh_packet_send_debug(ssh, "X11 forwarding disabled by key options.");
return 0;
}
if (!options.x11_forwarding) {
@@ -2657,31 +2585,26 @@ session_setup_x11fwd(Session *s)
}
if (options.xauth_location == NULL ||
(stat(options.xauth_location, &st) == -1)) {
- packet_send_debug("No xauth program; cannot forward with spoofing.");
- return 0;
- }
- if (options.use_login) {
- packet_send_debug("X11 forwarding disabled; "
- "not compatible with UseLogin=yes.");
+ ssh_packet_send_debug(ssh, "No xauth program; cannot forward X11.");
return 0;
}
if (s->display != NULL) {
debug("X11 display already set.");
return 0;
}
- if (x11_create_display_inet(options.x11_display_offset,
+ if (x11_create_display_inet(ssh, options.x11_display_offset,
options.x11_use_localhost, s->single_connection,
&s->display_number, &s->x11_chanids) == -1) {
debug("x11_create_display_inet failed.");
return 0;
}
for (i = 0; s->x11_chanids[i] != -1; i++) {
- channel_register_cleanup(s->x11_chanids[i],
+ channel_register_cleanup(ssh, s->x11_chanids[i],
session_close_single_x11, 0);
}
/* Set up a suitable value for the DISPLAY variable. */
- if (gethostname(hostname, sizeof(hostname)) < 0)
+ if (gethostname(hostname, sizeof(hostname)) == -1)
fatal("gethostname: %.100s", strerror(errno));
/*
* auth_display must be used as the displayname when the
@@ -2703,7 +2626,7 @@ session_setup_x11fwd(Session *s)
he = gethostbyname(hostname);
if (he == NULL) {
error("Can't get IP address for X11 DISPLAY.");
- packet_send_debug("Can't get IP address for X11 DISPLAY.");
+ ssh_packet_send_debug(ssh, "Can't get IP address for X11 DISPLAY.");
return 0;
}
memcpy(&my_addr, he->h_addr_list[0], sizeof(struct in_addr));
@@ -2721,13 +2644,13 @@ session_setup_x11fwd(Session *s)
}
static void
-do_authenticated2(Authctxt *authctxt)
+do_authenticated2(struct ssh *ssh, Authctxt *authctxt)
{
- server_loop2(authctxt);
+ server_loop2(ssh, authctxt);
}
void
-do_cleanup(Authctxt *authctxt)
+do_cleanup(struct ssh *ssh, Authctxt *authctxt)
{
static int called = 0;
@@ -2762,17 +2685,41 @@ do_cleanup(Authctxt *authctxt)
#endif
#ifdef GSSAPI
- if (compat20 && options.gss_cleanup_creds)
+ if (options.gss_cleanup_creds)
ssh_gssapi_cleanup_creds();
#endif
/* remove agent socket */
auth_sock_cleanup_proc(authctxt->pw);
+ /* remove userauth info */
+ if (auth_info_file != NULL) {
+ temporarily_use_uid(authctxt->pw);
+ unlink(auth_info_file);
+ restore_uid();
+ free(auth_info_file);
+ auth_info_file = NULL;
+ }
+
/*
* Cleanup ptys/utmp only if privsep is disabled,
* or if running in monitor.
*/
if (!use_privsep || mm_is_monitor())
- session_destroy_all(session_pty_cleanup2);
+ session_destroy_all(ssh, session_pty_cleanup2);
}
+
+/* Return a name for the remote host that fits inside utmp_size */
+
+const char *
+session_get_remote_name_or_ip(struct ssh *ssh, u_int utmp_size, int use_dns)
+{
+ const char *remote = "";
+
+ if (utmp_size > 0)
+ remote = auth_get_canonical_hostname(ssh, use_dns);
+ if (utmp_size == 0 || strlen(remote) > utmp_size)
+ remote = ssh_remote_ipaddr(ssh);
+ return remote;
+}
+