Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

856 lines
25 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: security.cxx
//
// Contents:
//
//--------------------------------------------------------------------------
#include "act.hxx"
#include <alloca.h>
#include <ntlsa.h>
#define SECURITY_WIN32
#define SECURITY_KERBEROS
#include <security.h>
#include <secint.h>
// the constant generic mapping structure
GENERIC_MAPPING sGenericMapping = {
READ_CONTROL,
READ_CONTROL,
READ_CONTROL,
READ_CONTROL};
// Well-known low-privilege service account sids
const SID sidLocalSystem = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SYSTEM_RID };
const SID sidLocalService = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_LOCAL_SERVICE_RID };
const SID sidNetworkService = {SID_REVISION, 1, SECURITY_NT_AUTHORITY, SECURITY_NETWORK_SERVICE_RID };
//-------------------------------------------------------------------------
//
// CheckForAccess
//
// Checks whether the given token has COM_RIGHTS_EXECUTE access in the
// given security descriptor.
//
//-------------------------------------------------------------------------
BOOL
CheckForAccess(
IN CToken * pToken,
IN SECURITY_DESCRIPTOR * pSD
)
{
// if we have an empty SD, deny everyone
if (!pSD)
return FALSE;
//
// Some history here: we used to say, if pToken is NULL (implying an
// unsecure activation), parse the security descriptor to see if
// Everyone is granted access, and if so, allow the activation to
// proceed. This was a DCOM-specific policy decision. In .NET Server
// we changed instead to mapping an unsecure (unauthenticated) client
// to the Anonymous identity. (Another DCOM-specific policy decision,
// but it probably makes more sense than the original one). And so we
// no longer parse the security descriptor, instead we just do a
// straight-forward access check.
//
HANDLE hToken = pToken->GetToken();
BOOL fAccess = FALSE;
BOOL fSuccess = FALSE;
DWORD dwGrantedAccess;
PRIVILEGE_SET sPrivilegeSet;
DWORD dwSetLen = sizeof( sPrivilegeSet );
sPrivilegeSet.PrivilegeCount = 1;
sPrivilegeSet.Control = 0;
fSuccess = AccessCheck( (PSECURITY_DESCRIPTOR) pSD,
hToken,
COM_RIGHTS_EXECUTE,
&sGenericMapping,
&sPrivilegeSet,
&dwSetLen,
&dwGrantedAccess,
&fAccess );
if (fSuccess && fAccess)
return TRUE;
if (!fSuccess)
{
CairoleDebugOut((DEB_ERROR, "Bad Security Descriptor 0x%08x, Access Check returned 0x%x\n", pSD, GetLastError() ));
}
return FALSE;
}
HRESULT IsLowPrivilegeServiceAccount (LPCWSTR pwszDomain, LPCWSTR pwszName, BOOL* pfSvcAccount)
{
if (!pwszName || !pfSvcAccount)
{
return E_POINTER;
}
*pfSvcAccount = FALSE;
HRESULT hr = S_OK;
BYTE pbSid [sizeof (sidLocalService)] = {0};
DWORD cbSid = sizeof (pbSid);
WCHAR wszDomain [DNLEN + 1] = {0};
DWORD cchDomain = sizeof (wszDomain) / sizeof (wszDomain[0]);
SID_NAME_USE eUse;
LPCWSTR pwszFullName = pwszName;
LPWSTR pwszCopyFullName = NULL;
// Build the full domain\account string if necessary
if (pwszDomain)
{
SIZE_T cchFullNameLen = lstrlenW (pwszDomain) + 1 + lstrlenW (pwszName) + 1;
SafeAllocaAllocate (pwszCopyFullName, cchFullNameLen * sizeof (WCHAR));
if (!pwszCopyFullName)
{
return E_OUTOFMEMORY;
}
_snwprintf (pwszCopyFullName, cchFullNameLen, L"%s\\%s", pwszDomain, pwszName);
pwszCopyFullName [cchFullNameLen - 1] = L'\0';
pwszFullName = pwszCopyFullName;
}
// Lookup the sid for the account
if (!LookupAccountName(NULL, pwszFullName, pbSid, &cbSid, wszDomain, &cchDomain, &eUse))
{
// Either our sid was too small, or a failure occurred.
// If the former, returning *pfSvcAccount = FALSE is correct
// If the latter, the subsequent call to LogonUser will catch it
hr = S_FALSE;
}
else
{
// Compare to well known service sids
if (eUse == SidTypeWellKnownGroup &&
(EqualSid (pbSid, (PSID) &sidLocalService) || EqualSid (pbSid, (PSID) &sidNetworkService)))
{
*pfSvcAccount = TRUE;
}
}
SafeAllocaFree (pwszCopyFullName);
return hr;
}
HRESULT IsLocalSystemAccount(LPCWSTR pwszDomain, LPCWSTR pwszName, BOOL* pfLocalSystemAccount)
{
if (!pwszName || !pfLocalSystemAccount)
{
return E_POINTER;
}
*pfLocalSystemAccount = FALSE;
HRESULT hr = S_OK;
BYTE pbSid [sizeof (sidLocalSystem)] = {0};
DWORD cbSid = sizeof (pbSid);
WCHAR wszDomain [DNLEN + 1] = {0};
DWORD cchDomain = sizeof (wszDomain) / sizeof (wszDomain[0]);
SID_NAME_USE eUse;
LPCWSTR pwszFullName = pwszName;
LPWSTR pwszCopyFullName = NULL;
// Build the full domain\account string if necessary
if (pwszDomain)
{
SIZE_T cchFullNameLen = lstrlenW (pwszDomain) + 1 + lstrlenW (pwszName) + 1;
SafeAllocaAllocate (pwszCopyFullName, cchFullNameLen * sizeof (WCHAR));
if (!pwszCopyFullName)
{
return E_OUTOFMEMORY;
}
_snwprintf (pwszCopyFullName, cchFullNameLen, L"%s\\%s", pwszDomain, pwszName);
pwszCopyFullName [cchFullNameLen - 1] = L'\0';
pwszFullName = pwszCopyFullName;
}
// Lookup the sid for the account
if (!LookupAccountName(NULL, pwszFullName, pbSid, &cbSid, wszDomain, &cchDomain, &eUse))
{
// Either our sid was too small, or a failure occurred.
// If the former, returning *pfLocalSystemAccount = FALSE is correct
// If the latter, the subsequent call to LogonUser will catch it
hr = S_FALSE;
}
else
{
// Compare to well known service sids
if (eUse == SidTypeWellKnownGroup &&
(EqualSid (pbSid, (PSID) &sidLocalSystem)))
{
*pfLocalSystemAccount = TRUE;
}
}
SafeAllocaFree (pwszCopyFullName);
return hr;
}
HANDLE
GetRunAsToken(
DWORD clsctx,
WCHAR *pwszAppID,
WCHAR *pwszRunAsDomainName,
WCHAR *pwszRunAsUserName,
BOOL fForLaunch)
{
LSA_OBJECT_ATTRIBUTES sObjAttributes;
HANDLE hPolicy = NULL;
LSA_UNICODE_STRING sKey;
WCHAR wszKey[CLSIDSTR_MAX+5];
PLSA_UNICODE_STRING psPassword;
HANDLE hToken;
NTSTATUS Status;
PKERB_INTERACTIVE_LOGON LogonInfo;
ULONG LogonInfoSize = sizeof(KERB_INTERACTIVE_LOGON);
STRING Name;
ULONG PackageId;
TOKEN_SOURCE SourceContext;
PKERB_INTERACTIVE_PROFILE Profile = NULL;
ULONG ProfileSize;
LUID LogonId;
QUOTA_LIMITS Quotas;
NTSTATUS SubStatus;
PUCHAR Where;
UNICODE_STRING usRunAsUserName, usRunAsDomainName;
PTOKEN_GROUPS TokenGroups = NULL;
HRESULT hr = E_FAIL;
if ( !pwszAppID )
{
// if we have a RunAs, we'd better have an appid....
return 0;
}
ASSERT(gLSAHandle);
ASSERT(gSidService);
ASSERT(gpwszDefaultDomainName[0]);
// formulate the access key
lstrcpyW(wszKey, L"SCM:");
lstrcatW(wszKey, pwszAppID );
// UNICODE_STRING length fields are in bytes and include the NULL
// terminator
sKey.Length = (USHORT)((lstrlenW(wszKey) + 1) * sizeof(WCHAR));
sKey.MaximumLength = (CLSIDSTR_MAX + 5) * sizeof(WCHAR);
sKey.Buffer = wszKey;
// Open the local security policy
InitializeObjectAttributes(&sObjAttributes, NULL, 0L, NULL, NULL);
if (!NT_SUCCESS(LsaOpenPolicy(NULL, &sObjAttributes,
POLICY_GET_PRIVATE_INFORMATION, &hPolicy)))
{
return 0;
}
// Read the user's password
if (!NT_SUCCESS(LsaRetrievePrivateData(hPolicy, &sKey, &psPassword)))
{
LsaClose(hPolicy);
return 0;
}
// Close the policy handle, we're done with it now.
LsaClose(hPolicy);
// Possible for LsaRetrievePrivateData to return success but with a NULL
// psPassword. If this happens we fail.
if (!psPassword)
{
return 0;
}
//
// Special case of NT AUTHORITY\System - cannot use LsaLogonUser to obtain such a
// token, so we use our own process token. Note that we currently only support
// this on the server registration code-path, and not the server-launch code path.
//
if (!fForLaunch)
{
BOOL fLocalSystemAccount = FALSE;
hr = IsLocalSystemAccount(pwszRunAsDomainName, pwszRunAsUserName, &fLocalSystemAccount);
if (SUCCEEDED(hr)) // keep going here in case of errors, LsaLogonUser will just fail below.
{
// If SYSTEM and user has supplied a blank password (for compatibility
// reasons), use our own token
if (fLocalSystemAccount && !lstrcmpiW(psPassword->Buffer, L""))
{
BOOL fResult = FALSE;
HANDLE hProcess = NULL;
HANDLE hProcessToken = NULL;
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId());
if (hProcess)
{
fResult = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hProcessToken);
ASSERT(!fResult || hProcessToken);
CloseHandle(hProcess);
}
return hProcessToken;
}
}
}
BOOLEAN b = RtlCreateUnicodeString(&usRunAsUserName, pwszRunAsUserName);
if (FALSE == b)
{
SecureZeroMemory(psPassword->Buffer, psPassword->Length);
LsaFreeMemory( psPassword );
return 0;
}
if ( (pwszRunAsDomainName[0] == L'.') && (pwszRunAsDomainName[1] == L'\0'))
b = RtlCreateUnicodeString(&usRunAsDomainName, gpwszDefaultDomainName);
else
b = RtlCreateUnicodeString(&usRunAsDomainName, pwszRunAsDomainName);
if (FALSE == b)
{
RtlFreeUnicodeString(&usRunAsUserName);
SecureZeroMemory(psPassword->Buffer, psPassword->Length);
LsaFreeMemory( psPassword );
return 0;
}
LogonInfoSize += usRunAsUserName.MaximumLength + usRunAsDomainName.MaximumLength + psPassword->MaximumLength ;
LogonInfo = (PKERB_INTERACTIVE_LOGON) LocalAlloc(LMEM_ZEROINIT, LogonInfoSize);
if (!LogonInfo)
{
RtlFreeUnicodeString(&usRunAsUserName);
RtlFreeUnicodeString(&usRunAsDomainName);
SecureZeroMemory(psPassword->Buffer, psPassword->Length);
LsaFreeMemory( psPassword );
return NULL;
}
LogonInfo->MessageType = KerbInteractiveLogon;
Where = (PUCHAR) (LogonInfo + 1);
LogonInfo->UserName.Buffer = (LPWSTR) Where;
LogonInfo->UserName.MaximumLength = usRunAsUserName.MaximumLength ;
LogonInfo->UserName.Length = usRunAsUserName.Length ;
RtlCopyMemory( LogonInfo->UserName.Buffer,
usRunAsUserName.Buffer,
usRunAsUserName.MaximumLength );
Where += LogonInfo->UserName.Length + sizeof(WCHAR);
LogonInfo->LogonDomainName.Buffer = (LPWSTR) Where ;
LogonInfo->LogonDomainName.MaximumLength = usRunAsDomainName.MaximumLength;
LogonInfo->LogonDomainName.Length = usRunAsDomainName.Length ;
RtlCopyMemory( LogonInfo->LogonDomainName.Buffer,
usRunAsDomainName.Buffer,
usRunAsDomainName.MaximumLength );
Where += LogonInfo->LogonDomainName.Length + sizeof(WCHAR);
LogonInfo->Password.Buffer = (LPWSTR) Where;
LogonInfo->Password.MaximumLength = psPassword->MaximumLength;
LogonInfo->Password.Length = psPassword->Length - sizeof(WCHAR); // The LSA API retrives length=maxlength
RtlCopyMemory( LogonInfo->Password.Buffer,
psPassword->Buffer,
LogonInfo->Password.MaximumLength );
// Clear the password
SecureZeroMemory(psPassword->Buffer, psPassword->Length);
LsaFreeMemory( psPassword );
RtlFreeUnicodeString(&usRunAsUserName);
RtlFreeUnicodeString(&usRunAsDomainName);
Where += LogonInfo->Password.Length + sizeof(WCHAR);
strncpy(
SourceContext.SourceName,
"DCOMSCM",sizeof(SourceContext.SourceName)
);
Status = NtAllocateLocallyUniqueId(
&SourceContext.SourceIdentifier
);
if (!NT_SUCCESS(Status))
{
SecureZeroMemory(LogonInfo, LogonInfoSize);
LocalFree(LogonInfo);
return NULL ;
}
RtlInitString( &Name, NEGOSSP_NAME_A);
Status = LsaLookupAuthenticationPackage(
gLSAHandle,
&Name,
&PackageId
);
if (!NT_SUCCESS(Status))
{
SecureZeroMemory(LogonInfo, LogonInfoSize);
LocalFree(LogonInfo);
return NULL ;
}
//
// Now call LsaLogonUser
//
RtlInitString(
&Name,
"DCOMSCM"
);
BOOL fSvcAccount = FALSE;
if (FAILED (IsLowPrivilegeServiceAccount (pwszRunAsDomainName, pwszRunAsUserName, &fSvcAccount)))
{
SecureZeroMemory(LogonInfo, LogonInfoSize);
LocalFree(LogonInfo);
return NULL;
}
// Service accounts should have blank passwords
ASSERT (!fSvcAccount || (psPassword->Buffer && !psPassword->Buffer[0]));
#define TOKEN_GROUP_COUNT 1
// if local/network service, no need to add the serivce SID
if (!fSvcAccount)
{
TokenGroups = (PTOKEN_GROUPS)LocalAlloc(LMEM_ZEROINIT, sizeof(TOKEN_GROUPS) +
(TOKEN_GROUP_COUNT - ANYSIZE_ARRAY) * sizeof(SID_AND_ATTRIBUTES));
if (TokenGroups == NULL) {
SecureZeroMemory(LogonInfo, LogonInfoSize);
LocalFree(LogonInfo);
return NULL ;
}
// Add the service SID to the token so the resulting
// process can impersonate
TokenGroups->GroupCount = TOKEN_GROUP_COUNT;
TokenGroups->Groups[0].Sid = gSidService;
TokenGroups->Groups[0].Attributes =
SE_GROUP_MANDATORY | SE_GROUP_ENABLED |
SE_GROUP_ENABLED_BY_DEFAULT;
}
Status = LsaLogonUser(
gLSAHandle,
&Name,
fSvcAccount ? Service : Batch,
PackageId,
LogonInfo,
LogonInfoSize,
TokenGroups, //NULL for service accounts
&SourceContext,
(PVOID *) &Profile,
&ProfileSize,
&LogonId,
&hToken,
&Quotas,
&SubStatus
);
SecureZeroMemory(LogonInfo, LogonInfoSize);
LocalFree(LogonInfo);
LocalFree(TokenGroups);
// Log the specifed user on
if (!NT_SUCCESS(Status))
{
// a-sergiv (Sergei O. Ivanov), 6-17-99
// Fix for com+ 9383/nt 272085
// Apply event filters
DWORD dwActLogLvl = GetActivationFailureLoggingLevel();
if(dwActLogLvl == 2)
return 0;
if(dwActLogLvl != 1 && clsctx & CLSCTX_NO_FAILURE_LOG)
return 0;
// for this message,
// %1 is the error number string
// %2 is the domain name
// %3 is the user name
// %4 is the CLSID
HANDLE LogHandle;
LPWSTR Strings[4]; // array of message strings.
WCHAR wszErrnum[20];
WCHAR wszClsid[GUIDSTR_MAX];
// Save the error number
wsprintf(wszErrnum, L"%lu",GetLastError() );
Strings[0] = wszErrnum;
// Put in the RunAs identity
Strings[1] = pwszRunAsDomainName;
Strings[2] = pwszRunAsUserName;
// Get the clsid
Strings[3] = pwszAppID;
// Get the log handle, then report then event.
LogHandle = RegisterEventSource( NULL,
SCM_EVENT_SOURCE );
if ( LogHandle )
{
ReportEvent( LogHandle,
EVENTLOG_ERROR_TYPE,
0, // event category
EVENT_RPCSS_RUNAS_CANT_LOGIN,
NULL, // SID
4, // 4 strings passed
0, // 0 bytes of binary
(LPCTSTR *)Strings, // array of strings
NULL ); // no raw data
// clean up the event log handle
DeregisterEventSource(LogHandle);
}
return 0;
}
else
{
if (Profile)
{
LsaFreeReturnBuffer(Profile);
}
}
return hToken;
}
BOOL
DuplicateTokenAsPrimary(
HANDLE hUserToken,
PSID psidUserSid,
HANDLE *hPrimaryToken
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
PSECURITY_DESCRIPTOR psdNewProcessTokenSD;
NTSTATUS NtStatus;
*hPrimaryToken = NULL;
if (hUserToken == NULL)
{
return(FALSE);
}
//
// Create the security descriptor that we want to put in the Token.
//
CAccessInfo AccessInfo(psidUserSid);
psdNewProcessTokenSD = AccessInfo.IdentifyAccess(
FALSE,
TOKEN_ADJUST_PRIVILEGES | TOKEN_ADJUST_GROUPS |
TOKEN_ADJUST_DEFAULT | TOKEN_QUERY |
TOKEN_DUPLICATE | TOKEN_IMPERSONATE | READ_CONTROL,
TOKEN_QUERY
);
if (psdNewProcessTokenSD == NULL)
{
CairoleDebugOut((DEB_ERROR, "Failed to create SD for process token\n"));
return(FALSE);
}
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0,
NULL,
psdNewProcessTokenSD
);
NtStatus = NtDuplicateToken(
hUserToken, // Duplicate this token
TOKEN_ALL_ACCESS, // Give me this access to the resulting token
&ObjectAttributes,
FALSE, // EffectiveOnly
TokenPrimary, // TokenType
hPrimaryToken // Duplicate token handle stored here
);
if (!NT_SUCCESS(NtStatus))
{
CairoleDebugOut((DEB_ERROR, "CreateAndSetProcessToken failed to duplicate primary token for new user process, status = 0x%lx\n", NtStatus));
return(FALSE);
}
return TRUE;
}
BOOL
DuplicateTokenForSessionUse(
HANDLE hUserToken,
HANDLE *hDuplicate
)
{
OBJECT_ATTRIBUTES ObjectAttributes;
PSECURITY_DESCRIPTOR psdNewProcessTokenSD;
NTSTATUS NtStatus;
if (hUserToken == NULL) {
return(TRUE);
}
*hDuplicate = NULL;
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0,
NULL,
NULL
);
NtStatus = NtDuplicateToken(
hUserToken, // Duplicate this token
TOKEN_ALL_ACCESS, //Give me this access to the resulting token
&ObjectAttributes,
FALSE, // EffectiveOnly
TokenPrimary, // TokenType
hDuplicate // Duplicate token handle stored here
);
if (!NT_SUCCESS(NtStatus)) {
CairoleDebugOut((DEB_ERROR, "CreateAndSetProcessToken failed to duplicate primary token for new user process, status = 0x%lx\n", NtStatus));
return(FALSE);
}
return TRUE;
}
/***************************************************************************\
* GetUserSid
*
* Allocs space for the user sid, fills it in and returns a pointer.
* The sid should be freed by calling DeleteUserSid.
*
* Note the sid returned is the user's real sid, not the per-logon sid.
*
* Returns pointer to sid or NULL on failure.
*
* History:
* 26-Aug-92 Davidc Created.
* 31-Mar-94 AndyH Copied from Winlogon, changed arg from pGlobals
\***************************************************************************/
PSID
GetUserSid(
HANDLE hUserToken
)
{
BYTE achBuffer[100];
PTOKEN_USER pUser = (PTOKEN_USER) &achBuffer;
PSID pSid;
DWORD dwBytesRequired;
NTSTATUS NtStatus;
BOOL fAllocatedBuffer = FALSE;
NtStatus = NtQueryInformationToken(
hUserToken, // Handle
TokenUser, // TokenInformationClass
pUser, // TokenInformation
sizeof(achBuffer), // TokenInformationLength
&dwBytesRequired // ReturnLength
);
if (!NT_SUCCESS(NtStatus))
{
if (NtStatus != STATUS_BUFFER_TOO_SMALL)
{
ASSERT(NtStatus == STATUS_BUFFER_TOO_SMALL);
return NULL;
}
//
// Allocate space for the user info
//
pUser = (PTOKEN_USER) PrivMemAlloc(dwBytesRequired);
if (pUser == NULL)
{
CairoleDebugOut((DEB_ERROR, "Failed to allocate %d bytes\n", dwBytesRequired));
ASSERT(pUser != NULL);
return NULL;
}
fAllocatedBuffer = TRUE;
//
// Read in the UserInfo
//
NtStatus = NtQueryInformationToken(
hUserToken, // Handle
TokenUser, // TokenInformationClass
pUser, // TokenInformation
dwBytesRequired, // TokenInformationLength
&dwBytesRequired // ReturnLength
);
if (!NT_SUCCESS(NtStatus))
{
CairoleDebugOut((DEB_ERROR, "Failed to query user info from user token, status = 0x%lx\n", NtStatus));
ASSERT(NtStatus == STATUS_SUCCESS);
PrivMemFree((HANDLE)pUser);
return NULL;
}
}
// Alloc buffer for copy of SID
dwBytesRequired = RtlLengthSid(pUser->User.Sid);
pSid = (PSID) PrivMemAlloc(dwBytesRequired);
if (pSid == NULL)
{
CairoleDebugOut((DEB_ERROR, "Failed to allocate %d bytes\n", dwBytesRequired));
if (fAllocatedBuffer == TRUE)
{
PrivMemFree((HANDLE)pUser);
}
return NULL;
}
// Copy SID
NtStatus = RtlCopySid(dwBytesRequired, pSid, pUser->User.Sid);
if (fAllocatedBuffer == TRUE)
{
PrivMemFree((HANDLE)pUser);
}
if (!NT_SUCCESS(NtStatus))
{
CairoleDebugOut((DEB_ERROR, "RtlCopySid failed, status = 0x%lx\n", NtStatus));
ASSERT(NtStatus != STATUS_SUCCESS);
PrivMemFree(pSid);
pSid = NULL;
}
return pSid;
}
HANDLE GetUserTokenForSession(
ULONG ulSessionId
)
{
BOOL fRet = FALSE;
HANDLE hToken = NULL;
//
// We used to have a lot of complicated code for doing this
// logic. The WTSQueryUserToken api replaces all of that
// quite nicely. Only downside is that wtsapi32.dll has a
// moderately large dependency list. Since under normal
// conditions we won't need to use this api until after someone
// logs on, we delay-load link to wtsapi32 to avoid the load
// hit during boot.
//
fRet = WTSQueryUserToken(ulSessionId, &hToken);
if (!fRet)
{
return NULL;
}
ASSERT(hToken);
return hToken;
}
// Global default launch permissions
CSecDescriptor* gpDefaultLaunchPermissions;
CSecDescriptor*
GetDefaultLaunchPermissions()
{
CSecDescriptor* pSD = NULL;
gpClientLock->LockShared();
pSD = gpDefaultLaunchPermissions;
if (pSD)
pSD->IncRefCount();
gpClientLock->UnlockShared();
return pSD;
}
void
SetDefaultLaunchPermissions(CSecDescriptor* pNewLaunchPerms)
{
CSecDescriptor* pOldSD = NULL;
gpClientLock->LockExclusive();
pOldSD = gpDefaultLaunchPermissions;
gpDefaultLaunchPermissions = pNewLaunchPerms;
if (gpDefaultLaunchPermissions)
gpDefaultLaunchPermissions->IncRefCount();
gpClientLock->UnlockExclusive();
if (pOldSD)
pOldSD->DecRefCount();
return;
}
CSecDescriptor::CSecDescriptor(SECURITY_DESCRIPTOR* pSD) : _lRefs(1)
{
ASSERT(pSD);
_pSD = pSD; // we own it now
}
CSecDescriptor::~CSecDescriptor()
{
ASSERT(_lRefs == 0);
ASSERT(_pSD);
PrivMemFree(_pSD);
}
void CSecDescriptor::IncRefCount()
{
ASSERT(_lRefs > 0);
LONG lRefs = InterlockedIncrement(&_lRefs);
}
void CSecDescriptor::DecRefCount()
{
ASSERT(_lRefs > 0);
LONG lRefs = InterlockedDecrement(&_lRefs);
if (lRefs == 0)
{
delete this;
}
}
SECURITY_DESCRIPTOR* CSecDescriptor::GetSD()
{
ASSERT(_pSD);
ASSERT(_lRefs > 0);
return _pSD;
}