ntsec.c (7794B)
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/. */ 5 6 #include "primpl.h" 7 8 /* 9 * ntsec.c 10 * 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. 15 */ 16 17 /* 18 * The security identifiers (SIDs) for owner, primary group, 19 * and the Everyone (World) group. 20 * 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. 25 */ 26 static struct { 27 PSID owner; 28 PSID group; 29 PSID everyone; 30 } _pr_nt_sids; 31 32 /* 33 * Initialize the SIDs for owner, primary group, and the Everyone 34 * group in the _pr_nt_sids structure. 35 * 36 * This function needs to be called by NSPR initialization. 37 */ 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; 51 52 /* 53 * Look up and make a copy of the owner and primary group 54 * SIDs in the access token of the calling process. 55 */ 56 rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); 57 if (rv == 0) { 58 /* 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. 63 * 64 * A process with insufficient access permissions may fail 65 * with the error code ERROR_ACCESS_DENIED. 66 */ 67 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, 68 ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d", 69 GetLastError())); 70 return; 71 } 72 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); 81 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); 90 91 rv = CloseHandle(hToken); 92 PR_ASSERT(rv != 0); 93 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 99 } 100 101 /* 102 * Free the SIDs for owner, primary group, and the Everyone group 103 * in the _pr_nt_sids structure. 104 * 105 * This function needs to be called by NSPR cleanup. 106 */ 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); 113 } 114 if (_pr_nt_sids.group) { 115 PR_Free(_pr_nt_sids.group); 116 } 117 if (_pr_nt_sids.everyone) { 118 FreeSid(_pr_nt_sids.everyone); 119 } 120 #endif 121 } 122 123 /* 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. 129 * 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. 133 */ 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; 145 146 if (_pr_nt_sids.owner == NULL) { 147 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); 148 return PR_FAILURE; 149 } 150 151 pSD = (PSECURITY_DESCRIPTOR)PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); 152 if (pSD == NULL) { 153 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 154 goto failed; 155 } 156 if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { 157 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 158 goto failed; 159 } 160 if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) { 161 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 162 goto failed; 163 } 164 if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) { 165 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 166 goto failed; 167 } 168 169 /* 170 * Construct a discretionary access-control list with three 171 * access-control entries, one each for owner, primary group, 172 * and Everyone. 173 */ 174 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; 182 } 183 if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) { 184 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 185 goto failed; 186 } 187 accessMask = 0; 188 if (mode & 00400) { 189 accessMask |= accessTable[0]; 190 } 191 if (mode & 00200) { 192 accessMask |= accessTable[1]; 193 } 194 if (mode & 00100) { 195 accessMask |= accessTable[2]; 196 } 197 if (accessMask && 198 !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, _pr_nt_sids.owner)) { 199 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 200 goto failed; 201 } 202 accessMask = 0; 203 if (mode & 00040) { 204 accessMask |= accessTable[0]; 205 } 206 if (mode & 00020) { 207 accessMask |= accessTable[1]; 208 } 209 if (mode & 00010) { 210 accessMask |= accessTable[2]; 211 } 212 if (accessMask && 213 !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, _pr_nt_sids.group)) { 214 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 215 goto failed; 216 } 217 accessMask = 0; 218 if (mode & 00004) { 219 accessMask |= accessTable[0]; 220 } 221 if (mode & 00002) { 222 accessMask |= accessTable[1]; 223 } 224 if (mode & 00001) { 225 accessMask |= accessTable[2]; 226 } 227 if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, 228 _pr_nt_sids.everyone)) { 229 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 230 goto failed; 231 } 232 233 if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) { 234 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); 235 goto failed; 236 } 237 238 *resultSD = pSD; 239 *resultACL = pACL; 240 return PR_SUCCESS; 241 242 failed: 243 if (pSD) { 244 PR_Free(pSD); 245 } 246 if (pACL) { 247 PR_Free(pACL); 248 } 249 return PR_FAILURE; 250 #endif 251 } 252 253 /* 254 * Free the specified security descriptor and access-control list 255 * previously created by _PR_NT_MakeSecurityDescriptorACL. 256 */ 257 void _PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL) { 258 if (pSD) { 259 PR_Free(pSD); 260 } 261 if (pACL) { 262 PR_Free(pACL); 263 } 264 }