]> cygwin.com Git - cygwin-apps/setup.git/blob - win32.cc
* mount.cc (is_admin): Drop function. It's incorrectly implemented
[cygwin-apps/setup.git] / win32.cc
1 /*
2 * Copyright (c) 2007 Brian Dessent
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by Brian Dessent <brian@dessent.net>
13 *
14 */
15
16 #if 0
17 static const char *cvsid =
18 "\n%%% $Id$\n";
19 #endif
20
21 #include "win32.h"
22 #include <memory>
23 #include <malloc.h>
24 #include "LogFile.h"
25 #include "resource.h"
26 #include "state.h"
27 #include "ini.h"
28 #include <sys/stat.h>
29
30 NTSecurity nt_sec;
31
32 PSECURITY_DESCRIPTOR
33 NTSecurity::GetPosixPerms (const char *fname, PSID owner_sid, PSID group_sid,
34 mode_t mode, SECURITY_DESCRIPTOR &out_sd, acl_t &acl)
35 {
36 DWORD u_attribute, g_attribute, o_attribute;
37 DWORD offset = 0;
38
39 /* Initialize out SD */
40 if (!InitializeSecurityDescriptor (&out_sd, SECURITY_DESCRIPTOR_REVISION))
41 log (LOG_TIMESTAMP) << "InitializeSecurityDescriptor(" << fname
42 << ") failed: " << GetLastError () << endLog;
43 out_sd.Control |= SE_DACL_PROTECTED;
44
45 /* Initialize ACL and fill with almost POSIX-like permissions.
46 Note that the current user always requires write permissions, otherwise
47 creating files in directories with restricted permissions fails. */
48 if (!InitializeAcl (&acl.acl , sizeof acl, ACL_REVISION))
49 log (LOG_TIMESTAMP) << "InitializeAcl(" << fname << ") failed: "
50 << GetLastError () << endLog;
51 /* USER */
52 /* Default user to current user. */
53 if (!owner_sid)
54 owner_sid = ownerSID.user.User.Sid;
55 u_attribute = STANDARD_RIGHTS_ALL | FILE_GENERIC_READ | FILE_GENERIC_WRITE;
56 if (mode & 0100) // S_IXUSR
57 u_attribute |= FILE_GENERIC_EXECUTE;
58 if ((mode & 0300) == 0300) // S_IWUSR | S_IXUSR
59 u_attribute |= FILE_DELETE_CHILD;
60 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, u_attribute, owner_sid))
61 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
62 << ", owner) failed: " << GetLastError () << endLog;
63 else
64 offset++;
65 /* GROUP */
66 /* Default group to current primary group. */
67 if (!group_sid)
68 group_sid = groupSID;
69 g_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
70 if (mode & 0040) // S_IRGRP
71 g_attribute |= FILE_GENERIC_READ;
72 if (mode & 0020) // S_IWGRP
73 g_attribute |= FILE_GENERIC_WRITE;
74 if (mode & 0010) // S_IXGRP
75 g_attribute |= FILE_GENERIC_EXECUTE;
76 if ((mode & 01030) == 00030) // S_IWGRP | S_IXGRP, !S_ISVTX
77 g_attribute |= FILE_DELETE_CHILD;
78 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, g_attribute, group_sid))
79 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
80 << ", group) failed: " << GetLastError () << endLog;
81 else
82 offset++;
83 /* OTHER */
84 o_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
85 if (mode & 0004) // S_IROTH
86 o_attribute |= FILE_GENERIC_READ;
87 if (mode & 0002) // S_IWOTH
88 o_attribute |= FILE_GENERIC_WRITE;
89 if (mode & 0001) // S_IXOTH
90 o_attribute |= FILE_GENERIC_EXECUTE;
91 if ((mode & 01003) == 00003) // S_IWOTH | S_IXOTH, !S_ISVTX
92 o_attribute |= FILE_DELETE_CHILD;
93 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, o_attribute,
94 everyOneSID.theSID ()))
95 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
96 << ", everyone) failed: " << GetLastError () << endLog;
97 else
98 offset++;
99 if (mode & 07000) /* At least one of S_ISUID, S_ISGID, S_ISVTX */
100 {
101 DWORD attribute = 0;
102 if (mode & 04000) // S_ISUID
103 attribute |= FILE_APPEND_DATA;
104 if (mode & 02000) // S_ISGID
105 attribute |= FILE_WRITE_DATA;
106 if (mode & 01000) // S_ISVTX
107 attribute |= FILE_READ_DATA;
108 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, attribute,
109 nullSID.theSID ()))
110 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
111 << ", null) failed: " << GetLastError () << endLog;
112 else
113 offset++;
114 }
115 /* For directories, we also add inherit-only ACEs for CREATOR OWNER,
116 CREATOR GROUP, and EVERYONE (aka OTHER). */
117 if (mode & S_IFDIR)
118 {
119 if (mode & 01000) // S_ISVTX
120 {
121 /* Don't allow default write permissions for group and other
122 in a S_ISVTX dir. */
123 /* GROUP */
124 g_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
125 if (mode & 0040) // S_IRGRP
126 g_attribute |= FILE_GENERIC_READ;
127 if (mode & 0010) // S_IXGRP
128 g_attribute |= FILE_GENERIC_EXECUTE;
129 /* OTHER */
130 o_attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
131 if (mode & 0004) // S_IROTH
132 o_attribute |= FILE_GENERIC_READ;
133 if (mode & 0001) // S_IXOTH
134 o_attribute |= FILE_GENERIC_EXECUTE;
135 }
136 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, u_attribute,
137 cr_ownerSID.theSID ()))
138 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
139 << ", creator owner) failed: "
140 << GetLastError () << endLog;
141 else
142 {
143 ACCESS_ALLOWED_ACE *ace;
144 if (GetAce (&acl.acl, offset, (PVOID *) &ace))
145 ace->Header.AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
146 | INHERIT_ONLY_ACE;
147 offset++;
148 }
149 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, g_attribute,
150 cr_groupSID.theSID ()))
151 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
152 << ", creator group) failed: "
153 << GetLastError () << endLog;
154 else
155 {
156 ACCESS_ALLOWED_ACE *ace;
157 if (GetAce (&acl.acl, offset, (PVOID *) &ace))
158 ace->Header.AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
159 | INHERIT_ONLY_ACE;
160 offset++;
161 }
162 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, o_attribute,
163 everyOneSID.theSID ()))
164 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
165 << ", everyone inherit) failed: "
166 << GetLastError () << endLog;
167 else
168 {
169 ACCESS_ALLOWED_ACE *ace;
170 if (GetAce (&acl.acl, offset, (PVOID *) &ace))
171 ace->Header.AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE
172 | INHERIT_ONLY_ACE;
173 offset++;
174 }
175 }
176
177 /* Set SD's DACL to just created ACL. */
178 if (!SetSecurityDescriptorDacl (&out_sd, TRUE, &acl.acl, FALSE))
179 log (LOG_TIMESTAMP) << "SetSecurityDescriptorDacl(" << fname
180 << ") failed: " << GetLastError () << endLog;
181 return &out_sd;
182 }
183
184 void
185 NTSecurity::NoteFailedAPI (const std::string &api)
186 {
187 log (LOG_TIMESTAMP) << api << "() failed: " << GetLastError () << endLog;
188 }
189
190 void
191 NTSecurity::initialiseWellKnownSIDs ()
192 {
193 SID_IDENTIFIER_AUTHORITY n_sid_auth = { SECURITY_NULL_SID_AUTHORITY };
194 /* Get the SID for "NULL" S-1-0-0 */
195 if (!AllocateAndInitializeSid (&n_sid_auth, 1, SECURITY_NULL_RID,
196 0, 0, 0, 0, 0, 0, 0, &nullSID.theSID ()))
197 return;
198 SID_IDENTIFIER_AUTHORITY e_sid_auth = { SECURITY_WORLD_SID_AUTHORITY };
199 /* Get the SID for "Everyone" S-1-1-0 */
200 if (!AllocateAndInitializeSid (&e_sid_auth, 1, SECURITY_WORLD_RID,
201 0, 0, 0, 0, 0, 0, 0, &everyOneSID.theSID ()))
202 return;
203 SID_IDENTIFIER_AUTHORITY nt_sid_auth = { SECURITY_NT_AUTHORITY };
204 /* Get the SID for "Administrators" S-1-5-32-544 */
205 if (!AllocateAndInitializeSid (&nt_sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
206 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
207 &administratorsSID.theSID ()))
208 return;
209 /* Get the SID for "Users" S-1-5-32-545 */
210 if (!AllocateAndInitializeSid (&nt_sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
211 DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0,
212 &usersSID.theSID ()))
213 return;
214 SID_IDENTIFIER_AUTHORITY c_sid_auth = { SECURITY_CREATOR_SID_AUTHORITY };
215 /* Get the SID for "CREATOR OWNER" S-1-3-0 */
216 if (!AllocateAndInitializeSid (&c_sid_auth, 1, SECURITY_CREATOR_OWNER_RID,
217 0, 0, 0, 0, 0, 0, 0, &cr_ownerSID.theSID ()))
218 return;
219 /* Get the SID for "CREATOR GROUP" S-1-3-1 */
220 if (!AllocateAndInitializeSid (&c_sid_auth, 1, SECURITY_CREATOR_GROUP_RID,
221 0, 0, 0, 0, 0, 0, 0, &cr_groupSID.theSID ()))
222 return;
223 wellKnownSIDsinitialized (true);
224 }
225
226 void
227 NTSecurity::setDefaultDACL ()
228 {
229 /* To assure that the created files have a useful ACL, the
230 default DACL in the process token is set to full access to
231 everyone. This applies to files and subdirectories created
232 in directories which don't propagate permissions to child
233 objects.
234 To assure that the files group is meaningful, a token primary
235 group of None is changed to Users or Administrators.
236 This is the fallback if real POSIX permissions don't
237 work for some reason. */
238
239 /* Create a buffer which has enough room to contain the TOKEN_DEFAULT_DACL
240 structure plus an ACL with one ACE. */
241 size_t bufferSize = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE)
242 + GetLengthSid (everyOneSID.theSID ()) - sizeof (DWORD);
243
244 std::auto_ptr<char> buf (new char[bufferSize]);
245
246 /* First initialize the TOKEN_DEFAULT_DACL structure. */
247 PACL dacl = (PACL) buf.get ();
248
249 /* Initialize the ACL for containing one ACE. */
250 if (!InitializeAcl (dacl, bufferSize, ACL_REVISION))
251 {
252 NoteFailedAPI ("InitializeAcl");
253 return;
254 }
255
256 /* Create the ACE which grants full access to "Everyone" and store it
257 in dacl. */
258 if (!AddAccessAllowedAce
259 (dacl, ACL_REVISION, GENERIC_ALL, everyOneSID.theSID ()))
260 {
261 NoteFailedAPI ("AddAccessAllowedAce");
262 return;
263 }
264
265 /* Set the default DACL to the above computed ACL. */
266 if (!SetTokenInformation (token.theHANDLE(), TokenDefaultDacl, &dacl,
267 bufferSize))
268 NoteFailedAPI ("SetTokenInformation");
269 }
270
271 void
272 NTSecurity::setBackupPrivileges ()
273 {
274 LUID backup, restore;
275 if (!LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &backup))
276 NoteFailedAPI ("LookupPrivilegeValue");
277 else if (!LookupPrivilegeValue (NULL, SE_RESTORE_NAME, &restore))
278 NoteFailedAPI ("LookupPrivilegeValue");
279 else
280 {
281 PTOKEN_PRIVILEGES new_privs;
282
283 new_privs = (PTOKEN_PRIVILEGES) alloca (sizeof (TOKEN_PRIVILEGES)
284 + sizeof (LUID_AND_ATTRIBUTES));
285 new_privs->PrivilegeCount = 2;
286 new_privs->Privileges[0].Luid = backup;
287 new_privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
288 new_privs->Privileges[1].Luid = restore;
289 new_privs->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
290 if (!AdjustTokenPrivileges (token.theHANDLE (), FALSE, new_privs,
291 0, NULL, NULL))
292 NoteFailedAPI ("AdjustTokenPrivileges");
293 else if (GetLastError () == ERROR_NOT_ALL_ASSIGNED)
294 log (LOG_TIMESTAMP) << "User has NO backup/restore rights" << endLog;
295 else
296 log (LOG_TIMESTAMP) << "User has backup/restore rights" << endLog;
297 }
298 }
299
300 void
301 NTSecurity::resetPrimaryGroup ()
302 {
303 if (primaryGroupSID.pgrp.PrimaryGroup)
304 {
305 log (LOG_TIMESTAMP) << "Changing gid back to original" << endLog;
306 if (!SetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
307 &primaryGroupSID, sizeof primaryGroupSID))
308 NoteFailedAPI ("SetTokenInformation");
309 }
310 }
311
312 void
313 NTSecurity::setAdminGroup ()
314 {
315 TOKEN_PRIMARY_GROUP tpg;
316
317 tpg.PrimaryGroup = administratorsSID.theSID ();
318 log (LOG_TIMESTAMP) << "Changing gid to Administrators" << endLog;
319 if (!SetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
320 &tpg, sizeof tpg))
321 NoteFailedAPI ("SetTokenInformation");
322 else
323 groupSID = administratorsSID.theSID ();
324 }
325
326 void
327 NTSecurity::setDefaultSecurity ()
328 {
329 /* Get the processes access token. */
330 if (!OpenProcessToken (GetCurrentProcess (),
331 TOKEN_READ | TOKEN_ADJUST_DEFAULT
332 | TOKEN_ADJUST_PRIVILEGES, &token.theHANDLE ()))
333 {
334 NoteFailedAPI ("OpenProcessToken");
335 return;
336 }
337
338 /* Set backup and restore privileges if available. */
339 setBackupPrivileges ();
340
341 /* If initializing the well-known SIDs didn't work, we're finished here. */
342 if (!wellKnownSIDsinitialized ())
343 return;
344
345 /* Set the default DACL to all permissions for everyone as a fallback. */
346 setDefaultDACL ();
347
348 /* Get the user */
349 if (!GetTokenInformation (token.theHANDLE (), TokenUser, &ownerSID,
350 sizeof ownerSID, &size))
351 {
352 NoteFailedAPI ("GetTokenInformation(user)");
353 return;
354 }
355 /* Make it the owner */
356 TOKEN_OWNER owner = { ownerSID.user.User.Sid };
357 if (!SetTokenInformation (token.theHANDLE (), TokenOwner, &owner,
358 sizeof owner))
359 {
360 NoteFailedAPI ("SetTokenInformation(owner)");
361 return;
362 }
363 /* Get original primary group. The token's primary group will be reset
364 to the original group right before we call the postinstall scripts.
365 This is necessary, otherwise, if the installing user is a domain user,
366 the group information created by the postinstall calls to `mkpasswd -c,
367 mkgroup -c' will be plain wrong. */
368 if (!GetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
369 &primaryGroupSID, sizeof primaryGroupSID, &size))
370 {
371 NoteFailedAPI("GetTokenInformation(pgrp)");
372 primaryGroupSID.pgrp.PrimaryGroup = (PSID) NULL;
373 }
374 groupSID = primaryGroupSID.pgrp.PrimaryGroup;
375 /* Try to set the primary group to the Administrators group, but only if
376 "Install for all users" has been chosen. If it doesn't work, we're
377 no admin and that's all there's to say about it. */
378 if (root_scope == IDC_ROOT_SYSTEM)
379 setAdminGroup ();
380 }
381
382 bool
383 NTSecurity::isRunAsAdmin ()
384 {
385 BOOL is_run_as_admin = FALSE;
386 if (!CheckTokenMembership(NULL, administratorsSID.theSID (), &is_run_as_admin))
387 NoteFailedAPI("CheckTokenMembership(administratorsSID)");
388 return (is_run_as_admin == TRUE);
389 }
390
391
392 VersionInfo::VersionInfo ()
393 {
394 v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
395 if (GetVersionEx (&v) == 0)
396 {
397 log (LOG_PLAIN) << "GetVersionEx () failed: " << GetLastError ()
398 << endLog;
399
400 /* If GetVersionEx fails we really should bail with an error of some kind,
401 but for now just assume we're on NT and continue. */
402 v.dwPlatformId = VER_PLATFORM_WIN32_NT;
403 }
404 }
405
406 /* This is the Construct on First Use idiom to avoid static initialization
407 order problems. */
408 VersionInfo& GetVer ()
409 {
410 static VersionInfo *vi = new VersionInfo ();
411 return *vi;
412 }
This page took 0.058996 seconds and 6 git commands to generate.