| OLD | NEW |
| (Empty) |
| 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 { | |
| 40 #ifdef WINCE /* not supported */ | |
| 41 return; | |
| 42 #else | |
| 43 SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; | |
| 44 HANDLE hToken = NULL; /* initialized to an arbitrary value to | |
| 45 * silence a Purify UMR warning */ | |
| 46 PSID infoBuffer[1024/sizeof(PSID)]; /* defined as an array of PSIDs | |
| 47 * to force proper alignment */ | |
| 48 PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) infoBuffer; | |
| 49 PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup | |
| 50 = (PTOKEN_PRIMARY_GROUP) infoBuffer; | |
| 51 DWORD dwLength; | |
| 52 BOOL rv; | |
| 53 | |
| 54 /* | |
| 55 * Look up and make a copy of the owner and primary group | |
| 56 * SIDs in the access token of the calling process. | |
| 57 */ | |
| 58 rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken); | |
| 59 if (rv == 0) { | |
| 60 /* | |
| 61 * On non-NT systems, this function is not implemented | |
| 62 * (error code ERROR_CALL_NOT_IMPLEMENTED), and neither are | |
| 63 * the other security functions. There is no point in | |
| 64 * going further. | |
| 65 * | |
| 66 * A process with insufficient access permissions may fail | |
| 67 * with the error code ERROR_ACCESS_DENIED. | |
| 68 */ | |
| 69 PR_LOG(_pr_io_lm, PR_LOG_DEBUG, | |
| 70 ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d", | |
| 71 GetLastError())); | |
| 72 return; | |
| 73 } | |
| 74 | |
| 75 rv = GetTokenInformation(hToken, TokenOwner, infoBuffer, | |
| 76 sizeof(infoBuffer), &dwLength); | |
| 77 PR_ASSERT(rv != 0); | |
| 78 dwLength = GetLengthSid(pTokenOwner->Owner); | |
| 79 _pr_nt_sids.owner = (PSID) PR_Malloc(dwLength); | |
| 80 PR_ASSERT(_pr_nt_sids.owner != NULL); | |
| 81 rv = CopySid(dwLength, _pr_nt_sids.owner, pTokenOwner->Owner); | |
| 82 PR_ASSERT(rv != 0); | |
| 83 | |
| 84 rv = GetTokenInformation(hToken, TokenPrimaryGroup, infoBuffer, | |
| 85 sizeof(infoBuffer), &dwLength); | |
| 86 PR_ASSERT(rv != 0); | |
| 87 dwLength = GetLengthSid(pTokenPrimaryGroup->PrimaryGroup); | |
| 88 _pr_nt_sids.group = (PSID) PR_Malloc(dwLength); | |
| 89 PR_ASSERT(_pr_nt_sids.group != NULL); | |
| 90 rv = CopySid(dwLength, _pr_nt_sids.group, | |
| 91 pTokenPrimaryGroup->PrimaryGroup); | |
| 92 PR_ASSERT(rv != 0); | |
| 93 | |
| 94 rv = CloseHandle(hToken); | |
| 95 PR_ASSERT(rv != 0); | |
| 96 | |
| 97 /* Create a well-known SID for the Everyone group. */ | |
| 98 rv = AllocateAndInitializeSid(&SIDAuthWorld, 1, | |
| 99 SECURITY_WORLD_RID, | |
| 100 0, 0, 0, 0, 0, 0, 0, | |
| 101 &_pr_nt_sids.everyone); | |
| 102 PR_ASSERT(rv != 0); | |
| 103 #endif | |
| 104 } | |
| 105 | |
| 106 /* | |
| 107 * Free the SIDs for owner, primary group, and the Everyone group | |
| 108 * in the _pr_nt_sids structure. | |
| 109 * | |
| 110 * This function needs to be called by NSPR cleanup. | |
| 111 */ | |
| 112 void | |
| 113 _PR_NT_FreeSids(void) | |
| 114 { | |
| 115 #ifdef WINCE | |
| 116 return; | |
| 117 #else | |
| 118 if (_pr_nt_sids.owner) { | |
| 119 PR_Free(_pr_nt_sids.owner); | |
| 120 } | |
| 121 if (_pr_nt_sids.group) { | |
| 122 PR_Free(_pr_nt_sids.group); | |
| 123 } | |
| 124 if (_pr_nt_sids.everyone) { | |
| 125 FreeSid(_pr_nt_sids.everyone); | |
| 126 } | |
| 127 #endif | |
| 128 } | |
| 129 | |
| 130 /* | |
| 131 * Construct a security descriptor whose discretionary access-control | |
| 132 * list implements the specified mode bits. The SIDs for owner, group, | |
| 133 * and everyone are obtained from the global _pr_nt_sids structure. | |
| 134 * Both the security descriptor and access-control list are returned | |
| 135 * and should be freed by a _PR_NT_FreeSecurityDescriptorACL call. | |
| 136 * | |
| 137 * The accessTable array maps NSPR's read, write, and execute access | |
| 138 * rights to the corresponding NT access rights for the securable | |
| 139 * object. | |
| 140 */ | |
| 141 PRStatus | |
| 142 _PR_NT_MakeSecurityDescriptorACL( | |
| 143 PRIntn mode, | |
| 144 DWORD accessTable[], | |
| 145 PSECURITY_DESCRIPTOR *resultSD, | |
| 146 PACL *resultACL) | |
| 147 { | |
| 148 #ifdef WINCE | |
| 149 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 150 return PR_FAILURE; | |
| 151 #else | |
| 152 PSECURITY_DESCRIPTOR pSD = NULL; | |
| 153 PACL pACL = NULL; | |
| 154 DWORD cbACL; /* size of ACL */ | |
| 155 DWORD accessMask; | |
| 156 | |
| 157 if (_pr_nt_sids.owner == NULL) { | |
| 158 PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0); | |
| 159 return PR_FAILURE; | |
| 160 } | |
| 161 | |
| 162 pSD = (PSECURITY_DESCRIPTOR) PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH); | |
| 163 if (pSD == NULL) { | |
| 164 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 165 goto failed; | |
| 166 } | |
| 167 if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { | |
| 168 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 169 goto failed; | |
| 170 } | |
| 171 if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) { | |
| 172 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 173 goto failed; | |
| 174 } | |
| 175 if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) { | |
| 176 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 177 goto failed; | |
| 178 } | |
| 179 | |
| 180 /* | |
| 181 * Construct a discretionary access-control list with three | |
| 182 * access-control entries, one each for owner, primary group, | |
| 183 * and Everyone. | |
| 184 */ | |
| 185 | |
| 186 cbACL = sizeof(ACL) | |
| 187 + 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) | |
| 188 + GetLengthSid(_pr_nt_sids.owner) | |
| 189 + GetLengthSid(_pr_nt_sids.group) | |
| 190 + GetLengthSid(_pr_nt_sids.everyone); | |
| 191 pACL = (PACL) PR_Malloc(cbACL); | |
| 192 if (pACL == NULL) { | |
| 193 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 194 goto failed; | |
| 195 } | |
| 196 if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) { | |
| 197 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 198 goto failed; | |
| 199 } | |
| 200 accessMask = 0; | |
| 201 if (mode & 00400) accessMask |= accessTable[0]; | |
| 202 if (mode & 00200) accessMask |= accessTable[1]; | |
| 203 if (mode & 00100) accessMask |= accessTable[2]; | |
| 204 if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, | |
| 205 _pr_nt_sids.owner)) { | |
| 206 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 207 goto failed; | |
| 208 } | |
| 209 accessMask = 0; | |
| 210 if (mode & 00040) accessMask |= accessTable[0]; | |
| 211 if (mode & 00020) accessMask |= accessTable[1]; | |
| 212 if (mode & 00010) accessMask |= accessTable[2]; | |
| 213 if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, | |
| 214 _pr_nt_sids.group)) { | |
| 215 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 216 goto failed; | |
| 217 } | |
| 218 accessMask = 0; | |
| 219 if (mode & 00004) accessMask |= accessTable[0]; | |
| 220 if (mode & 00002) accessMask |= accessTable[1]; | |
| 221 if (mode & 00001) accessMask |= accessTable[2]; | |
| 222 if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask, | |
| 223 _pr_nt_sids.everyone)) { | |
| 224 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 225 goto failed; | |
| 226 } | |
| 227 | |
| 228 if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) { | |
| 229 _PR_MD_MAP_DEFAULT_ERROR(GetLastError()); | |
| 230 goto failed; | |
| 231 } | |
| 232 | |
| 233 *resultSD = pSD; | |
| 234 *resultACL = pACL; | |
| 235 return PR_SUCCESS; | |
| 236 | |
| 237 failed: | |
| 238 if (pSD) { | |
| 239 PR_Free(pSD); | |
| 240 } | |
| 241 if (pACL) { | |
| 242 PR_Free(pACL); | |
| 243 } | |
| 244 return PR_FAILURE; | |
| 245 #endif | |
| 246 } | |
| 247 | |
| 248 /* | |
| 249 * Free the specified security descriptor and access-control list | |
| 250 * previously created by _PR_NT_MakeSecurityDescriptorACL. | |
| 251 */ | |
| 252 void | |
| 253 _PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL) | |
| 254 { | |
| 255 if (pSD) { | |
| 256 PR_Free(pSD); | |
| 257 } | |
| 258 if (pACL) { | |
| 259 PR_Free(pACL); | |
| 260 } | |
| 261 } | |
| OLD | NEW |