From baeb17eb76772a2dbbcc4d52a22ddfc405276db1 Mon Sep 17 00:00:00 2001 From: Alex Wilson Date: Fri, 4 Sep 2015 11:04:30 -0700 Subject: [PATCH 29/34] Accept LANG and LC_* environment variables from clients by default This preserves most of the old SunSSH locale negotiation behaviour (at least the parts that are most commonly used). diff -wpruN --no-dereference '--exclude=*.orig' a~/servconf.c a/servconf.c --- a~/servconf.c 1970-01-01 00:00:00 +++ a/servconf.c 1970-01-01 00:00:00 @@ -201,6 +201,7 @@ initialize_server_options(ServerOptions options->client_alive_count_max = -1; options->num_authkeys_files = 0; options->num_accept_env = 0; + options->default_accept_env = 1; options->num_setenv = 0; options->permit_tun = -1; options->permitted_opens = NULL; @@ -536,6 +537,32 @@ fill_default_server_options(ServerOption options->max_sessions = DEFAULT_SESSIONS_MAX; if (options->use_dns == -1) options->use_dns = 0; + if (options->default_accept_env == 1) { + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LANG"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_ALL"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_CTYPE"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_COLLATE"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_TIME"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_NUMERIC"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_MONETARY"); + opt_array_append("[default]", 0, "AcceptEnv", + &options->accept_env, &options->num_accept_env, + "LC_MESSAGES"); + } if (options->client_alive_interval == -1) options->client_alive_interval = 0; if (options->client_alive_count_max == -1) @@ -2329,9 +2356,12 @@ process_server_config_line_depth(ServerO if (*arg == '\0' || strchr(arg, '=') != NULL) fatal("%s line %d: Invalid environment name.", filename, linenum); + options->default_accept_env = 0; found = 1; if (!*activep) continue; + if (strcmp(arg, "none") == 0) + continue; opt_array_append(filename, linenum, keyword, &options->accept_env, &options->num_accept_env, arg); diff -wpruN --no-dereference '--exclude=*.orig' a~/servconf.h a/servconf.h --- a~/servconf.h 1970-01-01 00:00:00 +++ a/servconf.h 1970-01-01 00:00:00 @@ -179,6 +179,7 @@ typedef struct { char **subsystem_args; u_int num_accept_env; + int default_accept_env; char **accept_env; u_int num_setenv; char **setenv; diff -wpruN --no-dereference '--exclude=*.orig' a~/session.c a/session.c --- a~/session.c 1970-01-01 00:00:00 +++ a/session.c 1970-01-01 00:00:00 @@ -831,6 +831,18 @@ check_quietlogin(Session *s, const char } /* + * If the given environment variable is set in the daemon's environment, + * push it into the new child as well. If it is unset, do nothing. + */ +static void +child_inherit_env(char ***envp, u_int *envsizep, const char *name) +{ + char *value; + if ((value = getenv(name)) != NULL) + child_set_env(envp, envsizep, 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 '#') @@ -1014,6 +1026,16 @@ do_setup_env(struct ssh *ssh, Session *s ssh_gssapi_do_child(&env, &envsize); #endif + /* Default to the system-wide locale/language settings. */ + child_inherit_env(&env, &envsize, "LANG"); + child_inherit_env(&env, &envsize, "LC_ALL"); + child_inherit_env(&env, &envsize, "LC_CTYPE"); + child_inherit_env(&env, &envsize, "LC_COLLATE"); + child_inherit_env(&env, &envsize, "LC_TIME"); + child_inherit_env(&env, &envsize, "LC_NUMERIC"); + child_inherit_env(&env, &envsize, "LC_MONETARY"); + child_inherit_env(&env, &envsize, "LC_MESSAGES"); + /* Set basic environment. */ for (i = 0; i < s->num_env; i++) child_set_env(&env, &envsize, s->env[i].name, s->env[i].val); @@ -1057,8 +1079,7 @@ do_setup_env(struct ssh *ssh, Session *s /* Normal systems set SHELL by default. */ child_set_env(&env, &envsize, "SHELL", shell); - if (getenv("TZ")) - child_set_env(&env, &envsize, "TZ", getenv("TZ")); + child_inherit_env(&env, &envsize, "TZ"); if (s->term) child_set_env(&env, &envsize, "TERM", s->term); if (s->display) diff -wpruN --no-dereference '--exclude=*.orig' a~/sshd_config a/sshd_config --- a~/sshd_config 1970-01-01 00:00:00 +++ a/sshd_config 1970-01-01 00:00:00 @@ -26,6 +26,10 @@ #SyslogFacility AUTH #LogLevel INFO +# Use the client's locale/language settings +#AcceptEnv LANG LC_ALL LC_CTYPE LC_COLLATE LC_TIME LC_NUMERIC +#AcceptEnv LC_MONETARY LC_MESSAGES + # Authentication: #LoginGraceTime 2m diff -wpruN --no-dereference '--exclude=*.orig' a~/sshd_config.5 a/sshd_config.5 --- a~/sshd_config.5 1970-01-01 00:00:00 +++ a/sshd_config.5 1970-01-01 00:00:00 @@ -86,7 +86,20 @@ directives. Be warned that some environment variables could be used to bypass restricted user environments. For this reason, care should be taken in the use of this directive. -The default is not to accept any environment variables. +The default is to accept only +.Ev LANG +and the +.Ev LC_* +family of environment variables. If any +.Cm AcceptEnv +directives are present in your config file, they will replace this default +.Po +ie, only the variables you list will be passed into the session's +.Xr environ 7 +.Pc . +You can also use an argument of +.Dq none +to specify that no environment variables should be passed. .It Cm AddressFamily Specifies which address family should be used by .Xr sshd 8 .