Bug 1946184 - Fix computing the CSD margin right after calling HideWindowChrome(...
[gecko.git] / nsprpub / pr / src / md / windows / ntsec.c
blobd551bd9f2a78cb2f85e7fcbec35bfe2fdb692ddc
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "primpl.h"
8 /*
9 * ntsec.c
11 * Implement the POSIX-style mode bits (access permissions) for
12 * files and other securable objects in Windows NT using Windows
13 * NT's security descriptors with appropriate discretionary
14 * access-control lists.
18 * The security identifiers (SIDs) for owner, primary group,
19 * and the Everyone (World) group.
21 * These SIDs are looked up during NSPR initialization and
22 * saved in this global structure (see _PR_NT_InitSids) so
23 * that _PR_NT_MakeSecurityDescriptorACL doesn't need to
24 * look them up every time.
26 static struct {
27 PSID owner;
28 PSID group;
29 PSID everyone;
30 } _pr_nt_sids;
33 * Initialize the SIDs for owner, primary group, and the Everyone
34 * group in the _pr_nt_sids structure.
36 * This function needs to be called by NSPR initialization.
38 void _PR_NT_InitSids(void) {
39 #ifdef WINCE /* not supported */
40 return;
41 #else
42 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
43 HANDLE hToken = NULL; /* initialized to an arbitrary value to
44 * silence a Purify UMR warning */
45 PSID infoBuffer[1024 / sizeof(PSID)]; /* defined as an array of PSIDs
46 * to force proper alignment */
47 PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER)infoBuffer;
48 PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup = (PTOKEN_PRIMARY_GROUP)infoBuffer;
49 DWORD dwLength;
50 BOOL rv;
53 * Look up and make a copy of the owner and primary group
54 * SIDs in the access token of the calling process.
56 rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
57 if (rv == 0) {
59 * On non-NT systems, this function is not implemented
60 * (error code ERROR_CALL_NOT_IMPLEMENTED), and neither are
61 * the other security functions. There is no point in
62 * going further.
64 * A process with insufficient access permissions may fail
65 * with the error code ERROR_ACCESS_DENIED.
67 PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
68 ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d",
69 GetLastError()));
70 return;
73 rv = GetTokenInformation(hToken, TokenOwner, infoBuffer, sizeof(infoBuffer),
74 &dwLength);
75 PR_ASSERT(rv != 0);
76 dwLength = GetLengthSid(pTokenOwner->Owner);
77 _pr_nt_sids.owner = (PSID)PR_Malloc(dwLength);
78 PR_ASSERT(_pr_nt_sids.owner != NULL);
79 rv = CopySid(dwLength, _pr_nt_sids.owner, pTokenOwner->Owner);
80 PR_ASSERT(rv != 0);
82 rv = GetTokenInformation(hToken, TokenPrimaryGroup, infoBuffer,
83 sizeof(infoBuffer), &dwLength);
84 PR_ASSERT(rv != 0);
85 dwLength = GetLengthSid(pTokenPrimaryGroup->PrimaryGroup);
86 _pr_nt_sids.group = (PSID)PR_Malloc(dwLength);
87 PR_ASSERT(_pr_nt_sids.group != NULL);
88 rv = CopySid(dwLength, _pr_nt_sids.group, pTokenPrimaryGroup->PrimaryGroup);
89 PR_ASSERT(rv != 0);
91 rv = CloseHandle(hToken);
92 PR_ASSERT(rv != 0);
94 /* Create a well-known SID for the Everyone group. */
95 rv = AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0,
96 0, 0, 0, 0, &_pr_nt_sids.everyone);
97 PR_ASSERT(rv != 0);
98 #endif
102 * Free the SIDs for owner, primary group, and the Everyone group
103 * in the _pr_nt_sids structure.
105 * This function needs to be called by NSPR cleanup.
107 void _PR_NT_FreeSids(void) {
108 #ifdef WINCE
109 return;
110 #else
111 if (_pr_nt_sids.owner) {
112 PR_Free(_pr_nt_sids.owner);
114 if (_pr_nt_sids.group) {
115 PR_Free(_pr_nt_sids.group);
117 if (_pr_nt_sids.everyone) {
118 FreeSid(_pr_nt_sids.everyone);
120 #endif
124 * Construct a security descriptor whose discretionary access-control
125 * list implements the specified mode bits. The SIDs for owner, group,
126 * and everyone are obtained from the global _pr_nt_sids structure.
127 * Both the security descriptor and access-control list are returned
128 * and should be freed by a _PR_NT_FreeSecurityDescriptorACL call.
130 * The accessTable array maps NSPR's read, write, and execute access
131 * rights to the corresponding NT access rights for the securable
132 * object.
134 PRStatus _PR_NT_MakeSecurityDescriptorACL(PRIntn mode, DWORD accessTable[],
135 PSECURITY_DESCRIPTOR* resultSD,
136 PACL* resultACL) {
137 #ifdef WINCE
138 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
139 return PR_FAILURE;
140 #else
141 PSECURITY_DESCRIPTOR pSD = NULL;
142 PACL pACL = NULL;
143 DWORD cbACL; /* size of ACL */
144 DWORD accessMask;
146 if (_pr_nt_sids.owner == NULL) {
147 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
148 return PR_FAILURE;
151 pSD = (PSECURITY_DESCRIPTOR)PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
152 if (pSD == NULL) {
153 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
154 goto failed;
156 if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
157 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
158 goto failed;
160 if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) {
161 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
162 goto failed;
164 if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) {
165 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
166 goto failed;
170 * Construct a discretionary access-control list with three
171 * access-control entries, one each for owner, primary group,
172 * and Everyone.
175 cbACL = sizeof(ACL) + 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) +
176 GetLengthSid(_pr_nt_sids.owner) + GetLengthSid(_pr_nt_sids.group) +
177 GetLengthSid(_pr_nt_sids.everyone);
178 pACL = (PACL)PR_Malloc(cbACL);
179 if (pACL == NULL) {
180 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
181 goto failed;
183 if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
184 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
185 goto failed;
187 accessMask = 0;
188 if (mode & 00400) {
189 accessMask |= accessTable[0];
191 if (mode & 00200) {
192 accessMask |= accessTable[1];
194 if (mode & 00100) {
195 accessMask |= accessTable[2];
197 if (accessMask &&
198 !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, _pr_nt_sids.owner)) {
199 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
200 goto failed;
202 accessMask = 0;
203 if (mode & 00040) {
204 accessMask |= accessTable[0];
206 if (mode & 00020) {
207 accessMask |= accessTable[1];
209 if (mode & 00010) {
210 accessMask |= accessTable[2];
212 if (accessMask &&
213 !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, _pr_nt_sids.group)) {
214 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
215 goto failed;
217 accessMask = 0;
218 if (mode & 00004) {
219 accessMask |= accessTable[0];
221 if (mode & 00002) {
222 accessMask |= accessTable[1];
224 if (mode & 00001) {
225 accessMask |= accessTable[2];
227 if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
228 _pr_nt_sids.everyone)) {
229 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
230 goto failed;
233 if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) {
234 _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
235 goto failed;
238 *resultSD = pSD;
239 *resultACL = pACL;
240 return PR_SUCCESS;
242 failed:
243 if (pSD) {
244 PR_Free(pSD);
246 if (pACL) {
247 PR_Free(pACL);
249 return PR_FAILURE;
250 #endif
254 * Free the specified security descriptor and access-control list
255 * previously created by _PR_NT_MakeSecurityDescriptorACL.
257 void _PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL) {
258 if (pSD) {
259 PR_Free(pSD);
261 if (pACL) {
262 PR_Free(pACL);