summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auth-rhosts.c6
-rw-r--r--auth.c3
-rw-r--r--misc.c58
-rw-r--r--misc.h2
-rw-r--r--readconf.c3
-rw-r--r--ssh.12
-rw-r--r--ssh_config.52
7 files changed, 63 insertions, 13 deletions
diff --git a/auth-rhosts.c b/auth-rhosts.c
index 7a10210b6..587f53721 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -260,8 +260,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
260 return 0; 260 return 0;
261 } 261 }
262 if (options.strict_modes && 262 if (options.strict_modes &&
263 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 263 !secure_permissions(&st, pw->pw_uid)) {
264 (st.st_mode & 022) != 0)) {
265 logit("Rhosts authentication refused for %.100s: " 264 logit("Rhosts authentication refused for %.100s: "
266 "bad ownership or modes for home directory.", pw->pw_name); 265 "bad ownership or modes for home directory.", pw->pw_name);
267 auth_debug_add("Rhosts authentication refused for %.100s: " 266 auth_debug_add("Rhosts authentication refused for %.100s: "
@@ -287,8 +286,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
287 * allowing access to their account by anyone. 286 * allowing access to their account by anyone.
288 */ 287 */
289 if (options.strict_modes && 288 if (options.strict_modes &&
290 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 289 !secure_permissions(&st, pw->pw_uid)) {
291 (st.st_mode & 022) != 0)) {
292 logit("Rhosts authentication refused for %.100s: bad modes for %.200s", 290 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
293 pw->pw_name, buf); 291 pw->pw_name, buf);
294 auth_debug_add("Bad file modes for %.200s", buf); 292 auth_debug_add("Bad file modes for %.200s", buf);
diff --git a/auth.c b/auth.c
index 687c57b42..aed3c13ac 100644
--- a/auth.c
+++ b/auth.c
@@ -474,8 +474,7 @@ check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
474 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 474 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
475 if (options.strict_modes && 475 if (options.strict_modes &&
476 (stat(user_hostfile, &st) == 0) && 476 (stat(user_hostfile, &st) == 0) &&
477 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 477 !secure_permissions(&st, pw->pw_uid)) {
478 (st.st_mode & 022) != 0)) {
479 logit("Authentication refused for %.100s: " 478 logit("Authentication refused for %.100s: "
480 "bad owner or modes for %.200s", 479 "bad owner or modes for %.200s",
481 pw->pw_name, user_hostfile); 480 pw->pw_name, user_hostfile);
diff --git a/misc.c b/misc.c
index 3a31d5c18..073d3be19 100644
--- a/misc.c
+++ b/misc.c
@@ -61,8 +61,9 @@
61#include <netdb.h> 61#include <netdb.h>
62#ifdef HAVE_PATHS_H 62#ifdef HAVE_PATHS_H
63# include <paths.h> 63# include <paths.h>
64#include <pwd.h>
65#endif 64#endif
65#include <pwd.h>
66#include <grp.h>
66#ifdef SSH_TUN_OPENBSD 67#ifdef SSH_TUN_OPENBSD
67#include <net/if.h> 68#include <net/if.h>
68#endif 69#endif
@@ -1125,6 +1126,55 @@ percent_expand(const char *string, ...)
1125} 1126}
1126 1127
1127int 1128int
1129secure_permissions(struct stat *st, uid_t uid)
1130{
1131 if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
1132 return 0;
1133 if ((st->st_mode & 002) != 0)
1134 return 0;
1135 if ((st->st_mode & 020) != 0) {
1136 /* If the file is group-writable, the group in question must
1137 * have exactly one member, namely the file's owner.
1138 * (Zero-member groups are typically used by setgid
1139 * binaries, and are unlikely to be suitable.)
1140 */
1141 struct passwd *pw;
1142 struct group *gr;
1143 int members = 0;
1144
1145 gr = getgrgid(st->st_gid);
1146 if (!gr)
1147 return 0;
1148
1149 /* Check primary group memberships. */
1150 while ((pw = getpwent()) != NULL) {
1151 if (pw->pw_gid == gr->gr_gid) {
1152 ++members;
1153 if (pw->pw_uid != uid)
1154 return 0;
1155 }
1156 }
1157 endpwent();
1158
1159 pw = getpwuid(st->st_uid);
1160 if (!pw)
1161 return 0;
1162
1163 /* Check supplementary group memberships. */
1164 if (gr->gr_mem[0]) {
1165 ++members;
1166 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
1167 gr->gr_mem[1])
1168 return 0;
1169 }
1170
1171 if (!members)
1172 return 0;
1173 }
1174 return 1;
1175}
1176
1177int
1128tun_open(int tun, int mode, char **ifname) 1178tun_open(int tun, int mode, char **ifname)
1129{ 1179{
1130#if defined(CUSTOM_SYS_TUN_OPEN) 1180#if defined(CUSTOM_SYS_TUN_OPEN)
@@ -1909,8 +1959,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1909 snprintf(err, errlen, "%s is not a regular file", buf); 1959 snprintf(err, errlen, "%s is not a regular file", buf);
1910 return -1; 1960 return -1;
1911 } 1961 }
1912 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 1962 if (!secure_permissions(stp, uid)) {
1913 (stp->st_mode & 022) != 0) {
1914 snprintf(err, errlen, "bad ownership or modes for file %s", 1963 snprintf(err, errlen, "bad ownership or modes for file %s",
1915 buf); 1964 buf);
1916 return -1; 1965 return -1;
@@ -1925,8 +1974,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1925 strlcpy(buf, cp, sizeof(buf)); 1974 strlcpy(buf, cp, sizeof(buf));
1926 1975
1927 if (stat(buf, &st) == -1 || 1976 if (stat(buf, &st) == -1 ||
1928 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 1977 !secure_permissions(&st, uid)) {
1929 (st.st_mode & 022) != 0) {
1930 snprintf(err, errlen, 1978 snprintf(err, errlen,
1931 "bad ownership or modes for directory %s", buf); 1979 "bad ownership or modes for directory %s", buf);
1932 return -1; 1980 return -1;
diff --git a/misc.h b/misc.h
index 4a05db2da..5db594b91 100644
--- a/misc.h
+++ b/misc.h
@@ -188,6 +188,8 @@ struct notifier_ctx *notify_start(int, const char *, ...)
188 __attribute__((format(printf, 2, 3))); 188 __attribute__((format(printf, 2, 3)));
189void notify_complete(struct notifier_ctx *); 189void notify_complete(struct notifier_ctx *);
190 190
191int secure_permissions(struct stat *st, uid_t uid);
192
191#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 193#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
192#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 194#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
193#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) 195#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
diff --git a/readconf.c b/readconf.c
index 2399208f8..7f251dd4a 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1902,8 +1902,7 @@ read_config_file_depth(const char *filename, struct passwd *pw,
1902 1902
1903 if (fstat(fileno(f), &sb) == -1) 1903 if (fstat(fileno(f), &sb) == -1)
1904 fatal("fstat %s: %s", filename, strerror(errno)); 1904 fatal("fstat %s: %s", filename, strerror(errno));
1905 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1905 if (!secure_permissions(&sb, getuid()))
1906 (sb.st_mode & 022) != 0))
1907 fatal("Bad owner or permissions on %s", filename); 1906 fatal("Bad owner or permissions on %s", filename);
1908 } 1907 }
1909 1908
diff --git a/ssh.1 b/ssh.1
index db5c65bc7..cf991e4ee 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1506,6 +1506,8 @@ The file format and configuration options are described in
1506.Xr ssh_config 5 . 1506.Xr ssh_config 5 .
1507Because of the potential for abuse, this file must have strict permissions: 1507Because of the potential for abuse, this file must have strict permissions:
1508read/write for the user, and not writable by others. 1508read/write for the user, and not writable by others.
1509It may be group-writable provided that the group in question contains only
1510the user.
1509.Pp 1511.Pp
1510.It Pa ~/.ssh/environment 1512.It Pa ~/.ssh/environment
1511Contains additional definitions for environment variables; see 1513Contains additional definitions for environment variables; see
diff --git a/ssh_config.5 b/ssh_config.5
index 3079db19b..e61a0fd43 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1952,6 +1952,8 @@ The format of this file is described above.
1952This file is used by the SSH client. 1952This file is used by the SSH client.
1953Because of the potential for abuse, this file must have strict permissions: 1953Because of the potential for abuse, this file must have strict permissions:
1954read/write for the user, and not writable by others. 1954read/write for the user, and not writable by others.
1955It may be group-writable provided that the group in question contains only
1956the user.
1955.It Pa /etc/ssh/ssh_config 1957.It Pa /etc/ssh/ssh_config
1956Systemwide configuration file. 1958Systemwide configuration file.
1957This file provides defaults for those 1959This file provides defaults for those