tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }