From 27c240a1d57a6d9c9480bf828fa765ad558a4783 Mon Sep 17 00:00:00 2001 From: 90 Date: Wed, 6 Mar 2024 20:41:16 +0000 Subject: [PATCH 1/5] Add alternative sshd environment and rc file options --- auth.c | 7 ++--- auth.h | 2 +- auth2-pubkey.c | 4 +-- servconf.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++-- servconf.h | 7 +++++ session.c | 54 ++++++++++++++++++++++---------------- 6 files changed, 114 insertions(+), 31 deletions(-) diff --git a/auth.c b/auth.c index 3b380d9bbd2..c6ca6dc8ef0 100644 --- a/auth.c +++ b/auth.c @@ -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; @@ -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)); } @@ -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 */ diff --git a/auth.h b/auth.h index 6d2d3976234..2a6e43535b9 100644 --- a/auth.h +++ b/auth.h @@ -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 *); diff --git a/auth2-pubkey.c b/auth2-pubkey.c index 3f49e1df3b7..94b3556ce7c 100644 --- a/auth2-pubkey.c +++ b/auth2-pubkey.c @@ -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); diff --git a/servconf.c b/servconf.c index 4b434909ab2..5093e227352 100644 --- a/servconf.c +++ b/servconf.c @@ -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; @@ -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; @@ -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) @@ -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; @@ -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, @@ -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, @@ -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 }, @@ -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 }, @@ -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: + value = 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 && value == 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; @@ -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: + value = 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 && value == 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; @@ -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, diff --git a/servconf.h b/servconf.h index ed7b72e8e0e..ec1a4f9afdc 100644 --- a/servconf.h +++ b/servconf.h @@ -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 */ @@ -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); \ diff --git a/session.c b/session.c index c821dcd4462..8ee3fc337bc 100644 --- a/session.c +++ b/session.c @@ -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; @@ -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 @@ -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, From 13b96c5dc8885361e060de608728983aa9f68582 Mon Sep 17 00:00:00 2001 From: 90 Date: Thu, 4 Apr 2024 16:51:27 +0100 Subject: [PATCH 2/5] Add safeguards for custom environment/rc files --- session.c | 41 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/session.c b/session.c index 8ee3fc337bc..7c173668218 100644 --- a/session.c +++ b/session.c @@ -832,6 +832,40 @@ check_quietlogin(Session *s, const char *command) return 0; } +static int +safe_user_file(const char *filename, struct passwd *pw) +{ + struct stat st; + char *path; + + if (stat(filename, &st) == -1) { + fprintf(stderr, "User file %s not found, ignoring.\n", + filename); + return 0; + } + + path = realpath(filename, NULL); + if (strncmp(path, pw->pw_dir, strlen(pw->pw_dir)) == 0) { + if (st.st_uid != pw->pw_uid) { + fprintf(stderr, "Bad owner on %s, ignoring.\n", + filename); + return 0; + } + if ((st.st_mode & 077) != 0) { + fprintf(stderr, + "Permissions too open (%3o) on %s, ignoring.\n", + st.st_mode & 0777u, filename); + return 0; + } + return 1; + } + if (st.st_uid != 0) { + fprintf(stderr, "%s not root-owned, ignoring.\n", filename); + return 0; + } + return 1; +} + /* * Reads environment variables from the given file and adds/overrides them * into the environment. If the file does not exist, this does nothing. @@ -1121,8 +1155,9 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) 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); + if (safe_user_file(userenv, pw)) + read_environment_file(&env, &envsize, userenv, + options.permit_user_env_allowlist); } free(userenv); } @@ -1218,7 +1253,7 @@ do_rc_files(struct ssh *ssh, Session *s, const char *shell) 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 (safe_user_file(user_rc, s->pw)) { if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL, user_rc) == -1) fatal_f("xasprintf: %s", strerror(errno)); From 03bcc2f0735a3235107bc2b4246b05e11d4b896d Mon Sep 17 00:00:00 2001 From: 90 Date: Thu, 4 Apr 2024 17:16:13 +0100 Subject: [PATCH 3/5] Remove spammy "file not found" warning --- session.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/session.c b/session.c index 7c173668218..7aec15d4208 100644 --- a/session.c +++ b/session.c @@ -838,29 +838,26 @@ safe_user_file(const char *filename, struct passwd *pw) struct stat st; char *path; - if (stat(filename, &st) == -1) { - fprintf(stderr, "User file %s not found, ignoring.\n", - filename); + if (stat(filename, &st) == -1) return 0; - } path = realpath(filename, NULL); if (strncmp(path, pw->pw_dir, strlen(pw->pw_dir)) == 0) { if (st.st_uid != pw->pw_uid) { fprintf(stderr, "Bad owner on %s, ignoring.\n", - filename); + path); return 0; } if ((st.st_mode & 077) != 0) { fprintf(stderr, "Permissions too open (%3o) on %s, ignoring.\n", - st.st_mode & 0777u, filename); + st.st_mode & 0777u, path); return 0; } return 1; } if (st.st_uid != 0) { - fprintf(stderr, "%s not root-owned, ignoring.\n", filename); + fprintf(stderr, "%s not root-owned, ignoring.\n", path); return 0; } return 1; From 00b4e37a42112104bb40327ac4f89cb054ce34d3 Mon Sep 17 00:00:00 2001 From: 90 Date: Fri, 5 Apr 2024 17:21:46 +0100 Subject: [PATCH 4/5] Rework file ownership checks based on parent dir owner --- session.c | 56 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 34 insertions(+), 22 deletions(-) diff --git a/session.c b/session.c index 7aec15d4208..39bede1d3dd 100644 --- a/session.c +++ b/session.c @@ -832,33 +832,45 @@ check_quietlogin(Session *s, const char *command) return 0; } +/* + * Check that any custom user environment/rc file is "safe" to run, i.e. + * - it belongs to either the superuser or to the logged in user, of which + * the latter must also own the parent directory + * - if it belongs to the logged in user, either the file or its parent dir + * is only accessible to the user + */ static int -safe_user_file(const char *filename, struct passwd *pw) +safe_user_file(const char *filename, uid_t uid) { struct stat st; - char *path; + char *lastsep; + uid_t dirowner; + mode_t dirmode; + /* Gather parent dir owner and mode first */ + lastsep = strrchr(filename, '/'); + *lastsep = '\0'; if (stat(filename, &st) == -1) return 0; - - path = realpath(filename, NULL); - if (strncmp(path, pw->pw_dir, strlen(pw->pw_dir)) == 0) { - if (st.st_uid != pw->pw_uid) { - fprintf(stderr, "Bad owner on %s, ignoring.\n", - path); - return 0; - } - if ((st.st_mode & 077) != 0) { - fprintf(stderr, - "Permissions too open (%3o) on %s, ignoring.\n", - st.st_mode & 0777u, path); - return 0; - } - return 1; - } - if (st.st_uid != 0) { - fprintf(stderr, "%s not root-owned, ignoring.\n", path); + dirowner = st.st_uid; + dirmode = st.st_mode; + /* Then gather actual file info */ + *lastsep = '/'; + if (stat(filename, &st) == -1) + return 0; + + if (st.st_uid != 0 && st.st_uid != uid && st.st_uid != dirowner) { + fprintf(stderr, "Bad owner on %s, ignoring.\n", + filename); return 0; + } + + if (st.st_uid == uid && + (st.st_mode & 077) != 0 && (dirmode & 077) != 0) { + fprintf(stderr, + "Permissions too open on %s or its parent dir, ignoring.\n", + filename); + return 0; } return 1; } @@ -1152,7 +1164,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) for (i = 0; i < options.num_user_env_files; i++) { userenv = expand_user_file(options.user_env_files[i], pw, "UserEnvironment"); - if (safe_user_file(userenv, pw)) + if (safe_user_file(userenv, pw->pw_uid)) read_environment_file(&env, &envsize, userenv, options.permit_user_env_allowlist); } @@ -1250,7 +1262,7 @@ do_rc_files(struct ssh *ssh, Session *s, const char *shell) for (i = 0; i < options.num_user_rc_files; i++) { user_rc = expand_user_file(options.user_rc_files[i], s->pw, "UserRC"); - if (safe_user_file(user_rc, s->pw)) { + if (safe_user_file(user_rc, s->pw->pw_uid)) { if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL, user_rc) == -1) fatal_f("xasprintf: %s", strerror(errno)); From a57e10fa7fd797b9ef1e779e7228fc1de2aee2b5 Mon Sep 17 00:00:00 2001 From: 90 Date: Sun, 7 Apr 2024 14:24:52 +0100 Subject: [PATCH 5/5] Switch back to $HOME check --- session.c | 67 +++++++++++++++++++++++++++---------------------------- 1 file changed, 33 insertions(+), 34 deletions(-) diff --git a/session.c b/session.c index 39bede1d3dd..3025762cc24 100644 --- a/session.c +++ b/session.c @@ -834,45 +834,44 @@ check_quietlogin(Session *s, const char *command) /* * Check that any custom user environment/rc file is "safe" to run, i.e. - * - it belongs to either the superuser or to the logged in user, of which - * the latter must also own the parent directory - * - if it belongs to the logged in user, either the file or its parent dir - * is only accessible to the user + * - If the file is located in the logged-in user's $HOME, it is owned by the + * user and accessible *only* to the user + * - If the file is located outside the user's $HOME, it is owned by the super + * user */ static int -safe_user_file(const char *filename, uid_t uid) +safe_user_file(const char *filename, struct passwd *pw) { struct stat st; - char *lastsep; - uid_t dirowner; - mode_t dirmode; + char *path; + int safe = 0; - /* Gather parent dir owner and mode first */ - lastsep = strrchr(filename, '/'); - *lastsep = '\0'; if (stat(filename, &st) == -1) - return 0; - dirowner = st.st_uid; - dirmode = st.st_mode; - /* Then gather actual file info */ - *lastsep = '/'; - if (stat(filename, &st) == -1) - return 0; - - if (st.st_uid != 0 && st.st_uid != uid && st.st_uid != dirowner) { - fprintf(stderr, "Bad owner on %s, ignoring.\n", - filename); - return 0; - } + return safe; - if (st.st_uid == uid && - (st.st_mode & 077) != 0 && (dirmode & 077) != 0) { - fprintf(stderr, - "Permissions too open on %s or its parent dir, ignoring.\n", - filename); - return 0; + path = realpath(filename, NULL); + if (strncmp(path, pw->pw_dir, strlen(pw->pw_dir)) == 0) { + if (st.st_uid != pw->pw_uid) { + fprintf(stderr, "Bad owner on %s, ignoring.\n", path); + goto out; + } + if ((st.st_mode & 077) != 0) { + fprintf(stderr, + "Permissions too open (%3o) on %s, ignoring.\n", + st.st_mode & 0777u, path); + goto out; + } + safe = 1; + goto out; } - return 1; + if (st.st_uid != 0 || st.st_gid != 0) { + fprintf(stderr, "%s not root-owned, ignoring.\n", path); + goto out; + } + safe = 1; +out: + free(path); + return safe; } /* @@ -1164,7 +1163,7 @@ do_setup_env(struct ssh *ssh, Session *s, const char *shell) for (i = 0; i < options.num_user_env_files; i++) { userenv = expand_user_file(options.user_env_files[i], pw, "UserEnvironment"); - if (safe_user_file(userenv, pw->pw_uid)) + if (safe_user_file(userenv, pw)) read_environment_file(&env, &envsize, userenv, options.permit_user_env_allowlist); } @@ -1262,7 +1261,7 @@ do_rc_files(struct ssh *ssh, Session *s, const char *shell) for (i = 0; i < options.num_user_rc_files; i++) { user_rc = expand_user_file(options.user_rc_files[i], s->pw, "UserRC"); - if (safe_user_file(user_rc, s->pw->pw_uid)) { + if (safe_user_file(user_rc, s->pw)) { if (xasprintf(&cmd, "%s -c '%s %s'", shell, _PATH_BSHELL, user_rc) == -1) fatal_f("xasprintf: %s", strerror(errno)); @@ -1278,7 +1277,7 @@ do_rc_files(struct ssh *ssh, Session *s, const char *shell) 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,