diff options
Diffstat (limited to 'crypto/openssh/session.c')
-rw-r--r-- | crypto/openssh/session.c | 240 |
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); |