diff options
Diffstat (limited to 'debian/patches/user-group-modes.patch')
-rw-r--r-- | debian/patches/user-group-modes.patch | 202 |
1 files changed, 202 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..ddedbf79a --- /dev/null +++ b/debian/patches/user-group-modes.patch | |||
@@ -0,0 +1,202 @@ | |||
1 | Description: 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. | ||
9 | Author: Colin Watson <cjwatson@debian.org> | ||
10 | Bug: https://bugzilla.mindrot.org/show_bug.cgi?id=1060 | ||
11 | Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=314347 | ||
12 | Last-Update: 2013-05-07 | ||
13 | |||
14 | Index: 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 | @@ -1132,8 +1134,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 | |||
37 | Index: 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 | ||
50 | Index: 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 | ||
63 | Index: 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; | ||
97 | Index: 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 | @@ -642,6 +643,55 @@ | ||
113 | } | ||
114 | |||
115 | int | ||
116 | +secure_permissions(struct stat *st, uid_t uid) | ||
117 | +{ | ||
118 | + if (!platform_sys_dir_uid(st->st_uid) && st->st_uid != uid) | ||
119 | + return 0; | ||
120 | + if ((st->st_mode & 002) != 0) | ||
121 | + return 0; | ||
122 | + if ((st->st_mode & 020) != 0) { | ||
123 | + /* If the file is group-writable, the group in question must | ||
124 | + * have exactly one member, namely the file's owner. | ||
125 | + * (Zero-member groups are typically used by setgid | ||
126 | + * binaries, and are unlikely to be suitable.) | ||
127 | + */ | ||
128 | + struct passwd *pw; | ||
129 | + struct group *gr; | ||
130 | + int members = 0; | ||
131 | + | ||
132 | + gr = getgrgid(st->st_gid); | ||
133 | + if (!gr) | ||
134 | + return 0; | ||
135 | + | ||
136 | + /* Check primary group memberships. */ | ||
137 | + while ((pw = getpwent()) != NULL) { | ||
138 | + if (pw->pw_gid == gr->gr_gid) { | ||
139 | + ++members; | ||
140 | + if (pw->pw_uid != uid) | ||
141 | + return 0; | ||
142 | + } | ||
143 | + } | ||
144 | + endpwent(); | ||
145 | + | ||
146 | + pw = getpwuid(st->st_uid); | ||
147 | + if (!pw) | ||
148 | + return 0; | ||
149 | + | ||
150 | + /* Check supplementary group memberships. */ | ||
151 | + if (gr->gr_mem[0]) { | ||
152 | + ++members; | ||
153 | + if (strcmp(pw->pw_name, gr->gr_mem[0]) || | ||
154 | + gr->gr_mem[1]) | ||
155 | + return 0; | ||
156 | + } | ||
157 | + | ||
158 | + if (!members) | ||
159 | + return 0; | ||
160 | + } | ||
161 | + return 1; | ||
162 | +} | ||
163 | + | ||
164 | +int | ||
165 | tun_open(int tun, int mode) | ||
166 | { | ||
167 | #if defined(CUSTOM_SYS_TUN_OPEN) | ||
168 | Index: b/misc.h | ||
169 | =================================================================== | ||
170 | --- a/misc.h | ||
171 | +++ b/misc.h | ||
172 | @@ -103,4 +103,6 @@ | ||
173 | int ask_permission(const char *, ...) __attribute__((format(printf, 1, 2))); | ||
174 | int read_keyfile_line(FILE *, const char *, char *, size_t, u_long *); | ||
175 | |||
176 | +int secure_permissions(struct stat *st, uid_t uid); | ||
177 | + | ||
178 | #endif /* _MISC_H */ | ||
179 | Index: b/auth-rhosts.c | ||
180 | =================================================================== | ||
181 | --- a/auth-rhosts.c | ||
182 | +++ b/auth-rhosts.c | ||
183 | @@ -256,8 +256,7 @@ | ||
184 | return 0; | ||
185 | } | ||
186 | if (options.strict_modes && | ||
187 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
188 | - (st.st_mode & 022) != 0)) { | ||
189 | + !secure_permissions(&st, pw->pw_uid)) { | ||
190 | logit("Rhosts authentication refused for %.100s: " | ||
191 | "bad ownership or modes for home directory.", pw->pw_name); | ||
192 | auth_debug_add("Rhosts authentication refused for %.100s: " | ||
193 | @@ -283,8 +282,7 @@ | ||
194 | * allowing access to their account by anyone. | ||
195 | */ | ||
196 | if (options.strict_modes && | ||
197 | - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || | ||
198 | - (st.st_mode & 022) != 0)) { | ||
199 | + !secure_permissions(&st, pw->pw_uid)) { | ||
200 | logit("Rhosts authentication refused for %.100s: bad modes for %.200s", | ||
201 | pw->pw_name, buf); | ||
202 | auth_debug_add("Bad file modes for %.200s", buf); | ||