diff options
| author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-08-28 10:47:58 +0000 | 
|---|---|---|
| committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2018-08-28 10:47:58 +0000 | 
| commit | d46065df2d60bfbd08939733bd79b2a440d6fbc8 (patch) | |
| tree | 720921fc9471de3c67f5b8dc1404c8f6c6a02cb1 /session.c | |
| parent | 3d0e42005d3bf786341ab96cfa1788bc601faa12 (diff) | |
Diffstat (limited to 'session.c')
| -rw-r--r-- | session.c | 240 | 
1 files changed, 148 insertions, 92 deletions
| diff --git a/session.c b/session.c index 58826db1698ac..f2cf52006e430 100644 --- a/session.c +++ b/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 @@ -69,12 +69,13 @@  #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" @@ -139,7 +140,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 */ @@ -248,11 +249,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 @@ -290,26 +294,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); +		}  	}  } @@ -322,14 +343,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); @@ -349,7 +378,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;  } @@ -500,7 +529,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. */ @@ -732,7 +761,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;  } @@ -842,24 +871,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; @@ -878,8 +909,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);  } @@ -916,7 +951,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; @@ -978,7 +1014,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; @@ -1052,46 +1088,10 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)  	if (getenv("TZ"))  		child_set_env(&env, &envsize, "TZ", getenv("TZ")); - -	/* 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 @@ -1111,7 +1111,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 @@ -1119,6 +1120,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 @@ -1141,16 +1173,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"); @@ -1324,7 +1380,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); @@ -1356,8 +1412,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); @@ -1858,7 +1916,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."); @@ -1893,8 +1950,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); | 
