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 57296e1f6..546aa0495 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -261,8 +261,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
261 return 0; 261 return 0;
262 } 262 }
263 if (options.strict_modes && 263 if (options.strict_modes &&
264 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 264 !secure_permissions(&st, pw->pw_uid)) {
265 (st.st_mode & 022) != 0)) {
266 logit("Rhosts authentication refused for %.100s: " 265 logit("Rhosts authentication refused for %.100s: "
267 "bad ownership or modes for home directory.", pw->pw_name); 266 "bad ownership or modes for home directory.", pw->pw_name);
268 auth_debug_add("Rhosts authentication refused for %.100s: " 267 auth_debug_add("Rhosts authentication refused for %.100s: "
@@ -288,8 +287,7 @@ auth_rhosts2(struct passwd *pw, const char *client_user, const char *hostname,
288 * allowing access to their account by anyone. 287 * allowing access to their account by anyone.
289 */ 288 */
290 if (options.strict_modes && 289 if (options.strict_modes &&
291 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 290 !secure_permissions(&st, pw->pw_uid)) {
292 (st.st_mode & 022) != 0)) {
293 logit("Rhosts authentication refused for %.100s: bad modes for %.200s", 291 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
294 pw->pw_name, buf); 292 pw->pw_name, buf);
295 auth_debug_add("Bad file modes for %.200s", buf); 293 auth_debug_add("Bad file modes for %.200s", buf);
diff --git a/auth.c b/auth.c
index f7a23afba..8ffd77662 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 009e02bc5..634b5060a 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
@@ -1104,6 +1105,55 @@ percent_expand(const char *string, ...)
1104} 1105}
1105 1106
1106int 1107int
1108secure_permissions(struct stat *st, uid_t uid)
1109{
1110 if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
1111 return 0;
1112 if ((st->st_mode & 002) != 0)
1113 return 0;
1114 if ((st->st_mode & 020) != 0) {
1115 /* If the file is group-writable, the group in question must
1116 * have exactly one member, namely the file's owner.
1117 * (Zero-member groups are typically used by setgid
1118 * binaries, and are unlikely to be suitable.)
1119 */
1120 struct passwd *pw;
1121 struct group *gr;
1122 int members = 0;
1123
1124 gr = getgrgid(st->st_gid);
1125 if (!gr)
1126 return 0;
1127
1128 /* Check primary group memberships. */
1129 while ((pw = getpwent()) != NULL) {
1130 if (pw->pw_gid == gr->gr_gid) {
1131 ++members;
1132 if (pw->pw_uid != uid)
1133 return 0;
1134 }
1135 }
1136 endpwent();
1137
1138 pw = getpwuid(st->st_uid);
1139 if (!pw)
1140 return 0;
1141
1142 /* Check supplementary group memberships. */
1143 if (gr->gr_mem[0]) {
1144 ++members;
1145 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
1146 gr->gr_mem[1])
1147 return 0;
1148 }
1149
1150 if (!members)
1151 return 0;
1152 }
1153 return 1;
1154}
1155
1156int
1107tun_open(int tun, int mode, char **ifname) 1157tun_open(int tun, int mode, char **ifname)
1108{ 1158{
1109#if defined(CUSTOM_SYS_TUN_OPEN) 1159#if defined(CUSTOM_SYS_TUN_OPEN)
@@ -1860,8 +1910,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1860 snprintf(err, errlen, "%s is not a regular file", buf); 1910 snprintf(err, errlen, "%s is not a regular file", buf);
1861 return -1; 1911 return -1;
1862 } 1912 }
1863 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 1913 if (!secure_permissions(stp, uid)) {
1864 (stp->st_mode & 022) != 0) {
1865 snprintf(err, errlen, "bad ownership or modes for file %s", 1914 snprintf(err, errlen, "bad ownership or modes for file %s",
1866 buf); 1915 buf);
1867 return -1; 1916 return -1;
@@ -1876,8 +1925,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1876 strlcpy(buf, cp, sizeof(buf)); 1925 strlcpy(buf, cp, sizeof(buf));
1877 1926
1878 if (stat(buf, &st) < 0 || 1927 if (stat(buf, &st) < 0 ||
1879 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 1928 !secure_permissions(&st, uid)) {
1880 (st.st_mode & 022) != 0) {
1881 snprintf(err, errlen, 1929 snprintf(err, errlen,
1882 "bad ownership or modes for directory %s", buf); 1930 "bad ownership or modes for directory %s", buf);
1883 return -1; 1931 return -1;
diff --git a/misc.h b/misc.h
index 5b4325aba..a4bdee187 100644
--- a/misc.h
+++ b/misc.h
@@ -175,6 +175,8 @@ int safe_path_fd(int, const char *, struct passwd *,
175char *read_passphrase(const char *, int); 175char *read_passphrase(const char *, int);
176int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); 176int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
177 177
178int secure_permissions(struct stat *st, uid_t uid);
179
178#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 180#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
179#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 181#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
180#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) 182#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
diff --git a/readconf.c b/readconf.c
index 3d0b6ff90..cd60007f8 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1846,8 +1846,7 @@ read_config_file_depth(const char *filename, struct passwd *pw,
1846 1846
1847 if (fstat(fileno(f), &sb) == -1) 1847 if (fstat(fileno(f), &sb) == -1)
1848 fatal("fstat %s: %s", filename, strerror(errno)); 1848 fatal("fstat %s: %s", filename, strerror(errno));
1849 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1849 if (!secure_permissions(&sb, getuid()))
1850 (sb.st_mode & 022) != 0))
1851 fatal("Bad owner or permissions on %s", filename); 1850 fatal("Bad owner or permissions on %s", filename);
1852 } 1851 }
1853 1852
diff --git a/ssh.1 b/ssh.1
index a1c7d2305..64ead5f57 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 250c92d04..bd1e9311d 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1885,6 +1885,8 @@ The format of this file is described above.
1885This file is used by the SSH client. 1885This file is used by the SSH client.
1886Because of the potential for abuse, this file must have strict permissions: 1886Because of the potential for abuse, this file must have strict permissions:
1887read/write for the user, and not writable by others. 1887read/write for the user, and not writable by others.
1888It may be group-writable provided that the group in question contains only
1889the user.
1888.It Pa /etc/ssh/ssh_config 1890.It Pa /etc/ssh/ssh_config
1889Systemwide configuration file. 1891Systemwide configuration file.
1890This file provides defaults for those 1892This file provides defaults for those