Bug Summary

File:security.cc
Location:line 697, column 7
Description:Value stored to 'saw_admins' is never read

Annotated Source Code

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
9This file is part of Cygwin.
10
11This software is a copyrighted work licensed under the terms of the
12Cygwin license. Please consult the file "CYGWIN_LICENSE" for
13details. */
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
34static 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
39LONG
40get_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
194LONG
195set_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
237static void
238get_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
331static void
332get_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
392static int
393get_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
416int
417get_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
431int
432get_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
468bool
469add_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
483bool
484add_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
498static PSECURITY_DESCRIPTOR
499alloc_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
862void
863set_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
873int
874get_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
901int
902get_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
913int
914create_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
924int
925set_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
938int
939set_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
950int
951set_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
972static int
973check_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
1050int
1051check_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
1068int
1069check_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}