File: | security.cc |
Location: | line 697, column 7 |
Description: | Value stored to 'saw_admins' is never read |
1 | /* security.cc: NT file access control functions |
2 | |
3 | Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, |
4 | 2006, 2007, 2008, 2009, 2010, 2011, 2012 Red Hat, Inc. |
5 | |
6 | Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de |
7 | Completely rewritten by Corinna Vinschen <corinna@vinschen.de> |
8 | |
9 | This file is part of Cygwin. |
10 | |
11 | This software is a copyrighted work licensed under the terms of the |
12 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for |
13 | details. */ |
14 | |
15 | #include "winsup.h" |
16 | #include <unistd.h> |
17 | #include <stdlib.h> |
18 | #include "cygerrno.h" |
19 | #include "security.h" |
20 | #include "path.h" |
21 | #include "fhandler.h" |
22 | #include "dtable.h" |
23 | #include "pinfo.h" |
24 | #include "cygheap.h" |
25 | #include "ntdll.h" |
26 | #include "pwdgrp.h" |
27 | #include "tls_pbuf.h" |
28 | #include <aclapi.h> |
29 | |
30 | #define ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001) (DACL_SECURITY_INFORMATION0x00000004 \ |
31 | | GROUP_SECURITY_INFORMATION0x00000002 \ |
32 | | OWNER_SECURITY_INFORMATION0x00000001) |
33 | |
34 | static NO_COPY__attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy" ))) GENERIC_MAPPING file_mapping = { FILE_GENERIC_READ(0x20000 | 0x00000001 | 0x00000080 | 0x00000008 | 0x100000L), |
35 | FILE_GENERIC_WRITE(0x20000 | 0x00000002 | 0x00000100 | 0x00000010 | 0x00000004 | 0x100000L), |
36 | FILE_GENERIC_EXECUTE(0x20000 | 0x00000080 | 0x00000020 | 0x100000L), |
37 | FILE_ALL_ACCESS(0xF0000 | 0x100000L | 0x1FF) }; |
38 | |
39 | LONG |
40 | get_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, |
41 | bool justcreated) |
42 | { |
43 | NTSTATUS status; |
44 | OBJECT_ATTRIBUTES attr; |
45 | IO_STATUS_BLOCK io; |
46 | ULONG len = SD_MAXIMUM_SIZE65536, rlen; |
47 | |
48 | /* Allocate space for the security descriptor. */ |
49 | if (!sd.malloc (len)) |
50 | { |
51 | set_errno (ENOMEM)__set_errno (__PRETTY_FUNCTION__, 51, (12)); |
52 | return -1; |
53 | } |
54 | /* Try to fetch the security descriptor if the handle is valid. */ |
55 | if (fh) |
56 | { |
57 | status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
58 | sd, len, &rlen); |
59 | if (!NT_SUCCESS (status)((status)>=0)) |
60 | { |
61 | debug_printf ("NtQuerySecurityObject (%S), status %p",((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "NtQuerySecurityObject (%S), status %p" , pc.get_nt_native_path (), status); 0; })) |
62 | pc.get_nt_native_path (), status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "NtQuerySecurityObject (%S), status %p" , pc.get_nt_native_path (), status); 0; })); |
63 | fh = NULL__null; |
64 | } |
65 | } |
66 | /* If the handle was NULL, or fetching with the original handle didn't work, |
67 | try to reopen the file with READ_CONTROL and fetch the security descriptor |
68 | using that handle. */ |
69 | if (!fh) |
70 | { |
71 | status = NtOpenFile (&fh, READ_CONTROL0x20000L, |
72 | pc.get_object_attr (attr, sec_none_nih), &io, |
73 | FILE_SHARE_VALID_FLAGS0x00000007, FILE_OPEN_FOR_BACKUP_INTENT0x00004000); |
74 | if (!NT_SUCCESS (status)((status)>=0)) |
75 | { |
76 | sd.free (); |
77 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 77, status); |
78 | return -1; |
79 | } |
80 | status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
81 | sd, len, &rlen); |
82 | NtClose (fh); |
83 | if (!NT_SUCCESS (status)((status)>=0)) |
84 | { |
85 | sd.free (); |
86 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 86, status); |
87 | return -1; |
88 | } |
89 | } |
90 | /* Ok, so we have a security descriptor now. Unfortunately, if you want |
91 | to know if an ACE is inherited from the parent object, you can't just |
92 | call NtQuerySecurityObject once. The problem is this: |
93 | |
94 | In the simple case, the SDs control word contains one of the |
95 | SE_DACL_AUTO_INHERITED or SE_DACL_PROTECTED flags, or at least one of |
96 | the ACEs has the INHERITED_ACE flag set. In all of these cases the |
97 | GetSecurityInfo function calls NtQuerySecurityObject only once, too, |
98 | apparently because it figures that the DACL is self-sufficient, which |
99 | it usually is. Windows Explorer, for instance, takes great care to |
100 | set these flags in a security descriptor if you change the ACL in the |
101 | GUI property dialog. |
102 | |
103 | The tricky case is if none of these flags is set in the SD. That means |
104 | the information whether or not an ACE has been inherited is not available |
105 | in the DACL of the object. In this case GetSecurityInfo also fetches the |
106 | SD from the parent directory and tests if the object's SD contains |
107 | inherited ACEs from the parent. The below code is closly emulating the |
108 | behaviour of GetSecurityInfo so we can get rid of this advapi32 dependency. |
109 | |
110 | However, this functionality is slow, and the extra information is only |
111 | required when the file has been created and the permissions are about |
112 | to be set to POSIX permissions. Therefore we only use it in case the |
113 | file just got created. |
114 | |
115 | Note that GetSecurityInfo has a problem on 5.1 and 5.2 kernels. Sometimes |
116 | it returns ERROR_INVALID_ADDRESS if a former request for the parent |
117 | directories' SD used NtQuerySecurityObject, rather than GetSecurityInfo |
118 | as well. See http://cygwin.com/ml/cygwin-developers/2011-03/msg00027.html |
119 | for the solution. This problem does not occur with the below code, so |
120 | the workaround has been removed. */ |
121 | if (justcreated) |
122 | { |
123 | SECURITY_DESCRIPTOR_CONTROL ctrl; |
124 | ULONG dummy; |
125 | PACL dacl; |
126 | BOOLEAN exists, def; |
127 | ACCESS_ALLOWED_ACE *ace; |
128 | UNICODE_STRING dirname; |
129 | PSECURITY_DESCRIPTOR psd, nsd; |
130 | tmp_pathbuf tp; |
131 | |
132 | /* Check SDs control flags. If SE_DACL_AUTO_INHERITED or |
133 | SE_DACL_PROTECTED is set we're done. */ |
134 | RtlGetControlSecurityDescriptor (sd, &ctrl, &dummy); |
135 | if (ctrl & (SE_DACL_AUTO_INHERITED1024 | SE_DACL_PROTECTED4096)) |
136 | return 0; |
137 | /* Otherwise iterate over the ACEs and see if any one of them has the |
138 | INHERITED_ACE flag set. If so, we're done. */ |
139 | if (NT_SUCCESS (RtlGetDaclSecurityDescriptor (sd, &exists, &dacl, &def))((RtlGetDaclSecurityDescriptor (sd, &exists, &dacl, & def))>=0) |
140 | && exists && dacl) |
141 | for (ULONG idx = 0; idx < dacl->AceCount; ++idx) |
142 | if (NT_SUCCESS (RtlGetAce (dacl, idx, (PVOID *) &ace))((RtlGetAce (dacl, idx, (PVOID *) &ace))>=0) |
143 | && (ace->Header.AceFlags & INHERITED_ACE16)) |
144 | return 0; |
145 | /* Otherwise, open the parent directory with READ_CONTROL... */ |
146 | RtlSplitUnicodePath (pc.get_nt_native_path (), &dirname, NULL__null); |
147 | InitializeObjectAttributes (&attr, &dirname, pc.objcaseinsensitive (),{ (&attr)->Length = sizeof(OBJECT_ATTRIBUTES); (&attr )->RootDirectory = (__null); (&attr)->Attributes = ( pc.objcaseinsensitive ()); (&attr)->ObjectName = (& dirname); (&attr)->SecurityDescriptor = (__null); (& attr)->SecurityQualityOfService = __null; } |
148 | NULL, NULL){ (&attr)->Length = sizeof(OBJECT_ATTRIBUTES); (&attr )->RootDirectory = (__null); (&attr)->Attributes = ( pc.objcaseinsensitive ()); (&attr)->ObjectName = (& dirname); (&attr)->SecurityDescriptor = (__null); (& attr)->SecurityQualityOfService = __null; }; |
149 | status = NtOpenFile (&fh, READ_CONTROL0x20000L, &attr, &io, |
150 | FILE_SHARE_VALID_FLAGS0x00000007, |
151 | FILE_OPEN_FOR_BACKUP_INTENT0x00004000 |
152 | | FILE_OPEN_REPARSE_POINT0x00200000); |
153 | if (!NT_SUCCESS (status)((status)>=0)) |
154 | { |
155 | debug_printf ("NtOpenFile (%S), status %p", &dirname, status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "NtOpenFile (%S), status %p" , &dirname, status); 0; })); |
156 | return 0; |
157 | } |
158 | /* ... fetch the parent's security descriptor ... */ |
159 | psd = (PSECURITY_DESCRIPTOR) tp.w_get (); |
160 | status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
161 | psd, len, &rlen); |
162 | NtClose (fh); |
163 | if (!NT_SUCCESS (status)((status)>=0)) |
164 | { |
165 | debug_printf ("NtQuerySecurityObject (%S), status %p",((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "NtQuerySecurityObject (%S), status %p" , &dirname, status); 0; })) |
166 | &dirname, status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "NtQuerySecurityObject (%S), status %p" , &dirname, status); 0; })); |
167 | return 0; |
168 | } |
169 | /* ... and create a new security descriptor in which all inherited ACEs |
170 | are marked with the INHERITED_ACE flag. For a description of the |
171 | undocumented RtlConvertToAutoInheritSecurityObject function from |
172 | ntdll.dll see the MSDN man page for the advapi32 function |
173 | ConvertToAutoInheritPrivateObjectSecurity. Fortunately the latter |
174 | is just a shim. */ |
175 | status = RtlConvertToAutoInheritSecurityObject (psd, sd, &nsd, NULL__null, |
176 | pc.isdir (), |
177 | &file_mapping); |
178 | if (!NT_SUCCESS (status)((status)>=0)) |
179 | { |
180 | debug_printf ("RtlConvertToAutoInheritSecurityObject (%S), status %p",((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "RtlConvertToAutoInheritSecurityObject (%S), status %p" , &dirname, status); 0; })) |
181 | &dirname, status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "RtlConvertToAutoInheritSecurityObject (%S), status %p" , &dirname, status); 0; })); |
182 | return 0; |
183 | } |
184 | /* Eventually copy the new security descriptor into sd and delete the |
185 | original one created by RtlConvertToAutoInheritSecurityObject from |
186 | the heap. */ |
187 | len = RtlLengthSecurityDescriptor (nsd); |
188 | memcpy ((PSECURITY_DESCRIPTOR) sd, nsd, len); |
189 | RtlDeleteSecurityObject (&nsd); |
190 | } |
191 | return 0; |
192 | } |
193 | |
194 | LONG |
195 | set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd, bool is_chown) |
196 | { |
197 | NTSTATUS status = STATUS_SUCCESS((NTSTATUS)0); |
198 | int retry = 0; |
199 | int res = -1; |
200 | |
201 | for (; retry < 2; ++retry) |
202 | { |
203 | if (fh) |
204 | { |
205 | status = NtSetSecurityObject (fh, |
206 | is_chown ? ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001) |
207 | : DACL_SECURITY_INFORMATION0x00000004, |
208 | sd); |
209 | if (NT_SUCCESS (status)((status)>=0)) |
210 | { |
211 | res = 0; |
212 | break; |
213 | } |
214 | } |
215 | if (!retry) |
216 | { |
217 | OBJECT_ATTRIBUTES attr; |
218 | IO_STATUS_BLOCK io; |
219 | status = NtOpenFile (&fh, (is_chown ? WRITE_OWNER0x80000L : 0) | WRITE_DAC0x40000L, |
220 | pc.get_object_attr (attr, sec_none_nih), |
221 | &io, FILE_SHARE_VALID_FLAGS0x00000007, |
222 | FILE_OPEN_FOR_BACKUP_INTENT0x00004000); |
223 | if (!NT_SUCCESS (status)((status)>=0)) |
224 | { |
225 | fh = NULL__null; |
226 | break; |
227 | } |
228 | } |
229 | } |
230 | if (retry && fh) |
231 | NtClose (fh); |
232 | if (!NT_SUCCESS (status)((status)>=0)) |
233 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 233, status); |
234 | return res; |
235 | } |
236 | |
237 | static void |
238 | get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid, |
239 | PSID group_sid, bool grp_member) |
240 | { |
241 | ACCESS_ALLOWED_ACE *ace; |
242 | int allow = 0; |
243 | int deny = 0; |
244 | int *flags, *anti; |
245 | |
246 | for (DWORD i = 0; i < acl->AceCount; ++i) |
247 | { |
248 | if (!NT_SUCCESS (RtlGetAce (acl, i, (PVOID *) &ace))((RtlGetAce (acl, i, (PVOID *) &ace))>=0)) |
249 | continue; |
250 | if (ace->Header.AceFlags & INHERIT_ONLY_ACE8) |
251 | continue; |
252 | switch (ace->Header.AceType) |
253 | { |
254 | case ACCESS_ALLOWED_ACE_TYPE(0x0): |
255 | flags = &allow; |
256 | anti = &deny; |
257 | break; |
258 | case ACCESS_DENIED_ACE_TYPE(0x1): |
259 | flags = &deny; |
260 | anti = &allow; |
261 | break; |
262 | default: |
263 | continue; |
264 | } |
265 | |
266 | cygpsid ace_sid ((PSID) &ace->SidStart); |
267 | if (ace_sid == well_known_world_sid) |
268 | { |
269 | if (ace->Mask & FILE_READ_BITS(0x00000001 | 0x80000000 | 0x10000000)) |
270 | *flags |= ((!(*anti & S_IROTH0000004)) ? S_IROTH0000004 : 0) |
271 | | ((!(*anti & S_IRGRP0000040)) ? S_IRGRP0000040 : 0) |
272 | | ((!(*anti & S_IRUSR0000400)) ? S_IRUSR0000400 : 0); |
273 | if (ace->Mask & FILE_WRITE_BITS(0x00000002 | 0x40000000 | 0x10000000)) |
274 | *flags |= ((!(*anti & S_IWOTH0000002)) ? S_IWOTH0000002 : 0) |
275 | | ((!(*anti & S_IWGRP0000020)) ? S_IWGRP0000020 : 0) |
276 | | ((!(*anti & S_IWUSR0000200)) ? S_IWUSR0000200 : 0); |
277 | if (ace->Mask & FILE_EXEC_BITS(0x00000020 | 0x20000000 | 0x10000000)) |
278 | *flags |= ((!(*anti & S_IXOTH0000001)) ? S_IXOTH0000001 : 0) |
279 | | ((!(*anti & S_IXGRP0000010)) ? S_IXGRP0000010 : 0) |
280 | | ((!(*anti & S_IXUSR0000100)) ? S_IXUSR0000100 : 0); |
281 | if ((S_ISDIR (*attribute)(((*attribute)&0170000) == 0040000)) && |
282 | (ace->Mask & (FILE_WRITE_DATA0x00000002 | FILE_EXECUTE0x00000020 | FILE_DELETE_CHILD0x00000040)) |
283 | == (FILE_WRITE_DATA0x00000002 | FILE_EXECUTE0x00000020)) |
284 | *flags |= S_ISVTX0001000; |
285 | } |
286 | else if (ace_sid == well_known_null_sid) |
287 | { |
288 | /* Read SUID, SGID and VTX bits from NULL ACE. */ |
289 | if (ace->Mask & FILE_READ_DATA0x00000001) |
290 | *flags |= S_ISVTX0001000; |
291 | if (ace->Mask & FILE_WRITE_DATA0x00000002) |
292 | *flags |= S_ISGID0002000; |
293 | if (ace->Mask & FILE_APPEND_DATA0x00000004) |
294 | *flags |= S_ISUID0004000; |
295 | } |
296 | else if (ace_sid == owner_sid) |
297 | { |
298 | if (ace->Mask & FILE_READ_BITS(0x00000001 | 0x80000000 | 0x10000000)) |
299 | *flags |= ((!(*anti & S_IRUSR0000400)) ? S_IRUSR0000400 : 0); |
300 | if (ace->Mask & FILE_WRITE_BITS(0x00000002 | 0x40000000 | 0x10000000)) |
301 | *flags |= ((!(*anti & S_IWUSR0000200)) ? S_IWUSR0000200 : 0); |
302 | if (ace->Mask & FILE_EXEC_BITS(0x00000020 | 0x20000000 | 0x10000000)) |
303 | *flags |= ((!(*anti & S_IXUSR0000100)) ? S_IXUSR0000100 : 0); |
304 | } |
305 | else if (ace_sid == group_sid) |
306 | { |
307 | if (ace->Mask & FILE_READ_BITS(0x00000001 | 0x80000000 | 0x10000000)) |
308 | *flags |= ((!(*anti & S_IRGRP0000040)) ? S_IRGRP0000040 : 0) |
309 | | ((grp_member && !(*anti & S_IRUSR0000400)) ? S_IRUSR0000400 : 0); |
310 | if (ace->Mask & FILE_WRITE_BITS(0x00000002 | 0x40000000 | 0x10000000)) |
311 | *flags |= ((!(*anti & S_IWGRP0000020)) ? S_IWGRP0000020 : 0) |
312 | | ((grp_member && !(*anti & S_IWUSR0000200)) ? S_IWUSR0000200 : 0); |
313 | if (ace->Mask & FILE_EXEC_BITS(0x00000020 | 0x20000000 | 0x10000000)) |
314 | *flags |= ((!(*anti & S_IXGRP0000010)) ? S_IXGRP0000010 : 0) |
315 | | ((grp_member && !(*anti & S_IXUSR0000100)) ? S_IXUSR0000100 : 0); |
316 | } |
317 | } |
318 | *attribute &= ~(S_IRWXU(0000400 | 0000200 | 0000100) | S_IRWXG(0000040 | 0000020 | 0000010) | S_IRWXO(0000004 | 0000002 | 0000001) | S_ISVTX0001000 | S_ISGID0002000 | S_ISUID0004000); |
319 | if (owner_sid && group_sid && RtlEqualSid (owner_sid, group_sid) |
320 | /* FIXME: temporary exception for /var/empty */ |
321 | && well_known_system_sid != group_sid) |
322 | { |
323 | allow &= ~(S_IRGRP0000040 | S_IWGRP0000020 | S_IXGRP0000010); |
324 | allow |= (((allow & S_IRUSR0000400) ? S_IRGRP0000040 : 0) |
325 | | ((allow & S_IWUSR0000200) ? S_IWGRP0000020 : 0) |
326 | | ((allow & S_IXUSR0000100) ? S_IXGRP0000010 : 0)); |
327 | } |
328 | *attribute |= allow; |
329 | } |
330 | |
331 | static void |
332 | get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute, |
333 | __uid32_t *uidret, __gid32_t *gidret) |
334 | { |
335 | if (!psd) |
336 | { |
337 | /* If reading the security descriptor failed, treat the object |
338 | as unreadable. */ |
339 | if (attribute) |
340 | *attribute &= ~(S_IRWXU(0000400 | 0000200 | 0000100) | S_IRWXG(0000040 | 0000020 | 0000010) | S_IRWXO(0000004 | 0000002 | 0000001)); |
341 | if (uidret) |
342 | *uidret = ILLEGAL_UID((__uid32_t)-1); |
343 | if (gidret) |
344 | *gidret = ILLEGAL_GID((__gid32_t)-1); |
345 | return; |
346 | } |
347 | |
348 | cygpsid owner_sid; |
349 | cygpsid group_sid; |
350 | NTSTATUS status; |
351 | BOOLEAN dummy; |
352 | |
353 | status = RtlGetOwnerSecurityDescriptor (psd, (PSID *) &owner_sid, &dummy); |
354 | if (!NT_SUCCESS (status)((status)>=0)) |
355 | debug_printf ("RtlGetOwnerSecurityDescriptor: %p", status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "RtlGetOwnerSecurityDescriptor: %p" , status); 0; })); |
356 | status = RtlGetGroupSecurityDescriptor (psd, (PSID *) &group_sid, &dummy); |
357 | if (!NT_SUCCESS (status)((status)>=0)) |
358 | debug_printf ("RtlGetGroupSecurityDescriptor: %p", status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "RtlGetGroupSecurityDescriptor: %p" , status); 0; })); |
359 | |
360 | __uid32_t uid; |
361 | __gid32_t gid; |
362 | bool grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid); |
363 | if (uidret) |
364 | *uidret = uid; |
365 | if (gidret) |
366 | *gidret = gid; |
367 | |
368 | if (!attribute) |
369 | { |
370 | syscall_printf ("uid %d, gid %d", uid, gid)((void) ({ if ((0x000010 & 0x008000) || strace.active ()) strace.prntf(0x000010, __PRETTY_FUNCTION__, "uid %d, gid %d" , uid, gid); 0; })); |
371 | return; |
372 | } |
373 | |
374 | PACL acl; |
375 | BOOLEAN acl_exists; |
376 | |
377 | status = RtlGetDaclSecurityDescriptor (psd, &acl_exists, &acl, &dummy); |
378 | if (!NT_SUCCESS (status)((status)>=0)) |
379 | { |
380 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 380, status); |
381 | *attribute &= ~(S_IRWXU(0000400 | 0000200 | 0000100) | S_IRWXG(0000040 | 0000020 | 0000010) | S_IRWXO(0000004 | 0000002 | 0000001)); |
382 | } |
383 | else if (!acl_exists || !acl) |
384 | *attribute |= S_IRWXU(0000400 | 0000200 | 0000100) | S_IRWXG(0000040 | 0000020 | 0000010) | S_IRWXO(0000004 | 0000002 | 0000001); |
385 | else |
386 | get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member); |
387 | |
388 | syscall_printf ("%sACL %x, uid %d, gid %d",((void) ({ if ((0x000010 & 0x008000) || strace.active ()) strace.prntf(0x000010, __PRETTY_FUNCTION__, "%sACL %x, uid %d, gid %d" , (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid); 0; } )) |
389 | (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid)((void) ({ if ((0x000010 & 0x008000) || strace.active ()) strace.prntf(0x000010, __PRETTY_FUNCTION__, "%sACL %x, uid %d, gid %d" , (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid); 0; } )); |
390 | } |
391 | |
392 | static int |
393 | get_reg_sd (HANDLE handle, security_descriptor &sd_ret) |
394 | { |
395 | LONG ret; |
396 | DWORD len = 0; |
397 | |
398 | ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
399 | sd_ret, &len); |
400 | if (ret == ERROR_INSUFFICIENT_BUFFER122L) |
401 | { |
402 | if (!sd_ret.malloc (len)) |
403 | set_errno (ENOMEM)__set_errno (__PRETTY_FUNCTION__, 403, (12)); |
404 | else |
405 | ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
406 | sd_ret, &len); |
407 | } |
408 | if (ret != ERROR_SUCCESS0L) |
409 | { |
410 | __seterrno ()seterrno ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 410); |
411 | return -1; |
412 | } |
413 | return 0; |
414 | } |
415 | |
416 | int |
417 | get_reg_attribute (HKEY hkey, mode_t *attribute, __uid32_t *uidret, |
418 | __gid32_t *gidret) |
419 | { |
420 | security_descriptor sd; |
421 | |
422 | if (!get_reg_sd (hkey, sd)) |
423 | { |
424 | get_info_from_sd (sd, attribute, uidret, gidret); |
425 | return 0; |
426 | } |
427 | /* The entries are already set to default values */ |
428 | return -1; |
429 | } |
430 | |
431 | int |
432 | get_file_attribute (HANDLE handle, path_conv &pc, |
433 | mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) |
434 | { |
435 | if (pc.has_acls ()) |
436 | { |
437 | security_descriptor sd; |
438 | |
439 | if (!get_file_sd (handle, pc, sd, false)) |
440 | { |
441 | get_info_from_sd (sd, attribute, uidret, gidret); |
442 | return 0; |
443 | } |
444 | /* ENOSYS is returned by get_file_sd if fetching the DACL from a remote |
445 | share returns STATUS_INVALID_NETWORK_RESPONSE, which in turn is |
446 | converted to ERROR_BAD_NET_RESP. This potentially occurs when trying |
447 | to fetch DACLs from a NT4 machine which is not part of the domain of |
448 | the requesting machine. */ |
449 | else if (get_errno ()((*__errno())) != ENOSYS88) |
450 | { |
451 | if (uidret) |
452 | *uidret = ILLEGAL_UID((__uid32_t)-1); |
453 | if (gidret) |
454 | *gidret = ILLEGAL_GID((__gid32_t)-1); |
455 | |
456 | return -1; |
457 | } |
458 | } |
459 | |
460 | if (uidret) |
461 | *uidret = myself->uid; |
462 | if (gidret) |
463 | *gidret = myself->gid; |
464 | |
465 | return -1; |
466 | } |
467 | |
468 | bool |
469 | add_access_allowed_ace (PACL acl, int offset, DWORD attributes, |
470 | PSID sid, size_t &len_add, DWORD inherit) |
471 | { |
472 | NTSTATUS status = RtlAddAccessAllowedAceEx (acl, ACL_REVISION2, inherit, |
473 | attributes, sid); |
474 | if (!NT_SUCCESS (status)((status)>=0)) |
475 | { |
476 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 476, status); |
477 | return false; |
478 | } |
479 | len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + RtlLengthSid (sid); |
480 | return true; |
481 | } |
482 | |
483 | bool |
484 | add_access_denied_ace (PACL acl, int offset, DWORD attributes, |
485 | PSID sid, size_t &len_add, DWORD inherit) |
486 | { |
487 | NTSTATUS status = RtlAddAccessDeniedAceEx (acl, ACL_REVISION2, inherit, |
488 | attributes, sid); |
489 | if (!NT_SUCCESS (status)((status)>=0)) |
490 | { |
491 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 491, status); |
492 | return false; |
493 | } |
494 | len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + RtlLengthSid (sid); |
495 | return true; |
496 | } |
497 | |
498 | static PSECURITY_DESCRIPTOR |
499 | alloc_sd (path_conv &pc, __uid32_t uid, __gid32_t gid, int attribute, |
500 | security_descriptor &sd_ret) |
501 | { |
502 | NTSTATUS status; |
503 | BOOLEAN dummy; |
504 | tmp_pathbuf tp; |
505 | |
506 | /* NOTE: If the high bit of attribute is set, we have just created |
507 | a file or directory. See below for an explanation. */ |
508 | |
509 | debug_printf("uid %d, gid %d, attribute %x", uid, gid, attribute)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "uid %d, gid %d, attribute %x" , uid, gid, attribute); 0; })); |
510 | |
511 | /* Get owner and group from current security descriptor. */ |
512 | PSID cur_owner_sid = NULL__null; |
513 | PSID cur_group_sid = NULL__null; |
514 | status = RtlGetOwnerSecurityDescriptor (sd_ret, &cur_owner_sid, &dummy); |
515 | if (!NT_SUCCESS (status)((status)>=0)) |
516 | debug_printf ("RtlGetOwnerSecurityDescriptor: %p", status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "RtlGetOwnerSecurityDescriptor: %p" , status); 0; })); |
517 | status = RtlGetGroupSecurityDescriptor (sd_ret, &cur_group_sid, &dummy); |
518 | if (!NT_SUCCESS (status)((status)>=0)) |
519 | debug_printf ("RtlGetGroupSecurityDescriptor: %p", status)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "RtlGetGroupSecurityDescriptor: %p" , status); 0; })); |
520 | |
521 | /* Get SID of owner. */ |
522 | cygsid owner_sid; |
523 | /* Check for current user first */ |
524 | if (uid == myself->uid) |
525 | owner_sid = cygheap->user.sid (); |
526 | else if (uid == ILLEGAL_UID((__uid32_t)-1)) |
527 | owner_sid = cur_owner_sid; |
528 | else if (!owner_sid.getfrompw (internal_getpwuid (uid))) |
529 | { |
530 | set_errno (EINVAL)__set_errno (__PRETTY_FUNCTION__, 530, (22)); |
531 | return NULL__null; |
532 | } |
533 | owner_sid.debug_print ("alloc_sd: owner SID ="); |
534 | |
535 | /* Get SID of new group. */ |
536 | cygsid group_sid; |
537 | /* Check for current user first */ |
538 | if (gid == myself->gid) |
539 | group_sid = cygheap->user.groups.pgsid; |
540 | else if (gid == ILLEGAL_GID((__gid32_t)-1)) |
541 | group_sid = cur_group_sid; |
542 | else if (!group_sid.getfromgr (internal_getgrgid (gid))) |
543 | { |
544 | set_errno (EINVAL)__set_errno (__PRETTY_FUNCTION__, 544, (22)); |
545 | return NULL__null; |
546 | } |
547 | group_sid.debug_print ("alloc_sd: group SID ="); |
548 | |
549 | /* Initialize local security descriptor. */ |
550 | SECURITY_DESCRIPTOR sd; |
551 | RtlCreateSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION1); |
552 | |
553 | /* We set the SE_DACL_PROTECTED flag here to prevent the DACL from being |
554 | modified by inheritable ACEs. */ |
555 | RtlSetControlSecurityDescriptor (&sd, SE_DACL_PROTECTED4096, SE_DACL_PROTECTED4096); |
556 | |
557 | /* Create owner for local security descriptor. */ |
558 | status = RtlSetOwnerSecurityDescriptor (&sd, owner_sid, FALSE0); |
559 | if (!NT_SUCCESS (status)((status)>=0)) |
560 | { |
561 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 561, status); |
562 | return NULL__null; |
563 | } |
564 | |
565 | /* Create group for local security descriptor. */ |
566 | status = RtlSetGroupSecurityDescriptor (&sd, group_sid, FALSE0); |
567 | if (!NT_SUCCESS (status)((status)>=0)) |
568 | { |
569 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 569, status); |
570 | return NULL__null; |
571 | } |
572 | |
573 | /* Initialize local access control list. */ |
574 | PACL acl = (PACL) tp.w_get (); |
575 | RtlCreateAcl (acl, ACL_MAXIMUM_SIZE65532, ACL_REVISION2); |
576 | |
577 | /* From here fill ACL. */ |
578 | size_t acl_len = sizeof (ACL); |
579 | int ace_off = 0; |
580 | /* Only used for sync objects (for ttys). The admins group should |
581 | always have the right to manipulate the ACL, so we have to make sure |
582 | that the ACL gives the admins group STANDARD_RIGHTS_ALL access. */ |
583 | bool saw_admins = false; |
584 | |
585 | /* Construct allow attribute for owner. |
586 | Don't set FILE_READ/WRITE_ATTRIBUTES unconditionally on Samba, otherwise |
587 | it enforces read permissions. Same for other's below. */ |
588 | DWORD owner_allow = STANDARD_RIGHTS_ALL0x1F0000 |
589 | | (pc.fs_is_samba () |
590 | ? 0 : (FILE_READ_ATTRIBUTES0x00000080 | FILE_WRITE_ATTRIBUTES0x00000100)); |
591 | if (attribute & S_IRUSR0000400) |
592 | owner_allow |= FILE_GENERIC_READ(0x20000 | 0x00000001 | 0x00000080 | 0x00000008 | 0x100000L); |
593 | if (attribute & S_IWUSR0000200) |
594 | owner_allow |= FILE_GENERIC_WRITE(0x20000 | 0x00000002 | 0x00000100 | 0x00000010 | 0x00000004 | 0x100000L); |
595 | if (attribute & S_IXUSR0000100) |
596 | owner_allow |= FILE_GENERIC_EXECUTE(0x20000 | 0x00000080 | 0x00000020 | 0x100000L) & ~FILE_READ_ATTRIBUTES0x00000080; |
597 | if (S_ISDIR (attribute)(((attribute)&0170000) == 0040000) |
598 | && (attribute & (S_IWUSR0000200 | S_IXUSR0000100)) == (S_IWUSR0000200 | S_IXUSR0000100)) |
599 | owner_allow |= FILE_DELETE_CHILD0x00000040; |
600 | /* For sync objects note that the owner is admin. */ |
601 | if (S_ISCHR (attribute)(((attribute)&0170000) == 0020000) && owner_sid == well_known_admins_sid) |
602 | saw_admins = true; |
603 | |
604 | /* Construct allow attribute for group. */ |
605 | DWORD group_allow = STANDARD_RIGHTS_READ0x20000 | SYNCHRONIZE0x100000L |
606 | | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES0x00000080); |
607 | if (attribute & S_IRGRP0000040) |
608 | group_allow |= FILE_GENERIC_READ(0x20000 | 0x00000001 | 0x00000080 | 0x00000008 | 0x100000L); |
609 | if (attribute & S_IWGRP0000020) |
610 | group_allow |= FILE_GENERIC_WRITE(0x20000 | 0x00000002 | 0x00000100 | 0x00000010 | 0x00000004 | 0x100000L); |
611 | if (attribute & S_IXGRP0000010) |
612 | group_allow |= FILE_GENERIC_EXECUTE(0x20000 | 0x00000080 | 0x00000020 | 0x100000L) & ~FILE_READ_ATTRIBUTES0x00000080; |
613 | if (S_ISDIR (attribute)(((attribute)&0170000) == 0040000) |
614 | && (attribute & (S_IWGRP0000020 | S_IXGRP0000010)) == (S_IWGRP0000020 | S_IXGRP0000010) |
615 | && !(attribute & S_ISVTX0001000)) |
616 | group_allow |= FILE_DELETE_CHILD0x00000040; |
617 | /* For sync objects, add STANDARD_RIGHTS_ALL for admins group. */ |
618 | if (S_ISCHR (attribute)(((attribute)&0170000) == 0020000) && group_sid == well_known_admins_sid) |
619 | { |
620 | group_allow |= STANDARD_RIGHTS_ALL0x1F0000; |
621 | saw_admins = true; |
622 | } |
623 | |
624 | /* Construct allow attribute for everyone. */ |
625 | DWORD other_allow = STANDARD_RIGHTS_READ0x20000 | SYNCHRONIZE0x100000L |
626 | | (pc.fs_is_samba () ? 0 : FILE_READ_ATTRIBUTES0x00000080); |
627 | if (attribute & S_IROTH0000004) |
628 | other_allow |= FILE_GENERIC_READ(0x20000 | 0x00000001 | 0x00000080 | 0x00000008 | 0x100000L); |
629 | if (attribute & S_IWOTH0000002) |
630 | other_allow |= FILE_GENERIC_WRITE(0x20000 | 0x00000002 | 0x00000100 | 0x00000010 | 0x00000004 | 0x100000L); |
631 | if (attribute & S_IXOTH0000001) |
632 | other_allow |= FILE_GENERIC_EXECUTE(0x20000 | 0x00000080 | 0x00000020 | 0x100000L) & ~FILE_READ_ATTRIBUTES0x00000080; |
633 | if (S_ISDIR (attribute)(((attribute)&0170000) == 0040000) |
634 | && (attribute & (S_IWOTH0000002 | S_IXOTH0000001)) == (S_IWOTH0000002 | S_IXOTH0000001) |
635 | && !(attribute & S_ISVTX0001000)) |
636 | other_allow |= FILE_DELETE_CHILD0x00000040; |
637 | |
638 | /* Construct SUID, SGID and VTX bits in NULL ACE. */ |
639 | DWORD null_allow = 0L; |
640 | if (attribute & (S_ISUID0004000 | S_ISGID0002000 | S_ISVTX0001000)) |
641 | { |
642 | if (attribute & S_ISUID0004000) |
643 | null_allow |= FILE_APPEND_DATA0x00000004; |
644 | if (attribute & S_ISGID0002000) |
645 | null_allow |= FILE_WRITE_DATA0x00000002; |
646 | if (attribute & S_ISVTX0001000) |
647 | null_allow |= FILE_READ_DATA0x00000001; |
648 | } |
649 | |
650 | /* Add owner and group permissions if SIDs are equal |
651 | and construct deny attributes for group and owner. */ |
652 | bool isownergroup; |
653 | if ((isownergroup = (owner_sid == group_sid))) |
654 | owner_allow |= group_allow; |
655 | |
656 | DWORD owner_deny = ~owner_allow & (group_allow | other_allow); |
657 | owner_deny &= ~(STANDARD_RIGHTS_READ0x20000 |
658 | | FILE_READ_ATTRIBUTES0x00000080 | FILE_WRITE_ATTRIBUTES0x00000100); |
659 | |
660 | DWORD group_deny = ~group_allow & other_allow; |
661 | group_deny &= ~(STANDARD_RIGHTS_READ0x20000 | FILE_READ_ATTRIBUTES0x00000080); |
662 | |
663 | /* Set deny ACE for owner. */ |
664 | if (owner_deny |
665 | && !add_access_denied_ace (acl, ace_off++, owner_deny, |
666 | owner_sid, acl_len, NO_INHERITANCE0x0)) |
667 | return NULL__null; |
668 | /* Set deny ACE for group here to respect the canonical order, |
669 | if this does not impact owner */ |
670 | if (group_deny && !(group_deny & owner_allow) && !isownergroup |
671 | && !add_access_denied_ace (acl, ace_off++, group_deny, |
672 | group_sid, acl_len, NO_INHERITANCE0x0)) |
673 | return NULL__null; |
674 | /* Set allow ACE for owner. */ |
675 | if (!add_access_allowed_ace (acl, ace_off++, owner_allow, |
676 | owner_sid, acl_len, NO_INHERITANCE0x0)) |
677 | return NULL__null; |
678 | /* Set deny ACE for group, if still needed. */ |
679 | if (group_deny & owner_allow && !isownergroup |
680 | && !add_access_denied_ace (acl, ace_off++, group_deny, |
681 | group_sid, acl_len, NO_INHERITANCE0x0)) |
682 | return NULL__null; |
683 | /* Set allow ACE for group. */ |
684 | if (!isownergroup |
685 | && !add_access_allowed_ace (acl, ace_off++, group_allow, |
686 | group_sid, acl_len, NO_INHERITANCE0x0)) |
687 | return NULL__null; |
688 | |
689 | /* For sync objects, if we didn't see the admins group so far, add entry |
690 | with STANDARD_RIGHTS_ALL access. */ |
691 | if (S_ISCHR (attribute)(((attribute)&0170000) == 0020000) && !saw_admins) |
692 | { |
693 | if (!add_access_allowed_ace (acl, ace_off++, STANDARD_RIGHTS_ALL0x1F0000, |
694 | well_known_admins_sid, acl_len, |
695 | NO_INHERITANCE0x0)) |
696 | return NULL__null; |
697 | saw_admins = true; |
Value stored to 'saw_admins' is never read | |
698 | } |
699 | |
700 | /* Set allow ACE for everyone. */ |
701 | if (!add_access_allowed_ace (acl, ace_off++, other_allow, |
702 | well_known_world_sid, acl_len, NO_INHERITANCE0x0)) |
703 | return NULL__null; |
704 | /* Set null ACE for special bits. */ |
705 | if (null_allow |
706 | && !add_access_allowed_ace (acl, ace_off++, null_allow, |
707 | well_known_null_sid, acl_len, NO_INHERITANCE0x0)) |
708 | return NULL__null; |
709 | |
710 | /* Fill ACL with unrelated ACEs from current security descriptor. */ |
711 | PACL oacl; |
712 | BOOLEAN acl_exists = FALSE0; |
713 | ACCESS_ALLOWED_ACE *ace; |
714 | |
715 | status = RtlGetDaclSecurityDescriptor (sd_ret, &acl_exists, &oacl, &dummy); |
716 | if (NT_SUCCESS (status)((status)>=0) && acl_exists && oacl) |
717 | for (DWORD i = 0; i < oacl->AceCount; ++i) |
718 | if (NT_SUCCESS (RtlGetAce (oacl, i, (PVOID *) &ace))((RtlGetAce (oacl, i, (PVOID *) &ace))>=0)) |
719 | { |
720 | cygpsid ace_sid ((PSID) &ace->SidStart); |
721 | |
722 | /* Always skip NULL SID as well as admins SID on virtual device files |
723 | in /proc/sys. */ |
724 | if (ace_sid == well_known_null_sid |
725 | || (S_ISCHR (attribute)(((attribute)&0170000) == 0020000) && ace_sid == well_known_admins_sid)) |
726 | continue; |
727 | /* Check for ACEs which are always created in the preceding code |
728 | and check for the default inheritence ACEs which will be created |
729 | for just created directories. Skip them for just created |
730 | directories or if they are not inherited. If they are inherited, |
731 | make sure they are *only* inherited, so they don't collide with |
732 | the permissions set in this function. */ |
733 | if ((ace_sid == cur_owner_sid) |
734 | || (ace_sid == owner_sid) |
735 | || (ace_sid == cur_group_sid) |
736 | || (ace_sid == group_sid) |
737 | || (ace_sid == well_known_creator_owner_sid) |
738 | || (ace_sid == well_known_creator_group_sid) |
739 | || (ace_sid == well_known_world_sid)) |
740 | { |
741 | if ((S_ISDIR (attribute)(((attribute)&0170000) == 0040000) && (attribute & S_JUSTCREATED0x80000000)) |
742 | || (ace->Header.AceFlags |
743 | & (CONTAINER_INHERIT_ACE2 | OBJECT_INHERIT_ACE1)) == 0) |
744 | continue; |
745 | else |
746 | ace->Header.AceFlags |= INHERIT_ONLY_ACE8; |
747 | } |
748 | if (attribute & S_JUSTCREATED0x80000000) |
749 | { |
750 | /* Since files and dirs are created with a NULL descriptor, |
751 | inheritence rules kick in. If no inheritable entries exist |
752 | in the parent object, Windows will create entries from the |
753 | user token's default DACL in the file DACL. These entries |
754 | are not desired and we drop them silently. */ |
755 | if (!(ace->Header.AceFlags & INHERITED_ACE16)) |
756 | continue; |
757 | /* Remove the INHERITED_ACE flag since on POSIX systems |
758 | inheritance is settled when the file has been created. |
759 | This also avoids error messages in Windows Explorer when |
760 | opening a file's security tab. Explorer complains if |
761 | inheritable ACEs are preceding non-inheritable ACEs. */ |
762 | ace->Header.AceFlags &= ~INHERITED_ACE16; |
763 | } |
764 | /* |
765 | * Add unrelated ACCESS_DENIED_ACE to the beginning but |
766 | * behind the owner_deny, ACCESS_ALLOWED_ACE to the end. |
767 | * FIXME: this would break the order of the inherit-only ACEs |
768 | */ |
769 | status = RtlAddAce (acl, ACL_REVISION2, |
770 | ace->Header.AceType == ACCESS_DENIED_ACE_TYPE(0x1) |
771 | ? (owner_deny ? 1 : 0) : MAXDWORD0xffffffff, |
772 | (LPVOID) ace, ace->Header.AceSize); |
773 | if (!NT_SUCCESS (status)((status)>=0)) |
774 | { |
775 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 775, status); |
776 | return NULL__null; |
777 | } |
778 | ace_off++; |
779 | acl_len += ace->Header.AceSize; |
780 | } |
781 | |
782 | /* Construct appropriate inherit attribute for new directories. Keep in |
783 | mind that we do this only for the sake of non-Cygwin applications. |
784 | Cygwin applications don't need this. */ |
785 | if (S_ISDIR (attribute)(((attribute)&0170000) == 0040000) && (attribute & S_JUSTCREATED0x80000000)) |
786 | { |
787 | const DWORD inherit = CONTAINER_INHERIT_ACE2 | OBJECT_INHERIT_ACE1 |
788 | | INHERIT_ONLY_ACE8; |
789 | #if 0 /* FIXME: Not done currently as this breaks the canonical order */ |
790 | /* Set deny ACE for owner. */ |
791 | if (owner_deny |
792 | && !add_access_denied_ace (acl, ace_off++, owner_deny, |
793 | well_known_creator_owner_sid, acl_len, inherit)) |
794 | return NULL__null; |
795 | /* Set deny ACE for group here to respect the canonical order, |
796 | if this does not impact owner */ |
797 | if (group_deny && !(group_deny & owner_allow) |
798 | && !add_access_denied_ace (acl, ace_off++, group_deny, |
799 | well_known_creator_group_sid, acl_len, inherit)) |
800 | return NULL__null; |
801 | #endif |
802 | /* Set allow ACE for owner. */ |
803 | if (!add_access_allowed_ace (acl, ace_off++, owner_allow, |
804 | well_known_creator_owner_sid, acl_len, |
805 | inherit)) |
806 | return NULL__null; |
807 | #if 0 /* FIXME: Not done currently as this breaks the canonical order and |
808 | won't be preserved on chown and chmod */ |
809 | /* Set deny ACE for group, conflicting with owner_allow. */ |
810 | if (group_deny & owner_allow |
811 | && !add_access_denied_ace (acl, ace_off++, group_deny, |
812 | well_known_creator_group_sid, acl_len, inherit)) |
813 | return NULL__null; |
814 | #endif |
815 | /* Set allow ACE for group. */ |
816 | if (!add_access_allowed_ace (acl, ace_off++, group_allow, |
817 | well_known_creator_group_sid, acl_len, |
818 | inherit)) |
819 | return NULL__null; |
820 | /* Set allow ACE for everyone. */ |
821 | if (!add_access_allowed_ace (acl, ace_off++, other_allow, |
822 | well_known_world_sid, acl_len, inherit)) |
823 | return NULL__null; |
824 | } |
825 | |
826 | /* Set AclSize to computed value. */ |
827 | acl->AclSize = acl_len; |
828 | debug_printf ("ACL-Size: %d", acl_len)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "ACL-Size: %d", acl_len ); 0; })); |
829 | |
830 | /* Create DACL for local security descriptor. */ |
831 | status = RtlSetDaclSecurityDescriptor (&sd, TRUE1, acl, FALSE0); |
832 | if (!NT_SUCCESS (status)((status)>=0)) |
833 | { |
834 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 834, status); |
835 | return NULL__null; |
836 | } |
837 | |
838 | /* Make self relative security descriptor. */ |
839 | DWORD sd_size = 0; |
840 | RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size); |
841 | if (sd_size <= 0) |
842 | { |
843 | __seterrno ()seterrno ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 843); |
844 | return NULL__null; |
845 | } |
846 | if (!sd_ret.malloc (sd_size)) |
847 | { |
848 | set_errno (ENOMEM)__set_errno (__PRETTY_FUNCTION__, 848, (12)); |
849 | return NULL__null; |
850 | } |
851 | status = RtlAbsoluteToSelfRelativeSD (&sd, sd_ret, &sd_size); |
852 | if (!NT_SUCCESS (status)((status)>=0)) |
853 | { |
854 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 854, status); |
855 | return NULL__null; |
856 | } |
857 | debug_printf ("Created SD-Size: %u", sd_ret.size ())((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "Created SD-Size: %u" , sd_ret.size ()); 0; })); |
858 | |
859 | return sd_ret; |
860 | } |
861 | |
862 | void |
863 | set_security_attribute (path_conv &pc, int attribute, PSECURITY_ATTRIBUTES psa, |
864 | security_descriptor &sd) |
865 | { |
866 | psa->lpSecurityDescriptor = sd.malloc (SECURITY_DESCRIPTOR_MIN_LENGTH20); |
867 | RtlCreateSecurityDescriptor ((PSECURITY_DESCRIPTOR) psa->lpSecurityDescriptor, |
868 | SECURITY_DESCRIPTOR_REVISION1); |
869 | psa->lpSecurityDescriptor = alloc_sd (pc, geteuid32 (), getegid32 (), |
870 | attribute, sd); |
871 | } |
872 | |
873 | int |
874 | get_object_sd (HANDLE handle, security_descriptor &sd) |
875 | { |
876 | ULONG len = 0; |
877 | NTSTATUS status; |
878 | |
879 | status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
880 | sd, len, &len); |
881 | if (status != STATUS_BUFFER_TOO_SMALL((NTSTATUS)0xC0000023L)) |
882 | { |
883 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 883, status); |
884 | return -1; |
885 | } |
886 | if (!sd.malloc (len)) |
887 | { |
888 | set_errno (ENOMEM)__set_errno (__PRETTY_FUNCTION__, 888, (12)); |
889 | return -1; |
890 | } |
891 | status = NtQuerySecurityObject (handle, ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001), |
892 | sd, len, &len); |
893 | if (!NT_SUCCESS (status)((status)>=0)) |
894 | { |
895 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 895, status); |
896 | return -1; |
897 | } |
898 | return 0; |
899 | } |
900 | |
901 | int |
902 | get_object_attribute (HANDLE handle, __uid32_t *uidret, __gid32_t *gidret, |
903 | mode_t *attribute) |
904 | { |
905 | security_descriptor sd; |
906 | |
907 | if (get_object_sd (handle, sd)) |
908 | return -1; |
909 | get_info_from_sd (sd, attribute, uidret, gidret); |
910 | return 0; |
911 | } |
912 | |
913 | int |
914 | create_object_sd_from_attribute (HANDLE handle, __uid32_t uid, __gid32_t gid, |
915 | mode_t attribute, security_descriptor &sd) |
916 | { |
917 | path_conv pc; |
918 | if ((handle && get_object_sd (handle, sd)) |
919 | || !alloc_sd (pc, uid, gid, attribute, sd)) |
920 | return -1; |
921 | return 0; |
922 | } |
923 | |
924 | int |
925 | set_object_sd (HANDLE handle, security_descriptor &sd, bool chown) |
926 | { |
927 | NTSTATUS status; |
928 | status = NtSetSecurityObject (handle, chown ? ALL_SECURITY_INFORMATION(0x00000004 | 0x00000002 | 0x00000001) |
929 | : DACL_SECURITY_INFORMATION0x00000004, sd); |
930 | if (!NT_SUCCESS (status)((status)>=0)) |
931 | { |
932 | __seterrno_from_nt_status (status)seterrno_from_nt_status ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 932, status); |
933 | return -1; |
934 | } |
935 | return 0; |
936 | } |
937 | |
938 | int |
939 | set_object_attribute (HANDLE handle, __uid32_t uid, __gid32_t gid, |
940 | mode_t attribute) |
941 | { |
942 | security_descriptor sd; |
943 | |
944 | if (create_object_sd_from_attribute (handle, uid, gid, attribute, sd) |
945 | || set_object_sd (handle, sd, uid != ILLEGAL_UID((__uid32_t)-1) || gid != ILLEGAL_GID((__gid32_t)-1))) |
946 | return -1; |
947 | return 0; |
948 | } |
949 | |
950 | int |
951 | set_file_attribute (HANDLE handle, path_conv &pc, |
952 | __uid32_t uid, __gid32_t gid, mode_t attribute) |
953 | { |
954 | int ret = -1; |
955 | |
956 | if (pc.has_acls ()) |
957 | { |
958 | security_descriptor sd; |
959 | |
960 | if (!get_file_sd (handle, pc, sd, (bool)(attribute & S_JUSTCREATED0x80000000)) |
961 | && alloc_sd (pc, uid, gid, attribute, sd)) |
962 | ret = set_file_sd (handle, pc, sd, |
963 | uid != ILLEGAL_UID((__uid32_t)-1) || gid != ILLEGAL_GID((__gid32_t)-1)); |
964 | } |
965 | else |
966 | ret = 0; |
967 | syscall_printf ("%d = set_file_attribute(%S, %d, %d, %p)",((void) ({ if ((0x000010 & 0x008000) || strace.active ()) strace.prntf(0x000010, __PRETTY_FUNCTION__, "%d = set_file_attribute(%S, %d, %d, %p)" , ret, pc.get_nt_native_path (), uid, gid, attribute); 0; })) |
968 | ret, pc.get_nt_native_path (), uid, gid, attribute)((void) ({ if ((0x000010 & 0x008000) || strace.active ()) strace.prntf(0x000010, __PRETTY_FUNCTION__, "%d = set_file_attribute(%S, %d, %d, %p)" , ret, pc.get_nt_native_path (), uid, gid, attribute); 0; })); |
969 | return ret; |
970 | } |
971 | |
972 | static int |
973 | check_access (security_descriptor &sd, GENERIC_MAPPING &mapping, |
974 | ACCESS_MASK desired, int flags, bool effective) |
975 | { |
976 | int ret = -1; |
977 | NTSTATUS status, allow; |
978 | ACCESS_MASK granted; |
979 | DWORD plen = sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES); |
980 | PPRIVILEGE_SET pset = (PPRIVILEGE_SET) alloca (plen)__builtin_alloca(plen); |
981 | HANDLE tok = ((effective && cygheap->user.issetuid ()) |
982 | ? cygheap->user.imp_token () |
983 | : hProcImpToken); |
984 | |
985 | if (!tok) |
986 | { |
987 | if (!DuplicateTokenEx (hProcToken, MAXIMUM_ALLOWED0x2000000, NULL__null, |
988 | SecurityImpersonation, TokenImpersonation, |
989 | &hProcImpToken)) |
990 | { |
991 | __seterrno ()seterrno ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 991); |
992 | return ret; |
993 | } |
994 | tok = hProcImpToken; |
995 | } |
996 | |
997 | status = NtAccessCheck (sd, tok, desired, &mapping, pset, &plen, &granted, |
998 | &allow); |
999 | if (!NT_SUCCESS (status)((status)>=0)) |
1000 | __seterrno ()seterrno ("/home/Yaakov/src/cygwin/src/winsup/cygwin/security.cc" , 1000); |
1001 | else if (!NT_SUCCESS (allow)((allow)>=0)) |
1002 | { |
1003 | /* CV, 2006-10-16: Now, that's really weird. Imagine a user who has no |
1004 | standard access to a file, but who has backup and restore privileges |
1005 | and these privileges are enabled in the access token. One would |
1006 | expect that the AccessCheck function takes this into consideration |
1007 | when returning the access status. Otherwise, why bother with the |
1008 | pset parameter, right? |
1009 | But not so. AccessCheck actually returns a status of "false" here, |
1010 | even though opening a file with backup resp. restore intent |
1011 | naturally succeeds for this user. This definitely spoils the results |
1012 | of access(2) for administrative users or the SYSTEM account. So, in |
1013 | case the access check fails, another check against the user's |
1014 | backup/restore privileges has to be made. Sigh. */ |
1015 | int granted_flags = 0; |
1016 | BOOLEAN has_priv; |
1017 | |
1018 | if (flags & R_OK4) |
1019 | { |
1020 | pset->PrivilegeCount = 1; |
1021 | pset->Control = 0; |
1022 | pset->Privilege[0].Luid.HighPart = 0L; |
1023 | pset->Privilege[0].Luid.LowPart = SE_BACKUP_PRIVILEGE17UL; |
1024 | pset->Privilege[0].Attributes = 0; |
1025 | status = NtPrivilegeCheck (tok, pset, &has_priv); |
1026 | if (NT_SUCCESS (status)((status)>=0) && has_priv) |
1027 | granted_flags |= R_OK4; |
1028 | } |
1029 | if (flags & W_OK2) |
1030 | { |
1031 | pset->PrivilegeCount = 1; |
1032 | pset->Control = 0; |
1033 | pset->Privilege[0].Luid.HighPart = 0L; |
1034 | pset->Privilege[0].Luid.LowPart = SE_RESTORE_PRIVILEGE18UL; |
1035 | pset->Privilege[0].Attributes = 0; |
1036 | status = NtPrivilegeCheck (tok, pset, &has_priv); |
1037 | if (NT_SUCCESS (status)((status)>=0) && has_priv) |
1038 | granted_flags |= W_OK2; |
1039 | } |
1040 | if (granted_flags == flags) |
1041 | ret = 0; |
1042 | else |
1043 | set_errno (EACCES)__set_errno (__PRETTY_FUNCTION__, 1043, (13)); |
1044 | } |
1045 | else |
1046 | ret = 0; |
1047 | return ret; |
1048 | } |
1049 | |
1050 | int |
1051 | check_file_access (path_conv &pc, int flags, bool effective) |
1052 | { |
1053 | security_descriptor sd; |
1054 | int ret = -1; |
1055 | ACCESS_MASK desired = 0; |
1056 | if (flags & R_OK4) |
1057 | desired |= FILE_READ_DATA0x00000001; |
1058 | if (flags & W_OK2) |
1059 | desired |= FILE_WRITE_DATA0x00000002; |
1060 | if (flags & X_OK1) |
1061 | desired |= FILE_EXECUTE0x00000020; |
1062 | if (!get_file_sd (pc.handle (), pc, sd, false)) |
1063 | ret = check_access (sd, file_mapping, desired, flags, effective); |
1064 | debug_printf ("flags %x, ret %d", flags, ret)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "flags %x, ret %d" , flags, ret); 0; })); |
1065 | return ret; |
1066 | } |
1067 | |
1068 | int |
1069 | check_registry_access (HANDLE hdl, int flags, bool effective) |
1070 | { |
1071 | security_descriptor sd; |
1072 | int ret = -1; |
1073 | static GENERIC_MAPPING NO_COPY__attribute__((nocommon)) __attribute__((section(".data_cygwin_nocopy" ))) reg_mapping = { KEY_READ0x20019, |
1074 | KEY_WRITE0x20006, |
1075 | KEY_EXECUTE0x20019, |
1076 | KEY_ALL_ACCESS0xf003f }; |
1077 | ACCESS_MASK desired = 0; |
1078 | if (flags & R_OK4) |
1079 | desired |= KEY_ENUMERATE_SUB_KEYS8; |
1080 | if (flags & W_OK2) |
1081 | desired |= KEY_SET_VALUE2; |
1082 | if (flags & X_OK1) |
1083 | desired |= KEY_QUERY_VALUE1; |
1084 | |
1085 | if ((HKEY) hdl == HKEY_PERFORMANCE_DATA((HKEY)0x80000004)) |
1086 | /* RegGetKeySecurity() always fails with ERROR_INVALID_HANDLE. */ |
1087 | ret = 0; |
1088 | else if (!get_reg_sd (hdl, sd)) |
1089 | ret = check_access (sd, reg_mapping, desired, flags, effective); |
1090 | |
1091 | /* As long as we can't write the registry... */ |
1092 | if (flags & W_OK2) |
1093 | { |
1094 | set_errno (EROFS)__set_errno (__PRETTY_FUNCTION__, 1094, (30)); |
1095 | ret = -1; |
1096 | } |
1097 | debug_printf ("flags %x, ret %d", flags, ret)((void) ({ if ((0x000040 & 0x008000) || strace.active ()) strace.prntf(0x000040, __PRETTY_FUNCTION__, "flags %x, ret %d" , flags, ret); 0; })); |
1098 | return ret; |
1099 | } |