Skip to content

Commit

Permalink
Add alternative sshd environment and rc file options
Browse files Browse the repository at this point in the history
  • Loading branch information
62832 committed Mar 6, 2024
1 parent c47e1c9 commit 98a3f1d
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 31 deletions.
7 changes: 4 additions & 3 deletions auth.c
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ auth_root_allowed(struct ssh *ssh, const char *method)
* This returns a buffer allocated by xmalloc.
*/
char *
expand_authorized_keys(const char *filename, struct passwd *pw)
expand_user_file(const char *filename, struct passwd *pw, const char *filetype)
{
char *file, uidstr[32], ret[PATH_MAX];
int i;
Expand All @@ -400,7 +400,7 @@ expand_authorized_keys(const char *filename, struct passwd *pw)

i = snprintf(ret, sizeof(ret), "%s/%s", pw->pw_dir, file);
if (i < 0 || (size_t)i >= sizeof(ret))
fatal("expand_authorized_keys: path too long");
fatal("expand_user_file (%s): path too long", filetype);
free(file);
return (xstrdup(ret));
}
Expand All @@ -410,7 +410,8 @@ authorized_principals_file(struct passwd *pw)
{
if (options.authorized_principals_file == NULL)
return NULL;
return expand_authorized_keys(options.authorized_principals_file, pw);
return expand_user_file(options.authorized_principals_file, pw,
"AuthorizedPrincipals");
}

/* return ok if key exists in sysfile or userfile */
Expand Down
2 changes: 1 addition & 1 deletion auth.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ int bsdauth_respond(void *, u_int, char **);
int allowed_user(struct ssh *, struct passwd *);
struct passwd * getpwnamallow(struct ssh *, const char *user);

char *expand_authorized_keys(const char *, struct passwd *pw);
char *expand_user_file(const char *, struct passwd *pw, const char *);
char *authorized_principals_file(struct passwd *);

