summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--auth-rhosts.c6
-rw-r--r--auth.c9
-rw-r--r--debian/changelog6
-rw-r--r--debian/patches/debian-config.patch2
-rw-r--r--debian/patches/user-group-modes.patch155
-rw-r--r--misc.c27
-rw-r--r--misc.h2
-rw-r--r--readconf.c22
8 files changed, 165 insertions, 64 deletions
diff --git a/auth-rhosts.c b/auth-rhosts.c
index 06ae7f0b9..f20278797 100644
--- a/auth-rhosts.c
+++ b/auth-rhosts.c
@@ -256,8 +256,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
256 return 0; 256 return 0;
257 } 257 }
258 if (options.strict_modes && 258 if (options.strict_modes &&
259 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 259 !secure_permissions(&st, pw->pw_uid)) {
260 (st.st_mode & 022) != 0)) {
261 logit("Rhosts authentication refused for %.100s: " 260 logit("Rhosts authentication refused for %.100s: "
262 "bad ownership or modes for home directory.", pw->pw_name); 261 "bad ownership or modes for home directory.", pw->pw_name);
263 auth_debug_add("Rhosts authentication refused for %.100s: " 262 auth_debug_add("Rhosts authentication refused for %.100s: "
@@ -283,8 +282,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam
283 * allowing access to their account by anyone. 282 * allowing access to their account by anyone.
284 */ 283 */
285 if (options.strict_modes && 284 if (options.strict_modes &&
286 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 285 !secure_permissions(&st, pw->pw_uid)) {
287 (st.st_mode & 022) != 0)) {
288 logit("Rhosts authentication refused for %.100s: bad modes for %.200s", 286 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
289 pw->pw_name, buf); 287 pw->pw_name, buf);
290 auth_debug_add("Bad file modes for %.200s", buf); 288 auth_debug_add("Bad file modes for %.200s", buf);
diff --git a/auth.c b/auth.c
index 54f4548f1..a188b891e 100644
--- a/auth.c
+++ b/auth.c
@@ -385,8 +385,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host,
385 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); 385 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
386 if (options.strict_modes && 386 if (options.strict_modes &&
387 (stat(user_hostfile, &st) == 0) && 387 (stat(user_hostfile, &st) == 0) &&
388 ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || 388 !secure_permissions(&st, pw->pw_uid)) {
389 (st.st_mode & 022) != 0)) {
390 logit("Authentication refused for %.100s: " 389 logit("Authentication refused for %.100s: "
391 "bad owner or modes for %.200s", 390 "bad owner or modes for %.200s",
392 pw->pw_name, user_hostfile); 391 pw->pw_name, user_hostfile);
@@ -438,8 +437,7 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,
438 437
439 /* check the open file to avoid races */ 438 /* check the open file to avoid races */
440 if (fstat(fileno(f), &st) < 0 || 439 if (fstat(fileno(f), &st) < 0 ||
441 (st.st_uid != 0 && st.st_uid != uid) || 440 !secure_permissions(&st, uid)) {
442 (st.st_mode & 022) != 0) {
443 snprintf(err, errlen, "bad ownership or modes for file %s", 441 snprintf(err, errlen, "bad ownership or modes for file %s",
444 buf); 442 buf);
445 return -1; 443 return -1;
@@ -455,8 +453,7 @@ secure_filename(FILE *f, const char *file, struct passwd *pw,
455 453
456 debug3("secure_filename: checking '%s'", buf); 454 debug3("secure_filename: checking '%s'", buf);
457 if (stat(buf, &st) < 0 || 455 if (stat(buf, &st) < 0 ||
458 (st.st_uid != 0 && st.st_uid != uid) || 456 !secure_permissions(&st, uid)) {
459 (st.st_mode & 022) != 0) {
460 snprintf(err, errlen, 457 snprintf(err, errlen,
461 "bad ownership or modes for directory %s", buf); 458 "bad ownership or modes for directory %s", buf);
462 return -1; 459 return -1;
diff --git a/debian/changelog b/debian/changelog
index 5790f4643..a27f3b57f 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -4,6 +4,12 @@ openssh (1:5.5p1-4) UNRELEASED; urgency=low
4 * Add powerpcspe to architecture list for libselinux1-dev build-dependency 4 * Add powerpcspe to architecture list for libselinux1-dev build-dependency
5 (closes: #579843). 5 (closes: #579843).
6 6
7 [ Colin Watson ]
8 * Allow ~/.ssh/authorized_keys and other secure files to be
9 group-writable, provided that the group in question contains only the
10 file's owner; this extends a patch previously applied to ~/.ssh/config
11 (closes: #581919).
12
7 -- Colin Watson <cjwatson@debian.org> Tue, 04 May 2010 13:32:17 +0100 13 -- Colin Watson <cjwatson@debian.org> Tue, 04 May 2010 13:32:17 +0100
8 14
9openssh (1:5.5p1-3) unstable; urgency=low 15openssh (1:5.5p1-3) unstable; urgency=low
diff --git a/debian/patches/debian-config.patch b/debian/patches/debian-config.patch
index a395d43a0..ac77919e6 100644
--- a/debian/patches/debian-config.patch
+++ b/debian/patches/debian-config.patch
@@ -24,7 +24,7 @@ Index: b/readconf.c
24=================================================================== 24===================================================================
25--- a/readconf.c 25--- a/readconf.c
26+++ b/readconf.c 26+++ b/readconf.c
27@@ -1152,7 +1152,7 @@ 27@@ -1132,7 +1132,7 @@
28 if (options->forward_x11 == -1) 28 if (options->forward_x11 == -1)
29 options->forward_x11 = 0; 29 options->forward_x11 = 0;
30 if (options->forward_x11_trusted == -1) 30 if (options->forward_x11_trusted == -1)
diff --git a/debian/patches/user-group-modes.patch b/debian/patches/user-group-modes.patch
index 4d7ebe566..8cf862049 100644
--- a/debian/patches/user-group-modes.patch
+++ b/debian/patches/user-group-modes.patch
@@ -1,10 +1,11 @@
1Description: Allow harmless group-writability 1Description: Allow harmless group-writability
2 Allow ~/.ssh/config to be group-writable, provided that the group in 2 Allow secure files (~/.ssh/config, ~/.ssh/authorized_keys, etc.) to be
3 question contains only the file's owner. Rejected upstream for IMO 3 group-writable, provided that the group in question contains only the
4 incorrect reasons (e.g. a misunderstanding about the contents of 4 file's owner. Rejected upstream for IMO incorrect reasons (e.g. a
5 gr->gr_mem). Given that per-user groups and umask 002 are the default 5 misunderstanding about the contents of gr->gr_mem). Given that
6 setup in Debian (for good reasons - this makes operating in setgid 6 per-user groups and umask 002 are the default setup in Debian (for good
7 directories with other groups much easier), we need to permit this. 7 reasons - this makes operating in setgid directories with other groups
8 much easier), we need to permit this by default.
8Author: Colin Watson <cjwatson@debian.org> 9Author: Colin Watson <cjwatson@debian.org>
9Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060 10Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060
10Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347 11Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347
@@ -23,36 +24,13 @@ Index: b/readconf.c
23 24
24 #include "xmalloc.h" 25 #include "xmalloc.h"
25 #include "ssh.h" 26 #include "ssh.h"
26@@ -1000,11 +1002,30 @@ 27@@ -1003,8 +1005,7 @@
27
28 if (checkperm) {
29 struct stat sb;
30+ int bad_modes = 0;
31 28
32 if (fstat(fileno(f), &sb) == -1) 29 if (fstat(fileno(f), &sb) == -1)
33 fatal("fstat %s: %s", filename, strerror(errno)); 30 fatal("fstat %s: %s", filename, strerror(errno));
34- if (((sb.st_uid != 0 && sb.st_uid != getuid()) || 31- if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
35- (sb.st_mode & 022) != 0)) 32- (sb.st_mode & 022) != 0))
36+ if (sb.st_uid != 0 && sb.st_uid != getuid()) 33+ if (!secure_permissions(&sb, getuid()))
37+ bad_modes = 1;
38+ if ((sb.st_mode & 020) != 0) {
39+ /* If the file is group-writable, the group in
40+ * question must have at most one member, namely the
41+ * file's owner.
42+ */
43+ struct passwd *pw = getpwuid(sb.st_uid);
44+ struct group *gr = getgrgid(sb.st_gid);
45+ if (!pw || !gr)
46+ bad_modes = 1;
47+ else if (gr->gr_mem[0]) {
48+ if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
49+ gr->gr_mem[1])
50+ bad_modes = 1;
51+ }
52+ }
53+ if ((sb.st_mode & 002) != 0)
54+ bad_modes = 1;
55+ if (bad_modes)
56 fatal("Bad owner or permissions on %s", filename); 34 fatal("Bad owner or permissions on %s", filename);
57 } 35 }
58 36
@@ -82,3 +60,118 @@ Index: b/ssh_config.5
82 .It Pa /etc/ssh/ssh_config 60 .It Pa /etc/ssh/ssh_config
83 Systemwide configuration file. 61 Systemwide configuration file.
84 This file provides defaults for those 62 This file provides defaults for those
63Index: b/auth.c
64===================================================================
65--- a/auth.c
66+++ b/auth.c
67@@ -385,8 +385,7 @@
68 user_hostfile = tilde_expand_filename(userfile, pw->pw_uid);
69 if (options.strict_modes &&
70 (stat(user_hostfile, &st) == 0) &&
71- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
72- (st.st_mode & 022) != 0)) {
73+ !secure_permissions(&st, pw->pw_uid)) {
74 logit("Authentication refused for %.100s: "
75 "bad owner or modes for %.200s",
76 pw->pw_name, user_hostfile);
77@@ -438,8 +437,7 @@
78
79 /* check the open file to avoid races */
80 if (fstat(fileno(f), &st) < 0 ||
81- (st.st_uid != 0 && st.st_uid != uid) ||
82- (st.st_mode & 022) != 0) {
83+ !secure_permissions(&st, uid)) {
84 snprintf(err, errlen, "bad ownership or modes for file %s",
85 buf);
86 return -1;
87@@ -455,8 +453,7 @@
88
89 debug3("secure_filename: checking '%s'", buf);
90 if (stat(buf, &st) < 0 ||
91- (st.st_uid != 0 && st.st_uid != uid) ||
92- (st.st_mode & 022) != 0) {
93+ !secure_permissions(&st, uid)) {
94 snprintf(err, errlen,
95 "bad ownership or modes for directory %s", buf);
96 return -1;
97Index: b/misc.c
98===================================================================
99--- a/misc.c
100+++ b/misc.c
101@@ -45,8 +45,9 @@
102 #include <netdb.h>
103 #ifdef HAVE_PATHS_H
104 # include <paths.h>
105-#include <pwd.h>
106 #endif
107+#include <pwd.h>
108+#include <grp.h>
109 #ifdef SSH_TUN_OPENBSD
110 #include <net/if.h>
111 #endif
112@@ -638,6 +639,30 @@
113 }
114
115 int
116+secure_permissions(struct stat *st, uid_t uid)
117+{
118+ if (st->st_uid != 0 && st->st_uid != uid)
119+ return 0;
120+ if ((st->st_mode & 020) != 0) {
121+ /* If the file is group-writable, the group in question must
122+ * have at most one member, namely the file's owner.
123+ */
124+ struct passwd *pw = getpwuid(st->st_uid);
125+ struct group *gr = getgrgid(st->st_gid);
126+ if (!pw || !gr)
127+ return 0;
128+ else if (gr->gr_mem[0]) {
129+ if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
130+ gr->gr_mem[1])
131+ return 0;
132+ }
133+ }
134+ if ((st->st_mode & 002) != 0)
135+ return 0;
136+ return 1;
137+}
138+
139+int
140 tun_open(int tun, int mode)
141 {
142 #if defined(CUSTOM_SYS_TUN_OPEN)
143Index: b/misc.h
144===================================================================
145--- a/misc.h
146+++ b/misc.h
147@@ -91,4 +91,6 @@
148 int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
149 int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
150
151+int secure_permissions(struct stat *st, uid_t uid);
152+
153 #endif /* _MISC_H */
154Index: b/auth-rhosts.c
155===================================================================
156--- a/auth-rhosts.c
157+++ b/auth-rhosts.c
158@@ -256,8 +256,7 @@
159 return 0;
160 }
161 if (options.strict_modes &&
162- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
163- (st.st_mode & 022) != 0)) {
164+ !secure_permissions(&st, pw->pw_uid)) {
165 logit("Rhosts authentication refused for %.100s: "
166 "bad ownership or modes for home directory.", pw->pw_name);
167 auth_debug_add("Rhosts authentication refused for %.100s: "
168@@ -283,8 +282,7 @@
169 * allowing access to their account by anyone.
170 */
171 if (options.strict_modes &&
172- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
173- (st.st_mode & 022) != 0)) {
174+ !secure_permissions(&st, pw->pw_uid)) {
175 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
176 pw->pw_name, buf);
177 auth_debug_add("Bad file modes for %.200s", buf);
diff --git a/misc.c b/misc.c
index e1f723123..4ca318423 100644
--- a/misc.c
+++ b/misc.c
@@ -45,8 +45,9 @@
45#include <netdb.h> 45#include <netdb.h>
46#ifdef HAVE_PATHS_H 46#ifdef HAVE_PATHS_H
47# include <paths.h> 47# include <paths.h>
48#include <pwd.h>
49#endif 48#endif
49#include <pwd.h>
50#include <grp.h>
50#ifdef SSH_TUN_OPENBSD 51#ifdef SSH_TUN_OPENBSD
51#include <net/if.h> 52#include <net/if.h>
52#endif 53#endif
@@ -638,6 +639,30 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz,
638} 639}
639 640
640int 641int
642secure_permissions(struct stat *st, uid_t uid)
643{
644 if (st->st_uid != 0 && st->st_uid != uid)
645 return 0;
646 if ((st->st_mode & 020) != 0) {
647 /* If the file is group-writable, the group in question must
648 * have at most one member, namely the file's owner.
649 */
650 struct passwd *pw = getpwuid(st->st_uid);
651 struct group *gr = getgrgid(st->st_gid);
652 if (!pw || !gr)
653 return 0;
654 else if (gr->gr_mem[0]) {
655 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
656 gr->gr_mem[1])
657 return 0;
658 }
659 }
660 if ((st->st_mode & 002) != 0)
661 return 0;
662 return 1;
663}
664
665int
641tun_open(int tun, int mode) 666tun_open(int tun, int mode)
642{ 667{
643#if defined(CUSTOM_SYS_TUN_OPEN) 668#if defined(CUSTOM_SYS_TUN_OPEN)
diff --git a/misc.h b/misc.h
index 32073acd4..8fbfc7985 100644
--- a/misc.h
+++ b/misc.h
@@ -91,4 +91,6 @@ char *read_passphrase(const char *, int);
91int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); 91int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
92int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); 92int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
93 93
94int secure_permissions(struct stat *st, uid_t uid);
95
94#endif /* _MISC_H */ 96#endif /* _MISC_H */
diff --git a/readconf.c b/readconf.c
index 487c3399b..2a5a706ab 100644
--- a/readconf.c
+++ b/readconf.c
@@ -1002,30 +1002,10 @@ read_config_file(const char *filename, const char *host, Options *options,
1002 1002
1003 if (checkperm) { 1003 if (checkperm) {
1004 struct stat sb; 1004 struct stat sb;
1005 int bad_modes = 0;
1006 1005
1007 if (fstat(fileno(f), &sb) == -1) 1006 if (fstat(fileno(f), &sb) == -1)
1008 fatal("fstat %s: %s", filename, strerror(errno)); 1007 fatal("fstat %s: %s", filename, strerror(errno));
1009 if (sb.st_uid != 0 && sb.st_uid != getuid()) 1008 if (!secure_permissions(&sb, getuid()))
1010 bad_modes = 1;
1011 if ((sb.st_mode & 020) != 0) {
1012 /* If the file is group-writable, the group in
1013 * question must have at most one member, namely the
1014 * file's owner.
1015 */
1016 struct passwd *pw = getpwuid(sb.st_uid);
1017 struct group *gr = getgrgid(sb.st_gid);
1018 if (!pw || !gr)
1019 bad_modes = 1;
1020 else if (gr->gr_mem[0]) {
1021 if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
1022 gr->gr_mem[1])
1023 bad_modes = 1;
1024 }
1025 }
1026 if ((sb.st_mode & 002) != 0)
1027 bad_modes = 1;
1028 if (bad_modes)
1029 fatal("Bad owner or permissions on %s", filename); 1009 fatal("Bad owner or permissions on %s", filename);
1030 } 1010 }
1031 1011