Back to index

lightning-sunbird  0.9+nobinonly
ntsec.c
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is the Netscape Portable Runtime (NSPR).
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 2000
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 #include "primpl.h"
00039 
00040 /*
00041  * ntsec.c
00042  *
00043  * Implement the POSIX-style mode bits (access permissions) for
00044  * files and other securable objects in Windows NT using Windows
00045  * NT's security descriptors with appropriate discretionary
00046  * access-control lists.
00047  */
00048 
00049 /*
00050  * The security identifiers (SIDs) for owner, primary group,
00051  * and the Everyone (World) group.
00052  *
00053  * These SIDs are looked up during NSPR initialization and
00054  * saved in this global structure (see _PR_NT_InitSids) so
00055  * that _PR_NT_MakeSecurityDescriptorACL doesn't need to
00056  * look them up every time.
00057  */
00058 static struct {
00059     PSID owner;
00060     PSID group;
00061     PSID everyone;
00062 } _pr_nt_sids;
00063 
00064 /*
00065  * Initialize the SIDs for owner, primary group, and the Everyone
00066  * group in the _pr_nt_sids structure.
00067  *
00068  * This function needs to be called by NSPR initialization.
00069  */
00070 void _PR_NT_InitSids(void)
00071 {
00072     SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY;
00073     HANDLE hToken = NULL; /* initialized to an arbitrary value to
00074                            * silence a Purify UMR warning */
00075     UCHAR infoBuffer[1024];
00076     PTOKEN_OWNER pTokenOwner = (PTOKEN_OWNER) infoBuffer;
00077     PTOKEN_PRIMARY_GROUP pTokenPrimaryGroup
00078             = (PTOKEN_PRIMARY_GROUP) infoBuffer;
00079     DWORD dwLength;
00080     BOOL rv;
00081 
00082     /*
00083      * Look up and make a copy of the owner and primary group
00084      * SIDs in the access token of the calling process.
00085      */
00086     rv = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken);
00087     if (rv == 0) {
00088         /*
00089          * On non-NT systems, this function is not implemented
00090          * (error code ERROR_CALL_NOT_IMPLEMENTED), and neither are
00091          * the other security functions.  There is no point in
00092          * going further.
00093          *
00094          * A process with insufficient access permissions may fail
00095          * with the error code ERROR_ACCESS_DENIED.
00096          */
00097         PR_LOG(_pr_io_lm, PR_LOG_DEBUG,
00098                 ("_PR_NT_InitSids: OpenProcessToken() failed. Error: %d",
00099                 GetLastError()));
00100         return;
00101     }
00102 
00103     rv = GetTokenInformation(hToken, TokenOwner, infoBuffer,
00104             sizeof(infoBuffer), &dwLength);
00105     PR_ASSERT(rv != 0);
00106     dwLength = GetLengthSid(pTokenOwner->Owner);
00107     _pr_nt_sids.owner = (PSID) PR_Malloc(dwLength);
00108     PR_ASSERT(_pr_nt_sids.owner != NULL);
00109     rv = CopySid(dwLength, _pr_nt_sids.owner, pTokenOwner->Owner);
00110     PR_ASSERT(rv != 0);
00111 
00112     rv = GetTokenInformation(hToken, TokenPrimaryGroup, infoBuffer,
00113             sizeof(infoBuffer), &dwLength);
00114     PR_ASSERT(rv != 0);
00115     dwLength = GetLengthSid(pTokenPrimaryGroup->PrimaryGroup);
00116     _pr_nt_sids.group = (PSID) PR_Malloc(dwLength);
00117     PR_ASSERT(_pr_nt_sids.group != NULL);
00118     rv = CopySid(dwLength, _pr_nt_sids.group,
00119             pTokenPrimaryGroup->PrimaryGroup);
00120     PR_ASSERT(rv != 0);
00121 
00122     rv = CloseHandle(hToken);
00123     PR_ASSERT(rv != 0);
00124 
00125     /* Create a well-known SID for the Everyone group. */
00126     rv = AllocateAndInitializeSid(&SIDAuthWorld, 1,
00127             SECURITY_WORLD_RID,
00128             0, 0, 0, 0, 0, 0, 0,
00129             &_pr_nt_sids.everyone);
00130     PR_ASSERT(rv != 0);
00131 }
00132 
00133 /*
00134  * Free the SIDs for owner, primary group, and the Everyone group
00135  * in the _pr_nt_sids structure.
00136  *
00137  * This function needs to be called by NSPR cleanup.
00138  */
00139 void
00140 _PR_NT_FreeSids(void)
00141 {
00142     if (_pr_nt_sids.owner) {
00143         PR_Free(_pr_nt_sids.owner);
00144     }
00145     if (_pr_nt_sids.group) {
00146         PR_Free(_pr_nt_sids.group);
00147     }
00148     if (_pr_nt_sids.everyone) {
00149         FreeSid(_pr_nt_sids.everyone);
00150     }
00151 }
00152 
00153 /*
00154  * Construct a security descriptor whose discretionary access-control
00155  * list implements the specified mode bits.  The SIDs for owner, group,
00156  * and everyone are obtained from the global _pr_nt_sids structure.
00157  * Both the security descriptor and access-control list are returned
00158  * and should be freed by a _PR_NT_FreeSecurityDescriptorACL call.
00159  *
00160  * The accessTable array maps NSPR's read, write, and execute access
00161  * rights to the corresponding NT access rights for the securable
00162  * object.
00163  */
00164 PRStatus
00165 _PR_NT_MakeSecurityDescriptorACL(
00166     PRIntn mode,
00167     DWORD accessTable[],
00168     PSECURITY_DESCRIPTOR *resultSD,
00169     PACL *resultACL)
00170 {
00171     PSECURITY_DESCRIPTOR pSD = NULL;
00172     PACL pACL = NULL;
00173     DWORD cbACL;  /* size of ACL */
00174     DWORD accessMask;
00175 
00176     if (_pr_nt_sids.owner == NULL) {
00177         PR_SetError(PR_NOT_IMPLEMENTED_ERROR, 0);
00178         return PR_FAILURE;
00179     }
00180 
00181     pSD = (PSECURITY_DESCRIPTOR) PR_Malloc(SECURITY_DESCRIPTOR_MIN_LENGTH);
00182     if (pSD == NULL) {
00183         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00184         goto failed;
00185     }
00186     if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) {
00187         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00188         goto failed;
00189     }
00190     if (!SetSecurityDescriptorOwner(pSD, _pr_nt_sids.owner, FALSE)) {
00191         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00192         goto failed;
00193     }
00194     if (!SetSecurityDescriptorGroup(pSD, _pr_nt_sids.group, FALSE)) {
00195         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00196         goto failed;
00197     }
00198 
00199     /*
00200      * Construct a discretionary access-control list with three
00201      * access-control entries, one each for owner, primary group,
00202      * and Everyone.
00203      */
00204 
00205     cbACL = sizeof(ACL)
00206           + 3 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))
00207           + GetLengthSid(_pr_nt_sids.owner)
00208           + GetLengthSid(_pr_nt_sids.group)
00209           + GetLengthSid(_pr_nt_sids.everyone);
00210     pACL = (PACL) PR_Malloc(cbACL);
00211     if (pACL == NULL) {
00212         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00213         goto failed;
00214     }
00215     if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
00216         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00217         goto failed;
00218     }
00219     accessMask = 0;
00220     if (mode & 00400) accessMask |= accessTable[0];
00221     if (mode & 00200) accessMask |= accessTable[1];
00222     if (mode & 00100) accessMask |= accessTable[2];
00223     if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
00224             _pr_nt_sids.owner)) {
00225         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00226         goto failed;
00227     }
00228     accessMask = 0;
00229     if (mode & 00040) accessMask |= accessTable[0];
00230     if (mode & 00020) accessMask |= accessTable[1];
00231     if (mode & 00010) accessMask |= accessTable[2];
00232     if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
00233             _pr_nt_sids.group)) {
00234         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00235         goto failed;
00236     }
00237     accessMask = 0;
00238     if (mode & 00004) accessMask |= accessTable[0];
00239     if (mode & 00002) accessMask |= accessTable[1];
00240     if (mode & 00001) accessMask |= accessTable[2];
00241     if (accessMask && !AddAccessAllowedAce(pACL, ACL_REVISION, accessMask,
00242             _pr_nt_sids.everyone)) {
00243         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00244         goto failed;
00245     }
00246 
00247     if (!SetSecurityDescriptorDacl(pSD, TRUE, pACL, FALSE)) {
00248         _PR_MD_MAP_DEFAULT_ERROR(GetLastError());
00249         goto failed;
00250     }
00251 
00252     *resultSD = pSD;
00253     *resultACL = pACL;
00254     return PR_SUCCESS;
00255 
00256 failed:
00257     if (pSD) {
00258         PR_Free(pSD);
00259     }
00260     if (pACL) {
00261         PR_Free(pACL);
00262     }
00263     return PR_FAILURE;
00264 }
00265 
00266 /*
00267  * Free the specified security descriptor and access-control list
00268  * previously created by _PR_NT_MakeSecurityDescriptorACL.
00269  */
00270 void
00271 _PR_NT_FreeSecurityDescriptorACL(PSECURITY_DESCRIPTOR pSD, PACL pACL)
00272 {
00273     if (pSD) {
00274         PR_Free(pSD);
00275     }
00276     if (pACL) {
00277         PR_Free(pACL);
00278     }
00279 }