diff options
-rw-r--r-- | auth-rhosts.c | 6 | ||||
-rw-r--r-- | auth.c | 3 | ||||
-rw-r--r-- | misc.c | 58 | ||||
-rw-r--r-- | misc.h | 2 | ||||
-rw-r--r-- | readconf.c | 3 | ||||
-rw-r--r-- | ssh.1 | 2 | ||||
-rw-r--r-- | ssh_config.5 | 2 |
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); |
@@ -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); |
@@ -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 | ||
1115 | int | 1116 | int |
1117 | secure_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 | |||
1165 | int | ||
1116 | tun_open(int tun, int mode, char **ifname) | 1166 | tun_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; |
@@ -181,6 +181,8 @@ int opt_match(const char **opts, const char *term); | |||
181 | char *read_passphrase(const char *, int); | 181 | char *read_passphrase(const char *, int); |
182 | int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); | 182 | int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); |
183 | 183 | ||
184 | int 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 | ||
@@ -1484,6 +1484,8 @@ The file format and configuration options are described in | |||
1484 | .Xr ssh_config 5 . | 1484 | .Xr ssh_config 5 . |
1485 | Because of the potential for abuse, this file must have strict permissions: | 1485 | Because of the potential for abuse, this file must have strict permissions: |
1486 | read/write for the user, and not writable by others. | 1486 | read/write for the user, and not writable by others. |
1487 | It may be group-writable provided that the group in question contains only | ||
1488 | the user. | ||
1487 | .Pp | 1489 | .Pp |
1488 | .It Pa ~/.ssh/environment | 1490 | .It Pa ~/.ssh/environment |
1489 | Contains additional definitions for environment variables; see | 1491 | Contains 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. | |||
1907 | This file is used by the SSH client. | 1907 | This file is used by the SSH client. |
1908 | Because of the potential for abuse, this file must have strict permissions: | 1908 | Because of the potential for abuse, this file must have strict permissions: |
1909 | read/write for the user, and not writable by others. | 1909 | read/write for the user, and not writable by others. |
1910 | It may be group-writable provided that the group in question contains only | ||
1911 | the user. | ||
1910 | .It Pa /etc/ssh/ssh_config | 1912 | .It Pa /etc/ssh/ssh_config |
1911 | Systemwide configuration file. | 1913 | Systemwide configuration file. |
1912 | This file provides defaults for those | 1914 | This file provides defaults for those |