int auth_key_is_revoked(struct sshkey *);
Expand Down
4 changes: 2 additions & 2 deletions auth2-pubkey.c
Original file line number Diff line number Diff line change
Expand Up @@ -777,8 +777,8 @@ user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key,
for (i = 0; !success && i < options.num_authkeys_files; i++) {
if (strcasecmp(options.authorized_keys_files[i], "none") == 0)
continue;
file = expand_authorized_keys(
options.authorized_keys_files[i], pw);
file = expand_user_file(options.authorized_keys_files[i], pw,
"AuthorizedKeys");
success = user_key_allowed2(pw, key, file,
remote_ip, remote_host, &opts);
free(file);
Expand Down
71 changes: 69 additions & 2 deletions servconf.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ initialize_server_options(ServerOptions *options)
options->x11_use_localhost = -1;
options->permit_tty = -1;
options->permit_user_rc = -1;
options->num_user_rc_files = 0;
options->xauth_location = NULL;
options->strict_modes = -1;
options->tcp_keep_alive = -1;
Expand All @@ -141,6 +142,7 @@ initialize_server_options(ServerOptions *options)
options->permit_empty_passwd = -1;
options->permit_user_env = -1;
options->permit_user_env_allowlist = NULL;
options->num_user_env_files = 0;
options->compression = -1;
options->rekey_limit = -1;
options->rekey_interval = -1;
Expand Down Expand Up @@ -332,6 +334,11 @@ fill_default_server_options(ServerOptions *options)
options->permit_tty = 1;
if (options->permit_user_rc == -1)
options->permit_user_rc = 1;
if (options->num_user_rc_files == 0)
opt_array_append("[default]", 0, "UserRCFiles",
&options->user_rc_files,
&options->num_user_rc_files,
_PATH_SSH_USER_RC);
if (options->strict_modes == -1)
options->strict_modes = 1;
if (options->tcp_keep_alive == -1)
Expand Down Expand Up @@ -372,6 +379,11 @@ fill_default_server_options(ServerOptions *options)
options->permit_user_env = 0;
options->permit_user_env_allowlist = NULL;
}
if (options->num_user_env_files == 0)
opt_array_append("[default]", 0, "UserEnvFiles",
&options->user_env_files,
&options->num_user_env_files,
_PATH_SSH_USER_DIR "/environment");
if (options->compression == -1)
#ifdef WITH_ZLIB
options->compression = COMP_DELAYED;
Expand Down Expand Up @@ -508,7 +520,8 @@ typedef enum {
sPrintMotd, sPrintLastLog, sIgnoreRhosts,
sX11Forwarding, sX11DisplayOffset, sX11UseLocalhost,
sPermitTTY, sStrictModes, sEmptyPasswd, sTCPKeepAlive,
sPermitUserEnvironment, sAllowTcpForwarding, sCompression,
sPermitUserEnvironment, sUserEnvironmentFile,
sAllowTcpForwarding, sCompression,
sRekeyLimit, sAllowUsers, sDenyUsers, sAllowGroups, sDenyGroups,
sIgnoreUserKnownHosts, sCiphers, sMacs, sPidFile, sModuliFile,
sGatewayPorts, sPubkeyAuthentication, sPubkeyAcceptedAlgorithms,
Expand All @@ -526,7 +539,7 @@ typedef enum {
sAuthorizedPrincipalsCommand, sAuthorizedPrincipalsCommandUser,
sKexAlgorithms, sCASignatureAlgorithms, sIPQoS, sVersionAddendum,
sAuthorizedKeysCommand, sAuthorizedKeysCommandUser,
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC,
sAuthenticationMethods, sHostKeyAgent, sPermitUserRC, sUserRCFile,
sStreamLocalBindMask, sStreamLocalBindUnlink,
sAllowStreamLocalForwarding, sFingerprintHash, sDisableForwarding,
sExposeAuthInfo, sRDomain, sPubkeyAuthOptions, sSecurityKeyProvider,
Expand Down Expand Up @@ -628,6 +641,7 @@ static struct {
{ "strictmodes", sStrictModes, SSHCFG_GLOBAL },
{ "permitemptypasswords", sEmptyPasswd, SSHCFG_ALL },
{ "permituserenvironment", sPermitUserEnvironment, SSHCFG_GLOBAL },
{ "userenvironmentfile", sUserEnvironmentFile, SSHCFG_GLOBAL },
{ "uselogin", sDeprecated, SSHCFG_GLOBAL },
{ "compression", sCompression, SSHCFG_GLOBAL },
{ "rekeylimit", sRekeyLimit, SSHCFG_ALL },
Expand Down Expand Up @@ -663,6 +677,7 @@ static struct {
{ "permittunnel", sPermitTunnel, SSHCFG_ALL },
{ "permittty", sPermitTTY, SSHCFG_ALL },
{ "permituserrc", sPermitUserRC, SSHCFG_ALL },
{ "userrcfile", sUserRCFile, SSHCFG_ALL },
{ "match", sMatch, SSHCFG_ALL },
{ "permitopen", sPermitOpen, SSHCFG_ALL },
{ "permitlisten", sPermitListen, SSHCFG_ALL },
Expand Down Expand Up @@ -1673,6 +1688,30 @@ process_server_config_line_depth(ServerOptions *options, char *line,
intptr = &options->permit_user_rc;
goto parse_flag;

/*
* These options can contain %X options expanded at
* connect time, so that you can specify paths like:
*
* UserRCFile /etc/ssh_user_rc/%u
*/
case sUserRCFile:
uvalue = options->num_user_rc_files;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
arg2 = tilde_expand_filename(arg, getuid());
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum, keyword,
&options->user_rc_files,
&options->num_user_rc_files, arg2);
}
free(arg2);
}
break;

case sStrictModes:
intptr = &options->strict_modes;
goto parse_flag;
Expand Down Expand Up @@ -1711,6 +1750,30 @@ process_server_config_line_depth(ServerOptions *options, char *line,
free(p);
break;

/*
* These options can contain %X options expanded at
* connect time, so that you can specify paths like:
*
* UserEnvironmentFile /etc/ssh_user_env/%u
*/
case sUserEnvironmentFile:
uvalue = options->num_user_env_files;
while ((arg = argv_next(&ac, &av)) != NULL) {
if (*arg == '\0') {
error("%s line %d: keyword %s empty argument",
filename, linenum, keyword);
goto out;
}
arg2 = tilde_expand_filename(arg, getuid());
if (*activep && uvalue == 0) {
opt_array_append(filename, linenum, keyword,
&options->user_env_files,
&options->num_user_env_files, arg2);
}
free(arg2);
}
break;

case sCompression:
intptr = &options->compression;
multistate_ptr = multistate_compression;
Expand Down Expand Up @@ -3175,6 +3238,10 @@ dump_config(ServerOptions *o)
/* string array arguments */
dump_cfg_strarray_oneline(sAuthorizedKeysFile, o->num_authkeys_files,
o->authorized_keys_files);
dump_cfg_strarray_oneline(sUserRCFile, o->num_user_rc_files,
o->user_rc_files);
dump_cfg_strarray_oneline(sUserEnvironmentFile, o->num_user_env_files,
o->user_env_files);
dump_cfg_strarray(sHostKeyFile, o->num_host_key_files,
o->host_key_files);
dump_cfg_strarray(sHostCertificate, o->num_host_cert_files,
Expand Down
7 changes: 7 additions & 0 deletions servconf.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,11 @@ typedef struct {
u_int num_channel_timeouts;

int unused_connection_timeout;

u_int num_user_env_files; /* alternative .ssh/environment files */
u_int num_user_rc_files; /* alternative .ssh/rc files */
char **user_env_files;
char **user_rc_files;
} ServerOptions;

/* Information about the incoming connection as used by Match */
Expand Down Expand Up @@ -281,6 +286,8 @@ TAILQ_HEAD(include_list, include_item);
M_CP_STROPT(routing_domain); \
M_CP_STROPT(permit_user_env_allowlist); \
M_CP_STRARRAYOPT(authorized_keys_files, num_authkeys_files); \
M_CP_STRARRAYOPT(user_rc_files, num_user_rc_files); \
M_CP_STRARRAYOPT(user_env_files, num_user_env_files); \
M_CP_STRARRAYOPT(allow_users, num_allow_users); \
M_CP_STRARRAYOPT(deny_users, num_deny_users); \
M_CP_STRARRAYOPT(allow_groups, num_allow_groups); \
Expand Down
54 changes: 31 additions & 23 deletions session.c
Original file line number Diff line number Diff line change
Expand Up @@ -984,7 +984,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, *value, **env, *laddr;
char *ocp, *cp, *value, **env, *laddr, *userenv = NULL;
struct passwd *pw = s->pw;
#if !defined (HAVE_LOGIN_CAP) && !defined (HAVE_CYGWIN)
char *path = NULL;
Expand Down Expand Up @@ -1116,12 +1116,15 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell)
}
}

/* read $HOME/.ssh/environment. */
/* read user environment files. */
if (options.permit_user_env) {
snprintf(buf, sizeof buf, "%.200s/%s/environment",
pw->pw_dir, _PATH_SSH_USER_DIR);
read_environment_file(&env, &envsize, buf,
options.permit_user_env_allowlist);
for (i = 0; i < options.num_user_env_files; i++) {
userenv = expand_user_file(options.user_env_files[i], pw,
"UserEnvironment");
read_environment_file(&env, &envsize, userenv,
options.permit_user_env_allowlist);
}
free(userenv);
}

#ifdef USE_PAM
Expand Down Expand Up @@ -1204,29 +1207,34 @@ do_rc_files(struct ssh *ssh, Session *s, const char *shell)
char *cmd = NULL, *user_rc = NULL;
int do_xauth;
struct stat st;
u_int i;

do_xauth =
s->display != NULL && s->auth_proto != NULL && s->auth_data != NULL;
xasprintf(&user_rc, "%s/%s", s->pw->pw_dir, _PATH_SSH_USER_RC);

/* ignore _PATH_SSH_USER_RC for subsystems and admin forced commands */
if (!s->is_subsystem && options.adm_forced_command == NULL &&
auth_opts->permit_user_rc && options.permit_user_rc &&
stat(user_rc, &st) >= 0) {
if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL,
user_rc) == -1)
fatal_f("xasprintf: %s", strerror(errno));
if (debug_flag)
fprintf(stderr, "Running %s\n", cmd);
f = popen(cmd, "w");
if (f) {
if (do_xauth)
fprintf(f, "%s %s\n", s->auth_proto,
s->auth_data);
pclose(f);
} else
fprintf(stderr, "Could not run %s\n",
user_rc);
auth_opts->permit_user_rc && options.permit_user_rc) {
for (i = 0; i < options.num_user_rc_files; i++) {
user_rc = expand_user_file(options.user_rc_files[i],
s->pw, "UserRC");
if (stat(user_rc, &st) >= 0) {
if (xasprintf(&cmd, "%s -c '%s %s'", shell,
_PATH_BSHELL, user_rc) == -1)
fatal_f("xasprintf: %s", strerror(errno));
if (debug_flag)
fprintf(stderr, "Running %s\n", cmd);
f = popen(cmd, "w");
if (f) {
if (do_xauth)
fprintf(f, "%s %s\n", s->auth_proto,
s->auth_data);
pclose(f);
} else
fprintf(stderr, "Could not run %s\n",
user_rc);
}
}
} else if (stat(_PATH_SSH_SYSTEM_RC, &st) >= 0) {
if (debug_flag)
fprintf(stderr, "Running %s %s\n", _PATH_BSHELL,
Expand Down

0 comments on commit 98a3f1d

Please sign in to comment.