]> cygwin.com Git - cygwin-apps/setup.git/blob - win32.cc
* win32.h (NTSecurity::primaryGroupSID): Convert to a structure for
[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
28 NTSecurity nt_sec;
29
30 void
31 TokenGroupCollection::populate ()
32 {
33 if (!GetTokenInformation (token.theHANDLE(), TokenGroups, buffer,
34 bufferSize, &bufferSize))
35 {
36 log (LOG_TIMESTAMP) << "GetTokenInformation() failed: " <<
37 GetLastError () << endLog;
38 return;
39 }
40 populated_ = true;
41 }
42
43 bool
44 TokenGroupCollection::find (SIDWrapper const &aSID) const
45 {
46 if (!populated ())
47 return false;
48 TOKEN_GROUPS *groups = (TOKEN_GROUPS *) buffer;
49 for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
50 if (EqualSid (groups->Groups[pg].Sid, aSID.theSID ()))
51 return true;
52 return false;
53 }
54
55 void
56 NTSecurity::SetPosixPerms (const char *fname, HANDLE fh, mode_t mode)
57 {
58 struct {
59 SECURITY_DESCRIPTOR sd;
60 char sidbuf[2 * MAX_SID_LEN];
61 } in_sd;
62 SECURITY_DESCRIPTOR out_sd;
63 DWORD len, attribute;
64 BOOL dummy;
65 PSID owner_sid = NULL;
66 PSID group_sid = NULL;
67 struct {
68 ACL acl;
69 char aclbuf[4 * (sizeof (ACCESS_ALLOWED_ACE) + MAX_SID_LEN)];
70 } acl;
71
72 if (!IsWindowsNT () || !wellKnownSIDsinitialized ())
73 return;
74 /* Get file's owner and group. */
75 if (!GetKernelObjectSecurity (fh, OWNER_SECURITY_INFORMATION
76 | GROUP_SECURITY_INFORMATION,
77 &in_sd.sd, sizeof in_sd, &len))
78 {
79 log (LOG_TIMESTAMP) << "GetKernelObjectSecurity(" << fname << ") failed: "
80 << GetLastError () << endLog;
81 return;
82 }
83 if (!GetSecurityDescriptorOwner (&in_sd.sd, &owner_sid, &dummy))
84 log (LOG_TIMESTAMP) << "GetSecurityDescriptorOwner(" << fname
85 << ") failed: " << GetLastError () << endLog;
86 if (!GetSecurityDescriptorGroup (&in_sd.sd, &group_sid, &dummy))
87 log (LOG_TIMESTAMP) << "GetSecurityDescriptorGroup(" << fname
88 << ") failed: " << GetLastError () << endLog;
89
90 /* Initialize out SD */
91 if (!InitializeSecurityDescriptor (&out_sd, SECURITY_DESCRIPTOR_REVISION))
92 log (LOG_TIMESTAMP) << "InitializeSecurityDescriptor(" << fname
93 << ") failed: " << GetLastError () << endLog;
94 if (OSMajorVersion () >= 5)
95 out_sd.Control |= SE_DACL_PROTECTED;
96
97 /* Initialize ACL and fill with almost POSIX-like permissions.
98 Note that the current user always requires write permissions, otherwise
99 creating files in directories with restricted permissions fails. */
100 if (!InitializeAcl (&acl.acl , sizeof acl, ACL_REVISION))
101 log (LOG_TIMESTAMP) << "InitializeAcl(" << fname << ") failed: "
102 << GetLastError () << endLog;
103 attribute = STANDARD_RIGHTS_ALL | FILE_GENERIC_READ | FILE_GENERIC_WRITE;
104 if (mode & 0100) // S_IXUSR
105 attribute |= FILE_GENERIC_EXECUTE;
106 if ((mode & 0300) == 0300) // S_IWUSR | S_IXUSR
107 attribute |= FILE_DELETE_CHILD;
108 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, attribute, owner_sid))
109 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
110 << ", owner) failed: " << GetLastError () << endLog;
111 attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
112 if (mode & 0040) // S_IRGRP
113 attribute |= FILE_GENERIC_READ;
114 if (mode & 0020) // S_IWGRP
115 attribute |= FILE_GENERIC_WRITE;
116 if (mode & 0010) // S_IXGRP
117 attribute |= FILE_GENERIC_EXECUTE;
118 if ((mode & 01030) == 00030) // S_IWGRP | S_IXGRP, !S_ISVTX
119 attribute |= FILE_DELETE_CHILD;
120 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, attribute, group_sid))
121 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
122 << ", group) failed: " << GetLastError () << endLog;
123 attribute = STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES;
124 if (mode & 0004) // S_IROTH
125 attribute |= FILE_GENERIC_READ;
126 if (mode & 0002) // S_IWOTH
127 attribute |= FILE_GENERIC_WRITE;
128 if (mode & 0001) // S_IXOTH
129 attribute |= FILE_GENERIC_EXECUTE;
130 if ((mode & 01003) == 00003) // S_IWOTH | S_IXOTH, !S_ISVTX
131 attribute |= FILE_DELETE_CHILD;
132 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, attribute,
133 everyOneSID.theSID ()))
134 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
135 << ", everyone) failed: " << GetLastError () << endLog;
136 if (mode & 07000) /* At least one of S_ISUID, S_ISGID, S_ISVTX */
137 {
138 attribute = 0;
139 if (mode & 04000) // S_ISUID
140 attribute |= FILE_APPEND_DATA;
141 if (mode & 02000) // S_ISGID
142 attribute |= FILE_WRITE_DATA;
143 if (mode & 01000) // S_ISVTX
144 attribute |= FILE_READ_DATA;
145 if (!AddAccessAllowedAce (&acl.acl, ACL_REVISION, attribute,
146 nullSID.theSID ()))
147 log (LOG_TIMESTAMP) << "AddAccessAllowedAce(" << fname
148 << ", null) failed: " << GetLastError () << endLog;
149 }
150
151 /* Set SD's DACL to just created ACL. */
152 if (!SetSecurityDescriptorDacl (&out_sd, TRUE, &acl.acl, FALSE))
153 log (LOG_TIMESTAMP) << "SetSecurityDescriptorDacl(" << fname
154 << ") failed: " << GetLastError () << endLog;
155
156 /* Write DACL back to file. */
157 if (!SetKernelObjectSecurity (fh, DACL_SECURITY_INFORMATION, &out_sd))
158 log (LOG_TIMESTAMP) << "SetKernelObjectSecurity(" << fname << ") failed: "
159 << GetLastError () << endLog;
160 }
161
162 void
163 NTSecurity::NoteFailedAPI (const std::string &api)
164 {
165 log (LOG_TIMESTAMP) << api << "() failed: " << GetLastError () << endLog;
166 }
167
168 void
169 NTSecurity::initialiseWellKnownSIDs ()
170 {
171 SID_IDENTIFIER_AUTHORITY n_sid_auth = { SECURITY_NULL_SID_AUTHORITY };
172 /* Get the SID for "NULL" S-1-0-0 */
173 if (!AllocateAndInitializeSid (&n_sid_auth, 1, SECURITY_NULL_RID,
174 0, 0, 0, 0, 0, 0, 0, &nullSID.theSID ()))
175 {
176 NoteFailedAPI ("AllocateAndInitializeSid(null)");
177 return;
178 }
179 SID_IDENTIFIER_AUTHORITY e_sid_auth = { SECURITY_WORLD_SID_AUTHORITY };
180 /* Get the SID for "Everyone" S-1-1-0 */
181 if (!AllocateAndInitializeSid (&e_sid_auth, 1, SECURITY_WORLD_RID,
182 0, 0, 0, 0, 0, 0, 0, &everyOneSID.theSID ()))
183 {
184 NoteFailedAPI ("AllocateAndInitializeSid(everyone)");
185 return;
186 }
187 SID_IDENTIFIER_AUTHORITY nt_sid_auth = { SECURITY_NT_AUTHORITY };
188 /* Get the SID for "Administrators" S-1-5-32-544 */
189 if (!AllocateAndInitializeSid (&nt_sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
190 DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
191 &administratorsSID.theSID ()))
192 {
193 NoteFailedAPI ("AllocateAndInitializeSid(admins)");
194 return;
195 }
196 /* Get the SID for "Users" S-1-5-32-545 */
197 if (!AllocateAndInitializeSid (&nt_sid_auth, 2, SECURITY_BUILTIN_DOMAIN_RID,
198 DOMAIN_ALIAS_RID_USERS, 0, 0, 0, 0, 0, 0,
199 &usersSID.theSID ()))
200 {
201 NoteFailedAPI ("AllocateAndInitializeSid(users)");
202 return;
203 }
204 wellKnownSIDsinitialized (true);
205 }
206
207 void
208 NTSecurity::setDefaultDACL ()
209 {
210 /* To assure that the created files have a useful ACL, the
211 default DACL in the process token is set to full access to
212 everyone. This applies to files and subdirectories created
213 in directories which don't propagate permissions to child
214 objects.
215 To assure that the files group is meaningful, a token primary
216 group of None is changed to Users or Administrators.
217 This is the fallback if real POSIX permissions don't
218 work for some reason. */
219
220 /* Create a buffer which has enough room to contain the TOKEN_DEFAULT_DACL
221 structure plus an ACL with one ACE. */
222 size_t bufferSize = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE)
223 + GetLengthSid (everyOneSID.theSID ()) - sizeof (DWORD);
224
225 std::auto_ptr<char> buf (new char[bufferSize]);
226
227 /* First initialize the TOKEN_DEFAULT_DACL structure. */
228 PACL dacl = (PACL) buf.get ();
229
230 /* Initialize the ACL for containing one ACE. */
231 if (!InitializeAcl (dacl, bufferSize, ACL_REVISION))
232 {
233 NoteFailedAPI ("InitializeAcl");
234 return;
235 }
236
237 /* Create the ACE which grants full access to "Everyone" and store it
238 in dacl. */
239 if (!AddAccessAllowedAce
240 (dacl, ACL_REVISION, GENERIC_ALL, everyOneSID.theSID ()))
241 {
242 NoteFailedAPI ("AddAccessAllowedAce");
243 return;
244 }
245
246 /* Set the default DACL to the above computed ACL. */
247 if (!SetTokenInformation (token.theHANDLE(), TokenDefaultDacl, &dacl,
248 bufferSize))
249 NoteFailedAPI ("SetTokenInformation");
250 }
251
252 void
253 NTSecurity::setBackupPrivileges ()
254 {
255 LUID backup, restore;
256 if (!LookupPrivilegeValue (NULL, SE_BACKUP_NAME, &backup))
257 NoteFailedAPI ("LookupPrivilegeValue");
258 else if (!LookupPrivilegeValue (NULL, SE_RESTORE_NAME, &restore))
259 NoteFailedAPI ("LookupPrivilegeValue");
260 else
261 {
262 PTOKEN_PRIVILEGES new_privs;
263
264 new_privs = (PTOKEN_PRIVILEGES) alloca (sizeof (TOKEN_PRIVILEGES)
265 + sizeof (LUID_AND_ATTRIBUTES));
266 new_privs->PrivilegeCount = 2;
267 new_privs->Privileges[0].Luid = backup;
268 new_privs->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
269 new_privs->Privileges[1].Luid = restore;
270 new_privs->Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
271 if (!AdjustTokenPrivileges (token.theHANDLE (), FALSE, new_privs,
272 0, NULL, NULL))
273 NoteFailedAPI ("AdjustTokenPrivileges");
274 else if (GetLastError () == ERROR_NOT_ALL_ASSIGNED)
275 log (LOG_TIMESTAMP) << "User has NO backup/restore rights" << endLog;
276 else
277 log (LOG_TIMESTAMP) << "User has backup/restore rights" << endLog;
278 }
279 }
280
281 void
282 NTSecurity::resetPrimaryGroup ()
283 {
284 if (primaryGroupSID.pgrp.PrimaryGroup)
285 {
286 log (LOG_TIMESTAMP) << "Changing gid back to original" << endLog;
287 if (!SetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
288 &primaryGroupSID, sizeof primaryGroupSID))
289 NoteFailedAPI ("SetTokenInformation");
290 }
291 }
292
293 void
294 NTSecurity::setAdminGroup ()
295 {
296 TOKEN_PRIMARY_GROUP tpg;
297
298 tpg.PrimaryGroup = administratorsSID.theSID ();
299 log (LOG_TIMESTAMP) << "Changing gid to Administrators" << endLog;
300 if (!SetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
301 &tpg, sizeof tpg))
302 NoteFailedAPI ("SetTokenInformation");
303 }
304
305 void
306 NTSecurity::setDefaultSecurity ()
307 {
308 /* First initialize the well known SIDs used later on. */
309 initialiseWellKnownSIDs ();
310
311 /* Get the processes access token. */
312 if (!OpenProcessToken (GetCurrentProcess (),
313 TOKEN_READ | TOKEN_ADJUST_DEFAULT
314 | TOKEN_ADJUST_PRIVILEGES, &token.theHANDLE ()))
315 {
316 NoteFailedAPI ("OpenProcessToken");
317 return;
318 }
319
320 /* Set backup and restore privileges if available. */
321 setBackupPrivileges ();
322
323 /* If initializing the well-known SIDs didn't work, we're finished here. */
324 if (!wellKnownSIDsinitialized ())
325 return;
326
327 /* Set the default DACL to all permissions for everyone as a fallback. */
328 setDefaultDACL ();
329
330 /* Get the user */
331 struct {
332 TOKEN_USER user;
333 char buf[MAX_SID_LEN];
334 } tuser;
335 if (!GetTokenInformation (token.theHANDLE (), TokenUser, &tuser,
336 sizeof tuser, &size))
337 {
338 NoteFailedAPI ("GetTokenInformation(user)");
339 return;
340 }
341 /* Make it the owner */
342 TOKEN_OWNER owner = { tuser.user.User.Sid };
343 if (!SetTokenInformation (token.theHANDLE (), TokenOwner, &owner,
344 sizeof owner))
345 {
346 NoteFailedAPI ("SetTokenInformation(owner)");
347 return;
348 }
349 /* Get original primary group. The token's primary group will be reset
350 to the original group right before we call the postinstall scripts.
351 This is necessary, otherwise, if the installing user is a domain user,
352 the group information created by the postinstall calls to `mkpasswd -c,
353 mkgroup -c' will be plain wrong. */
354 if (!GetTokenInformation (token.theHANDLE (), TokenPrimaryGroup,
355 &primaryGroupSID, sizeof primaryGroupSID, &size))
356 {
357 NoteFailedAPI("GetTokenInformation(pgrp)");
358 primaryGroupSID.pgrp.PrimaryGroup = (PSID) NULL;
359 }
360 /* Get the token groups */
361 if (!GetTokenInformation (token.theHANDLE(), TokenGroups, NULL, 0, &size)
362 && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
363 {
364 NoteFailedAPI("GetTokenInformation(groups)");
365 return;
366 }
367 TokenGroupCollection ntGroups(size, token);
368 ntGroups.populate ();
369 if (!ntGroups.populated ())
370 return;
371 /* Set the primary group to the Administrators group, but only if
372 the user is admin and if "Install for all users" has been chosen. */
373 if (root_scope == IDC_ROOT_SYSTEM && ntGroups.find (administratorsSID))
374 setAdminGroup ();
375 }
376
377 VersionInfo::VersionInfo ()
378 {
379 v.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
380 if (GetVersionEx (&v) == 0)
381 {
382 log (LOG_PLAIN) << "GetVersionEx () failed: " << GetLastError ()
383 << endLog;
384
385 /* If GetVersionEx fails we really should bail with an error of some kind,
386 but for now just assume we're on NT and continue. */
387 v.dwPlatformId = VER_PLATFORM_WIN32_NT;
388 }
389 }
390
391 /* This is the Construct on First Use idiom to avoid static initialization
392 order problems. */
393 VersionInfo& GetVer ()
394 {
395 static VersionInfo *vi = new VersionInfo ();
396 return *vi;
397 }
This page took 0.08724 seconds and 6 git commands to generate.