aboutsummaryrefslogtreecommitdiff
path: root/crypto/openssh/session.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/openssh/session.c')
-rw-r--r--crypto/openssh/session.c240
1 files changed, 148 insertions, 92 deletions
diff --git a/crypto/openssh/session.c b/crypto/openssh/session.c
index f56899ba8f93..0141640f3076 100644
--- a/crypto/openssh/session.c
+++ b/crypto/openssh/session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: session.c,v 1.294 2018/03/03 03:15:51 djm Exp $ */
+/* $OpenBSD: session.c,v 1.305 2018/07/25 13:56:23 deraadt Exp $ */
/*
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
* All rights reserved
@@ -70,12 +70,13 @@ __RCSID("$FreeBSD$");
#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"
@@ -140,7 +141,7 @@ 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;
char *tun_fwd_ifnames; /* serverloop.c */
@@ -249,11 +250,14 @@ auth_input_request_forwarding(struct ssh *ssh, 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);
}
static void
@@ -291,26 +295,43 @@ prepare_auth_info_file(struct passwd *pw, struct sshbuf *info)
}
static void
-set_permitopen_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
+set_fwdpermit_from_authopts(struct ssh *ssh, const struct sshauthopt *opts)
{
char *tmp, *cp, *host;
int port;
size_t i;
- if ((options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
- return;
- channel_clear_permitted_opens(ssh);
- 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_permitted_opens(ssh, host, port);
- free(tmp);
+ 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);
+ }
+ }
+ 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);
+ }
}
}
@@ -323,14 +344,22 @@ do_authenticated(struct ssh *ssh, Authctxt *authctxt)
/* setup the channel layer */
/* XXX - streamlocal? */
- set_permitopen_from_authopts(ssh, auth_opts);
- if (!auth_opts->permit_port_forwarding_flag ||
- options.disable_forwarding ||
- (options.allow_tcp_forwarding & FORWARD_LOCAL) == 0)
- channel_disable_adm_local_opens(ssh);
- else
- channel_permit_all_opens(ssh);
+ set_fwdpermit_from_authopts(ssh, auth_opts);
+ 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();
prepare_auth_info_file(authctxt->pw, authctxt->session_info);
@@ -350,7 +379,7 @@ xauth_valid_string(const char *s)
if (!isalnum((u_char)s[i]) &&
s[i] != '.' && s[i] != ':' && s[i] != '/' &&
s[i] != '-' && s[i] != '_')
- return 0;
+ return 0;
}
return 1;
}
@@ -501,7 +530,7 @@ do_exec_no_pty(struct ssh *ssh, 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. */
@@ -733,7 +762,7 @@ do_exec(struct ssh *ssh, 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;
}
@@ -843,24 +872,26 @@ check_quietlogin(Session *s, const char *command)
* 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;
@@ -879,8 +910,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);
}
@@ -917,7 +952,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;
@@ -979,7 +1015,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
char buf[256];
size_t n;
u_int i, envsize;
- char *ocp, *cp, **env, *laddr;
+ char *ocp, *cp, *value, **env, *laddr;
struct passwd *pw = s->pw;
#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
char *path = NULL;
@@ -1073,46 +1109,10 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
/* Normal systems set SHELL by default. */
child_set_env(&env, &envsize, "SHELL", shell);
-
- /* 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';
- child_set_env(&env, &envsize, ocp, cp + 1);
- }
- free(ocp);
- }
- }
-
- /* 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(packet_get_connection_in());
- 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 (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);
/*
* Since we clear KRB5CCNAME at startup, if it's set now then it
@@ -1132,7 +1132,8 @@ do_setup_env(struct ssh *ssh, 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
@@ -1140,6 +1141,37 @@ do_setup_env(struct ssh *ssh, 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
@@ -1162,16 +1194,40 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
}
#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) {
- 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(packet_get_connection_in());
+ 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");
@@ -1343,7 +1399,7 @@ safely_chroot(const char *path, uid_t uid)
void
do_setusercontext(struct passwd *pw)
{
- char *chroot_path, *tmp;
+ char uidstr[32], *chroot_path, *tmp;
platform_setusercontext(pw);
@@ -1375,8 +1431,10 @@ do_setusercontext(struct passwd *pw)
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);
@@ -1877,7 +1935,6 @@ static int
session_pty_req(struct ssh *ssh, Session *s)
{
u_int len;
- int n_bytes;
if (!auth_opts->permit_pty_flag || !options.permit_tty) {
debug("Allocating a pty not permitted for this connection.");
@@ -1912,8 +1969,7 @@ session_pty_req(struct ssh *ssh, Session *s)
}
debug("session_pty_req: session %d alloc %s", s->self, s->tty);
- n_bytes = packet_remaining();
- tty_parse_modes(s->ttyfd, &n_bytes);
+ ssh_tty_parse_modes(ssh, s->ttyfd);
if (!use_privsep)
pty_setowner(s->pw, s->tty);