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 ecf956f06..4dccd5e6a 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 6aec36052..68a1e4a76 100644
--- a/auth.c
+++ b/auth.c
@@ -467,8 +467,7 @@ check_key_in_hostfiles(struct passwd *pw, struct sshkey *key, const char *host,
467 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 467 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
468 if (options.strict_modes && 468 if (options.strict_modes &&
469 (stat(user_hostfile, &st) == 0) && 469 (stat(user_hostfile, &st) == 0) &&
470 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 470 !secure_permissions(&st, pw->pw_uid)) {
471 (st.st_mode & 022) != 0)) {
472 logit("Authentication refused for %.100s: " 471 logit("Authentication refused for %.100s: "
473 "bad owner or modes for %.200s", 472 "bad owner or modes for %.200s",
474 pw->pw_name, user_hostfile); 473 pw->pw_name, user_hostfile);
diff --git a/misc.c b/misc.c
index 05950a471..40aeeef36 100644
--- a/misc.c
+++ b/misc.c
@@ -57,8 +57,9 @@
57#include <netdb.h> 57#include <netdb.h>
58#ifdef HAVE_PATHS_H 58#ifdef HAVE_PATHS_H
59# include <paths.h> 59# include <paths.h>
60#include <pwd.h>
61#endif 60#endif
61#include <pwd.h>
62#include <grp.h>
62#ifdef SSH_TUN_OPENBSD 63#ifdef SSH_TUN_OPENBSD
63#include <net/if.h> 64#include <net/if.h>
64#endif 65#endif
@@ -724,6 +725,55 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
724} 725}
725 726
726int 727int
728secure_permissions(struct stat *st, uid_t uid)
729{
730 if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
731 return 0;
732 if ((st->st_mode & 002) != 0)
733 return 0;
734 if ((st->st_mode & 020) != 0) {
735 /* If the file is group-writable, the group in question must
736 * have exactly one member, namely the file's owner.
737 * (Zero-member groups are typically used by setgid
738 * binaries, and are unlikely to be suitable.)
739 */
740 struct passwd *pw;
741 struct group *gr;
742 int members = 0;
743
744 gr = getgrgid(st->st_gid);
745 if (!gr)
746 return 0;
747
748 /* Check primary group memberships. */
749 while ((pw = getpwent()) != NULL) {
750 if (pw->pw_gid == gr->gr_gid) {
751 ++members;
752 if (pw->pw_uid != uid)
753 return 0;
754 }
755 }
756 endpwent();
757
758 pw = getpwuid(st->st_uid);
759 if (!pw)
760 return 0;
761
762 /* Check supplementary group memberships. */
763 if (gr->gr_mem[0]) {
764 ++members;
765 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
766 gr->gr_mem[1])
767 return 0;
768 }
769
770 if (!members)
771 return 0;
772 }
773 return 1;
774}
775
776int
727tun_open(int tun, int mode) 777tun_open(int tun, int mode)
728{ 778{
729#if defined(CUSTOM_SYS_TUN_OPEN) 779#if defined(CUSTOM_SYS_TUN_OPEN)
@@ -1626,8 +1676,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1626 snprintf(err, errlen, "%s is not a regular file", buf); 1676 snprintf(err, errlen, "%s is not a regular file", buf);
1627 return -1; 1677 return -1;
1628 } 1678 }
1629 if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || 1679 if (!secure_permissions(stp, uid)) {
1630 (stp->st_mode & 022) != 0) {
1631 snprintf(err, errlen, "bad ownership or modes for file %s", 1680 snprintf(err, errlen, "bad ownership or modes for file %s",
1632 buf); 1681 buf);
1633 return -1; 1682 return -1;
@@ -1642,8 +1691,7 @@ safe_path(const char *name, struct stat *stp, const char *pw_dir,
1642 strlcpy(buf, cp, sizeof(buf)); 1691 strlcpy(buf, cp, sizeof(buf));
1643 1692
1644 if (stat(buf, &st) < 0 || 1693 if (stat(buf, &st) < 0 ||
1645 (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || 1694 !secure_permissions(&st, uid)) {
1646 (st.st_mode & 022) != 0) {
1647 snprintf(err, errlen, 1695 snprintf(err, errlen,
1648 "bad ownership or modes for directory %s", buf); 1696 "bad ownership or modes for directory %s", buf);
1649 return -1; 1697 return -1;
diff --git a/misc.h b/misc.h
index 153d11375..d8759ab10 100644
--- a/misc.h
+++ b/misc.h
@@ -163,6 +163,8 @@ char *read_passphrase(const char *, int);
163int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); 163int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
164int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); 164int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
165 165
166int secure_permissions(struct stat *st, uid_t uid);
167
166#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 168#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
167#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b)) 169#define MAXIMUM(a, b) (((a) > (b)) ? (a) : (b))
168#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y)) 170#define ROUNDUP(x, y) ((((x)+((y)-1))/(y))*(y))
diff --git a/readconf.c b/readconf.c
index 45caa0951..be3d58737 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1766,8 +1766,7 @@ read_config_file_depth(const char *filename, struct passwd *pw,
1766 1766
1767 if (fstat(fileno(f), &sb) == -1) 1767 if (fstat(fileno(f), &sb) == -1)
1768 fatal("fstat %s: %s", filename, strerror(errno)); 1768 fatal("fstat %s: %s", filename, strerror(errno));
1769 if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 1769 if (!secure_permissions(&sb, getuid()))
1770 (sb.st_mode & 022) != 0))
1771 fatal("Bad owner or permissions on %s", filename); 1770 fatal("Bad owner or permissions on %s", filename);
1772 } 1771 }
1773 1772
diff --git a/ssh.1 b/ssh.1
index 2ab1697f9..3cc94688c 100644
--- a/ssh.1
+++ b/ssh.1
@@ -1456,6 +1456,8 @@ The file format and configuration options are described in
1456.Xr ssh_config 5 . 1456.Xr ssh_config 5 .
1457Because of the potential for abuse, this file must have strict permissions: 1457Because of the potential for abuse, this file must have strict permissions:
1458read/write for the user, and not writable by others. 1458read/write for the user, and not writable by others.
1459It may be group-writable provided that the group in question contains only
1460the user.
1459.Pp 1461.Pp
1460.It Pa ~/.ssh/environment 1462.It Pa ~/.ssh/environment
1461Contains additional definitions for environment variables; see 1463Contains additional definitions for environment variables; see
diff --git a/ssh_config.5 b/ssh_config.5
index d6f43c2dd..7810a418e 100644
--- a/ssh_config.5
+++ b/ssh_config.5
@@ -1786,6 +1786,8 @@ The format of this file is described above.
1786This file is used by the SSH client. 1786This file is used by the SSH client.
1787Because of the potential for abuse, this file must have strict permissions: 1787Because of the potential for abuse, this file must have strict permissions:
1788read/write for the user, and not accessible by others. 1788read/write for the user, and not accessible by others.
1789It may be group-writable provided that the group in question contains only
1790the user.
1789.It Pa /etc/ssh/ssh_config 1791.It Pa /etc/ssh/ssh_config
1790Systemwide configuration file. 1792Systemwide configuration file.
1791This file provides defaults for those 1793This file provides defaults for those