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 47c27773c..fc0c05bae 100644
--- a/auth.c
+++ b/auth.c
@@ -473,8 +473,7 @@ check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
473 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 473 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
474 if (options.strict_modes && 474 if (options.strict_modes &&
475 (stat(user_hostfile, &st) == 0) && 475 (stat(user_hostfile, &st) == 0) &&
476 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 476 !secure_permissions(&st, pw->pw_uid)) {
477 (st.st_mode & 022) != 0)) {
478 logit("Authentication refused for %.100s: " 477 logit("Authentication refused for %.100s: "
479 "bad owner or modes for %.200s", 478 "bad owner or modes for %.200s",
480 pw->pw_name, user_hostfile); 479 pw->pw_name, user_hostfile);
diff --git a/misc.c b/misc.c
index 88833d7ff..42eeb425a 100644
--- a/misc.c
+++ b/misc.c
@@ -59,8 +59,9 @@
59#include <netdb.h> 59#include <netdb.h>
60#ifdef HAVE_PATHS_H 60#ifdef HAVE_PATHS_H
61# include <paths.h> 61# include <paths.h>
62#include <pwd.h>
63#endif 62#endif
63#include <pwd.h>
64#include <grp.h>
64#ifdef SSH_TUN_OPENBSD 65#ifdef SSH_TUN_OPENBSD
65#include <net/if.h> 66#include <net/if.h>
66#endif 67#endif
@@ -1113,6 +1114,55 @@ percent_expand(const char *string, ...)
1113} 1114}
1114 1115
1115int 1116int
1117secure_permissions(struct stat *st, uid_t uid)
1118{
1119 if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
1120 return 0;
1121 if ((st->st_mode & 002) != 0)
1122 return 0;
1123 if ((st->st_mode & 020) != 0) {
1124 /* If the file is group-writable, the group in question must
1125 * have exactly one member, namely the file's owner.
1126 * (Zero-member groups are typically used by setgid
1127 * binaries, and are unlikely to be suitable.)
1128 */
1129 struct passwd *pw;
1130 struct group *gr;
1131 int members = 0;
1132
1133 gr = getgrgid(st->st_gid);
1134 if (!gr)
1135 return 0;
1136
1137 /* Check primary group memberships. */
1138 while ((pw = getpwent()) != NULL) {
1139 if (pw->pw_gid == gr->gr_gid) {
1140 ++members;
1141 if (pw->pw_uid != uid)
1142 return 0;
1143 }
1144 }
1145 endpwent();
1146
1147 pw = getpwuid(st->st_uid);
1148 if (!pw)
1149 return 0;
1150
1151 /* Check supplementary group memberships. */
1152 if (gr->gr_mem[0]) {
1153 ++members;
1154 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
1155 gr->gr_mem[1])
1156 return 0;
1157 }
1158
1159 if (!members)
1160 return 0;
1161 }
1162 return 1;
1163}
1164
1165int
1116tun_open(int tun, int mode, char **ifname) 1166tun_open(int tun, int mode, char **ifname)
1117{ 1167{
1118#if defined(CUSTOM_SYS_TUN_OPEN) 1168#if defined(CUSTOM_SYS_TUN_OPEN)
@@ -1869,8 +1919,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1869 snprintf(err, errlen, "%s is not a regular file", buf); 1919 snprintf(err, errlen, "%s is not a regular file", buf);
1870 return -1; 1920 return -1;
1871 } 1921 }
1872 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 1922 if (!secure_permissions(stp, uid)) {
1873 (stp->st_mode & 022) != 0) {
1874 snprintf(err, errlen, "bad ownership or modes for file %s", 1923 snprintf(err, errlen, "bad ownership or modes for file %s",
1875 buf); 1924 buf);
1876 return -1; 1925 return -1;
@@ -1885,8 +1934,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1885 strlcpy(buf, cp, sizeof(buf)); 1934 strlcpy(buf, cp, sizeof(buf));
1886 1935
1887 if (stat(buf, &st) == -1 || 1936 if (stat(buf, &st) == -1 ||
1888 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 1937 !secure_permissions(&st, uid)) {
1889 (st.st_mode & 022) != 0) {
1890 snprintf(err, errlen, 1938 snprintf(err, errlen,
1891 "bad ownership or modes for directory %s", buf); 1939 "bad ownership or modes for directory %s", buf);
1892 return -1; 1940 return -1;
diff --git a/misc.h b/misc.h
index bcc34f980..869895d3a 100644
--- a/misc.h
+++ b/misc.h
@@ -181,6 +181,8 @@ int opt_match(const char **opts, const char *term);
181char *read_passphrase(const char *, int); 181char *read_passphrase(const char *, int);
182int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); 182int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
183 183
184int secure_permissions(struct stat *st, uid_t uid);
185
184#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 186#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
185#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 187#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
186#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) 188#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
diff --git a/readconf.c b/readconf.c
index 09787c0e5..16d2729dd 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1855,8 +1855,7 @@ read_config_file_depth(const char *filename, struct passwd *pw,
1855 1855
1856 if (fstat(fileno(f), &sb) == -1) 1856 if (fstat(fileno(f), &sb) == -1)
1857 fatal("fstat %s: %s", filename, strerror(errno)); 1857 fatal("fstat %s: %s", filename, strerror(errno));
1858 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1858 if (!secure_permissions(&sb, getuid()))
1859 (sb.st_mode & 022) != 0))
1860 fatal("Bad owner or permissions on %s", filename); 1859 fatal("Bad owner or permissions on %s", filename);
1861 } 1860 }
1862 1861
diff --git a/ssh.1 b/ssh.1
index 26940ad55..20e4c4efa 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1484,6 +1484,8 @@ The file format and configuration options are described in
1484.Xr ssh_config 5 . 1484.Xr ssh_config 5 .
1485Because of the potential for abuse, this file must have strict permissions: 1485Because of the potential for abuse, this file must have strict permissions:
1486read/write for the user, and not writable by others. 1486read/write for the user, and not writable by others.
1487It may be group-writable provided that the group in question contains only
1488the user.
1487.Pp 1489.Pp
1488.It Pa ~/.ssh/environment 1490.It Pa ~/.ssh/environment
1489Contains additional definitions for environment variables; see 1491Contains additional definitions for environment variables; see
diff --git a/ssh_config.5 b/ssh_config.5
index bc04d8d02..2c74b57c0 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1907,6 +1907,8 @@ The format of this file is described above.
1907This file is used by the SSH client. 1907This file is used by the SSH client.
1908Because of the potential for abuse, this file must have strict permissions: 1908Because of the potential for abuse, this file must have strict permissions:
1909read/write for the user, and not writable by others. 1909read/write for the user, and not writable by others.
1910It may be group-writable provided that the group in question contains only
1911the user.
1910.It Pa /etc/ssh/ssh_config 1912.It Pa /etc/ssh/ssh_config
1911Systemwide configuration file. 1913Systemwide configuration file.
1912This file provides defaults for those 1914This file provides defaults for those