summaryrefslogtreecommitdiff
path: root/debian/patches/user-group-modes.patch
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/user-group-modes.patch')
-rw-r--r--debian/patches/user-group-modes.patch250
1 files changed, 250 insertions, 0 deletions
diff --git a/debian/patches/user-group-modes.patch b/debian/patches/user-group-modes.patch
new file mode 100644
index 000000000..d0de9c006
--- /dev/null
+++ b/debian/patches/user-group-modes.patch
@@ -0,0 +1,250 @@
1Description: Allow harmless group-writability
2 Allow secure files (~/.ssh/config, ~/.ssh/authorized_keys, etc.) to be
3 group-writable, provided that the group in question contains only the
4 file's owner. Rejected upstream for IMO incorrect reasons (e.g. a
5 misunderstanding about the contents of gr->gr_mem). Given that
6 per-user groups and umask 002 are the default setup in Debian (for good
7 reasons - this makes operating in setgid directories with other groups
8 much easier), we need to permit this by default.
9Author: Colin Watson <cjwatson@debian.org>
10Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060
11Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347
12Last-Update: 2013-05-16
13
14Index: b/readconf.c
15===================================================================
16--- a/readconf.c
17+++ b/readconf.c
18@@ -30,6 +30,8 @@
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22+#include <pwd.h>
23+#include <grp.h>
24
25 #include "xmalloc.h"
26 #include "ssh.h"
27@@ -1150,8 +1152,7 @@
28
29 if (fstat(fileno(f), &sb) == -1)
30 fatal("fstat %s: %s", filename, strerror(errno));
31- if (((sb.st_uid != 0 && sb.st_uid != getuid()) ||
32- (sb.st_mode & 022) != 0))
33+ if (!secure_permissions(&sb, getuid()))
34 fatal("Bad owner or permissions on %s", filename);
35 }
36
37Index: b/ssh.1
38===================================================================
39--- a/ssh.1
40+++ b/ssh.1
41@@ -1320,6 +1320,8 @@
42 .Xr ssh_config 5 .
43 Because of the potential for abuse, this file must have strict permissions:
44 read/write for the user, and not accessible by others.
45+It may be group-writable provided that the group in question contains only
46+the user.
47 .Pp
48 .It Pa ~/.ssh/environment
49 Contains additional definitions for environment variables; see
50Index: b/ssh_config.5
51===================================================================
52--- a/ssh_config.5
53+++ b/ssh_config.5
54@@ -1356,6 +1356,8 @@
55 This file is used by the SSH client.
56 Because of the potential for abuse, this file must have strict permissions:
57 read/write for the user, and not accessible by others.
58+It may be group-writable provided that the group in question contains only
59+the user.
60 .It Pa /etc/ssh/ssh_config
61 Systemwide configuration file.
62 This file provides defaults for those
63Index: b/auth.c
64===================================================================
65--- a/auth.c
66+++ b/auth.c
67@@ -386,8 +386,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@@ -449,8 +448,7 @@
78 snprintf(err, errlen, "%s is not a regular file", buf);
79 return -1;
80 }
81- if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) ||
82- (stp->st_mode & 022) != 0) {
83+ if (!secure_permissions(stp, uid)) {
84 snprintf(err, errlen, "bad ownership or modes for file %s",
85 buf);
86 return -1;
87@@ -465,8 +463,7 @@
88 strlcpy(buf, cp, sizeof(buf));
89
90 if (stat(buf, &st) < 0 ||
91- (!platform_sys_dir_uid(st.st_uid) && 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@@ -48,8 +48,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@@ -58,6 +59,7 @@
113 #include "misc.h"
114 #include "log.h"
115 #include "ssh.h"
116+#include "platform.h"
117
118 /* remove newline at end of string */
119 char *
120@@ -641,6 +643,71 @@
121 return -1;
122 }
123
124+/*
125+ * return 1 if the specified uid is a uid that may own a system directory
126+ * otherwise 0.
127+ */
128+int
129+platform_sys_dir_uid(uid_t uid)
130+{
131+ if (uid == 0)
132+ return 1;
133+#ifdef PLATFORM_SYS_DIR_UID
134+ if (uid == PLATFORM_SYS_DIR_UID)
135+ return 1;
136+#endif
137+ return 0;
138+}
139+
140+int
141+secure_permissions(struct stat *st, uid_t uid)
142+{
143+ if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid)
144+ return 0;
145+ if ((st->st_mode & 002) != 0)
146+ return 0;
147+ if ((st->st_mode & 020) != 0) {
148+ /* If the file is group-writable, the group in question must
149+ * have exactly one member, namely the file's owner.
150+ * (Zero-member groups are typically used by setgid
151+ * binaries, and are unlikely to be suitable.)
152+ */
153+ struct passwd *pw;
154+ struct group *gr;
155+ int members = 0;
156+
157+ gr = getgrgid(st->st_gid);
158+ if (!gr)
159+ return 0;
160+
161+ /* Check primary group memberships. */
162+ while ((pw = getpwent()) != NULL) {
163+ if (pw->pw_gid == gr->gr_gid) {
164+ ++members;
165+ if (pw->pw_uid != uid)
166+ return 0;
167+ }
168+ }
169+ endpwent();
170+
171+ pw = getpwuid(st->st_uid);
172+ if (!pw)
173+ return 0;
174+
175+ /* Check supplementary group memberships. */
176+ if (gr->gr_mem[0]) {
177+ ++members;
178+ if (strcmp(pw->pw_name, gr->gr_mem[0]) ||
179+ gr->gr_mem[1])
180+ return 0;
181+ }
182+
183+ if (!members)
184+ return 0;
185+ }
186+ return 1;
187+}
188+
189 int
190 tun_open(int tun, int mode)
191 {
192Index: b/misc.h
193===================================================================
194--- a/misc.h
195+++ b/misc.h
196@@ -103,4 +103,6 @@
197 int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2)));
198 int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *);
199
200+int secure_permissions(struct stat *st, uid_t uid);
201+
202 #endif /* _MISC_H */
203Index: b/auth-rhosts.c
204===================================================================
205--- a/auth-rhosts.c
206+++ b/auth-rhosts.c
207@@ -256,8 +256,7 @@
208 return 0;
209 }
210 if (options.strict_modes &&
211- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
212- (st.st_mode & 022) != 0)) {
213+ !secure_permissions(&st, pw->pw_uid)) {
214 logit("Rhosts authentication refused for %.100s: "
215 "bad ownership or modes for home directory.", pw->pw_name);
216 auth_debug_add("Rhosts authentication refused for %.100s: "
217@@ -283,8 +282,7 @@
218 * allowing access to their account by anyone.
219 */
220 if (options.strict_modes &&
221- ((st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
222- (st.st_mode & 022) != 0)) {
223+ !secure_permissions(&st, pw->pw_uid)) {
224 logit("Rhosts authentication refused for %.100s: bad modes for %.200s",
225 pw->pw_name, buf);
226 auth_debug_add("Bad file modes for %.200s", buf);
227Index: b/platform.c
228===================================================================
229--- a/platform.c
230+++ b/platform.c
231@@ -194,19 +194,3 @@
232 return NULL;
233 #endif
234 }
235-
236-/*
237- * return 1 if the specified uid is a uid that may own a system directory
238- * otherwise 0.
239- */
240-int
241-platform_sys_dir_uid(uid_t uid)
242-{
243- if (uid == 0)
244- return 1;
245-#ifdef PLATFORM_SYS_DIR_UID
246- if (uid == PLATFORM_SYS_DIR_UID)
247- return 1;
248-#endif
249- return 0;
250-}