]>
Commit | Line | Data |
---|---|---|
1fd5e000 CF |
1 | /* security.cc: NT security functions |
2 | ||
ab2dbccc | 3 | Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003 Red Hat, Inc. |
1fd5e000 CF |
4 | |
5 | Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de | |
fc168ded | 6 | Completely rewritten by Corinna Vinschen <corinna@vinschen.de> |
1fd5e000 CF |
7 | |
8 | This file is part of Cygwin. | |
9 | ||
10 | This software is a copyrighted work licensed under the terms of the | |
11 | Cygwin license. Please consult the file "CYGWIN_LICENSE" for | |
12 | details. */ | |
13 | ||
4c8d72de | 14 | #include "winsup.h" |
1fd5e000 CF |
15 | #include <grp.h> |
16 | #include <pwd.h> | |
17 | #include <unistd.h> | |
18 | #include <stdlib.h> | |
1fd5e000 CF |
19 | #include <limits.h> |
20 | #include <sys/types.h> | |
21 | #include <sys/stat.h> | |
22 | #include <sys/acl.h> | |
1fd5e000 | 23 | #include <ctype.h> |
b2939a81 | 24 | #include <winnls.h> |
ee1d77e4 CF |
25 | #include <wingdi.h> |
26 | #include <winuser.h> | |
57ff940d CV |
27 | #include <wininet.h> |
28 | #include <ntsecapi.h> | |
29 | #include <subauth.h> | |
74fcdaec | 30 | #include <aclapi.h> |
bccd5e0d | 31 | #include "cygerrno.h" |
6b91b8d5 | 32 | #include "security.h" |
bccd5e0d CF |
33 | #include "fhandler.h" |
34 | #include "path.h" | |
e2ebe117 CF |
35 | #include "dtable.h" |
36 | #include "pinfo.h" | |
1f0f8e12 | 37 | #include "cygheap.h" |
1fcc912f CV |
38 | #include <ntdef.h> |
39 | #include "ntdll.h" | |
40 | #include "lm.h" | |
d6ffc075 | 41 | #include "pwdgrp.h" |
1fcc912f | 42 | |
3872e9a4 | 43 | bool allow_ntsec; |
5827f4d9 CV |
44 | /* allow_smbntsec is handled exclusively in path.cc (path_conv::check). |
45 | It's defined here because of it's strong relationship to allow_ntsec. | |
46 | The default is TRUE to reflect the old behaviour. */ | |
3872e9a4 | 47 | bool allow_smbntsec; |
1fd5e000 | 48 | |
5519d543 CV |
49 | cygsid * |
50 | cygsidlist::alloc_sids (int n) | |
51 | { | |
52 | if (n > 0) | |
53 | return (cygsid *) cmalloc (HEAP_STR, n * sizeof (cygsid)); | |
54 | else | |
55 | return NULL; | |
56 | } | |
57 | ||
58 | void | |
59 | cygsidlist::free_sids () | |
60 | { | |
61 | if (sids) | |
62 | cfree (sids); | |
5a8746b7 CV |
63 | sids = NULL; |
64 | count = maxcount = 0; | |
65 | type = cygsidlist_empty; | |
5519d543 CV |
66 | } |
67 | ||
380aaf2d | 68 | extern "C" void |
64b30629 CV |
69 | cygwin_set_impersonation_token (const HANDLE hToken) |
70 | { | |
71 | debug_printf ("set_impersonation_token (%d)", hToken); | |
ea3ba114 CV |
72 | cygheap->user.external_token = hToken; |
73 | return; | |
64b30629 CV |
74 | } |
75 | ||
1fcc912f | 76 | void |
57ff940d CV |
77 | extract_nt_dom_user (const struct passwd *pw, char *domain, char *user) |
78 | { | |
c6d90e84 | 79 | char *d, *u, *c; |
57ff940d | 80 | |
c6d90e84 | 81 | domain[0] = 0; |
5519d543 | 82 | strlcpy (user, pw->pw_name, UNLEN + 1); |
57ff940d | 83 | debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos); |
b2939a81 | 84 | |
c6d90e84 CV |
85 | if ((d = strstr (pw->pw_gecos, "U-")) != NULL && |
86 | (d == pw->pw_gecos || d[-1] == ',')) | |
57ff940d | 87 | { |
0c8455c3 CV |
88 | c = strechr (d + 2, ','); |
89 | if ((u = strechr (d + 2, '\\')) >= c) | |
c6d90e84 CV |
90 | u = d + 1; |
91 | else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2) | |
5519d543 | 92 | strlcpy (domain, d + 2, u - d - 1); |
c6d90e84 | 93 | if (c - u <= UNLEN + 1) |
a113a3c5 | 94 | strlcpy (user, u + 1, c - u); |
57ff940d | 95 | } |
c6d90e84 CV |
96 | if (domain[0]) |
97 | return; | |
98 | ||
99 | cygsid psid; | |
100 | DWORD ulen = UNLEN + 1; | |
101 | DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; | |
102 | SID_NAME_USE use; | |
103 | if (psid.getfrompw (pw)) | |
104 | LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use); | |
57ff940d CV |
105 | } |
106 | ||
380aaf2d | 107 | extern "C" HANDLE |
64b30629 CV |
108 | cygwin_logon_user (const struct passwd *pw, const char *password) |
109 | { | |
ba946828 | 110 | if (!wincap.has_security ()) |
64b30629 CV |
111 | { |
112 | set_errno (ENOSYS); | |
113 | return INVALID_HANDLE_VALUE; | |
114 | } | |
115 | if (!pw) | |
116 | { | |
117 | set_errno (EINVAL); | |
118 | return INVALID_HANDLE_VALUE; | |
119 | } | |
120 | ||
57ff940d CV |
121 | char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; |
122 | char nt_user[UNLEN + 1]; | |
64b30629 CV |
123 | HANDLE hToken; |
124 | ||
57ff940d | 125 | extract_nt_dom_user (pw, nt_domain, nt_user); |
e03f5f73 | 126 | debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password); |
57ff940d | 127 | if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password, |
5519d543 CV |
128 | LOGON32_LOGON_INTERACTIVE, |
129 | LOGON32_PROVIDER_DEFAULT, | |
130 | &hToken) | |
64b30629 | 131 | || !SetHandleInformation (hToken, |
b0e82b74 CF |
132 | HANDLE_FLAG_INHERIT, |
133 | HANDLE_FLAG_INHERIT)) | |
64b30629 CV |
134 | { |
135 | __seterrno (); | |
136 | return INVALID_HANDLE_VALUE; | |
137 | } | |
138 | debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name); | |
139 | return hToken; | |
140 | } | |
141 | ||
57ff940d CV |
142 | static void |
143 | str2lsa (LSA_STRING &tgt, const char *srcstr) | |
144 | { | |
1fcc912f | 145 | tgt.Length = strlen (srcstr); |
57ff940d CV |
146 | tgt.MaximumLength = tgt.Length + 1; |
147 | tgt.Buffer = (PCHAR) srcstr; | |
148 | } | |
149 | ||
150 | static void | |
151 | str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr) | |
152 | { | |
1fcc912f | 153 | tgt.Length = strlen (srcstr); |
57ff940d CV |
154 | tgt.MaximumLength = tgt.Length + 1; |
155 | tgt.Buffer = (PCHAR) buf; | |
03a2ce9a | 156 | memcpy (buf, srcstr, tgt.MaximumLength); |
57ff940d CV |
157 | } |
158 | ||
99069065 | 159 | void |
57ff940d CV |
160 | str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr) |
161 | { | |
1fcc912f | 162 | tgt.Length = strlen (srcstr) * sizeof (WCHAR); |
03a2ce9a | 163 | tgt.MaximumLength = tgt.Length + sizeof (WCHAR); |
57ff940d | 164 | tgt.Buffer = (PWCHAR) buf; |
b2939a81 | 165 | sys_mbstowcs (buf, srcstr, tgt.MaximumLength); |
57ff940d CV |
166 | } |
167 | ||
5519d543 | 168 | #if 0 /* unused */ |
1fcc912f CV |
169 | static void |
170 | lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size) | |
171 | { | |
172 | size = (size - 1) * sizeof (WCHAR); | |
173 | if (src.Length < size) | |
174 | size = src.Length; | |
175 | memcpy (tgt, src.Buffer, size); | |
176 | size >>= 1; | |
177 | tgt[size] = 0; | |
178 | } | |
1eb934b7 | 179 | #endif |
1fcc912f | 180 | |
74b2f73e CV |
181 | static void |
182 | lsa2str (char *tgt, LSA_UNICODE_STRING &src, int size) | |
183 | { | |
184 | if (src.Length / 2 < size) | |
185 | size = src.Length / 2; | |
186 | sys_wcstombs (tgt, src.Buffer, size); | |
187 | tgt[size] = 0; | |
188 | } | |
189 | ||
1fcc912f CV |
190 | static LSA_HANDLE |
191 | open_local_policy () | |
192 | { | |
193 | LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 }; | |
2d6ce5c2 | 194 | LSA_HANDLE lsa = INVALID_HANDLE_VALUE; |
1fcc912f | 195 | |
03a2ce9a | 196 | NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa); |
1fcc912f | 197 | if (ret != STATUS_SUCCESS) |
d6dc9825 | 198 | __seterrno_from_win_error (LsaNtStatusToWinError (ret)); |
1fcc912f CV |
199 | return lsa; |
200 | } | |
201 | ||
202 | static void | |
203 | close_local_policy (LSA_HANDLE &lsa) | |
204 | { | |
205 | if (lsa != INVALID_HANDLE_VALUE) | |
206 | LsaClose (lsa); | |
207 | lsa = INVALID_HANDLE_VALUE; | |
208 | } | |
209 | ||
5519d543 | 210 | #if 0 /* unused */ |
1fcc912f CV |
211 | static BOOL |
212 | get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain) | |
213 | { | |
214 | NET_API_STATUS ret; | |
c8c3824d | 215 | WCHAR *buf; |
1fcc912f CV |
216 | char name[INTERNET_MAX_HOST_NAME_LENGTH + 1]; |
217 | WCHAR account[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
218 | WCHAR primary[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
219 | PPOLICY_ACCOUNT_DOMAIN_INFO adi; | |
220 | PPOLICY_PRIMARY_DOMAIN_INFO pdi; | |
221 | ||
222 | if ((ret = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation, | |
1ff9f4b9 | 223 | (PVOID *) &adi)) != STATUS_SUCCESS) |
1fcc912f | 224 | { |
03a2ce9a | 225 | __seterrno_from_win_error (LsaNtStatusToWinError (ret)); |
1fcc912f CV |
226 | return FALSE; |
227 | } | |
228 | lsa2wchar (account, adi->DomainName, INTERNET_MAX_HOST_NAME_LENGTH + 1); | |
229 | LsaFreeMemory (adi); | |
230 | if ((ret = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation, | |
1ff9f4b9 | 231 | (PVOID *) &pdi)) != STATUS_SUCCESS) |
1fcc912f | 232 | { |
03a2ce9a | 233 | __seterrno_from_win_error (LsaNtStatusToWinError (ret)); |
1fcc912f CV |
234 | return FALSE; |
235 | } | |
236 | lsa2wchar (primary, pdi->Name, INTERNET_MAX_HOST_NAME_LENGTH + 1); | |
237 | LsaFreeMemory (pdi); | |
c8c3824d CV |
238 | /* If the SID given in the primary domain info is NULL, the machine is |
239 | not member of a domain. The name in the primary domain info is the | |
240 | name of the workgroup then. */ | |
241 | if (pdi->Sid && | |
5519d543 CV |
242 | (ret = |
243 | NetGetDCName (NULL, primary, (LPBYTE *) &buf)) == STATUS_SUCCESS) | |
1fcc912f | 244 | { |
c8c3824d | 245 | sys_wcstombs (name, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); |
9b15f5fa | 246 | strcpy (logonserver, name); |
1fcc912f | 247 | if (domain) |
1ff9f4b9 | 248 | sys_wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1); |
1fcc912f CV |
249 | } |
250 | else | |
251 | { | |
b2939a81 | 252 | sys_wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1); |
9b15f5fa CV |
253 | strcpy (logonserver, "\\\\"); |
254 | strcat (logonserver, name); | |
1fcc912f | 255 | if (domain) |
1ff9f4b9 | 256 | sys_wcstombs (domain, account, INTERNET_MAX_HOST_NAME_LENGTH + 1); |
1fcc912f CV |
257 | } |
258 | if (ret == STATUS_SUCCESS) | |
259 | NetApiBufferFree (buf); | |
1fcc912f CV |
260 | return TRUE; |
261 | } | |
1eb934b7 | 262 | #endif |
1fcc912f CV |
263 | |
264 | BOOL | |
5f74ae83 | 265 | get_logon_server (const char *domain, char *server, WCHAR *wserver) |
1fcc912f | 266 | { |
1eb934b7 CV |
267 | WCHAR wdomain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; |
268 | NET_API_STATUS ret; | |
44480f46 | 269 | WCHAR *buf; |
1eb934b7 CV |
270 | DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1; |
271 | ||
891bb974 | 272 | /* Empty domain is interpreted as local system */ |
5f74ae83 | 273 | if ((GetComputerName (server + 2, &size)) && |
891bb974 | 274 | (strcasematch (domain, server + 2) || !domain[0])) |
1fcc912f | 275 | { |
1eb934b7 CV |
276 | server[0] = server[1] = '\\'; |
277 | if (wserver) | |
7c02f861 | 278 | sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1); |
1eb934b7 | 279 | return TRUE; |
1fcc912f | 280 | } |
1eb934b7 CV |
281 | |
282 | /* Try to get the primary domain controller for the domain */ | |
283 | sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1); | |
5f74ae83 | 284 | if ((ret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf)) == STATUS_SUCCESS) |
1eb934b7 CV |
285 | { |
286 | sys_wcstombs (server, buf, INTERNET_MAX_HOST_NAME_LENGTH + 1); | |
287 | if (wserver) | |
5519d543 CV |
288 | for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);) |
289 | ; | |
1eb934b7 CV |
290 | NetApiBufferFree (buf); |
291 | return TRUE; | |
292 | } | |
293 | __seterrno_from_win_error (ret); | |
294 | return FALSE; | |
1fcc912f CV |
295 | } |
296 | ||
297 | static BOOL | |
5519d543 CV |
298 | get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user, |
299 | char *domain) | |
1fcc912f | 300 | { |
1eb934b7 | 301 | char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; |
462f4eff | 302 | WCHAR wuser[UNLEN + 1]; |
b2939a81 | 303 | sys_mbstowcs (wuser, user, UNLEN + 1); |
462f4eff | 304 | LPGROUP_USERS_INFO_0 buf; |
1eb934b7 | 305 | DWORD cnt, tot, len; |
1fcc912f CV |
306 | NET_API_STATUS ret; |
307 | ||
1eb934b7 | 308 | /* Look only on logonserver */ |
c9fbce26 CV |
309 | ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf, |
310 | MAX_PREFERRED_LENGTH, &cnt, &tot); | |
c9fbce26 | 311 | if (ret) |
1fcc912f | 312 | { |
d6dc9825 | 313 | __seterrno_from_win_error (ret); |
1fcc912f CV |
314 | /* It's no error when the user name can't be found. */ |
315 | return ret == NERR_UserNotFound; | |
316 | } | |
317 | ||
03a2ce9a CF |
318 | len = strlen (domain); |
319 | strcpy (dgroup, domain); | |
1eb934b7 CV |
320 | dgroup[len++] = '\\'; |
321 | ||
1fcc912f CV |
322 | for (DWORD i = 0; i < cnt; ++i) |
323 | { | |
324 | cygsid gsid; | |
0c8455c3 | 325 | DWORD glen = MAX_SID_LEN; |
1fcc912f | 326 | char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; |
1eb934b7 | 327 | DWORD dlen = sizeof (domain); |
1fcc912f CV |
328 | SID_NAME_USE use = SidTypeInvalid; |
329 | ||
1eb934b7 CV |
330 | sys_wcstombs (dgroup + len, buf[i].grui0_name, GNLEN + 1); |
331 | if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use)) | |
5519d543 | 332 | debug_printf ("LookupAccountName(%s): %E", dgroup); |
1eb934b7 | 333 | else if (legal_sid_type (use)) |
5519d543 CV |
334 | grp_list += gsid; |
335 | else | |
336 | debug_printf ("Global group %s invalid. Domain: %s Use: %d", | |
337 | dgroup, domain, use); | |
1fcc912f CV |
338 | } |
339 | ||
340 | NetApiBufferFree (buf); | |
341 | return TRUE; | |
342 | } | |
343 | ||
344 | static BOOL | |
1eb934b7 | 345 | is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list) |
1fcc912f CV |
346 | { |
347 | LPLOCALGROUP_MEMBERS_INFO_0 buf; | |
348 | DWORD cnt, tot; | |
c9fbce26 CV |
349 | NET_API_STATUS ret; |
350 | BOOL retval = FALSE; | |
351 | ||
1eb934b7 | 352 | /* Members can be users or global groups */ |
3d4b75de | 353 | ret = NetLocalGroupGetMembers (NULL, wgroup, 0, (LPBYTE *) &buf, |
c9fbce26 | 354 | MAX_PREFERRED_LENGTH, &cnt, &tot, NULL); |
c9fbce26 | 355 | if (ret) |
1fcc912f CV |
356 | return FALSE; |
357 | ||
c9fbce26 | 358 | for (DWORD bidx = 0; !retval && bidx < cnt; ++bidx) |
1eb934b7 | 359 | if (EqualSid (pusersid, buf[bidx].lgrmi0_sid)) |
c9fbce26 | 360 | retval = TRUE; |
1fcc912f | 361 | else |
c9fbce26 | 362 | for (int glidx = 0; !retval && glidx < grp_list.count; ++glidx) |
1fcc912f | 363 | if (EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi0_sid)) |
c9fbce26 | 364 | retval = TRUE; |
1fcc912f CV |
365 | |
366 | NetApiBufferFree (buf); | |
c9fbce26 | 367 | return retval; |
1fcc912f CV |
368 | } |
369 | ||
370 | static BOOL | |
1eb934b7 | 371 | get_user_local_groups (cygsidlist &grp_list, PSID pusersid) |
1fcc912f CV |
372 | { |
373 | LPLOCALGROUP_INFO_0 buf; | |
374 | DWORD cnt, tot; | |
375 | NET_API_STATUS ret; | |
376 | ||
3d4b75de | 377 | ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf, |
c9fbce26 | 378 | MAX_PREFERRED_LENGTH, &cnt, &tot, NULL); |
c9fbce26 | 379 | if (ret) |
1fcc912f | 380 | { |
d6dc9825 | 381 | __seterrno_from_win_error (ret); |
1fcc912f CV |
382 | return FALSE; |
383 | } | |
384 | ||
6e8a0232 | 385 | char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; |
1eb934b7 | 386 | char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2]; |
6e8a0232 CV |
387 | DWORD blen, llen; |
388 | SID_NAME_USE use; | |
389 | ||
390 | blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1; | |
391 | if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use) | |
392 | || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1))) | |
1eb934b7 | 393 | { |
5519d543 CV |
394 | __seterrno (); |
395 | return FALSE; | |
1eb934b7 | 396 | } |
6e8a0232 | 397 | bgroup[blen++] = lgroup[llen++] = '\\'; |
1eb934b7 | 398 | |
1fcc912f | 399 | for (DWORD i = 0; i < cnt; ++i) |
1eb934b7 | 400 | if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list)) |
1fcc912f CV |
401 | { |
402 | cygsid gsid; | |
0c8455c3 | 403 | DWORD glen = MAX_SID_LEN; |
1fcc912f | 404 | char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; |
1eb934b7 | 405 | DWORD dlen = sizeof (domain); |
1fcc912f | 406 | |
6e8a0232 | 407 | use = SidTypeInvalid; |
1eb934b7 CV |
408 | sys_wcstombs (bgroup + blen, buf[i].lgrpi0_name, GNLEN + 1); |
409 | if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use)) | |
1fcc912f | 410 | { |
095a1272 | 411 | if (GetLastError () != ERROR_NONE_MAPPED) |
5519d543 | 412 | debug_printf ("LookupAccountName(%s): %E", bgroup); |
095a1272 CV |
413 | strcpy (lgroup + llen, bgroup + blen); |
414 | if (!LookupAccountName (NULL, lgroup, gsid, &glen, | |
415 | domain, &dlen, &use)) | |
5519d543 | 416 | debug_printf ("LookupAccountName(%s): %E", lgroup); |
1fcc912f | 417 | } |
095a1272 CV |
418 | if (!legal_sid_type (use)) |
419 | debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use); | |
420 | else if (!grp_list.contains (gsid)) | |
1fcc912f CV |
421 | grp_list += gsid; |
422 | } | |
1fcc912f CV |
423 | NetApiBufferFree (buf); |
424 | return TRUE; | |
425 | } | |
426 | ||
427 | static BOOL | |
428 | sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid) | |
429 | { | |
430 | if (!grps) | |
431 | return FALSE; | |
432 | for (DWORD i = 0; i < grps->GroupCount; ++i) | |
433 | if (sid == grps->Groups[i].Sid) | |
434 | return TRUE; | |
435 | return FALSE; | |
436 | } | |
437 | ||
5519d543 | 438 | #if 0 /* Unused */ |
1fcc912f CV |
439 | static BOOL |
440 | get_user_primary_group (WCHAR *wlogonserver, const char *user, | |
1eb934b7 | 441 | PSID pusersid, cygsid &pgrpsid) |
1fcc912f CV |
442 | { |
443 | LPUSER_INFO_3 buf; | |
444 | WCHAR wuser[UNLEN + 1]; | |
c9fbce26 CV |
445 | NET_API_STATUS ret; |
446 | BOOL retval = FALSE; | |
8b43d272 | 447 | UCHAR count = 0; |
1fcc912f | 448 | |
dbcb7578 | 449 | if (well_known_system_sid == pusersid) |
1fcc912f CV |
450 | { |
451 | pgrpsid = well_known_system_sid; | |
452 | return TRUE; | |
453 | } | |
454 | ||
b2939a81 | 455 | sys_mbstowcs (wuser, user, UNLEN + 1); |
c9fbce26 | 456 | ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf); |
c9fbce26 CV |
457 | if (ret) |
458 | { | |
d6dc9825 | 459 | __seterrno_from_win_error (ret); |
c9fbce26 CV |
460 | return FALSE; |
461 | } | |
462 | ||
1eb934b7 | 463 | pgrpsid = pusersid; |
5519d543 CV |
464 | if (IsValidSid (pgrpsid) |
465 | && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) | |
1fcc912f CV |
466 | { |
467 | *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; | |
c9fbce26 | 468 | retval = TRUE; |
1fcc912f CV |
469 | } |
470 | NetApiBufferFree (buf); | |
c9fbce26 | 471 | return retval; |
1fcc912f | 472 | } |
095a1272 | 473 | #endif |
1fcc912f | 474 | |
095a1272 | 475 | static void |
44480f46 | 476 | get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list) |
f41d24a1 | 477 | { |
57196405 | 478 | struct __group32 *gr; |
095a1272 | 479 | cygsid gsid; |
f41d24a1 CV |
480 | |
481 | for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) | |
482 | { | |
095a1272 CV |
483 | if (gr->gr_gid == (__gid32_t) pw->pw_gid) |
484 | goto found; | |
485 | else if (gr->gr_mem) | |
f41d24a1 | 486 | for (int gi = 0; gr->gr_mem[gi]; ++gi) |
095a1272 CV |
487 | if (strcasematch (pw->pw_name, gr->gr_mem[gi])) |
488 | goto found; | |
489 | continue; | |
490 | found: | |
491 | if (gsid.getfromgr (gr) && !grp_list.contains (gsid)) | |
492 | grp_list += gsid; | |
493 | ||
f41d24a1 | 494 | } |
f41d24a1 CV |
495 | } |
496 | ||
5519d543 CV |
497 | static void |
498 | get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps, | |
499 | LUID auth_luid, int &auth_pos) | |
1fcc912f | 500 | { |
1fcc912f | 501 | auth_pos = -1; |
5519d543 CV |
502 | if (my_grps) |
503 | { | |
504 | if (sid_in_token_groups (my_grps, well_known_local_sid)) | |
505 | grp_list += well_known_local_sid; | |
506 | if (sid_in_token_groups (my_grps, well_known_dialup_sid)) | |
507 | grp_list += well_known_dialup_sid; | |
508 | if (sid_in_token_groups (my_grps, well_known_network_sid)) | |
509 | grp_list += well_known_network_sid; | |
510 | if (sid_in_token_groups (my_grps, well_known_batch_sid)) | |
511 | grp_list += well_known_batch_sid; | |
512 | if (sid_in_token_groups (my_grps, well_known_interactive_sid)) | |
513 | grp_list += well_known_interactive_sid; | |
514 | if (sid_in_token_groups (my_grps, well_known_service_sid)) | |
515 | grp_list += well_known_service_sid; | |
516 | } | |
517 | else | |
518 | { | |
519 | grp_list += well_known_local_sid; | |
520 | grp_list += well_known_interactive_sid; | |
521 | } | |
522 | if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */ | |
523 | { | |
524 | char buf[64]; | |
525 | __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart, | |
526 | auth_luid.LowPart); | |
527 | grp_list += buf; | |
528 | auth_pos = grp_list.count - 1; | |
529 | } | |
530 | } | |
1eb934b7 | 531 | |
5519d543 CV |
532 | static BOOL |
533 | get_initgroups_sidlist (cygsidlist &grp_list, | |
534 | PSID usersid, PSID pgrpsid, struct passwd *pw, | |
535 | PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos, | |
536 | BOOL &special_pgrp) | |
537 | { | |
1fcc912f | 538 | grp_list += well_known_world_sid; |
095a1272 | 539 | grp_list += well_known_authenticated_users_sid; |
dbcb7578 | 540 | if (well_known_system_sid == usersid) |
1fcc912f | 541 | { |
5519d543 | 542 | auth_pos = -1; |
3a157c0d | 543 | grp_list += well_known_admins_sid; |
095a1272 | 544 | get_unix_group_sidlist (pw, grp_list); |
1fcc912f CV |
545 | } |
546 | else | |
547 | { | |
5519d543 CV |
548 | char user[UNLEN + 1]; |
549 | char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
550 | WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3]; | |
551 | char server[INTERNET_MAX_HOST_NAME_LENGTH + 3]; | |
552 | ||
553 | get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos); | |
095a1272 | 554 | extract_nt_dom_user (pw, domain, user); |
fdb93cd2 CV |
555 | if (get_logon_server (domain, server, wserver)) |
556 | get_user_groups (wserver, grp_list, user, domain); | |
095a1272 CV |
557 | get_unix_group_sidlist (pw, grp_list); |
558 | if (!get_user_local_groups (grp_list, usersid)) | |
7c02f861 | 559 | return FALSE; |
1fcc912f | 560 | } |
5519d543 CV |
561 | /* special_pgrp true if pgrpsid is not in normal groups */ |
562 | if ((special_pgrp = !grp_list.contains (pgrpsid))) | |
563 | grp_list += pgrpsid; | |
1fcc912f CV |
564 | return TRUE; |
565 | } | |
566 | ||
5519d543 CV |
567 | static void |
568 | get_setgroups_sidlist (cygsidlist &tmp_list, PTOKEN_GROUPS my_grps, | |
569 | user_groups &groups, LUID auth_luid, int &auth_pos) | |
570 | { | |
571 | PSID pgpsid = groups.pgsid; | |
572 | tmp_list += well_known_world_sid; | |
573 | tmp_list += well_known_authenticated_users_sid; | |
574 | get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos); | |
575 | for (int gidx = 0; gidx < groups.sgsids.count; gidx++) | |
576 | tmp_list += groups.sgsids.sids[gidx]; | |
577 | if (!groups.sgsids.contains (pgpsid)) | |
578 | tmp_list += pgpsid; | |
579 | } | |
580 | ||
1fcc912f CV |
581 | static const char *sys_privs[] = { |
582 | SE_TCB_NAME, | |
583 | SE_ASSIGNPRIMARYTOKEN_NAME, | |
584 | SE_CREATE_TOKEN_NAME, | |
585 | SE_CHANGE_NOTIFY_NAME, | |
586 | SE_SECURITY_NAME, | |
587 | SE_BACKUP_NAME, | |
588 | SE_RESTORE_NAME, | |
589 | SE_SYSTEMTIME_NAME, | |
590 | SE_SHUTDOWN_NAME, | |
591 | SE_REMOTE_SHUTDOWN_NAME, | |
592 | SE_TAKE_OWNERSHIP_NAME, | |
593 | SE_DEBUG_NAME, | |
594 | SE_SYSTEM_ENVIRONMENT_NAME, | |
595 | SE_SYSTEM_PROFILE_NAME, | |
596 | SE_PROF_SINGLE_PROCESS_NAME, | |
597 | SE_INC_BASE_PRIORITY_NAME, | |
598 | SE_LOAD_DRIVER_NAME, | |
599 | SE_CREATE_PAGEFILE_NAME, | |
600 | SE_INCREASE_QUOTA_NAME | |
601 | }; | |
602 | ||
603 | #define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *)) | |
604 | ||
605 | PTOKEN_PRIVILEGES | |
606 | get_system_priv_list (cygsidlist &grp_list) | |
607 | { | |
608 | LUID priv; | |
5519d543 CV |
609 | PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) |
610 | malloc (sizeof (ULONG) + 20 * sizeof (LUID_AND_ATTRIBUTES)); | |
1fcc912f CV |
611 | if (!privs) |
612 | { | |
613 | debug_printf ("malloc (system_privs) failed."); | |
614 | return NULL; | |
615 | } | |
616 | privs->PrivilegeCount = 0; | |
617 | ||
618 | for (DWORD i = 0; i < SYSTEM_PERMISSION_COUNT; ++i) | |
619 | if (LookupPrivilegeValue (NULL, sys_privs[i], &priv)) | |
620 | { | |
621 | privs->Privileges[privs->PrivilegeCount].Luid = priv; | |
622 | privs->Privileges[privs->PrivilegeCount].Attributes = | |
5519d543 | 623 | SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; |
1fcc912f CV |
624 | ++privs->PrivilegeCount; |
625 | } | |
626 | return privs; | |
627 | } | |
628 | ||
629 | PTOKEN_PRIVILEGES | |
630 | get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list) | |
631 | { | |
632 | PLSA_UNICODE_STRING privstrs; | |
633 | ULONG cnt; | |
634 | PTOKEN_PRIVILEGES privs = NULL; | |
635 | NTSTATUS ret; | |
636 | char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
637 | ||
638 | if (usersid == well_known_system_sid) | |
639 | return get_system_priv_list (grp_list); | |
640 | ||
641 | for (int grp = -1; grp < grp_list.count; ++grp) | |
642 | { | |
643 | if (grp == -1) | |
1ff9f4b9 | 644 | { |
5519d543 CV |
645 | if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs, |
646 | &cnt)) != STATUS_SUCCESS) | |
1ff9f4b9 CF |
647 | continue; |
648 | } | |
1fcc912f | 649 | else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp], |
1ff9f4b9 CF |
650 | &privstrs, &cnt)) |
651 | != STATUS_SUCCESS) | |
1fcc912f CV |
652 | continue; |
653 | for (ULONG i = 0; i < cnt; ++i) | |
1ff9f4b9 CF |
654 | { |
655 | LUID priv; | |
656 | PTOKEN_PRIVILEGES tmp; | |
657 | DWORD tmp_count; | |
658 | ||
03a2ce9a | 659 | lsa2str (buf, privstrs[i], sizeof (buf) - 1); |
1ff9f4b9 CF |
660 | if (!LookupPrivilegeValue (NULL, buf, &priv)) |
661 | continue; | |
662 | ||
663 | for (DWORD p = 0; privs && p < privs->PrivilegeCount; ++p) | |
664 | if (!memcmp (&priv, &privs->Privileges[p].Luid, sizeof (LUID))) | |
665 | goto next_account_right; | |
666 | ||
667 | tmp_count = privs ? privs->PrivilegeCount : 0; | |
668 | tmp = (PTOKEN_PRIVILEGES) | |
5519d543 CV |
669 | realloc (privs, sizeof (ULONG) + |
670 | (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES)); | |
1ff9f4b9 CF |
671 | if (!tmp) |
672 | { | |
1fcc912f CV |
673 | if (privs) |
674 | free (privs); | |
1ff9f4b9 | 675 | LsaFreeMemory (privstrs); |
1fcc912f | 676 | debug_printf ("realloc (privs) failed."); |
1ff9f4b9 CF |
677 | return NULL; |
678 | } | |
679 | tmp->PrivilegeCount = tmp_count; | |
680 | privs = tmp; | |
681 | privs->Privileges[privs->PrivilegeCount].Luid = priv; | |
682 | privs->Privileges[privs->PrivilegeCount].Attributes = | |
5519d543 | 683 | SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT; |
1ff9f4b9 CF |
684 | ++privs->PrivilegeCount; |
685 | ||
686 | next_account_right: | |
687 | ; | |
688 | } | |
1fcc912f CV |
689 | LsaFreeMemory (privstrs); |
690 | } | |
691 | return privs; | |
692 | } | |
693 | ||
5519d543 CV |
694 | /* Accept a token if |
695 | - the requested usersid matches the TokenUser and | |
696 | - if setgroups has been called: | |
5bf785a0 | 697 | the token groups that are listed in /etc/group match the union of |
5519d543 CV |
698 | the requested primary and supplementary groups in gsids. |
699 | - else the (unknown) implicitly requested supplementary groups and those | |
5bf785a0 | 700 | in the token are the groups associated with the usersid. We assume |
5519d543 CV |
701 | they match and verify only the primary groups. |
702 | The requested primary group must appear in the token. | |
703 | The primary group in the token is a group associated with the usersid, | |
704 | except if the token is internal and the group is in the token SD | |
705 | (see create_token). In that latter case that group must match the | |
706 | requested primary group. */ | |
ebbdc703 | 707 | BOOL |
5519d543 | 708 | verify_token (HANDLE token, cygsid &usersid, user_groups &groups, BOOL *pintern) |
1fcc912f | 709 | { |
ebbdc703 CV |
710 | DWORD size; |
711 | BOOL intern = FALSE; | |
712 | ||
713 | if (pintern) | |
714 | { | |
715 | TOKEN_SOURCE ts; | |
70249d56 | 716 | if (!GetTokenInformation (token, TokenSource, |
ebbdc703 CV |
717 | &ts, sizeof ts, &size)) |
718 | debug_printf ("GetTokenInformation(): %E"); | |
5519d543 CV |
719 | else |
720 | *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8); | |
ebbdc703 CV |
721 | } |
722 | /* Verify usersid */ | |
723 | cygsid tok_usersid = NO_SID; | |
724 | if (!GetTokenInformation (token, TokenUser, | |
725 | &tok_usersid, sizeof tok_usersid, &size)) | |
5519d543 CV |
726 | debug_printf ("GetTokenInformation(): %E"); |
727 | if (usersid != tok_usersid) | |
728 | return FALSE; | |
ebbdc703 | 729 | |
5519d543 CV |
730 | /* For an internal token, if setgroups was not called and if the sd group |
731 | is not well_known_null_sid, it must match pgrpsid */ | |
732 | if (intern && !groups.issetgroups ()) | |
ebbdc703 | 733 | { |
5519d543 | 734 | char sd_buf[MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR)]; |
ea3ba114 | 735 | cygpsid gsid (NO_SID); |
5519d543 | 736 | if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION, |
ebbdc703 CV |
737 | (PSECURITY_DESCRIPTOR) sd_buf, |
738 | sizeof sd_buf, &size)) | |
5519d543 CV |
739 | debug_printf ("GetKernelObjectSecurity(): %E"); |
740 | else if (!GetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) sd_buf, | |
ea3ba114 | 741 | (PSID *) &gsid, (BOOL *) &size)) |
5519d543 CV |
742 | debug_printf ("GetSecurityDescriptorGroup(): %E"); |
743 | if (well_known_null_sid != gsid) | |
744 | return gsid == groups.pgsid; | |
ebbdc703 | 745 | } |
5519d543 | 746 | |
b4ece40c PH |
747 | PTOKEN_GROUPS my_grps; |
748 | bool saw_buf[NGROUPS_MAX] = {}; | |
749 | bool *saw = saw_buf, sawpg = false, ret = false; | |
ebbdc703 CV |
750 | |
751 | if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) && | |
03a2ce9a | 752 | GetLastError () != ERROR_INSUFFICIENT_BUFFER) |
f70389b5 | 753 | debug_printf ("GetTokenInformation(token, TokenGroups): %E"); |
b4ece40c PH |
754 | else if (!(my_grps = (PTOKEN_GROUPS) alloca (size))) |
755 | debug_printf ("alloca (my_grps) failed."); | |
ebbdc703 | 756 | else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size)) |
f70389b5 | 757 | debug_printf ("GetTokenInformation(my_token, TokenGroups): %E"); |
5519d543 | 758 | else if (!groups.issetgroups ()) /* setgroups was never called */ |
b4ece40c | 759 | ret = sid_in_token_groups (my_grps, groups.pgsid) |
df04ae29 | 760 | || groups.pgsid == usersid; |
5519d543 CV |
761 | else /* setgroups was called */ |
762 | { | |
763 | struct __group32 *gr; | |
764 | cygsid gsid; | |
b4ece40c PH |
765 | if (groups.sgsids.count > (int) (sizeof (saw_buf) / sizeof (*saw_buf)) |
766 | && !(saw = (bool *) calloc (groups.sgsids.count, sizeof (bool)))) | |
5519d543 CV |
767 | goto done; |
768 | ||
769 | /* token groups found in /etc/group match the user.gsids ? */ | |
770 | for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) | |
771 | if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid)) | |
772 | { | |
773 | int pos = groups.sgsids.position (gsid); | |
774 | if (pos >= 0) | |
b4ece40c | 775 | saw[pos] = true; |
5519d543 | 776 | else if (groups.pgsid == gsid) |
b4ece40c PH |
777 | sawpg = true; |
778 | else if (gsid != well_known_world_sid | |
779 | && gsid != usersid) | |
5519d543 CV |
780 | goto done; |
781 | } | |
782 | for (int gidx = 0; gidx < groups.sgsids.count; gidx++) | |
783 | if (!saw[gidx]) | |
784 | goto done; | |
b4ece40c PH |
785 | ret = sawpg |
786 | || groups.sgsids.contains (groups.pgsid) | |
787 | || groups.pgsid == usersid; | |
5519d543 CV |
788 | } |
789 | done: | |
5519d543 CV |
790 | if (saw != saw_buf) |
791 | free (saw); | |
ebbdc703 | 792 | return ret; |
1fcc912f CV |
793 | } |
794 | ||
795 | HANDLE | |
5519d543 | 796 | create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw) |
1fcc912f CV |
797 | { |
798 | NTSTATUS ret; | |
2d6ce5c2 | 799 | LSA_HANDLE lsa = INVALID_HANDLE_VALUE; |
1fcc912f CV |
800 | int old_priv_state; |
801 | ||
5519d543 | 802 | cygsidlist tmp_gsids (cygsidlist_auto, 12); |
1fcc912f CV |
803 | |
804 | SECURITY_QUALITY_OF_SERVICE sqos = | |
805 | { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE }; | |
5519d543 | 806 | OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos }; |
ebbdc703 | 807 | PSECURITY_ATTRIBUTES psa; |
5519d543 | 808 | BOOL special_pgrp = FALSE; |
f6fc31e1 | 809 | char sa_buf[1024]; |
1fcc912f | 810 | LUID auth_luid = SYSTEM_LUID; |
5519d543 | 811 | LARGE_INTEGER exp = { QuadPart:0x7fffffffffffffffLL }; |
1fcc912f CV |
812 | |
813 | TOKEN_USER user; | |
5519d543 | 814 | PTOKEN_GROUPS new_tok_gsids = NULL; |
1fcc912f CV |
815 | PTOKEN_PRIVILEGES privs = NULL; |
816 | TOKEN_OWNER owner; | |
817 | TOKEN_PRIMARY_GROUP pgrp; | |
5519d543 | 818 | char acl_buf[MAX_DACL_LEN (5)]; |
1fcc912f CV |
819 | TOKEN_DEFAULT_DACL dacl; |
820 | TOKEN_SOURCE source; | |
821 | TOKEN_STATISTICS stats; | |
03a2ce9a | 822 | memcpy (source.SourceName, "Cygwin.1", 8); |
1fcc912f CV |
823 | source.SourceIdentifier.HighPart = 0; |
824 | source.SourceIdentifier.LowPart = 0x0101; | |
825 | ||
cecb74ae | 826 | HANDLE token = INVALID_HANDLE_VALUE; |
1fcc912f CV |
827 | HANDLE primary_token = INVALID_HANDLE_VALUE; |
828 | ||
829 | HANDLE my_token = INVALID_HANDLE_VALUE; | |
5519d543 | 830 | PTOKEN_GROUPS my_tok_gsids = NULL; |
1fcc912f CV |
831 | DWORD size; |
832 | ||
833 | /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */ | |
834 | if ((old_priv_state = set_process_privilege (SE_CREATE_TOKEN_NAME)) < 0) | |
835 | goto out; | |
1ff9f4b9 | 836 | |
1fcc912f | 837 | /* Open policy object. */ |
2d6ce5c2 | 838 | if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE) |
1fcc912f CV |
839 | goto out; |
840 | ||
1fcc912f CV |
841 | /* User, owner, primary group. */ |
842 | user.User.Sid = usersid; | |
843 | user.User.Attributes = 0; | |
844 | owner.Owner = usersid; | |
845 | ||
846 | /* Retrieve authentication id and group list from own process. */ | |
03a2ce9a | 847 | if (!OpenProcessToken (hMainProc, TOKEN_QUERY, &my_token)) |
f70389b5 | 848 | debug_printf ("OpenProcessToken(my_token): %E"); |
1fcc912f CV |
849 | else |
850 | { | |
851 | /* Switching user context to SYSTEM doesn't inherit the authentication | |
5bf785a0 | 852 | id of the user account running current process. */ |
1fcc912f CV |
853 | if (usersid != well_known_system_sid) |
854 | if (!GetTokenInformation (my_token, TokenStatistics, | |
855 | &stats, sizeof stats, &size)) | |
5519d543 | 856 | debug_printf |
f70389b5 | 857 | ("GetTokenInformation(my_token, TokenStatistics): %E"); |
1fcc912f CV |
858 | else |
859 | auth_luid = stats.AuthenticationId; | |
860 | ||
861 | /* Retrieving current processes group list to be able to inherit | |
5bf785a0 | 862 | some important well known group sids. */ |
1fcc912f | 863 | if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) && |
462f4eff | 864 | GetLastError () != ERROR_INSUFFICIENT_BUFFER) |
f70389b5 | 865 | debug_printf ("GetTokenInformation(my_token, TokenGroups): %E"); |
5519d543 CV |
866 | else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size))) |
867 | debug_printf ("malloc (my_tok_gsids) failed."); | |
868 | else if (!GetTokenInformation (my_token, TokenGroups, my_tok_gsids, | |
1fcc912f CV |
869 | size, &size)) |
870 | { | |
f70389b5 | 871 | debug_printf ("GetTokenInformation(my_token, TokenGroups): %E"); |
5519d543 CV |
872 | free (my_tok_gsids); |
873 | my_tok_gsids = NULL; | |
1fcc912f | 874 | } |
2d3dab2e | 875 | CloseHandle (my_token); |
1fcc912f CV |
876 | } |
877 | ||
878 | /* Create list of groups, the user is member in. */ | |
879 | int auth_pos; | |
5519d543 CV |
880 | if (new_groups.issetgroups ()) |
881 | get_setgroups_sidlist (tmp_gsids, my_tok_gsids, new_groups, auth_luid, | |
882 | auth_pos); | |
883 | else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw, | |
884 | my_tok_gsids, auth_luid, auth_pos, | |
885 | special_pgrp)) | |
1fcc912f CV |
886 | goto out; |
887 | ||
888 | /* Primary group. */ | |
5519d543 | 889 | pgrp.PrimaryGroup = new_groups.pgsid; |
1fcc912f CV |
890 | |
891 | /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */ | |
5519d543 CV |
892 | char grps_buf[sizeof (ULONG) + tmp_gsids.count * sizeof (SID_AND_ATTRIBUTES)]; |
893 | new_tok_gsids = (PTOKEN_GROUPS) grps_buf; | |
894 | new_tok_gsids->GroupCount = tmp_gsids.count; | |
895 | for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i) | |
1fcc912f | 896 | { |
5519d543 CV |
897 | new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i]; |
898 | new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY | | |
899 | SE_GROUP_ENABLED_BY_DEFAULT | SE_GROUP_ENABLED; | |
1fcc912f | 900 | } |
5519d543 CV |
901 | if (auth_pos >= 0) |
902 | new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID; | |
1fcc912f CV |
903 | |
904 | /* Retrieve list of privileges of that user. */ | |
5519d543 | 905 | if (!(privs = get_priv_list (lsa, usersid, tmp_gsids))) |
1fcc912f CV |
906 | goto out; |
907 | ||
908 | /* Create default dacl. */ | |
c61ada9b | 909 | if (!sec_acl ((PACL) acl_buf, false, false, |
5519d543 CV |
910 | tmp_gsids.contains (well_known_admins_sid) ? |
911 | well_known_admins_sid : usersid)) | |
1fcc912f CV |
912 | goto out; |
913 | dacl.DefaultDacl = (PACL) acl_buf; | |
914 | ||
915 | /* Let's be heroic... */ | |
916 | ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation, | |
5519d543 CV |
917 | &auth_luid, &exp, &user, new_tok_gsids, privs, &owner, |
918 | &pgrp, &dacl, &source); | |
1fcc912f | 919 | if (ret) |
d6dc9825 | 920 | __seterrno_from_win_error (RtlNtStatusToDosError (ret)); |
1fcc912f CV |
921 | else if (GetLastError () == ERROR_PROC_NOT_FOUND) |
922 | { | |
923 | __seterrno (); | |
924 | debug_printf ("Loading NtCreateToken failed."); | |
925 | } | |
ebbdc703 CV |
926 | else |
927 | { | |
928 | /* Set security descriptor and primary group */ | |
c61ada9b | 929 | psa = sec_user (sa_buf, usersid); |
2402700d | 930 | if (psa->lpSecurityDescriptor && |
5519d543 CV |
931 | !SetSecurityDescriptorGroup ((PSECURITY_DESCRIPTOR) |
932 | psa->lpSecurityDescriptor, | |
933 | special_pgrp ? new_groups.pgsid | |
934 | : well_known_null_sid, | |
935 | FALSE)) | |
936 | debug_printf ("SetSecurityDescriptorGroup %E"); | |
ebbdc703 | 937 | /* Convert to primary token. */ |
5519d543 CV |
938 | if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, psa, SecurityImpersonation, |
939 | TokenPrimary, &primary_token)) | |
2402700d CF |
940 | { |
941 | __seterrno (); | |
942 | debug_printf ("DuplicateTokenEx %E"); | |
943 | } | |
ebbdc703 | 944 | } |
1fcc912f CV |
945 | |
946 | out: | |
947 | if (old_priv_state >= 0) | |
948 | set_process_privilege (SE_CREATE_TOKEN_NAME, old_priv_state); | |
949 | if (token != INVALID_HANDLE_VALUE) | |
950 | CloseHandle (token); | |
951 | if (privs) | |
952 | free (privs); | |
5519d543 CV |
953 | if (my_tok_gsids) |
954 | free (my_tok_gsids); | |
1fcc912f CV |
955 | close_local_policy (lsa); |
956 | ||
957 | debug_printf ("%d = create_token ()", primary_token); | |
958 | return primary_token; | |
959 | } | |
960 | ||
57ff940d CV |
961 | int subauth_id = 255; |
962 | ||
963 | HANDLE | |
964 | subauth (struct passwd *pw) | |
965 | { | |
966 | LSA_STRING name; | |
967 | HANDLE lsa_hdl; | |
968 | LSA_OPERATIONAL_MODE sec_mode; | |
969 | NTSTATUS ret, ret2; | |
970 | ULONG package_id, size; | |
971 | struct { | |
972 | LSA_STRING str; | |
973 | CHAR buf[16]; | |
974 | } origin; | |
975 | struct { | |
976 | MSV1_0_LM20_LOGON auth; | |
977 | WCHAR dombuf[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
978 | WCHAR usrbuf[UNLEN + 1]; | |
979 | WCHAR wkstbuf[1]; | |
980 | CHAR authinf1[1]; | |
981 | CHAR authinf2[1]; | |
982 | } subbuf; | |
983 | TOKEN_SOURCE ts; | |
984 | PMSV1_0_LM20_LOGON_PROFILE profile; | |
985 | LUID luid; | |
57ff940d CV |
986 | QUOTA_LIMITS quota; |
987 | char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; | |
988 | char nt_user[UNLEN + 1]; | |
1fcc912f CV |
989 | SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE }; |
990 | HANDLE user_token = INVALID_HANDLE_VALUE; | |
991 | HANDLE primary_token = INVALID_HANDLE_VALUE; | |
992 | int old_tcb_state; | |
57ff940d | 993 | |
03a2ce9a | 994 | if ((old_tcb_state = set_process_privilege (SE_TCB_NAME)) < 0) |
1fcc912f | 995 | return INVALID_HANDLE_VALUE; |
57ff940d CV |
996 | |
997 | /* Register as logon process. */ | |
998 | str2lsa (name, "Cygwin"); | |
a2cdb048 | 999 | SetLastError (0); |
03a2ce9a | 1000 | ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode); |
57ff940d CV |
1001 | if (ret != STATUS_SUCCESS) |
1002 | { | |
1003 | debug_printf ("LsaRegisterLogonProcess: %d", ret); | |
03a2ce9a | 1004 | __seterrno_from_win_error (LsaNtStatusToWinError (ret)); |
1fcc912f | 1005 | goto out; |
57ff940d | 1006 | } |
5aac6665 CV |
1007 | else if (GetLastError () == ERROR_PROC_NOT_FOUND) |
1008 | { | |
1009 | debug_printf ("Couldn't load Secur32.dll"); | |
1fcc912f | 1010 | goto out; |
5aac6665 | 1011 | } |
57ff940d CV |
1012 | /* Get handle to MSV1_0 package. */ |
1013 | str2lsa (name, MSV1_0_PACKAGE_NAME); | |
03a2ce9a | 1014 | ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id); |
57ff940d CV |
1015 | if (ret != STATUS_SUCCESS) |
1016 | { | |
1017 | debug_printf ("LsaLookupAuthenticationPackage: %d", ret); | |
03a2ce9a CF |
1018 | __seterrno_from_win_error (LsaNtStatusToWinError (ret)); |
1019 | LsaDeregisterLogonProcess (lsa_hdl); | |
1fcc912f | 1020 | goto out; |
57ff940d CV |
1021 | } |
1022 | /* Create origin. */ | |
1023 | str2buf2lsa (origin.str, origin.buf, "Cygwin"); | |
1024 | /* Create token source. */ | |
03a2ce9a | 1025 | memcpy (ts.SourceName, "Cygwin.1", 8); |
42938841 CV |
1026 | ts.SourceIdentifier.HighPart = 0; |
1027 | ts.SourceIdentifier.LowPart = 0x0100; | |
57ff940d CV |
1028 | /* Get user information. */ |
1029 | extract_nt_dom_user (pw, nt_domain, nt_user); | |
1030 | /* Fill subauth with values. */ | |
1031 | subbuf.auth.MessageType = MsV1_0NetworkLogon; | |
03a2ce9a CF |
1032 | str2buf2uni (subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain); |
1033 | str2buf2uni (subbuf.auth.UserName, subbuf.usrbuf, nt_user); | |
1034 | str2buf2uni (subbuf.auth.Workstation, subbuf.wkstbuf, ""); | |
1035 | memcpy (subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH); | |
1036 | str2buf2lsa (subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, ""); | |
5519d543 | 1037 | str2buf2lsa (subbuf.auth.CaseInsensitiveChallengeResponse,subbuf.authinf2,""); |
57ff940d CV |
1038 | subbuf.auth.ParameterControl = 0 | (subauth_id << 24); |
1039 | /* Try to logon... */ | |
03a2ce9a | 1040 | ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Network, |
5519d543 CV |
1041 | package_id, &subbuf, sizeof subbuf, |
1042 | NULL, &ts, (PVOID *) &profile, &size, | |
1043 | &luid, &user_token, "a, &ret2); | |
57ff940d CV |
1044 | if (ret != STATUS_SUCCESS) |
1045 | { | |
1046 | debug_printf ("LsaLogonUser: %d", ret); | |
03a2ce9a CF |
1047 | __seterrno_from_win_error (LsaNtStatusToWinError (ret)); |
1048 | LsaDeregisterLogonProcess (lsa_hdl); | |
1fcc912f | 1049 | goto out; |
57ff940d | 1050 | } |
03a2ce9a | 1051 | LsaFreeReturnBuffer (profile); |
57ff940d | 1052 | /* Convert to primary token. */ |
57ff940d | 1053 | if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa, |
5519d543 | 1054 | SecurityImpersonation, TokenPrimary, &primary_token)) |
1fcc912f CV |
1055 | __seterrno (); |
1056 | ||
1057 | out: | |
03a2ce9a | 1058 | set_process_privilege (SE_TCB_NAME, old_tcb_state); |
1fcc912f CV |
1059 | if (user_token != INVALID_HANDLE_VALUE) |
1060 | CloseHandle (user_token); | |
57ff940d CV |
1061 | return primary_token; |
1062 | } | |
1063 | ||
d6581f44 | 1064 | /* read_sd reads a security descriptor from a file. |
1fd5e000 | 1065 | In case of error, -1 is returned and errno is set. |
dd67f9db CV |
1066 | If sd_buf is too small, 0 is returned and sd_size |
1067 | is set to the needed buffer size. | |
1068 | On success, 1 is returned. | |
1069 | ||
1070 | GetFileSecurity() is used instead of BackupRead() | |
1071 | to avoid access denied errors if the caller has | |
1072 | not the permission to open that file for read. | |
1073 | ||
1074 | Originally the function should return the size | |
1075 | of the SD on success. Unfortunately NT returns | |
1076 | 0 in `len' on success, while W2K returns the | |
1077 | correct size! | |
1fd5e000 CF |
1078 | */ |
1079 | ||
1080 | LONG | |
03a2ce9a | 1081 | read_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size) |
1fd5e000 CF |
1082 | { |
1083 | /* Check parameters */ | |
2a6fc028 | 1084 | if (!sd_size) |
1fd5e000 CF |
1085 | { |
1086 | set_errno (EINVAL); | |
1087 | return -1; | |
1088 | } | |
1089 | ||
03a2ce9a | 1090 | debug_printf ("file = %s", file); |
1fd5e000 | 1091 | |
d6581f44 | 1092 | DWORD len = 0; |
ee1d77e4 | 1093 | const char *pfile = file; |
5519d543 | 1094 | char fbuf[PATH_MAX]; |
ee1d77e4 CF |
1095 | if (current_codepage == oem_cp) |
1096 | { | |
1097 | DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file)); | |
1098 | bzero (fbuf, sizeof (fbuf)); | |
03a2ce9a | 1099 | OemToCharBuff (file, fbuf, fname_len); |
ee1d77e4 CF |
1100 | pfile = fbuf; |
1101 | } | |
1102 | ||
2a6fc028 | 1103 | if (!GetFileSecurity (pfile, |
462f4eff | 1104 | OWNER_SECURITY_INFORMATION |
5519d543 CV |
1105 | | GROUP_SECURITY_INFORMATION |
1106 | | DACL_SECURITY_INFORMATION, | |
1107 | sd_buf, *sd_size, &len)) | |
1fd5e000 CF |
1108 | { |
1109 | __seterrno (); | |
1110 | return -1; | |
1111 | } | |
03a2ce9a | 1112 | debug_printf ("file = %s: len=%d", file, len); |
d6581f44 | 1113 | if (len > *sd_size) |
1fd5e000 | 1114 | { |
d6581f44 CV |
1115 | *sd_size = len; |
1116 | return 0; | |
1fd5e000 | 1117 | } |
dd67f9db | 1118 | return 1; |
1fd5e000 CF |
1119 | } |
1120 | ||
1121 | LONG | |
03a2ce9a | 1122 | write_sd (const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size) |
1fd5e000 CF |
1123 | { |
1124 | /* Check parameters */ | |
2a6fc028 | 1125 | if (!sd_buf || !sd_size) |
1fd5e000 CF |
1126 | { |
1127 | set_errno (EINVAL); | |
1128 | return -1; | |
1129 | } | |
1130 | ||
62cd433e CV |
1131 | BOOL dummy; |
1132 | cygpsid owner; | |
1133 | ||
1134 | if (!GetSecurityDescriptorOwner (sd_buf, (PSID *) &owner, &dummy)) | |
1135 | { | |
1136 | __seterrno (); | |
1137 | return -1; | |
1138 | } | |
1139 | /* Try turning privilege on, may not have WRITE_OWNER or WRITE_DAC access. | |
1140 | Must have privilege to set different owner, else BackupWrite misbehaves */ | |
1141 | static int NO_COPY saved_res; /* 0: never, 1: failed, 2 & 3: OK */ | |
1142 | int res; | |
1143 | if (!saved_res || cygheap->user.issetuid ()) | |
1144 | { | |
1145 | res = 2 + set_process_privilege (SE_RESTORE_NAME, true, | |
1146 | cygheap->user.issetuid ()); | |
1147 | if (!cygheap->user.issetuid ()) | |
1148 | saved_res = res; | |
1149 | } | |
1150 | else | |
1151 | res = saved_res; | |
1152 | if (res == 1 && owner != cygheap->user.sid ()) | |
1153 | return -1; | |
1154 | ||
d6581f44 CV |
1155 | HANDLE fh; |
1156 | fh = CreateFile (file, | |
b0e82b74 CF |
1157 | WRITE_OWNER | WRITE_DAC, |
1158 | FILE_SHARE_READ | FILE_SHARE_WRITE, | |
1159 | &sec_none_nih, | |
1160 | OPEN_EXISTING, | |
1161 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, | |
1162 | NULL); | |
1fd5e000 | 1163 | |
d6581f44 | 1164 | if (fh == INVALID_HANDLE_VALUE) |
1fd5e000 CF |
1165 | { |
1166 | __seterrno (); | |
1167 | return -1; | |
1168 | } | |
1169 | ||
1170 | LPVOID context = NULL; | |
1171 | DWORD bytes_written = 0; | |
1172 | WIN32_STREAM_ID header; | |
1173 | ||
1174 | memset (&header, 0, sizeof (header)); | |
1175 | /* write new security info header */ | |
1176 | header.dwStreamId = BACKUP_SECURITY_DATA; | |
1177 | header.dwStreamAttributes = STREAM_CONTAINS_SECURITY; | |
1178 | header.Size.HighPart = 0; | |
d6581f44 | 1179 | header.Size.LowPart = sd_size; |
1fd5e000 | 1180 | header.dwStreamNameSize = 0; |
d6581f44 | 1181 | if (!BackupWrite (fh, (LPBYTE) &header, |
1fd5e000 CF |
1182 | 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER), |
1183 | &bytes_written, FALSE, TRUE, &context)) | |
1184 | { | |
1185 | __seterrno (); | |
d6581f44 | 1186 | CloseHandle (fh); |
1fd5e000 CF |
1187 | return -1; |
1188 | } | |
1189 | ||
1190 | /* write new security descriptor */ | |
d6581f44 | 1191 | if (!BackupWrite (fh, (LPBYTE) sd_buf, |
1fd5e000 CF |
1192 | header.Size.LowPart + header.dwStreamNameSize, |
1193 | &bytes_written, FALSE, TRUE, &context)) | |
1194 | { | |
1195 | /* Samba returns ERROR_NOT_SUPPORTED. | |
5bf785a0 CF |
1196 | FAT returns ERROR_INVALID_SECURITY_DESCR. |
1197 | This shouldn't return as error, but better be ignored. */ | |
1fd5e000 CF |
1198 | DWORD ret = GetLastError (); |
1199 | if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR) | |
1200 | { | |
1201 | __seterrno (); | |
d6581f44 CV |
1202 | BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context); |
1203 | CloseHandle (fh); | |
1fd5e000 CF |
1204 | return -1; |
1205 | } | |
1206 | } | |
1207 | ||
1208 | /* terminate the restore process */ | |
d6581f44 CV |
1209 | BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context); |
1210 | CloseHandle (fh); | |
1fd5e000 CF |
1211 | return 0; |
1212 | } | |
1213 | ||
38170b13 | 1214 | static void |
407b8df6 | 1215 | get_attribute_from_acl (mode_t *attribute, PACL acl, PSID owner_sid, |
c90e1cf1 | 1216 | PSID group_sid, BOOL grp_member) |
38170b13 CV |
1217 | { |
1218 | ACCESS_ALLOWED_ACE *ace; | |
1219 | int allow = 0; | |
1220 | int deny = 0; | |
1221 | int *flags, *anti; | |
1222 | ||
1223 | for (DWORD i = 0; i < acl->AceCount; ++i) | |
1224 | { | |
1225 | if (!GetAce (acl, i, (PVOID *) &ace)) | |
1226 | continue; | |
1227 | if (ace->Header.AceFlags & INHERIT_ONLY) | |
1228 | continue; | |
1229 | switch (ace->Header.AceType) | |
1230 | { | |
1231 | case ACCESS_ALLOWED_ACE_TYPE: | |
1232 | flags = &allow; | |
1233 | anti = &deny; | |
1234 | break; | |
1235 | case ACCESS_DENIED_ACE_TYPE: | |
1236 | flags = &deny; | |
1237 | anti = &allow; | |
1238 | break; | |
1239 | default: | |
1240 | continue; | |
1241 | } | |
1242 | ||
0c8455c3 | 1243 | cygpsid ace_sid ((PSID) &ace->SidStart); |
38170b13 CV |
1244 | if (ace_sid == well_known_world_sid) |
1245 | { | |
1246 | if (ace->Mask & FILE_READ_DATA) | |
dbcb7578 | 1247 | *flags |= ((!(*anti & S_IROTH)) ? S_IROTH : 0) |
38170b13 CV |
1248 | | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) |
1249 | | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); | |
1250 | if (ace->Mask & FILE_WRITE_DATA) | |
dbcb7578 | 1251 | *flags |= ((!(*anti & S_IWOTH)) ? S_IWOTH : 0) |
38170b13 CV |
1252 | | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) |
1253 | | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); | |
1254 | if (ace->Mask & FILE_EXECUTE) | |
dbcb7578 | 1255 | *flags |= ((!(*anti & S_IXOTH)) ? S_IXOTH : 0) |
9a751621 CF |
1256 | | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) |
1257 | | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); | |
b1897d27 | 1258 | if ((S_ISDIR (*attribute)) && |
38170b13 CV |
1259 | (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD)) |
1260 | == (FILE_WRITE_DATA | FILE_EXECUTE)) | |
1261 | *flags |= S_ISVTX; | |
1262 | } | |
1263 | else if (ace_sid == well_known_null_sid) | |
1264 | { | |
1265 | /* Read SUID, SGID and VTX bits from NULL ACE. */ | |
1266 | if (ace->Mask & FILE_READ_DATA) | |
1267 | *flags |= S_ISVTX; | |
1268 | if (ace->Mask & FILE_WRITE_DATA) | |
1269 | *flags |= S_ISGID; | |
1270 | if (ace->Mask & FILE_APPEND_DATA) | |
1271 | *flags |= S_ISUID; | |
1272 | } | |
dbcb7578 | 1273 | else if (ace_sid == owner_sid) |
38170b13 CV |
1274 | { |
1275 | if (ace->Mask & FILE_READ_DATA) | |
dbcb7578 | 1276 | *flags |= ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); |
38170b13 | 1277 | if (ace->Mask & FILE_WRITE_DATA) |
dbcb7578 | 1278 | *flags |= ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); |
38170b13 | 1279 | if (ace->Mask & FILE_EXECUTE) |
dbcb7578 | 1280 | *flags |= ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); |
38170b13 | 1281 | } |
dbcb7578 | 1282 | else if (ace_sid == group_sid) |
38170b13 CV |
1283 | { |
1284 | if (ace->Mask & FILE_READ_DATA) | |
dbcb7578 | 1285 | *flags |= ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) |
38170b13 CV |
1286 | | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); |
1287 | if (ace->Mask & FILE_WRITE_DATA) | |
dbcb7578 | 1288 | *flags |= ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) |
38170b13 CV |
1289 | | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); |
1290 | if (ace->Mask & FILE_EXECUTE) | |
dbcb7578 | 1291 | *flags |= ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) |
38170b13 CV |
1292 | | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); |
1293 | } | |
1294 | } | |
1295 | *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID); | |
dbcb7578 CV |
1296 | if (owner_sid && group_sid && EqualSid (owner_sid, group_sid) |
1297 | /* FIXME: temporary exception for /var/empty */ | |
1298 | && well_known_system_sid != group_sid) | |
1299 | { | |
1300 | allow &= ~(S_IRGRP | S_IWGRP | S_IXGRP); | |
1301 | allow |= (((allow & S_IRUSR) ? S_IRGRP : 0) | |
1302 | | ((allow & S_IWUSR) ? S_IWGRP : 0) | |
1303 | | ((allow & S_IXUSR) ? S_IXGRP : 0)); | |
1304 | } | |
38170b13 | 1305 | *attribute |= allow; |
38170b13 CV |
1306 | return; |
1307 | } | |
1308 | ||
2e23862a CV |
1309 | static void |
1310 | get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute, | |
a8d7ae61 | 1311 | __uid32_t *uidret, __gid32_t *gidret) |
1fd5e000 | 1312 | { |
2e23862a | 1313 | if (!psd) |
1fd5e000 | 1314 | { |
2e23862a CV |
1315 | /* If reading the security descriptor failed, treat the object |
1316 | as unreadable. */ | |
1317 | if (attribute) | |
1318 | *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO); | |
1319 | if (uidret) | |
1320 | *uidret = ILLEGAL_UID; | |
1321 | if (gidret) | |
1322 | *gidret = ILLEGAL_GID; | |
1323 | return; | |
1fd5e000 CF |
1324 | } |
1325 | ||
0c8455c3 CV |
1326 | cygpsid owner_sid; |
1327 | cygpsid group_sid; | |
1fd5e000 CF |
1328 | BOOL dummy; |
1329 | ||
0c8455c3 | 1330 | if (!GetSecurityDescriptorOwner (psd, (PSID *) &owner_sid, &dummy)) |
1fd5e000 | 1331 | debug_printf ("GetSecurityDescriptorOwner %E"); |
0c8455c3 | 1332 | if (!GetSecurityDescriptorGroup (psd, (PSID *) &group_sid, &dummy)) |
1fd5e000 CF |
1333 | debug_printf ("GetSecurityDescriptorGroup %E"); |
1334 | ||
0c8455c3 CV |
1335 | __uid32_t uid; |
1336 | __gid32_t gid; | |
1337 | BOOL grp_member = get_sids_info (owner_sid, group_sid, &uid, &gid); | |
5d4af61e CV |
1338 | if (uidret) |
1339 | *uidret = uid; | |
1340 | if (gidret) | |
1341 | *gidret = gid; | |
1342 | ||
2a6fc028 | 1343 | if (!attribute) |
5d4af61e | 1344 | { |
2e23862a CV |
1345 | syscall_printf ("uid %d, gid %d", uid, gid); |
1346 | return; | |
5d4af61e CV |
1347 | } |
1348 | ||
2e23862a CV |
1349 | PACL acl; |
1350 | BOOL acl_exists; | |
1351 | ||
1352 | if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) | |
1fd5e000 | 1353 | { |
2e23862a CV |
1354 | __seterrno (); |
1355 | debug_printf ("GetSecurityDescriptorDacl %E"); | |
1356 | *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO); | |
1fd5e000 | 1357 | } |
2e23862a CV |
1358 | else if (!acl_exists || !acl) |
1359 | *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; | |
1360 | else | |
1361 | get_attribute_from_acl (attribute, acl, owner_sid, group_sid, grp_member); | |
1fd5e000 | 1362 | |
2e23862a CV |
1363 | syscall_printf ("%sACL = %x, uid %d, gid %d", |
1364 | (!acl_exists || !acl)?"NO ":"", *attribute, uid, gid); | |
1365 | return; | |
1366 | } | |
1367 | ||
1368 | static void | |
1369 | get_nt_attribute (const char *file, mode_t *attribute, | |
1370 | __uid32_t *uidret, __gid32_t *gidret) | |
1371 | { | |
1372 | /* Yeah, sounds too much, but I've seen SDs of 2100 bytes! */ | |
1373 | DWORD sd_size = 4096; | |
1374 | char sd_buf[4096]; | |
1375 | PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; | |
1376 | ||
1377 | if (read_sd (file, psd, &sd_size) <= 0) | |
1378 | { | |
1379 | debug_printf ("read_sd %E"); | |
1380 | psd = NULL; | |
1381 | } | |
1382 | ||
1383 | get_info_from_sd (psd, attribute, uidret, gidret); | |
1384 | return; | |
1fd5e000 CF |
1385 | } |
1386 | ||
1387 | int | |
d6581f44 | 1388 | get_file_attribute (int use_ntsec, const char *file, |
407b8df6 | 1389 | mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) |
1fd5e000 | 1390 | { |
10b06c5e | 1391 | int res; |
2e23862a | 1392 | syscall_printf ("file: %s", file); |
10b06c5e | 1393 | |
2d388e43 | 1394 | if (use_ntsec && allow_ntsec && wincap.has_security ()) |
10b06c5e | 1395 | { |
2e23862a | 1396 | get_nt_attribute (file, attribute, uidret, gidret); |
3eb27a4e | 1397 | return 0; |
10b06c5e | 1398 | } |
1fd5e000 | 1399 | |
5d4af61e | 1400 | if (uidret) |
ea3ba114 | 1401 | *uidret = myself->uid; |
5d4af61e | 1402 | if (gidret) |
ea3ba114 | 1403 | *gidret = myself->gid; |
1fd5e000 | 1404 | |
2a6fc028 | 1405 | if (!attribute) |
5d4af61e | 1406 | return 0; |
1fd5e000 | 1407 | |
149da470 ED |
1408 | if (allow_ntea) |
1409 | { | |
1410 | int oatt = *attribute; | |
c90e1cf1 | 1411 | res = NTReadEA (file, ".UNIXATTR", (char *)attribute, sizeof (*attribute)); |
149da470 ED |
1412 | *attribute |= oatt; |
1413 | } | |
1414 | else | |
1415 | res = 0; | |
1fd5e000 | 1416 | |
5d4af61e | 1417 | return res > 0 ? 0 : -1; |
1fd5e000 CF |
1418 | } |
1419 | ||
2e23862a | 1420 | static void |
5519d543 | 1421 | get_nt_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, |
407b8df6 | 1422 | mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) |
74fcdaec | 1423 | { |
2e23862a CV |
1424 | PSECURITY_DESCRIPTOR psd; |
1425 | char sd_buf[4096]; | |
74fcdaec | 1426 | |
98b36ec8 | 1427 | if (object_type == SE_REGISTRY_KEY) |
5519d543 | 1428 | { |
2e23862a CV |
1429 | /* use different code for registry handles, for performance reasons */ |
1430 | psd = (PSECURITY_DESCRIPTOR) & sd_buf[0]; | |
98b36ec8 CV |
1431 | DWORD len = sizeof (sd_buf); |
1432 | if (ERROR_SUCCESS != RegGetKeySecurity ((HKEY) handle, | |
df04ae29 CF |
1433 | DACL_SECURITY_INFORMATION | |
1434 | GROUP_SECURITY_INFORMATION | | |
1435 | OWNER_SECURITY_INFORMATION, | |
1436 | psd, &len)) | |
1437 | { | |
1438 | __seterrno (); | |
1439 | debug_printf ("RegGetKeySecurity %E"); | |
1440 | psd = NULL; | |
1441 | } | |
2e23862a | 1442 | } |
98b36ec8 CV |
1443 | else |
1444 | { | |
1445 | if (ERROR_SUCCESS != GetSecurityInfo (handle, object_type, | |
2e23862a CV |
1446 | DACL_SECURITY_INFORMATION | |
1447 | GROUP_SECURITY_INFORMATION | | |
1448 | OWNER_SECURITY_INFORMATION, | |
1449 | NULL, NULL, NULL, NULL, &psd)) | |
df04ae29 | 1450 | { |
2e23862a CV |
1451 | __seterrno (); |
1452 | debug_printf ("GetSecurityInfo %E"); | |
1453 | psd = NULL; | |
1454 | } | |
74fcdaec CF |
1455 | } |
1456 | ||
2e23862a CV |
1457 | get_info_from_sd (psd, attribute, uidret, gidret); |
1458 | if (psd != (PSECURITY_DESCRIPTOR) & sd_buf[0]) | |
1459 | LocalFree (psd); | |
74fcdaec | 1460 | |
2e23862a | 1461 | return; |
74fcdaec CF |
1462 | } |
1463 | ||
1464 | int | |
1465 | get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, | |
407b8df6 | 1466 | mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret) |
74fcdaec | 1467 | { |
2d388e43 | 1468 | if (allow_ntsec && wincap.has_security ()) |
74fcdaec | 1469 | { |
2e23862a CV |
1470 | get_nt_object_attribute (handle, object_type, attribute, uidret, gidret); |
1471 | return 0; | |
74fcdaec | 1472 | } |
2e23862a CV |
1473 | /* The entries are already set to default values */ |
1474 | return -1; | |
74fcdaec CF |
1475 | } |
1476 | ||
c0d1968a CV |
1477 | BOOL |
1478 | add_access_allowed_ace (PACL acl, int offset, DWORD attributes, | |
1479 | PSID sid, size_t &len_add, DWORD inherit) | |
1fd5e000 | 1480 | { |
2a6fc028 | 1481 | if (!AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid)) |
1fd5e000 CF |
1482 | { |
1483 | __seterrno (); | |
1484 | return FALSE; | |
1485 | } | |
1486 | ACCESS_ALLOWED_ACE *ace; | |
dbcb7578 | 1487 | if (inherit && GetAce (acl, offset, (PVOID *) &ace)) |
1fd5e000 | 1488 | ace->Header.AceFlags |= inherit; |
dbcb7578 | 1489 | len_add += sizeof (ACCESS_ALLOWED_ACE) - sizeof (DWORD) + GetLengthSid (sid); |
1fd5e000 CF |
1490 | return TRUE; |
1491 | } | |
1492 | ||
c0d1968a CV |
1493 | BOOL |
1494 | add_access_denied_ace (PACL acl, int offset, DWORD attributes, | |
1495 | PSID sid, size_t &len_add, DWORD inherit) | |
1fd5e000 | 1496 | { |
2a6fc028 | 1497 | if (!AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid)) |
1fd5e000 CF |
1498 | { |
1499 | __seterrno (); | |
1500 | return FALSE; | |
1501 | } | |
1502 | ACCESS_DENIED_ACE *ace; | |
dbcb7578 | 1503 | if (inherit && GetAce (acl, offset, (PVOID *) &ace)) |
1fd5e000 | 1504 | ace->Header.AceFlags |= inherit; |
5519d543 | 1505 | len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) + GetLengthSid (sid); |
1fd5e000 CF |
1506 | return TRUE; |
1507 | } | |
1508 | ||
1509 | PSECURITY_DESCRIPTOR | |
2e8abfc1 | 1510 | alloc_sd (__uid32_t uid, __gid32_t gid, int attribute, |
1fd5e000 CF |
1511 | PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret) |
1512 | { | |
1513 | BOOL dummy; | |
1514 | ||
dbcb7578 | 1515 | debug_printf("uid %d, gid %d, attribute %x", uid, gid, attribute); |
2a6fc028 | 1516 | if (!sd_ret || !sd_size_ret) |
1fd5e000 CF |
1517 | { |
1518 | set_errno (EINVAL); | |
1519 | return NULL; | |
1520 | } | |
1521 | ||
dbcb7578 CV |
1522 | /* Get owner and group from current security descriptor. */ |
1523 | PSID cur_owner_sid = NULL; | |
1524 | PSID cur_group_sid = NULL; | |
1525 | if (!GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy)) | |
1526 | debug_printf ("GetSecurityDescriptorOwner %E"); | |
1527 | if (!GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy)) | |
1528 | debug_printf ("GetSecurityDescriptorGroup %E"); | |
1529 | ||
dd0208eb | 1530 | /* Get SID of owner. */ |
ab2dbccc | 1531 | cygsid owner_sid; |
dd0208eb CV |
1532 | /* Check for current user first */ |
1533 | if (uid == myself->uid) | |
1534 | owner_sid = cygheap->user.sid (); | |
dbcb7578 CV |
1535 | else if (uid == ILLEGAL_UID) |
1536 | owner_sid = cur_owner_sid; | |
d6ffc075 | 1537 | else if (!owner_sid.getfrompw (internal_getpwuid (uid))) |
dd0208eb | 1538 | { |
dbcb7578 CV |
1539 | set_errno (EINVAL); |
1540 | return NULL; | |
dd0208eb CV |
1541 | } |
1542 | owner_sid.debug_print ("alloc_sd: owner SID ="); | |
1fd5e000 | 1543 | |
dd0208eb | 1544 | /* Get SID of new group. */ |
ab2dbccc | 1545 | cygsid group_sid; |
329b9ead CF |
1546 | /* Check for current user first */ |
1547 | if (gid == myself->gid) | |
1548 | group_sid = cygheap->user.groups.pgsid; | |
dbcb7578 CV |
1549 | else if (gid == ILLEGAL_GID) |
1550 | group_sid = cur_group_sid; | |
d6ffc075 | 1551 | else if (!group_sid.getfromgr (internal_getgrgid (gid))) |
dbcb7578 CV |
1552 | { |
1553 | set_errno (EINVAL); | |
1554 | return NULL; | |
1555 | } | |
1556 | group_sid.debug_print ("alloc_sd: group SID ="); | |
1557 | ||
c434bd08 | 1558 | /* Initialize local security descriptor. */ |
1fd5e000 | 1559 | SECURITY_DESCRIPTOR sd; |
2a6fc028 | 1560 | if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) |
1fd5e000 CF |
1561 | { |
1562 | __seterrno (); | |
1563 | return NULL; | |
1564 | } | |
1565 | ||
aa2b85cc | 1566 | /* |
b2652452 CV |
1567 | * We set the SE_DACL_PROTECTED flag here to prevent the DACL from being |
1568 | * modified by inheritable ACEs. | |
1569 | * This flag as well as the SetSecurityDescriptorControl call are available | |
1570 | * only since Win2K. | |
aa2b85cc | 1571 | */ |
ba946828 | 1572 | if (wincap.has_security_descriptor_control ()) |
aa2b85cc CV |
1573 | SetSecurityDescriptorControl (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED); |
1574 | ||
c434bd08 | 1575 | /* Create owner for local security descriptor. */ |
03a2ce9a | 1576 | if (!SetSecurityDescriptorOwner (&sd, owner_sid, FALSE)) |
1fd5e000 CF |
1577 | { |
1578 | __seterrno (); | |
1579 | return NULL; | |
1580 | } | |
c434bd08 CV |
1581 | |
1582 | /* Create group for local security descriptor. */ | |
dbcb7578 | 1583 | if (!SetSecurityDescriptorGroup (&sd, group_sid, FALSE)) |
1fd5e000 CF |
1584 | { |
1585 | __seterrno (); | |
1586 | return NULL; | |
1587 | } | |
1588 | ||
c434bd08 | 1589 | /* Initialize local access control list. */ |
1fd5e000 CF |
1590 | char acl_buf[3072]; |
1591 | PACL acl = (PACL) acl_buf; | |
2a6fc028 | 1592 | if (!InitializeAcl (acl, 3072, ACL_REVISION)) |
1fd5e000 CF |
1593 | { |
1594 | __seterrno (); | |
1595 | return NULL; | |
1596 | } | |
1597 | ||
c434bd08 | 1598 | /* From here fill ACL. */ |
1fd5e000 CF |
1599 | size_t acl_len = sizeof (ACL); |
1600 | int ace_off = 0; | |
1601 | ||
c434bd08 | 1602 | /* Construct allow attribute for owner. */ |
556ceaeb | 1603 | DWORD owner_allow = STANDARD_RIGHTS_ALL |
b0e82b74 | 1604 | | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; |
1fd5e000 CF |
1605 | if (attribute & S_IRUSR) |
1606 | owner_allow |= FILE_GENERIC_READ; | |
1607 | if (attribute & S_IWUSR) | |
556ceaeb | 1608 | owner_allow |= FILE_GENERIC_WRITE; |
1fd5e000 CF |
1609 | if (attribute & S_IXUSR) |
1610 | owner_allow |= FILE_GENERIC_EXECUTE; | |
b1897d27 CV |
1611 | if (S_ISDIR (attribute) |
1612 | && (attribute & (S_IWUSR | S_IXUSR)) == (S_IWUSR | S_IXUSR)) | |
1fd5e000 CF |
1613 | owner_allow |= FILE_DELETE_CHILD; |
1614 | ||
c434bd08 | 1615 | /* Construct allow attribute for group. */ |
1fd5e000 | 1616 | DWORD group_allow = STANDARD_RIGHTS_READ |
b0e82b74 | 1617 | | FILE_READ_ATTRIBUTES | FILE_READ_EA; |
1fd5e000 CF |
1618 | if (attribute & S_IRGRP) |
1619 | group_allow |= FILE_GENERIC_READ; | |
1620 | if (attribute & S_IWGRP) | |
3a157c0d | 1621 | group_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE; |
1fd5e000 CF |
1622 | if (attribute & S_IXGRP) |
1623 | group_allow |= FILE_GENERIC_EXECUTE; | |
b1897d27 CV |
1624 | if (S_ISDIR (attribute) |
1625 | && (attribute & (S_IWGRP | S_IXGRP)) == (S_IWGRP | S_IXGRP) | |
1626 | && !(attribute & S_ISVTX)) | |
1fd5e000 CF |
1627 | group_allow |= FILE_DELETE_CHILD; |
1628 | ||
c434bd08 | 1629 | /* Construct allow attribute for everyone. */ |
1fd5e000 | 1630 | DWORD other_allow = STANDARD_RIGHTS_READ |
b0e82b74 | 1631 | | FILE_READ_ATTRIBUTES | FILE_READ_EA; |
1fd5e000 CF |
1632 | if (attribute & S_IROTH) |
1633 | other_allow |= FILE_GENERIC_READ; | |
1634 | if (attribute & S_IWOTH) | |
3a157c0d | 1635 | other_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE; |
1fd5e000 CF |
1636 | if (attribute & S_IXOTH) |
1637 | other_allow |= FILE_GENERIC_EXECUTE; | |
b1897d27 CV |
1638 | if (S_ISDIR (attribute) |
1639 | && (attribute & (S_IWOTH | S_IXOTH)) == (S_IWOTH | S_IXOTH) | |
3a157c0d | 1640 | && !(attribute & S_ISVTX)) |
1fd5e000 | 1641 | other_allow |= FILE_DELETE_CHILD; |
75a57bf0 | 1642 | |
3a157c0d CV |
1643 | /* Construct SUID, SGID and VTX bits in NULL ACE. */ |
1644 | DWORD null_allow = 0L; | |
1645 | if (attribute & (S_ISUID | S_ISGID | S_ISVTX)) | |
1646 | { | |
1647 | if (attribute & S_ISUID) | |
1ff9f4b9 | 1648 | null_allow |= FILE_APPEND_DATA; |
3a157c0d | 1649 | if (attribute & S_ISGID) |
1ff9f4b9 | 1650 | null_allow |= FILE_WRITE_DATA; |
3a157c0d | 1651 | if (attribute & S_ISVTX) |
1ff9f4b9 | 1652 | null_allow |= FILE_READ_DATA; |
3a157c0d CV |
1653 | } |
1654 | ||
dbcb7578 CV |
1655 | /* Add owner and group permissions if SIDs are equal |
1656 | and construct deny attributes for group and owner. */ | |
ab2dbccc CV |
1657 | BOOL isownergroup; |
1658 | if ((isownergroup = (owner_sid == group_sid))) | |
1659 | owner_allow |= group_allow; | |
1660 | ||
dbcb7578 | 1661 | DWORD owner_deny = ~owner_allow & (group_allow | other_allow); |
1fd5e000 | 1662 | owner_deny &= ~(STANDARD_RIGHTS_READ |
b0e82b74 CF |
1663 | | FILE_READ_ATTRIBUTES | FILE_READ_EA |
1664 | | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA); | |
1fd5e000 | 1665 | |
ab2dbccc CV |
1666 | DWORD group_deny = ~group_allow & other_allow; |
1667 | group_deny &= ~(STANDARD_RIGHTS_READ | |
1668 | | FILE_READ_ATTRIBUTES | FILE_READ_EA); | |
154110f5 | 1669 | |
c434bd08 | 1670 | /* Set deny ACE for owner. */ |
1fd5e000 | 1671 | if (owner_deny |
2a6fc028 | 1672 | && !add_access_denied_ace (acl, ace_off++, owner_deny, |
ab2dbccc | 1673 | owner_sid, acl_len, NO_INHERITANCE)) |
3a157c0d | 1674 | return NULL; |
dbcb7578 CV |
1675 | /* Set deny ACE for group here to respect the canonical order, |
1676 | if this does not impact owner */ | |
ab2dbccc CV |
1677 | if (group_deny && !(group_deny & owner_allow) && !isownergroup |
1678 | && !add_access_denied_ace (acl, ace_off++, group_deny, | |
1679 | group_sid, acl_len, NO_INHERITANCE)) | |
1680 | return NULL; | |
c434bd08 | 1681 | /* Set allow ACE for owner. */ |
2a6fc028 | 1682 | if (!add_access_allowed_ace (acl, ace_off++, owner_allow, |
ab2dbccc | 1683 | owner_sid, acl_len, NO_INHERITANCE)) |
1fd5e000 | 1684 | return NULL; |
dbcb7578 | 1685 | /* Set deny ACE for group, if still needed. */ |
ab2dbccc | 1686 | if (group_deny & owner_allow && !isownergroup |
2a6fc028 | 1687 | && !add_access_denied_ace (acl, ace_off++, group_deny, |
ab2dbccc | 1688 | group_sid, acl_len, NO_INHERITANCE)) |
3a157c0d | 1689 | return NULL; |
c434bd08 | 1690 | /* Set allow ACE for group. */ |
ab2dbccc | 1691 | if (!isownergroup |
dbcb7578 | 1692 | && !add_access_allowed_ace (acl, ace_off++, group_allow, |
ab2dbccc | 1693 | group_sid, acl_len, NO_INHERITANCE)) |
1fd5e000 CF |
1694 | return NULL; |
1695 | ||
22ae5a5b CV |
1696 | /* Set allow ACE for everyone. */ |
1697 | if (!add_access_allowed_ace (acl, ace_off++, other_allow, | |
ab2dbccc | 1698 | well_known_world_sid, acl_len, NO_INHERITANCE)) |
22ae5a5b | 1699 | return NULL; |
3a157c0d CV |
1700 | /* Set null ACE for special bits. */ |
1701 | if (null_allow | |
1702 | && !add_access_allowed_ace (acl, ace_off++, null_allow, | |
654bad37 | 1703 | well_known_null_sid, acl_len, NO_INHERITANCE)) |
3a157c0d | 1704 | return NULL; |
22ae5a5b | 1705 | |
c434bd08 | 1706 | /* Fill ACL with unrelated ACEs from current security descriptor. */ |
1fd5e000 | 1707 | PACL oacl; |
ab2dbccc | 1708 | BOOL acl_exists = FALSE; |
1fd5e000 CF |
1709 | ACCESS_ALLOWED_ACE *ace; |
1710 | if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy) | |
1711 | && acl_exists && oacl) | |
1712 | for (DWORD i = 0; i < oacl->AceCount; ++i) | |
1713 | if (GetAce (oacl, i, (PVOID *) &ace)) | |
b0e82b74 | 1714 | { |
0c8455c3 CV |
1715 | cygpsid ace_sid ((PSID) &ace->SidStart); |
1716 | ||
c434bd08 | 1717 | /* Check for related ACEs. */ |
ab2dbccc CV |
1718 | if (ace_sid == well_known_null_sid) |
1719 | continue; | |
dbcb7578 CV |
1720 | if ((ace_sid == cur_owner_sid) |
1721 | || (ace_sid == owner_sid) | |
1722 | || (ace_sid == cur_group_sid) | |
1723 | || (ace_sid == group_sid) | |
ab2dbccc CV |
1724 | || (ace_sid == well_known_world_sid)) |
1725 | { | |
1726 | if (ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT) | |
1727 | ace->Header.AceFlags |= INHERIT_ONLY; | |
1728 | else | |
1729 | continue; | |
1730 | } | |
c434bd08 CV |
1731 | /* |
1732 | * Add unrelated ACCESS_DENIED_ACE to the beginning but | |
22ae5a5b | 1733 | * behind the owner_deny, ACCESS_ALLOWED_ACE to the end. |
ab2dbccc | 1734 | * FIXME: this would break the order of the inherit_only ACEs |
c434bd08 | 1735 | */ |
03a2ce9a | 1736 | if (!AddAce (acl, ACL_REVISION, |
ab2dbccc | 1737 | ace->Header.AceType == ACCESS_DENIED_ACE_TYPE? |
b0e82b74 CF |
1738 | (owner_deny ? 1 : 0) : MAXDWORD, |
1739 | (LPVOID) ace, ace->Header.AceSize)) | |
1740 | { | |
1741 | __seterrno (); | |
1742 | return NULL; | |
1743 | } | |
1744 | acl_len += ace->Header.AceSize; | |
b0e82b74 | 1745 | } |
1fd5e000 | 1746 | |
ab2dbccc | 1747 | /* Construct appropriate inherit attribute for new directories */ |
b1897d27 | 1748 | if (S_ISDIR (attribute) && !acl_exists ) |
ab2dbccc CV |
1749 | { |
1750 | const DWORD inherit = SUB_CONTAINERS_AND_OBJECTS_INHERIT | INHERIT_ONLY; | |
1751 | ||
1752 | #if 0 /* FIXME: Not done currently as this breaks the canonical order */ | |
1753 | /* Set deny ACE for owner. */ | |
1754 | if (owner_deny | |
1755 | && !add_access_denied_ace (acl, ace_off++, owner_deny, | |
1756 | well_known_creator_owner_sid, acl_len, inherit)) | |
1757 | return NULL; | |
1758 | /* Set deny ACE for group here to respect the canonical order, | |
1759 | if this does not impact owner */ | |
1760 | if (group_deny && !(group_deny & owner_allow) | |
1761 | && !add_access_denied_ace (acl, ace_off++, group_deny, | |
1762 | well_known_creator_group_sid, acl_len, inherit)) | |
1763 | return NULL; | |
1764 | #endif | |
1765 | /* Set allow ACE for owner. */ | |
1766 | if (!add_access_allowed_ace (acl, ace_off++, owner_allow, | |
1767 | well_known_creator_owner_sid, acl_len, inherit)) | |
1768 | return NULL; | |
1769 | #if 0 /* FIXME: Not done currently as this breaks the canonical order and | |
1770 | won't be preserved on chown and chmod */ | |
1771 | /* Set deny ACE for group, conflicting with owner_allow. */ | |
1772 | if (group_deny & owner_allow | |
1773 | && !add_access_denied_ace (acl, ace_off++, group_deny, | |
1774 | well_known_creator_group_sid, acl_len, inherit)) | |
1775 | return NULL; | |
1776 | #endif | |
1777 | /* Set allow ACE for group. */ | |
1778 | if (!add_access_allowed_ace (acl, ace_off++, group_allow, | |
1779 | well_known_creator_group_sid, acl_len, inherit)) | |
1780 | return NULL; | |
1781 | /* Set allow ACE for everyone. */ | |
1782 | if (!add_access_allowed_ace (acl, ace_off++, other_allow, | |
1783 | well_known_world_sid, acl_len, inherit)) | |
1784 | return NULL; | |
1785 | } | |
1786 | ||
c434bd08 | 1787 | /* Set AclSize to computed value. */ |
1fd5e000 CF |
1788 | acl->AclSize = acl_len; |
1789 | debug_printf ("ACL-Size: %d", acl_len); | |
1790 | ||
c434bd08 | 1791 | /* Create DACL for local security descriptor. */ |
2a6fc028 | 1792 | if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) |
1fd5e000 CF |
1793 | { |
1794 | __seterrno (); | |
1795 | return NULL; | |
1796 | } | |
1797 | ||
c434bd08 | 1798 | /* Make self relative security descriptor. */ |
1fd5e000 CF |
1799 | *sd_size_ret = 0; |
1800 | MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret); | |
1801 | if (*sd_size_ret <= 0) | |
1802 | { | |
1803 | __seterrno (); | |
1804 | return NULL; | |
1805 | } | |
2a6fc028 | 1806 | if (!MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret)) |
1fd5e000 CF |
1807 | { |
1808 | __seterrno (); | |
1809 | return NULL; | |
1810 | } | |
1fd5e000 CF |
1811 | debug_printf ("Created SD-Size: %d", *sd_size_ret); |
1812 | ||
ab2dbccc | 1813 | return sd_ret; |
1fd5e000 CF |
1814 | } |
1815 | ||
86fb0393 CV |
1816 | void |
1817 | set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, | |
1818 | void *sd_buf, DWORD sd_buf_size) | |
1819 | { | |
86fb0393 | 1820 | psa->lpSecurityDescriptor = sd_buf; |
5519d543 | 1821 | InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR) sd_buf, |
1ff9f4b9 | 1822 | SECURITY_DESCRIPTOR_REVISION); |
5519d543 CV |
1823 | psa->lpSecurityDescriptor = alloc_sd (geteuid32 (), getegid32 (), attribute, |
1824 | (PSECURITY_DESCRIPTOR) sd_buf, | |
86fb0393 CV |
1825 | &sd_buf_size); |
1826 | } | |
1827 | ||
1fd5e000 | 1828 | static int |
a8d7ae61 | 1829 | set_nt_attribute (const char *file, __uid32_t uid, __gid32_t gid, |
2e8abfc1 | 1830 | int attribute) |
1fd5e000 | 1831 | { |
ba946828 | 1832 | if (!wincap.has_security ()) |
1fd5e000 CF |
1833 | return 0; |
1834 | ||
1fd5e000 CF |
1835 | DWORD sd_size = 4096; |
1836 | char sd_buf[4096]; | |
1837 | PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; | |
1838 | ||
1839 | int ret; | |
d6581f44 | 1840 | if ((ret = read_sd (file, psd, &sd_size)) <= 0) |
1fd5e000 | 1841 | { |
d6581f44 | 1842 | debug_printf ("read_sd %E"); |
2a9366ff | 1843 | return -1; |
1fd5e000 CF |
1844 | } |
1845 | ||
1846 | sd_size = 4096; | |
2e8abfc1 | 1847 | if (!(psd = alloc_sd (uid, gid, attribute, psd, &sd_size))) |
1fd5e000 CF |
1848 | return -1; |
1849 | ||
d6581f44 | 1850 | return write_sd (file, psd, sd_size); |
1fd5e000 CF |
1851 | } |
1852 | ||
1853 | int | |
1854 | set_file_attribute (int use_ntsec, const char *file, | |
5519d543 | 1855 | __uid32_t uid, __gid32_t gid, int attribute) |
1fd5e000 | 1856 | { |
842c741f CV |
1857 | int ret = 0; |
1858 | ||
1859 | if (use_ntsec && allow_ntsec) | |
2e8abfc1 | 1860 | ret = set_nt_attribute (file, uid, gid, attribute); |
842c741f CV |
1861 | else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute, |
1862 | sizeof (attribute))) | |
1fd5e000 | 1863 | { |
842c741f CV |
1864 | __seterrno (); |
1865 | ret = -1; | |
1fd5e000 | 1866 | } |
1fd5e000 | 1867 | syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", |
5d4af61e CV |
1868 | ret, file, uid, gid, attribute); |
1869 | return ret; | |
1fd5e000 CF |
1870 | } |
1871 | ||
1872 | int | |
1873 | set_file_attribute (int use_ntsec, const char *file, int attribute) | |
1874 | { | |
1875 | return set_file_attribute (use_ntsec, file, | |
5519d543 | 1876 | myself->uid, myself->gid, attribute); |
1fd5e000 | 1877 | } |
cf762b08 CV |
1878 | |
1879 | int | |
1880 | check_file_access (const char *fn, int flags) | |
1881 | { | |
1882 | int ret = -1; | |
1883 | char sd_buf[4096]; | |
1884 | DWORD sd_size = sizeof sd_buf; | |
1885 | PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; | |
1886 | HANDLE hToken, hIToken; | |
1887 | BOOL status; | |
1888 | char pbuf[sizeof (PRIVILEGE_SET) + 3 * sizeof (LUID_AND_ATTRIBUTES)]; | |
1889 | DWORD desired = 0, granted, plength = sizeof pbuf; | |
1890 | static GENERIC_MAPPING NO_COPY mapping = { FILE_GENERIC_READ, | |
1891 | FILE_GENERIC_WRITE, | |
1892 | FILE_GENERIC_EXECUTE, | |
1893 | FILE_ALL_ACCESS }; | |
1894 | if (read_sd (fn, psd, &sd_size) <= 0) | |
1895 | goto done; | |
1896 | ||
1897 | if (cygheap->user.issetuid ()) | |
70249d56 | 1898 | hToken = cygheap->user.token (); |
cf762b08 CV |
1899 | else if (!OpenProcessToken (hMainProc, TOKEN_DUPLICATE, &hToken)) |
1900 | { | |
1901 | __seterrno (); | |
1902 | goto done; | |
1903 | } | |
1904 | if (!(status = DuplicateToken (hToken, SecurityIdentification, &hIToken))) | |
1905 | __seterrno (); | |
70249d56 | 1906 | if (!cygheap->user.issetuid ()) |
cf762b08 CV |
1907 | CloseHandle (hToken); |
1908 | if (!status) | |
1909 | goto done; | |
1910 | ||
1911 | if (flags & R_OK) | |
1912 | desired |= FILE_READ_DATA; | |
1913 | if (flags & W_OK) | |
1914 | desired |= FILE_WRITE_DATA; | |
1915 | if (flags & X_OK) | |
1916 | desired |= FILE_EXECUTE; | |
1917 | if (!AccessCheck (psd, hIToken, desired, &mapping, | |
1918 | (PPRIVILEGE_SET) pbuf, &plength, &granted, &status)) | |
1919 | __seterrno (); | |
1920 | else if (!status) | |
1921 | set_errno (EACCES); | |
1922 | else | |
1923 | ret = 0; | |
1924 | CloseHandle (hIToken); | |
1925 | done: | |
1926 | debug_printf ("flags %x, ret %d", flags, ret); | |
1927 | return ret; | |
1928 | } |