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.
1010 lines
24 KiB
1010 lines
24 KiB
/*++
|
|
|
|
Copyright (c) 1996, 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
secmisc.c
|
|
|
|
Abstract:
|
|
|
|
This module contains miscellaneous security routines for the Protected
|
|
Storage.
|
|
|
|
|
|
Author:
|
|
|
|
Scott Field (sfield) 25-Mar-97
|
|
|
|
--*/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include "secmisc.h"
|
|
|
|
#include "unicode5.h"
|
|
#include "debug.h"
|
|
|
|
BOOL
|
|
GetUserHKEYEx(
|
|
IN LPCWSTR szUser,
|
|
IN DWORD dwDesiredAccess,
|
|
IN OUT HKEY *hKeyUser,
|
|
IN BOOL fCheckDefault // check .Default registry hive when user's not available?
|
|
)
|
|
{
|
|
HKEY hKey = NULL;
|
|
LONG lRet;
|
|
|
|
//
|
|
// first, try HKEY_USERS\szUser
|
|
// note on WinNT, szUser is an textual sid of the form S-1-5-21-xxx ...
|
|
// on Win95, szUser is the username associated with the logged on user
|
|
//
|
|
|
|
//
|
|
// unfortunately, if szUser is null or empty, the RegOpenKeyEx below will
|
|
// succeed, which is not correct behavior for us. Check for this case
|
|
// and retry with default on if fCheckDefault is TRUE.
|
|
//
|
|
|
|
if(szUser == NULL || szUser[0] == L'\0') {
|
|
// invalid szUser specified.
|
|
lRet = ERROR_FILE_NOT_FOUND;
|
|
} else {
|
|
lRet = RegOpenKeyExU(
|
|
HKEY_USERS,
|
|
szUser,
|
|
0, // dwOptions
|
|
dwDesiredAccess,
|
|
&hKey
|
|
);
|
|
}
|
|
|
|
if( lRet != ERROR_SUCCESS && fCheckDefault ) {
|
|
|
|
//
|
|
// if that failed, try HKEY_USERS\.Default (for services on NT).
|
|
// TODO (lookat), for now, don't fall back to HKEY_USERS\.Default on Win95
|
|
// because that is shared across users when profiles are disabled.
|
|
//
|
|
|
|
lRet = RegOpenKeyExU(
|
|
HKEY_USERS,
|
|
L".Default",
|
|
0, // dwOptions
|
|
dwDesiredAccess,
|
|
&hKey
|
|
);
|
|
}
|
|
|
|
if(lRet != ERROR_SUCCESS) {
|
|
SetLastError( (DWORD)lRet );
|
|
return FALSE;
|
|
}
|
|
|
|
*hKeyUser = hKey;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetUserHKEY(
|
|
IN LPCWSTR szUser,
|
|
IN DWORD dwDesiredAccess,
|
|
IN OUT HKEY *hKeyUser
|
|
)
|
|
{
|
|
//
|
|
// winnt: try HKEY_USERS\.Default
|
|
// win95: don't go to HKEY_USERS\.Default when profiles disabled.
|
|
//
|
|
|
|
BOOL fRet = GetUserHKEYEx(szUser, dwDesiredAccess, hKeyUser, FALSE);
|
|
|
|
if(!fRet)
|
|
{
|
|
//
|
|
// see if local system. If so, retry against .Default
|
|
//
|
|
|
|
static const WCHAR szTextualSidSystem[] = TEXTUAL_SID_LOCAL_SYSTEM;
|
|
|
|
if( memcmp(szUser, szTextualSidSystem, sizeof(szTextualSidSystem)) == 0 )
|
|
fRet = GetUserHKEYEx(szUser, dwDesiredAccess, hKeyUser, TRUE);
|
|
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
BOOL
|
|
GetUserTextualSid(
|
|
IN HANDLE hUserToken, // optional
|
|
IN OUT LPWSTR lpBuffer,
|
|
IN OUT LPDWORD nSize
|
|
)
|
|
{
|
|
HANDLE hToken;
|
|
PSID pSidUser = NULL;
|
|
BOOL fSuccess = FALSE;
|
|
|
|
if(hUserToken == NULL)
|
|
{
|
|
if(!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hToken = hUserToken;
|
|
}
|
|
|
|
fSuccess = GetTokenUserSid(hToken, &pSidUser);
|
|
|
|
if(fSuccess)
|
|
{
|
|
//
|
|
// obtain the textual representaion of the Sid
|
|
//
|
|
|
|
fSuccess = GetTextualSid(
|
|
pSidUser, // user binary Sid
|
|
lpBuffer, // buffer for TextualSid
|
|
nSize // required/result buffer size in chars (including NULL)
|
|
);
|
|
}
|
|
|
|
if(pSidUser)
|
|
SSFree(pSidUser);
|
|
|
|
if(hToken != hUserToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
GetTextualSid(
|
|
IN PSID pSid, // binary Sid
|
|
IN OUT LPWSTR TextualSid, // buffer for Textual representaion of Sid
|
|
IN OUT LPDWORD dwBufferLen // required/provided TextualSid buffersize
|
|
)
|
|
{
|
|
PSID_IDENTIFIER_AUTHORITY psia;
|
|
DWORD dwSubAuthorities;
|
|
DWORD dwCounter;
|
|
DWORD dwSidSize;
|
|
|
|
|
|
if(!IsValidSid(pSid)) return FALSE;
|
|
|
|
// obtain SidIdentifierAuthority
|
|
psia = GetSidIdentifierAuthority(pSid);
|
|
|
|
// obtain sidsubauthority count
|
|
dwSubAuthorities = *GetSidSubAuthorityCount(pSid);
|
|
|
|
//
|
|
// compute buffer length (conservative guess)
|
|
// S-SID_REVISION- + identifierauthority- + subauthorities- + NULL
|
|
//
|
|
dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(WCHAR);
|
|
|
|
//
|
|
// check provided buffer length.
|
|
// If not large enough, indicate proper size and setlasterror
|
|
//
|
|
if(*dwBufferLen < dwSidSize) {
|
|
*dwBufferLen = dwSidSize;
|
|
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// prepare S-SID_REVISION-
|
|
//
|
|
dwSidSize = wsprintfW(TextualSid, L"S-%lu-", SID_REVISION );
|
|
|
|
//
|
|
// prepare SidIdentifierAuthority
|
|
//
|
|
if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) ) {
|
|
dwSidSize += wsprintfW(TextualSid + dwSidSize,
|
|
L"0x%02hx%02hx%02hx%02hx%02hx%02hx",
|
|
(USHORT)psia->Value[0],
|
|
(USHORT)psia->Value[1],
|
|
(USHORT)psia->Value[2],
|
|
(USHORT)psia->Value[3],
|
|
(USHORT)psia->Value[4],
|
|
(USHORT)psia->Value[5]);
|
|
} else {
|
|
dwSidSize += wsprintfW(TextualSid + dwSidSize,
|
|
L"%lu",
|
|
(ULONG)(psia->Value[5] ) +
|
|
(ULONG)(psia->Value[4] << 8) +
|
|
(ULONG)(psia->Value[3] << 16) +
|
|
(ULONG)(psia->Value[2] << 24) );
|
|
}
|
|
|
|
//
|
|
// loop through SidSubAuthorities
|
|
//
|
|
for (dwCounter = 0 ; dwCounter < dwSubAuthorities ; dwCounter++) {
|
|
dwSidSize += wsprintfW(TextualSid + dwSidSize,
|
|
L"-%lu", *GetSidSubAuthority(pSid, dwCounter) );
|
|
}
|
|
|
|
*dwBufferLen = dwSidSize + 1; // tell caller how many chars (include NULL)
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetThreadAuthenticationId(
|
|
IN HANDLE hThread,
|
|
IN OUT PLUID AuthenticationId
|
|
)
|
|
/*++
|
|
|
|
This function retrieves the authentication Id (LUID) from the access token
|
|
specified by the calling thread.
|
|
|
|
The thread specified by hThread must be impersonating a client.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hToken;
|
|
TOKEN_STATISTICS TokenInfo;
|
|
DWORD dwReturnLen;
|
|
BOOL bSuccess;
|
|
|
|
if(!OpenThreadToken(
|
|
hThread,
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken
|
|
)) return FALSE;
|
|
|
|
bSuccess = GetTokenInformation(
|
|
hToken,
|
|
TokenStatistics,
|
|
&TokenInfo,
|
|
sizeof(TokenInfo),
|
|
&dwReturnLen
|
|
);
|
|
|
|
CloseHandle(hToken);
|
|
|
|
if(!bSuccess) return FALSE;
|
|
|
|
memcpy(AuthenticationId, &(TokenInfo.AuthenticationId), sizeof(LUID));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetTokenAuthenticationId(
|
|
IN HANDLE hUserToken,
|
|
IN OUT PLUID AuthenticationId
|
|
)
|
|
/*++
|
|
|
|
This function retrieves the authentication Id (LUID) from the specified
|
|
access token.
|
|
|
|
--*/
|
|
{
|
|
TOKEN_STATISTICS TokenInfo;
|
|
DWORD dwReturnLen;
|
|
BOOL bSuccess;
|
|
HANDLE hToken = NULL;
|
|
|
|
if(hUserToken == NULL)
|
|
{
|
|
if(!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hToken = hUserToken;
|
|
}
|
|
|
|
bSuccess = GetTokenInformation(
|
|
hToken,
|
|
TokenStatistics,
|
|
&TokenInfo,
|
|
sizeof(TokenInfo),
|
|
&dwReturnLen
|
|
);
|
|
|
|
if(hToken != hUserToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
if(!bSuccess) return FALSE;
|
|
|
|
memcpy(AuthenticationId, &(TokenInfo.AuthenticationId), sizeof(LUID));
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
GetTokenUserSid(
|
|
IN HANDLE hUserToken, // token to query
|
|
IN OUT PSID *ppUserSid // resultant user sid
|
|
)
|
|
/*++
|
|
|
|
This function queries the access token specified by the
|
|
hToken parameter, and returns an allocated copy of the
|
|
TokenUser information on success.
|
|
|
|
The access token specified by hToken must be opened for
|
|
TOKEN_QUERY access.
|
|
|
|
On success, the return value is TRUE. The caller is
|
|
responsible for freeing the resultant UserSid via a call
|
|
to SSFree().
|
|
|
|
On failure, the return value is FALSE. The caller does
|
|
not need to free any buffer.
|
|
|
|
--*/
|
|
{
|
|
BYTE FastBuffer[256];
|
|
LPBYTE SlowBuffer = NULL;
|
|
PTOKEN_USER ptgUser;
|
|
DWORD cbBuffer;
|
|
BOOL fSuccess = FALSE;
|
|
HANDLE hToken = NULL;
|
|
|
|
*ppUserSid = NULL;
|
|
|
|
if(hUserToken == NULL)
|
|
{
|
|
if(!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hToken
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hToken = hUserToken;
|
|
}
|
|
|
|
//
|
|
// try querying based on a fast stack based buffer first.
|
|
//
|
|
|
|
ptgUser = (PTOKEN_USER)FastBuffer;
|
|
cbBuffer = sizeof(FastBuffer);
|
|
|
|
fSuccess = GetTokenInformation(
|
|
hToken, // identifies access token
|
|
TokenUser, // TokenUser info type
|
|
ptgUser, // retrieved info buffer
|
|
cbBuffer, // size of buffer passed-in
|
|
&cbBuffer // required buffer size
|
|
);
|
|
|
|
if(!fSuccess) {
|
|
|
|
if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
|
|
|
|
//
|
|
// try again with the specified buffer size
|
|
//
|
|
|
|
SlowBuffer = (LPBYTE)SSAlloc(cbBuffer);
|
|
|
|
if(SlowBuffer != NULL) {
|
|
ptgUser = (PTOKEN_USER)SlowBuffer;
|
|
|
|
fSuccess = GetTokenInformation(
|
|
hToken, // identifies access token
|
|
TokenUser, // TokenUser info type
|
|
ptgUser, // retrieved info buffer
|
|
cbBuffer, // size of buffer passed-in
|
|
&cbBuffer // required buffer size
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// if we got the token info successfully, copy the
|
|
// relevant element for the caller.
|
|
//
|
|
|
|
if(fSuccess) {
|
|
|
|
DWORD cbSid;
|
|
|
|
// reset to assume failure
|
|
fSuccess = FALSE;
|
|
|
|
cbSid = GetLengthSid(ptgUser->User.Sid);
|
|
|
|
*ppUserSid = SSAlloc( cbSid );
|
|
|
|
if(*ppUserSid != NULL) {
|
|
fSuccess = CopySid(cbSid, *ppUserSid, ptgUser->User.Sid);
|
|
}
|
|
else
|
|
{
|
|
fSuccess = FALSE;
|
|
}
|
|
}
|
|
|
|
if(!fSuccess) {
|
|
if(*ppUserSid) {
|
|
SSFree(*ppUserSid);
|
|
*ppUserSid = NULL;
|
|
}
|
|
}
|
|
|
|
if(SlowBuffer)
|
|
SSFree(SlowBuffer);
|
|
|
|
if(hToken != hUserToken)
|
|
{
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SetRegistrySecurity(
|
|
IN HKEY hKey
|
|
)
|
|
/*++
|
|
|
|
The function applies security to the specifed registry key such that only
|
|
Local System has Full Control to the registry key. Note that the owner
|
|
is not set, which results in a default owner of Administrators.
|
|
|
|
The specified hKey must to opened for WRITE_DAC access.
|
|
|
|
--*/
|
|
{
|
|
SID_IDENTIFIER_AUTHORITY sia = SECURITY_NT_AUTHORITY;
|
|
PSID pLocalSystemSid = NULL;
|
|
SECURITY_DESCRIPTOR sd;
|
|
PACL pDacl = NULL;
|
|
PACCESS_ALLOWED_ACE pAce;
|
|
DWORD dwAclSize;
|
|
LONG lRetCode;
|
|
BOOL bSuccess = FALSE; // assume this function fails
|
|
|
|
//
|
|
// prepare a Sid representing the Local System account
|
|
//
|
|
|
|
if(!AllocateAndInitializeSid(
|
|
&sia,
|
|
1,
|
|
SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&pLocalSystemSid
|
|
)) goto cleanup;
|
|
|
|
//
|
|
// compute size of new acl
|
|
//
|
|
|
|
dwAclSize = sizeof(ACL) +
|
|
1 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) ) +
|
|
GetLengthSid(pLocalSystemSid) ;
|
|
|
|
//
|
|
// allocate storage for Acl
|
|
//
|
|
|
|
pDacl = (PACL)SSAlloc(dwAclSize);
|
|
if(pDacl == NULL) goto cleanup;
|
|
|
|
if(!InitializeAcl(pDacl, dwAclSize, ACL_REVISION))
|
|
goto cleanup;
|
|
|
|
if(!AddAccessAllowedAce(
|
|
pDacl,
|
|
ACL_REVISION,
|
|
KEY_ALL_ACCESS,
|
|
pLocalSystemSid
|
|
)) goto cleanup;
|
|
|
|
//
|
|
// make it container inherit.
|
|
//
|
|
|
|
if(!GetAce(pDacl, 0, &pAce))
|
|
goto cleanup;
|
|
|
|
pAce->Header.AceFlags = CONTAINER_INHERIT_ACE;
|
|
|
|
if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))
|
|
goto cleanup;
|
|
|
|
if(!SetSecurityDescriptorDacl(&sd, TRUE, pDacl, FALSE)) {
|
|
goto cleanup;
|
|
}
|
|
|
|
//
|
|
// apply the security descriptor to the registry key
|
|
//
|
|
|
|
lRetCode = RegSetKeySecurity(
|
|
hKey,
|
|
(SECURITY_INFORMATION)DACL_SECURITY_INFORMATION,
|
|
&sd
|
|
);
|
|
|
|
if(lRetCode != ERROR_SUCCESS) {
|
|
goto cleanup;
|
|
}
|
|
|
|
bSuccess = TRUE; // indicate success
|
|
|
|
cleanup:
|
|
|
|
//
|
|
// free allocated resources
|
|
//
|
|
|
|
if(pDacl != NULL)
|
|
SSFree(pDacl);
|
|
|
|
if(pLocalSystemSid != NULL)
|
|
FreeSid(pLocalSystemSid);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
BOOL
|
|
SetPrivilege(
|
|
HANDLE hToken, // token handle
|
|
LPCWSTR Privilege, // Privilege to enable/disable
|
|
BOOL bEnablePrivilege // to enable or disable privilege
|
|
)
|
|
{
|
|
TOKEN_PRIVILEGES tp;
|
|
LUID luid;
|
|
TOKEN_PRIVILEGES tpPrevious;
|
|
DWORD cbPrevious=sizeof(TOKEN_PRIVILEGES);
|
|
|
|
if(!LookupPrivilegeValueW( NULL, Privilege, &luid )) return FALSE;
|
|
|
|
//
|
|
// first pass. get current privilege setting
|
|
//
|
|
tp.PrivilegeCount = 1;
|
|
tp.Privileges[0].Luid = luid;
|
|
tp.Privileges[0].Attributes = 0;
|
|
|
|
AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tp,
|
|
sizeof(TOKEN_PRIVILEGES),
|
|
&tpPrevious,
|
|
&cbPrevious
|
|
);
|
|
|
|
if (GetLastError() != ERROR_SUCCESS) return FALSE;
|
|
|
|
//
|
|
// second pass. set privilege based on previous setting
|
|
//
|
|
tpPrevious.PrivilegeCount = 1;
|
|
tpPrevious.Privileges[0].Luid = luid;
|
|
|
|
if(bEnablePrivilege) {
|
|
tpPrevious.Privileges[0].Attributes |= (SE_PRIVILEGE_ENABLED);
|
|
}
|
|
else {
|
|
tpPrevious.Privileges[0].Attributes ^= (SE_PRIVILEGE_ENABLED &
|
|
tpPrevious.Privileges[0].Attributes);
|
|
}
|
|
|
|
AdjustTokenPrivileges(
|
|
hToken,
|
|
FALSE,
|
|
&tpPrevious,
|
|
cbPrevious,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (GetLastError() != ERROR_SUCCESS) return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
SetCurrentPrivilege(
|
|
LPCWSTR Privilege, // Privilege to enable/disable
|
|
BOOL bEnablePrivilege // to enable or disable privilege
|
|
)
|
|
{
|
|
BOOL bSuccess=FALSE; // assume failure
|
|
HANDLE hToken;
|
|
|
|
if(OpenProcessToken(
|
|
GetCurrentProcess(),
|
|
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
|
|
&hToken
|
|
))
|
|
{
|
|
|
|
if(SetPrivilege(hToken, Privilege, bEnablePrivilege)) bSuccess=TRUE;
|
|
|
|
CloseHandle(hToken);
|
|
}
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
#if 0
|
|
BOOL
|
|
IsDelegating(
|
|
IN HANDLE hToken // token to query, open for at least TOKEN_QUERY access
|
|
)
|
|
/*++
|
|
|
|
This function determines if the specified access token represents an
|
|
impersonation at the delegation impersonate level.
|
|
|
|
The access token specified by the hToken parameter must be opened for
|
|
at least TOKEN_QUERY access.
|
|
|
|
If the return value is TRUE, the specified hToken is impersonating at
|
|
delegation level.
|
|
|
|
If the return value is FALSE, hToken does not represent delegation level
|
|
impersonation.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwImpersonationLevel;
|
|
DWORD cbTokenInfo;
|
|
|
|
if( GetTokenInformation(
|
|
hToken,
|
|
TokenImpersonationLevel,
|
|
&dwImpersonationLevel,
|
|
sizeof(dwImpersonationLevel),
|
|
&cbTokenInfo
|
|
) && dwImpersonationLevel == SecurityDelegation ) {
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
IsUserSidInDomain(
|
|
IN PSID pSidDomain, // domain Sid
|
|
IN PSID pSidUser // user Sid
|
|
)
|
|
/*++
|
|
|
|
This function determines if the user associated with the
|
|
pSidUser parameter exists in the domain specified by pSidDomain.
|
|
|
|
If the user is in the specified domain, the return value is TRUE.
|
|
Otherwise, the return value is FALSE.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwSubauthorityCount;
|
|
DWORD dwSubauthIndex;
|
|
|
|
//
|
|
// pickup count of subauthorities in domain sid. The domain Sid
|
|
// is the prefix associated with user sids, so use that count
|
|
// as the basis for our comparison.
|
|
//
|
|
|
|
dwSubauthorityCount = (DWORD)*GetSidSubAuthorityCount( pSidDomain );
|
|
|
|
if( dwSubauthorityCount >= (DWORD)*GetSidSubAuthorityCount( pSidUser ) )
|
|
return FALSE;
|
|
|
|
//
|
|
// compare identifier authority values.
|
|
//
|
|
|
|
if(memcmp( GetSidIdentifierAuthority(pSidDomain),
|
|
GetSidIdentifierAuthority(pSidUser),
|
|
sizeof(SID_IDENTIFIER_AUTHORITY) ) != 0)
|
|
return FALSE;
|
|
|
|
//
|
|
// loop through subauthorities comparing equality.
|
|
//
|
|
|
|
for(dwSubauthIndex = 0 ;
|
|
dwSubauthIndex < dwSubauthorityCount ;
|
|
dwSubauthIndex++) {
|
|
|
|
if( *GetSidSubAuthority(pSidDomain, dwSubauthIndex) !=
|
|
*GetSidSubAuthority(pSidUser, dwSubauthIndex) )
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if 0
|
|
BOOL
|
|
IsAdministrator(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
This function determines if the calling user is an Administrator.
|
|
|
|
On Windows 95, this function always returns TRUE, as there is
|
|
no difference between users on that platform.
|
|
|
|
On Windows NT, the caller of this function must be impersonating
|
|
the user which is to be queried. If the caller is not impersonating,
|
|
this function will always return FALSE.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hAccessToken;
|
|
SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
|
|
PSID psidAdministrators = NULL;
|
|
BOOL bSuccess;
|
|
|
|
if(!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hAccessToken
|
|
)) return FALSE;
|
|
|
|
bSuccess = AllocateAndInitializeSid(
|
|
&siaNtAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
DOMAIN_ALIAS_RID_ADMINS,
|
|
0, 0, 0, 0, 0, 0,
|
|
&psidAdministrators
|
|
);
|
|
|
|
if( bSuccess ) {
|
|
BOOL fIsMember = FALSE;
|
|
|
|
bSuccess = CheckTokenMembership( hAccessToken, psidAdministrators, &fIsMember );
|
|
|
|
if( bSuccess && !fIsMember )
|
|
bSuccess = FALSE;
|
|
|
|
}
|
|
|
|
CloseHandle( hAccessToken );
|
|
|
|
if(psidAdministrators)
|
|
FreeSid(psidAdministrators);
|
|
|
|
return bSuccess;
|
|
}
|
|
#endif
|
|
|
|
BOOL
|
|
IsLocal(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
This function determines if the calling user is logged on locally
|
|
|
|
On Windows NT, the caller of this function must be impersonating
|
|
the user which is to be queried. If the caller is not impersonating,
|
|
this function will always return FALSE.
|
|
|
|
--*/
|
|
{
|
|
HANDLE hAccessToken;
|
|
SID_IDENTIFIER_AUTHORITY siaLocalAuthority = SECURITY_LOCAL_SID_AUTHORITY;
|
|
PSID psidLocal = NULL;
|
|
BOOL bSuccess;
|
|
|
|
if(!OpenThreadToken(
|
|
GetCurrentThread(),
|
|
TOKEN_QUERY,
|
|
TRUE,
|
|
&hAccessToken
|
|
)) return FALSE;
|
|
|
|
bSuccess = AllocateAndInitializeSid(
|
|
&siaLocalAuthority,
|
|
1,
|
|
SECURITY_LOCAL_RID,
|
|
0, 0, 0, 0, 0, 0, 0,
|
|
&psidLocal
|
|
);
|
|
|
|
if( bSuccess ) {
|
|
BOOL fIsMember = FALSE;
|
|
|
|
bSuccess = CheckTokenMembership( hAccessToken, psidLocal, &fIsMember );
|
|
|
|
if( bSuccess && !fIsMember )
|
|
bSuccess = FALSE;
|
|
|
|
}
|
|
|
|
CloseHandle( hAccessToken );
|
|
|
|
if(psidLocal)
|
|
FreeSid(psidLocal);
|
|
|
|
return bSuccess;
|
|
}
|
|
|
|
|
|
BOOL
|
|
IsDomainController(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
This function returns TRUE if the current machine is a Windows NT
|
|
domain controller.
|
|
|
|
The function returns FALSE if the current machine is not a Windows NT
|
|
domain controller.
|
|
|
|
--*/
|
|
{
|
|
HMODULE hNtDll;
|
|
|
|
typedef BOOLEAN (NTAPI *RTLGETNTPRODUCTTYPE)(
|
|
OUT PNT_PRODUCT_TYPE NtProductType
|
|
);
|
|
|
|
RTLGETNTPRODUCTTYPE _RtlGetNtProductType;
|
|
NT_PRODUCT_TYPE NtProductType;
|
|
|
|
hNtDll = GetModuleHandleW(L"ntdll.dll");
|
|
if( hNtDll == NULL )
|
|
return FALSE;
|
|
|
|
|
|
_RtlGetNtProductType = (RTLGETNTPRODUCTTYPE)GetProcAddress( hNtDll, "RtlGetNtProductType" );
|
|
if( _RtlGetNtProductType == NULL )
|
|
return FALSE;
|
|
|
|
|
|
if(_RtlGetNtProductType( &NtProductType )) {
|
|
if( NtProductType == NtProductLanManNt )
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
#if 0
|
|
LONG
|
|
SecureRegDeleteValueU(
|
|
IN HKEY hKey, // handle of key
|
|
IN LPCWSTR lpValueName // address of value name
|
|
)
|
|
/*++
|
|
|
|
This function securely deletes a value from the registry. This approach
|
|
avoids leaving a copy of the old data in the registry backing file after
|
|
the delete has occurred.
|
|
|
|
The specified registry handle hKey must be opened for
|
|
REG_QUERY_VALUE | REG_SET_VALUE | DELETE access.
|
|
|
|
On success, the return value is ERROR_SUCCESS.
|
|
On error, the return value is a Win32 error code.
|
|
|
|
--*/
|
|
{
|
|
DWORD dwType;
|
|
DWORD cbData;
|
|
|
|
BYTE FastBuffer[ 256 ];
|
|
LPBYTE lpData;
|
|
LPBYTE SlowBuffer = NULL;
|
|
|
|
LONG lRet;
|
|
|
|
cbData = 0; // query size of value data.
|
|
|
|
//
|
|
// query the current size of the registry data.
|
|
// zero the current registry data of current size.
|
|
// delete the registry data.
|
|
// flush the change to disk.
|
|
// If errors occur, just do a regular delete.
|
|
//
|
|
|
|
lRet = RegQueryValueExU(
|
|
hKey,
|
|
lpValueName,
|
|
NULL,
|
|
&dwType,
|
|
NULL,
|
|
&cbData
|
|
);
|
|
|
|
if( lRet == ERROR_MORE_DATA ) {
|
|
|
|
BOOL fSet = TRUE; // assume ok to set
|
|
|
|
//
|
|
// select fast buffer if large enough. otherwise, allocate a buffer
|
|
//
|
|
|
|
if(cbData <= sizeof(FastBuffer)) {
|
|
lpData = FastBuffer;
|
|
} else {
|
|
SlowBuffer = (LPBYTE)SSAlloc( cbData );
|
|
|
|
if(SlowBuffer == NULL) {
|
|
fSet = FALSE; // failure.
|
|
} else {
|
|
lpData = SlowBuffer;
|
|
}
|
|
|
|
}
|
|
|
|
if( fSet ) {
|
|
|
|
ZeroMemory( lpData, cbData );
|
|
|
|
RegSetValueExU(
|
|
hKey,
|
|
lpValueName,
|
|
0,
|
|
dwType,
|
|
lpData,
|
|
cbData
|
|
);
|
|
}
|
|
}
|
|
|
|
lRet = RegDeleteValueU( hKey, lpValueName );
|
|
|
|
RegFlushKey( hKey );
|
|
|
|
if( SlowBuffer )
|
|
SSFree( SlowBuffer );
|
|
|
|
return lRet;
|
|
}
|
|
#endif
|