diff options
Diffstat (limited to 'debian/patches/user-group-modes.patch')
-rw-r--r-- | debian/patches/user-group-modes.patch | 266 |
1 files changed, 266 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..9382d5086 --- /dev/null +++ b/debian/patches/user-group-modes.patch | |||
@@ -0,0 +1,266 @@ | |||
1 | From 7016a7e8a6b854833132db253fd5e392984bd4ea Mon Sep 17 00:00:00 2001 | ||
2 | From: Colin Watson <cjwatson@debian.org> | ||
3 | Date: Sun, 9 Feb 2014 16:09:58 +0000 | ||
4 | Subject: Allow harmless group-writability | ||
5 | |||
6 | Allow secure files (~/.ssh/config, ~/.ssh/authorized_keys, etc.) to be | ||
7 | group-writable, provided that the group in question contains only the file's | ||
8 | owner. Rejected upstream for IMO incorrect reasons (e.g. a misunderstanding | ||
9 | about the contents of gr->gr_mem). Given that per-user groups and umask 002 | ||
10 | are the default setup in Debian (for good reasons - this makes operating in | ||
11 | setgid directories with other groups much easier), we need to permit this by | ||
12 | default. | ||
13 | |||
14 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060 | ||
15 | Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347 | ||
16 | Last-Update: 2013-09-14 | ||
17 | |||
18 | Patch-Name: user-group-modes.patch | ||
19 | --- | ||
20 | auth-rhosts.c | 6 ++---- | ||
21 | auth.c | 9 +++----- | ||
22 | misc.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- | ||
23 | misc.h | 2 ++ | ||
24 | platform.c | 16 -------------- | ||
25 | readconf.c | 5 +++-- | ||
26 | ssh.1 | 2 ++ | ||
27 | ssh_config.5 | 2 ++ | ||
28 | 8 files changed, 82 insertions(+), 29 deletions(-) | ||
29 | |||
30 | diff --git a/auth-rhosts.c b/auth-rhosts.c | ||
31 | index 06ae7f0..f202787 100644 | ||
32 | --- a/auth-rhosts.c | ||
33 | +++ b/auth-rhosts.c | ||
34 | @@ -256,8 +256,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam | ||
35 | return 0; | ||
36 | } | ||
37 | if (options.strict_modes && | ||
38 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
39 | - (st.st_mode & 022) != 0)) { | ||
40 | + !secure_permissions(&st, pw->pw_uid)) { | ||
41 | logit("Rhosts authentication refused for %.100s: " | ||
42 | "bad ownership or modes for home directory.", pw->pw_name); | ||
43 | auth_debug_add("Rhosts authentication refused for %.100s: " | ||
44 | @@ -283,8 +282,7 @@ auth_rhosts2_raw(struct passwd *pw, const char *client_user, const char *hostnam | ||
45 | * allowing access to their account by anyone. | ||
46 | */ | ||
47 | if (options.strict_modes && | ||
48 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
49 | - (st.st_mode & 022) != 0)) { | ||
50 | + !secure_permissions(&st, pw->pw_uid)) { | ||
51 | logit("Rhosts authentication refused for %.100s: bad modes for %.200s", | ||
52 | pw->pw_name, buf); | ||
53 | auth_debug_add("Bad file modes for %.200s", buf); | ||
54 | diff --git a/auth.c b/auth.c | ||
55 | index 6662e9a..7f6c6c8 100644 | ||
56 | --- a/auth.c | ||
57 | +++ b/auth.c | ||
58 | @@ -408,8 +408,7 @@ check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, | ||
59 | user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); | ||
60 | if (options.strict_modes && | ||
61 | (stat(user_hostfile, &st) == 0) && | ||
62 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
63 | - (st.st_mode & 022) != 0)) { | ||
64 | + !secure_permissions(&st, pw->pw_uid)) { | ||
65 | logit("Authentication refused for %.100s: " | ||
66 | "bad owner or modes for %.200s", | ||
67 | pw->pw_name, user_hostfile); | ||
68 | @@ -471,8 +470,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, | ||
69 | snprintf(err, errlen, "%s is not a regular file", buf); | ||
70 | return -1; | ||
71 | } | ||
72 | - if ((!platform_sys_dir_uid(stp->st_uid) && stp->st_uid != uid) || | ||
73 | - (stp->st_mode & 022) != 0) { | ||
74 | + if (!secure_permissions(stp, uid)) { | ||
75 | snprintf(err, errlen, "bad ownership or modes for file %s", | ||
76 | buf); | ||
77 | return -1; | ||
78 | @@ -487,8 +485,7 @@ auth_secure_path(const char *name, struct stat *stp, const char *pw_dir, | ||
79 | strlcpy(buf, cp, sizeof(buf)); | ||
80 | |||
81 | if (stat(buf, &st) < 0 || | ||
82 | - (!platform_sys_dir_uid(st.st_uid) && st.st_uid != uid) || | ||
83 | - (st.st_mode & 022) != 0) { | ||
84 | + !secure_permissions(&st, uid)) { | ||
85 | snprintf(err, errlen, | ||
86 | "bad ownership or modes for directory %s", buf); | ||
87 | return -1; | ||
88 | diff --git a/misc.c b/misc.c | ||
89 | index c3c8099..eb57bfc 100644 | ||
90 | --- a/misc.c | ||
91 | +++ b/misc.c | ||
92 | @@ -48,8 +48,9 @@ | ||
93 | #include <netdb.h> | ||
94 | #ifdef HAVE_PATHS_H | ||
95 | # include <paths.h> | ||
96 | -#include <pwd.h> | ||
97 | #endif | ||
98 | +#include <pwd.h> | ||
99 | +#include <grp.h> | ||
100 | #ifdef SSH_TUN_OPENBSD | ||
101 | #include <net/if.h> | ||
102 | #endif | ||
103 | @@ -58,6 +59,7 @@ | ||
104 | #include "misc.h" | ||
105 | #include "log.h" | ||
106 | #include "ssh.h" | ||
107 | +#include "platform.h" | ||
108 | |||
109 | /* remove newline at end of string */ | ||
110 | char * | ||
111 | @@ -642,6 +644,71 @@ read_keyfile_line(FILE *f, const char *filename, char *buf, size_t bufsz, | ||
112 | return -1; | ||
113 | } | ||
114 | |||
115 | +/* | ||
116 | + * return 1 if the specified uid is a uid that may own a system directory | ||
117 | + * otherwise 0. | ||
118 | + */ | ||
119 | +int | ||
120 | +platform_sys_dir_uid(uid_t uid) | ||
121 | +{ | ||
122 | + if (uid == 0) | ||
123 | + return 1; | ||
124 | +#ifdef PLATFORM_SYS_DIR_UID | ||
125 | + if (uid == PLATFORM_SYS_DIR_UID) | ||
126 | + return 1; | ||
127 | +#endif | ||
128 | + return 0; | ||
129 | +} | ||
130 | + | ||
131 | +int | ||
132 | +secure_permissions(struct stat *st, uid_t uid) | ||
133 | +{ | ||
134 | + if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid) | ||
135 | + return 0; | ||
136 | + if ((st->st_mode & 002) != 0) | ||
137 | + return 0; | ||
138 | + if ((st->st_mode & 020) != 0) { | ||
139 | + /* If the file is group-writable, the group in question must | ||
140 | + * have exactly one member, namely the file's owner. | ||
141 | + * (Zero-member groups are typically used by setgid | ||
142 | + * binaries, and are unlikely to be suitable.) | ||
143 | + */ | ||
144 | + struct passwd *pw; | ||
145 | + struct group *gr; | ||
146 | + int members = 0; | ||
147 | + | ||
148 | + gr = getgrgid(st->st_gid); | ||
149 | + if (!gr) | ||
150 | + return 0; | ||
151 | + | ||
152 | + /* Check primary group memberships. */ | ||
153 | + while ((pw = getpwent()) != NULL) { | ||
154 | + if (pw->pw_gid == gr->gr_gid) { | ||
155 | + ++members; | ||
156 | + if (pw->pw_uid != uid) | ||
157 | + return 0; | ||
158 | + } | ||
159 | + } | ||
160 | + endpwent(); | ||
161 | + | ||
162 | + pw = getpwuid(st->st_uid); | ||
163 | + if (!pw) | ||
164 | + return 0; | ||
165 | + | ||
166 | + /* Check supplementary group memberships. */ | ||
167 | + if (gr->gr_mem[0]) { | ||
168 | + ++members; | ||
169 | + if (strcmp(pw->pw_name, gr->gr_mem[0]) || | ||
170 | + gr->gr_mem[1]) | ||
171 | + return 0; | ||
172 | + } | ||
173 | + | ||
174 | + if (!members) | ||
175 | + return 0; | ||
176 | + } | ||
177 | + return 1; | ||
178 | +} | ||
179 | + | ||
180 | int | ||
181 | tun_open(int tun, int mode) | ||
182 | { | ||
183 | diff --git a/misc.h b/misc.h | ||
184 | index fceb306..51ba182 100644 | ||
185 | --- a/misc.h | ||
186 | +++ b/misc.h | ||
187 | @@ -104,4 +104,6 @@ char *read_passphrase(const char *, int); | ||
188 | int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); | ||
189 | int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); | ||
190 | |||
191 | +int secure_permissions(struct stat *st, uid_t uid); | ||
192 | + | ||
193 | #endif /* _MISC_H */ | ||
194 | diff --git a/platform.c b/platform.c | ||
195 | index a962f15..0b3bee1 100644 | ||
196 | --- a/platform.c | ||
197 | +++ b/platform.c | ||
198 | @@ -194,19 +194,3 @@ platform_krb5_get_principal_name(const char *pw_name) | ||
199 | return NULL; | ||
200 | #endif | ||
201 | } | ||
202 | - | ||
203 | -/* | ||
204 | - * return 1 if the specified uid is a uid that may own a system directory | ||
205 | - * otherwise 0. | ||
206 | - */ | ||
207 | -int | ||
208 | -platform_sys_dir_uid(uid_t uid) | ||
209 | -{ | ||
210 | - if (uid == 0) | ||
211 | - return 1; | ||
212 | -#ifdef PLATFORM_SYS_DIR_UID | ||
213 | - if (uid == PLATFORM_SYS_DIR_UID) | ||
214 | - return 1; | ||
215 | -#endif | ||
216 | - return 0; | ||
217 | -} | ||
218 | diff --git a/readconf.c b/readconf.c | ||
219 | index 2dcbf31..389de7d 100644 | ||
220 | --- a/readconf.c | ||
221 | +++ b/readconf.c | ||
222 | @@ -30,6 +30,8 @@ | ||
223 | #include <stdio.h> | ||
224 | #include <string.h> | ||
225 | #include <unistd.h> | ||
226 | +#include <pwd.h> | ||
227 | +#include <grp.h> | ||
228 | #ifdef HAVE_UTIL_H | ||
229 | #include <util.h> | ||
230 | #endif | ||
231 | @@ -1160,8 +1162,7 @@ read_config_file(const char *filename, const char *host, Options *options, | ||
232 | |||
233 | if (fstat(fileno(f), &sb) == -1) | ||
234 | fatal("fstat %s: %s", filename, strerror(errno)); | ||
235 | - if (((sb.st_uid != 0 && sb.st_uid != getuid()) || | ||
236 | - (sb.st_mode & 022) != 0)) | ||
237 | + if (!secure_permissions(&sb, getuid())) | ||
238 | fatal("Bad owner or permissions on %s", filename); | ||
239 | } | ||
240 | |||
241 | diff --git a/ssh.1 b/ssh.1 | ||
242 | index 66a7007..0b38ae1 100644 | ||
243 | --- a/ssh.1 | ||
244 | +++ b/ssh.1 | ||
245 | @@ -1338,6 +1338,8 @@ The file format and configuration options are described in | ||
246 | .Xr ssh_config 5 . | ||
247 | Because of the potential for abuse, this file must have strict permissions: | ||
248 | read/write for the user, and not writable by others. | ||
249 | +It may be group-writable provided that the group in question contains only | ||
250 | +the user. | ||
251 | .Pp | ||
252 | .It Pa ~/.ssh/environment | ||
253 | Contains additional definitions for environment variables; see | ||
254 | diff --git a/ssh_config.5 b/ssh_config.5 | ||
255 | index 135d833..1497cfc 100644 | ||
256 | --- a/ssh_config.5 | ||
257 | +++ b/ssh_config.5 | ||
258 | @@ -1382,6 +1382,8 @@ The format of this file is described above. | ||
259 | This file is used by the SSH client. | ||
260 | Because of the potential for abuse, this file must have strict permissions: | ||
261 | read/write for the user, and not accessible by others. | ||
262 | +It may be group-writable provided that the group in question contains only | ||
263 | +the user. | ||
264 | .It Pa /etc/ssh/ssh_config | ||
265 | Systemwide configuration file. | ||
266 | This file provides defaults for those | ||