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.
2665 lines
68 KiB
2665 lines
68 KiB
/*++
|
|
|
|
Copyright (c) 1996 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
sceutil.cpp
|
|
|
|
Abstract:
|
|
|
|
Shared APIs
|
|
|
|
Author:
|
|
|
|
Jin Huang
|
|
|
|
Revision History:
|
|
|
|
jinhuang 23-Jan-1998 merged from multiple modules
|
|
|
|
--*/
|
|
|
|
#include "headers.h"
|
|
#include "sceutil.h"
|
|
#include "infp.h"
|
|
#include <sddl.h>
|
|
#include "commonrc.h"
|
|
#include "client\CGenericLogger.h"
|
|
|
|
extern HINSTANCE MyModuleHandle;
|
|
|
|
BOOL
|
|
ScepLookupWellKnownName(
|
|
IN PWSTR Name,
|
|
IN OPTIONAL LSA_HANDLE LsaPolicy,
|
|
OPTIONAL OUT PWSTR *ppwszSid)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
|
|
PLSA_TRANSLATED_SID2 Sids=NULL;
|
|
BOOL fFound = FALSE;
|
|
BOOL fCloseHandle = FALSE;
|
|
PSID pBuiltinSid = NULL;
|
|
|
|
if ( Name == NULL ||
|
|
Name[0] == L'\0' ||
|
|
Name[0] == L'*')
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if ( NULL == LsaPolicy )
|
|
{
|
|
NtStatus = ScepOpenLsaPolicy(
|
|
POLICY_LOOKUP_NAMES,
|
|
&LsaPolicy,
|
|
TRUE
|
|
);
|
|
fCloseHandle = TRUE;
|
|
}
|
|
|
|
if( NT_SUCCESS(NtStatus))
|
|
{
|
|
NtStatus = ScepLsaLookupNames2(
|
|
LsaPolicy,
|
|
LSA_LOOKUP_ISOLATED_AS_LOCAL,
|
|
Name,
|
|
&RefDomains,
|
|
&Sids);
|
|
}
|
|
|
|
//
|
|
// if it's well known constants (such as everyone, Network Service) or
|
|
// it's a builtin account (such as Administrators),
|
|
// always store them in SID string format
|
|
//
|
|
|
|
if ( NT_SUCCESS(NtStatus) &&
|
|
ERROR_SUCCESS != ScepGetBuiltinSid(0, &pBuiltinSid))
|
|
{
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) &&
|
|
Sids &&
|
|
( Sids[0].Use == SidTypeWellKnownGroup ||
|
|
Sids[0].Use == SidTypeAlias &&
|
|
Sids[0].DomainIndex >=0 &&
|
|
RtlEqualSid(
|
|
RefDomains->Domains[Sids[0].DomainIndex].Sid,
|
|
pBuiltinSid)) &&
|
|
Sids[0].Sid != NULL)
|
|
{
|
|
fFound = TRUE;
|
|
|
|
if(ppwszSid)
|
|
{
|
|
NtStatus = ScepConvertSidToPrefixStringSid(
|
|
Sids[0].Sid, ppwszSid);
|
|
}
|
|
}
|
|
|
|
if ( Sids )
|
|
{
|
|
LsaFreeMemory(Sids);
|
|
}
|
|
|
|
if ( RefDomains )
|
|
{
|
|
LsaFreeMemory(RefDomains);
|
|
}
|
|
|
|
if( fCloseHandle && NULL != LsaPolicy )
|
|
{
|
|
LsaClose(LsaPolicy);
|
|
}
|
|
|
|
if ( pBuiltinSid )
|
|
{
|
|
ScepFree(pBuiltinSid);
|
|
}
|
|
|
|
return ( NT_SUCCESS(NtStatus) ? fFound : FALSE );
|
|
}
|
|
|
|
|
|
INT
|
|
ScepLookupPrivByName(
|
|
IN PCWSTR Right
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine looksup a user right in SCE_Rights table and returns the
|
|
index component in SCE_Rights. The index component indicates the bit
|
|
number for the user right.
|
|
|
|
Arguments:
|
|
|
|
Right - The user right to look up
|
|
|
|
Return value:
|
|
|
|
The index component in SCE_Rights table if a match is found,
|
|
-1 for no match
|
|
-- */
|
|
{
|
|
DWORD i;
|
|
|
|
for (i=0; i<cPrivCnt; i++) {
|
|
if ( _wcsicmp(Right, SCE_Privileges[i].Name) == 0 )
|
|
return (i);
|
|
}
|
|
return(-1);
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
WINAPI
|
|
SceLookupPrivRightName(
|
|
IN INT Priv,
|
|
OUT PWSTR Name,
|
|
OUT PINT NameLen
|
|
)
|
|
{
|
|
INT Len;
|
|
|
|
if ( Name != NULL && NameLen == NULL )
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
|
|
if ( Priv >= 0 && Priv < cPrivCnt ) {
|
|
Len = wcslen(SCE_Privileges[Priv].Name);
|
|
|
|
if ( Name != NULL ) {
|
|
if ( *NameLen >= Len )
|
|
wcscpy(Name, SCE_Privileges[Priv].Name);
|
|
else {
|
|
*NameLen = Len;
|
|
return(SCESTATUS_BUFFER_TOO_SMALL);
|
|
}
|
|
}
|
|
if ( NameLen != NULL)
|
|
*NameLen = Len;
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
|
|
} else
|
|
return SCESTATUS_RECORD_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
SceInfpOpenProfile(
|
|
IN PCWSTR ProfileName,
|
|
IN HINF *hInf
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine opens a profile and returns a handle. This handle may be used
|
|
when read information out of the profile using Setup APIs. The handle must
|
|
be closed by calling SCECloseInfProfile.
|
|
|
|
Arguments:
|
|
|
|
ProfileName - The profile to open
|
|
|
|
hInf - the address for inf handle
|
|
|
|
Return value:
|
|
|
|
SCESTATUS
|
|
*/
|
|
{
|
|
if ( ProfileName == NULL || hInf == NULL ) {
|
|
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
//
|
|
// Check to see if the INF file is opened OK.
|
|
// SetupOpenInfFile is defined in setupapi.h
|
|
//
|
|
|
|
*hInf = SetupOpenInfFile(ProfileName,
|
|
NULL,
|
|
INF_STYLE_WIN4,
|
|
NULL
|
|
);
|
|
if (*hInf == INVALID_HANDLE_VALUE)
|
|
return( ScepDosErrorToSceStatus( GetLastError() ) );
|
|
else
|
|
return( SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
SCESTATUS
|
|
SceInfpCloseProfile(
|
|
IN HINF hInf
|
|
)
|
|
{
|
|
|
|
if ( hInf != INVALID_HANDLE_VALUE )
|
|
SetupCloseInfFile( hInf );
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepConvertMultiSzToDelim(
|
|
IN PWSTR pValue,
|
|
IN DWORD Len,
|
|
IN WCHAR DelimFrom,
|
|
IN WCHAR Delim
|
|
)
|
|
/*
|
|
Convert the multi-sz delimiter \0 to space
|
|
*/
|
|
{
|
|
DWORD i;
|
|
|
|
for ( i=0; i<Len && pValue; i++) {
|
|
// if ( *(pValue+i) == L'\0' && *(pValue+i+1) != L'\0') {
|
|
if ( *(pValue+i) == DelimFrom && i+1 < Len &&
|
|
*(pValue+i+1) != L'\0' ) {
|
|
//
|
|
// a NULL delimiter is encounted and it's not the end (double NULL)
|
|
//
|
|
*(pValue+i) = Delim;
|
|
}
|
|
}
|
|
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
/*
|
|
|
|
SCESTATUS
|
|
SceInfpInfErrorToSceStatus(
|
|
IN SCEINF_STATUS InfErr
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine converts error codes from Inf routines into SCESTATUS code.
|
|
|
|
Arguments:
|
|
|
|
InfErr - The error code from Inf routines
|
|
|
|
Return Value:
|
|
|
|
SCESTATUS code
|
|
|
|
-- *//*
|
|
{
|
|
|
|
SCESTATUS rc;
|
|
|
|
switch ( InfErr ) {
|
|
case SCEINF_SUCCESS:
|
|
rc = SCESTATUS_SUCCESS;
|
|
break;
|
|
case SCEINF_PROFILE_NOT_FOUND:
|
|
rc = SCESTATUS_PROFILE_NOT_FOUND;
|
|
break;
|
|
case SCEINF_NOT_ENOUGH_MEMORY:
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
break;
|
|
case SCEINF_INVALID_PARAMETER:
|
|
rc = SCESTATUS_INVALID_PARAMETER;
|
|
break;
|
|
case SCEINF_CORRUPT_PROFILE:
|
|
rc = SCESTATUS_BAD_FORMAT;
|
|
break;
|
|
case SCEINF_INVALID_DATA:
|
|
rc = SCESTATUS_INVALID_DATA;
|
|
break;
|
|
case SCEINF_ACCESS_DENIED:
|
|
rc = SCESTATUS_ACCESS_DENIED;
|
|
break;
|
|
default:
|
|
rc = SCESTATUS_OTHER_ERROR;
|
|
break;
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
*/
|
|
//
|
|
// below are exported APIs in secedit.h
|
|
//
|
|
|
|
|
|
SCESTATUS
|
|
WINAPI
|
|
SceCreateDirectory(
|
|
IN PCWSTR ProfileLocation,
|
|
IN BOOL FileOrDir,
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor
|
|
)
|
|
{
|
|
return ( ScepCreateDirectory(ProfileLocation,
|
|
FileOrDir,
|
|
pSecurityDescriptor
|
|
));
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
WINAPI
|
|
SceCompareSecurityDescriptors(
|
|
IN AREA_INFORMATION Area,
|
|
IN PSECURITY_DESCRIPTOR pSD1,
|
|
IN PSECURITY_DESCRIPTOR pSD2,
|
|
IN SECURITY_INFORMATION SeInfo,
|
|
OUT PBOOL IsDifferent
|
|
)
|
|
{
|
|
SE_OBJECT_TYPE ObjectType;
|
|
BYTE resultSD=0;
|
|
SCESTATUS rc;
|
|
|
|
BOOL bContainer = FALSE;
|
|
|
|
switch ( Area) {
|
|
case AREA_REGISTRY_SECURITY:
|
|
ObjectType = SE_REGISTRY_KEY;
|
|
bContainer = TRUE;
|
|
break;
|
|
case AREA_FILE_SECURITY:
|
|
ObjectType = SE_FILE_OBJECT;
|
|
break;
|
|
case AREA_DS_OBJECTS:
|
|
ObjectType = SE_DS_OBJECT;
|
|
bContainer = TRUE;
|
|
break;
|
|
case AREA_SYSTEM_SERVICE:
|
|
ObjectType = SE_SERVICE;
|
|
break;
|
|
default:
|
|
ObjectType = SE_FILE_OBJECT;
|
|
break;
|
|
}
|
|
|
|
rc = ScepCompareObjectSecurity(
|
|
ObjectType,
|
|
bContainer,
|
|
pSD1,
|
|
pSD2,
|
|
SeInfo,
|
|
&resultSD);
|
|
|
|
if ( resultSD )
|
|
*IsDifferent = TRUE;
|
|
else
|
|
*IsDifferent = FALSE;
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
SCESTATUS
|
|
WINAPI
|
|
SceAddToNameStatusList(
|
|
IN OUT PSCE_NAME_STATUS_LIST *pNameStatusList,
|
|
IN PWSTR Name,
|
|
IN ULONG Len,
|
|
IN DWORD Status
|
|
)
|
|
{
|
|
return(ScepAddToNameStatusList(
|
|
pNameStatusList,
|
|
Name,
|
|
Len,
|
|
Status) );
|
|
}
|
|
|
|
SCESTATUS
|
|
WINAPI
|
|
SceAddToNameList(
|
|
IN OUT PSCE_NAME_LIST *pNameList,
|
|
IN PWSTR Name,
|
|
IN ULONG Len
|
|
)
|
|
{
|
|
return( ScepDosErrorToSceStatus(
|
|
ScepAddToNameList(
|
|
pNameList,
|
|
Name,
|
|
Len
|
|
) ) );
|
|
}
|
|
|
|
SCESTATUS
|
|
WINAPI
|
|
SceAddToObjectList(
|
|
IN OUT PSCE_OBJECT_LIST *pObjectList,
|
|
IN PWSTR Name,
|
|
IN ULONG Len,
|
|
IN BOOL IsContainer, // TRUE if the object is a container type
|
|
IN BYTE Status, // SCE_STATUS_IGNORE, SCE_STATUS_CHECK, SCE_STATUS_OVERWRITE
|
|
IN BYTE byFlags // SCE_CHECK_DUP if duplicate Name entry should not be added, SCE_INCREASE_COUNT
|
|
)
|
|
{
|
|
return(ScepDosErrorToSceStatus(
|
|
ScepAddToObjectList(
|
|
pObjectList,
|
|
Name,
|
|
Len,
|
|
IsContainer,
|
|
Status,
|
|
0,
|
|
byFlags
|
|
) ) );
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
SceCompareNameList(
|
|
IN PSCE_NAME_LIST pList1,
|
|
IN PSCE_NAME_LIST pList2
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine compares two name lists for exact match. Sequence is not
|
|
important in comparsion.
|
|
|
|
*/
|
|
{
|
|
PSCE_NAME_LIST pName1, pName2;
|
|
DWORD Count1=0, Count2=0;
|
|
|
|
|
|
if ( (pList2 == NULL && pList1 != NULL) ||
|
|
(pList2 != NULL && pList1 == NULL) ) {
|
|
// return(TRUE);
|
|
// should be not equal
|
|
return(FALSE);
|
|
}
|
|
|
|
for ( pName2=pList2; pName2 != NULL; pName2 = pName2->Next ) {
|
|
|
|
if ( pName2->Name == NULL ) {
|
|
continue;
|
|
}
|
|
Count2++;
|
|
}
|
|
|
|
for ( pName1=pList1; pName1 != NULL; pName1 = pName1->Next ) {
|
|
|
|
if ( pName1->Name == NULL ) {
|
|
continue;
|
|
}
|
|
Count1++;
|
|
|
|
for ( pName2=pList2; pName2 != NULL; pName2 = pName2->Next ) {
|
|
|
|
if ( pName2->Name == NULL ) {
|
|
continue;
|
|
}
|
|
if ( _wcsicmp(pName1->Name, pName2->Name) == 0 ) {
|
|
//
|
|
// find a match
|
|
//
|
|
break; // the second for loop
|
|
}
|
|
}
|
|
|
|
if ( pName2 == NULL ) {
|
|
//
|
|
// does not find a match
|
|
//
|
|
return(FALSE);
|
|
}
|
|
}
|
|
|
|
if ( Count1 != Count2 )
|
|
return(FALSE);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
WINAPI
|
|
SceEnumerateServices(
|
|
OUT PSCE_SERVICES *pServiceList,
|
|
IN BOOL bServiceNameOnly
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Enumerate all services installed on the local system. The information
|
|
returned include startup status and security descriptor on each service
|
|
object.
|
|
|
|
Arguments:
|
|
|
|
pServiceList - the list of services returned. Must be freed by LocalFree
|
|
|
|
return value:
|
|
|
|
ERROR_SUCCESS
|
|
Win32 error codes
|
|
|
|
*/
|
|
{
|
|
SC_HANDLE hScManager = NULL;
|
|
DWORD BytesNeeded, ServicesCount=0;
|
|
LPENUM_SERVICE_STATUS pEnumBuffer = NULL;
|
|
|
|
//
|
|
// check arguments
|
|
//
|
|
if ( NULL == pServiceList )
|
|
return(ERROR_INVALID_PARAMETER);
|
|
|
|
//
|
|
// open service control manager
|
|
//
|
|
hScManager = OpenSCManager(
|
|
NULL,
|
|
NULL,
|
|
MAXIMUM_ALLOWED //SC_MANAGER_ALL_ACCESS
|
|
// SC_MANAGER_CONNECT |
|
|
// SC_MANAGER_ENUMERATE_SERVICE |
|
|
// SC_MANAGER_QUERY_LOCK_STATUS
|
|
);
|
|
|
|
if ( NULL == hScManager ) {
|
|
|
|
return( GetLastError() );
|
|
}
|
|
|
|
DWORD rc=NO_ERROR;
|
|
DWORD i;
|
|
DWORD status;
|
|
|
|
if ( !bServiceNameOnly ) {
|
|
//
|
|
// Adjust privilege for setting SACL
|
|
//
|
|
status = SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, TRUE, NULL );
|
|
|
|
//
|
|
// if can't adjust privilege, ignore (will error out later if SACL is requested)
|
|
//
|
|
}
|
|
|
|
if ( !EnumServicesStatus(
|
|
hScManager,
|
|
SERVICE_WIN32, // do not expose driver | SERVICE_DRIVER,
|
|
SERVICE_STATE_ALL,
|
|
NULL,
|
|
0,
|
|
&BytesNeeded,
|
|
&ServicesCount,
|
|
NULL) ) {
|
|
|
|
rc = GetLastError();
|
|
|
|
if (rc == ERROR_MORE_DATA || rc == ERROR_INSUFFICIENT_BUFFER)
|
|
rc = ERROR_SUCCESS;
|
|
else
|
|
goto ExitHandler;
|
|
}
|
|
|
|
pEnumBuffer = (LPENUM_SERVICE_STATUS)LocalAlloc(LMEM_FIXED,(UINT)BytesNeeded);
|
|
|
|
if ( NULL == pEnumBuffer ) {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto ExitHandler;
|
|
}
|
|
|
|
if ( !EnumServicesStatus(
|
|
hScManager,
|
|
SERVICE_WIN32, // do not expose driver | SERVICE_DRIVER,
|
|
SERVICE_STATE_ALL,
|
|
pEnumBuffer,
|
|
BytesNeeded,
|
|
&BytesNeeded,
|
|
&ServicesCount,
|
|
NULL) ) {
|
|
|
|
rc = GetLastError();
|
|
goto ExitHandler;
|
|
|
|
}
|
|
|
|
for ( i=0; i < ServicesCount; i++ ) {
|
|
//
|
|
// add the service to our list
|
|
//
|
|
if ( bServiceNameOnly ) {
|
|
//
|
|
// only ask for service name, do not need to query
|
|
//
|
|
status = ScepAddOneServiceToList(
|
|
pEnumBuffer[i].lpServiceName,
|
|
pEnumBuffer[i].lpDisplayName,
|
|
0,
|
|
NULL,
|
|
0,
|
|
TRUE,
|
|
pServiceList
|
|
);
|
|
} else {
|
|
//
|
|
// query startup and security descriptor
|
|
//
|
|
status = ScepQueryAndAddService(
|
|
hScManager,
|
|
pEnumBuffer[i].lpServiceName,
|
|
pEnumBuffer[i].lpDisplayName,
|
|
pServiceList
|
|
);
|
|
}
|
|
|
|
if ( status != ERROR_SUCCESS ) {
|
|
rc = status;
|
|
goto ExitHandler;
|
|
}
|
|
}
|
|
|
|
ExitHandler:
|
|
|
|
if (pEnumBuffer) {
|
|
LocalFree(pEnumBuffer);
|
|
}
|
|
|
|
//
|
|
// clear memory and close handle
|
|
//
|
|
CloseServiceHandle (hScManager);
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
//
|
|
// free memory in pServiceList
|
|
//
|
|
SceFreePSCE_SERVICES(*pServiceList);
|
|
*pServiceList = NULL;
|
|
}
|
|
|
|
if ( !bServiceNameOnly ) {
|
|
//
|
|
// Adjust privilege for SACL
|
|
//
|
|
SceAdjustPrivilege( SE_SECURITY_PRIVILEGE, FALSE, NULL );
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ScepQueryAndAddService(
|
|
IN SC_HANDLE hScManager,
|
|
IN LPWSTR lpServiceName,
|
|
IN LPWSTR lpDisplayName,
|
|
OUT PSCE_SERVICES *pServiceList
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
Queries the security descriptor of the service and add all information
|
|
to PSCE_SERVICE list
|
|
|
|
Arguments:
|
|
|
|
hScManager - service control manager handle
|
|
|
|
lpServiceName - The service name
|
|
|
|
ServiceStatus - The service status
|
|
|
|
pServiceList - The service list to output
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS
|
|
Win32 errors
|
|
*/
|
|
{
|
|
SC_HANDLE hService;
|
|
DWORD rc=ERROR_SUCCESS;
|
|
|
|
if ( hScManager == NULL || lpServiceName == NULL || pServiceList == NULL ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// Open the service
|
|
// SERVICE_ALL_ACCESS |
|
|
// READ_CONTROL |
|
|
// ACCESS_SYSTEM_SECURITY
|
|
//
|
|
hService = OpenService(
|
|
hScManager,
|
|
lpServiceName,
|
|
MAXIMUM_ALLOWED |
|
|
ACCESS_SYSTEM_SECURITY
|
|
);
|
|
|
|
if ( hService != NULL ) {
|
|
//
|
|
// Query the startup type
|
|
//
|
|
DWORD BytesNeeded=0;
|
|
DWORD BufSize;
|
|
|
|
//
|
|
// Query configuration (Startup type)
|
|
// get size first
|
|
//
|
|
if ( !QueryServiceConfig(
|
|
hService,
|
|
NULL,
|
|
0,
|
|
&BytesNeeded
|
|
) ) {
|
|
|
|
rc = GetLastError();
|
|
|
|
if ( rc == ERROR_INSUFFICIENT_BUFFER ) {
|
|
//
|
|
// should always gets here
|
|
//
|
|
LPQUERY_SERVICE_CONFIG pConfig=NULL;
|
|
|
|
pConfig = (LPQUERY_SERVICE_CONFIG)LocalAlloc(0, BytesNeeded+1);
|
|
|
|
if ( pConfig != NULL ) {
|
|
|
|
rc = ERROR_SUCCESS;
|
|
BufSize=BytesNeeded;
|
|
//
|
|
// the real query for Startup type (pConfig->dwStartType)
|
|
//
|
|
if ( QueryServiceConfig(
|
|
hService,
|
|
pConfig,
|
|
BufSize,
|
|
&BytesNeeded
|
|
) ) {
|
|
//
|
|
// Query the security descriptor length
|
|
// the following function does not take NULL for the
|
|
// address of security descriptor so use a temp buffer first
|
|
// to get the real length
|
|
//
|
|
BYTE BufTmp[128];
|
|
SECURITY_INFORMATION SeInfo;
|
|
|
|
//
|
|
// only query DACL and SACL information
|
|
//
|
|
/*
|
|
SeInfo = DACL_SECURITY_INFORMATION |
|
|
SACL_SECURITY_INFORMATION |
|
|
GROUP_SECURITY_INFORMATION |
|
|
OWNER_SECURITY_INFORMATION;
|
|
*/
|
|
SeInfo = DACL_SECURITY_INFORMATION |
|
|
SACL_SECURITY_INFORMATION;
|
|
|
|
if ( !QueryServiceObjectSecurity(
|
|
hService,
|
|
SeInfo,
|
|
(PSECURITY_DESCRIPTOR)BufTmp,
|
|
128,
|
|
&BytesNeeded
|
|
) ) {
|
|
|
|
rc = GetLastError();
|
|
|
|
if ( rc == ERROR_INSUFFICIENT_BUFFER ||
|
|
rc == ERROR_MORE_DATA ) {
|
|
//
|
|
// if buffer is not enough, it is ok
|
|
// because BytesNeeded is the real length
|
|
//
|
|
rc = ERROR_SUCCESS;
|
|
}
|
|
} else
|
|
rc = ERROR_SUCCESS;
|
|
|
|
if ( rc == ERROR_SUCCESS ) {
|
|
//
|
|
// allocate buffer for security descriptor
|
|
//
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor=NULL;
|
|
|
|
pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, BytesNeeded+2);
|
|
|
|
if ( NULL != pSecurityDescriptor ) {
|
|
|
|
//
|
|
// query the security descriptor
|
|
//
|
|
BufSize = BytesNeeded;
|
|
|
|
if ( QueryServiceObjectSecurity(
|
|
hService,
|
|
SeInfo,
|
|
pSecurityDescriptor,
|
|
BufSize,
|
|
&BytesNeeded
|
|
) ) {
|
|
//
|
|
// create a service node and add it to the list
|
|
//
|
|
rc = ScepAddOneServiceToList(
|
|
lpServiceName,
|
|
lpDisplayName,
|
|
pConfig->dwStartType,
|
|
pSecurityDescriptor,
|
|
SeInfo,
|
|
TRUE,
|
|
pServiceList
|
|
);
|
|
} else {
|
|
//
|
|
// error query the security descriptor
|
|
//
|
|
rc = GetLastError();
|
|
}
|
|
|
|
if ( rc != ERROR_SUCCESS ) {
|
|
LocalFree(pSecurityDescriptor);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// cannot allocate memory for security descriptor
|
|
//
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
}
|
|
} else {
|
|
//
|
|
// cannot query config
|
|
//
|
|
rc = GetLastError();
|
|
}
|
|
|
|
LocalFree(pConfig);
|
|
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// should not fall in here, if it does, just return success
|
|
//
|
|
}
|
|
|
|
CloseServiceHandle(hService);
|
|
|
|
} else {
|
|
//
|
|
// cannot open service
|
|
//
|
|
rc = GetLastError();
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|
|
|
|
|
|
INT
|
|
ScepLookupPrivByValue(
|
|
IN DWORD Priv
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine looksup a privilege in SCE_Privileges table and returns the
|
|
index for the priv.
|
|
|
|
Arguments:
|
|
|
|
Priv - The privilege to look up
|
|
|
|
Return value:
|
|
|
|
The index in SCE_Privileges table if a match is found, or -1 for no match
|
|
-- */
|
|
{
|
|
DWORD i;
|
|
|
|
if ( Priv == 0 )
|
|
return (-1);
|
|
|
|
for ( i=0; i<cPrivCnt; i++) {
|
|
if ( SCE_Privileges[i].Value == Priv )
|
|
return i;
|
|
}
|
|
return (-1);
|
|
}
|
|
|
|
|
|
SCESTATUS
|
|
ScepGetProductType(
|
|
OUT PSCE_SERVER_TYPE srvProduct
|
|
)
|
|
{
|
|
|
|
NT_PRODUCT_TYPE theType;
|
|
|
|
if ( RtlGetNtProductType(&theType) ) {
|
|
|
|
#if _WIN32_WINNT>=0x0500
|
|
//
|
|
// NT5+
|
|
//
|
|
switch (theType) {
|
|
case NtProductLanManNt:
|
|
*srvProduct = SCESVR_DC_WITH_DS;
|
|
break;
|
|
case NtProductServer:
|
|
*srvProduct = SCESVR_NT5_SERVER;
|
|
break;
|
|
case NtProductWinNt:
|
|
*srvProduct = SCESVR_NT5_WKS;
|
|
break;
|
|
default:
|
|
*srvProduct = SCESVR_UNKNOWN;
|
|
}
|
|
#else
|
|
//
|
|
// NT4
|
|
//
|
|
switch (theType) {
|
|
case NtProductLanManNt:
|
|
*srvProduct = SCESVR_DC;
|
|
break;
|
|
case NtProductServer:
|
|
*srvProduct = SCESVR_NT4_SERVER;
|
|
break;
|
|
case NtProductWinNt:
|
|
*srvProduct = SCESVR_NT4_WKS;
|
|
break;
|
|
default:
|
|
*srvProduct = SCESVR_UNKNOWN;
|
|
}
|
|
#endif
|
|
} else {
|
|
*srvProduct = SCESVR_UNKNOWN;
|
|
}
|
|
return(SCESTATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
ScepAddTwoNamesToNameList(
|
|
OUT PSCE_NAME_LIST *pNameList,
|
|
IN BOOL bAddSeparator,
|
|
IN PWSTR Name1,
|
|
IN ULONG Length1,
|
|
IN PWSTR Name2,
|
|
IN ULONG Length2
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine adds two names (wchar) to the name list in the format of
|
|
Name1\Name2, or Name1Name2, depends if bSeparator is TRUE. This routine
|
|
is used for Domain\Account tracking list
|
|
|
|
Arguments:
|
|
|
|
pNameList - The name list to add to.
|
|
|
|
Name1 - The name 1 to add
|
|
|
|
Length1 - the length of name1 (number of wchars)
|
|
|
|
Name2 - the name 2 to add
|
|
|
|
Length2 - the length of name2 (number of wchars)
|
|
|
|
Return value:
|
|
|
|
Win32 error code
|
|
-- */
|
|
{
|
|
|
|
PSCE_NAME_LIST pList=NULL;
|
|
ULONG Length;
|
|
|
|
if ( pNameList == NULL )
|
|
return(ERROR_INVALID_PARAMETER);
|
|
|
|
if ( Name1 == NULL && Name2 == NULL )
|
|
return(NO_ERROR);
|
|
|
|
Length = Length1 + Length2;
|
|
|
|
if ( Length <= 0 )
|
|
return(NO_ERROR);
|
|
|
|
pList = (PSCE_NAME_LIST)ScepAlloc( (UINT)0, sizeof(SCE_NAME_LIST));
|
|
|
|
if ( pList == NULL )
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
|
|
if ( bAddSeparator ) {
|
|
Length++;
|
|
}
|
|
|
|
pList->Name = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (Length+1)*sizeof(TCHAR));
|
|
if ( pList->Name == NULL ) {
|
|
ScepFree(pList);
|
|
return(ERROR_NOT_ENOUGH_MEMORY);
|
|
}
|
|
|
|
if ( Name1 != NULL && Length1 > 0 )
|
|
wcsncpy(pList->Name, Name1, Length1);
|
|
|
|
if ( bAddSeparator ) {
|
|
wcsncat(pList->Name, L"\\", 1);
|
|
}
|
|
if ( Name2 != NULL && Length2 > 0 )
|
|
wcsncat(pList->Name, Name2, Length2);
|
|
|
|
pList->Next = *pNameList;
|
|
*pNameList = pList;
|
|
|
|
return(NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ScepDomainIdToSid(
|
|
IN PSID DomainId,
|
|
IN ULONG RelativeId,
|
|
OUT PSID *Sid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a domain Id and a relative ID create a SID
|
|
|
|
Arguments:
|
|
|
|
DomainId - The template SID to use.
|
|
|
|
RelativeId - The relative Id to append to the DomainId.
|
|
|
|
Sid - Returns a pointer to an allocated buffer containing the resultant
|
|
Sid. Free this buffer using NetpMemoryFree.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
--*/
|
|
{
|
|
UCHAR DomainIdSubAuthorityCount; // Number of sub authorities in domain ID
|
|
|
|
ULONG SidLength; // Length of newly allocated SID
|
|
|
|
//
|
|
// Allocate a Sid which has one more sub-authority than the domain ID.
|
|
//
|
|
|
|
DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
|
|
SidLength = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
|
|
|
|
if ((*Sid = (PSID) ScepAlloc( (UINT)0, SidLength )) == NULL ) {
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
//
|
|
// Initialize the new SID to have the same inital value as the
|
|
// domain ID.
|
|
//
|
|
|
|
if ( !NT_SUCCESS( RtlCopySid( SidLength, *Sid, DomainId ) ) ) {
|
|
ScepFree( *Sid );
|
|
*Sid = NULL;
|
|
return STATUS_INTERNAL_ERROR;
|
|
}
|
|
|
|
//
|
|
// Adjust the sub-authority count and
|
|
// add the relative Id unique to the newly allocated SID
|
|
//
|
|
|
|
(*(RtlSubAuthorityCountSid( *Sid ))) ++;
|
|
*RtlSubAuthoritySid( *Sid, DomainIdSubAuthorityCount ) = RelativeId;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepConvertSidToPrefixStringSid(
|
|
IN PSID pSid,
|
|
OUT PWSTR *StringSid
|
|
)
|
|
/*
|
|
The pair routine to convert stringsid to a Sid is ConvertStringSidToSid
|
|
defined in sddl.h
|
|
*/
|
|
{
|
|
if ( pSid == NULL || StringSid == NULL ) {
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
UNICODE_STRING UnicodeStringSid;
|
|
|
|
DWORD rc = RtlNtStatusToDosError(
|
|
RtlConvertSidToUnicodeString(&UnicodeStringSid,
|
|
pSid,
|
|
TRUE ));
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
*StringSid = (PWSTR)ScepAlloc(LPTR, UnicodeStringSid.Length+2*sizeof(WCHAR));
|
|
|
|
if ( *StringSid ) {
|
|
|
|
(*StringSid)[0] = L'*';
|
|
wcsncpy( (*StringSid)+1, UnicodeStringSid.Buffer, UnicodeStringSid.Length/2);
|
|
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtlFreeUnicodeString( &UnicodeStringSid );
|
|
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
|
|
NTSTATUS ScepIsMigratedAccount(
|
|
IN LSA_HANDLE LsaHandle,
|
|
IN PLSA_UNICODE_STRING pName,
|
|
IN PLSA_UNICODE_STRING pDomain,
|
|
IN PSID pSid,
|
|
OUT bool *pbMigratedAccount
|
|
)
|
|
{
|
|
NTSTATUS NtStatus = STATUS_SUCCESS;
|
|
DWORD rc;
|
|
LSA_UNICODE_STRING lusName;
|
|
PSCE_NAME_LIST pNameList = NULL;
|
|
PLSA_REFERENCED_DOMAIN_LIST pRefDomains = NULL;
|
|
PLSA_TRANSLATED_SID2 pSids = NULL;
|
|
|
|
rc = ScepAddTwoNamesToNameList(
|
|
&pNameList,
|
|
TRUE,
|
|
pDomain->Buffer,
|
|
pDomain->Length/2,
|
|
pName->Buffer,
|
|
pName->Length/2);
|
|
|
|
if (ERROR_SUCCESS != rc) {
|
|
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
RtlInitUnicodeString(&lusName, pNameList->Name);
|
|
|
|
NtStatus = LsaLookupNames2(
|
|
LsaHandle,
|
|
LSA_LOOKUP_ISOLATED_AS_LOCAL,
|
|
1,
|
|
&lusName,
|
|
&pRefDomains,
|
|
&pSids);
|
|
|
|
if (NT_SUCCESS(NtStatus)) {
|
|
|
|
*pbMigratedAccount = !EqualSid(pSid, pSids[0].Sid);
|
|
}
|
|
}
|
|
|
|
if (pRefDomains) {
|
|
|
|
LsaFreeMemory(pRefDomains);
|
|
}
|
|
|
|
if (pSids) {
|
|
|
|
LsaFreeMemory(pSids);
|
|
}
|
|
|
|
if (pNameList) {
|
|
|
|
ScepFreeNameList(pNameList);
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ScepConvertSidToName(
|
|
IN LSA_HANDLE LsaPolicy,
|
|
IN PSID AccountSid,
|
|
IN BOOL bFromDomain,
|
|
OUT PWSTR *AccountName,
|
|
OUT DWORD *Length OPTIONAL
|
|
)
|
|
{
|
|
if ( LsaPolicy == NULL || AccountSid == NULL ||
|
|
AccountName == NULL ) {
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
PSID pTmpSid=AccountSid;
|
|
PLSA_TRANSLATED_NAME Names=NULL;
|
|
PLSA_REFERENCED_DOMAIN_LIST ReferencedDomains=NULL;
|
|
|
|
NTSTATUS NtStatus = LsaLookupSids(
|
|
LsaPolicy,
|
|
1,
|
|
(PSID *)&pTmpSid,
|
|
&ReferencedDomains,
|
|
&Names
|
|
);
|
|
|
|
DWORD Len=0;
|
|
|
|
if ( NT_SUCCESS(NtStatus) ) {
|
|
|
|
if ( ( Names[0].Use != SidTypeInvalid &&
|
|
Names[0].Use != SidTypeUnknown ) ) {
|
|
|
|
//
|
|
// build the account name without domain name
|
|
//
|
|
if ( bFromDomain && Names[0].Use != SidTypeWellKnownGroup &&
|
|
ReferencedDomains->Entries > 0 &&
|
|
ReferencedDomains->Domains != NULL &&
|
|
Names[0].DomainIndex != -1 &&
|
|
(ULONG)(Names[0].DomainIndex) < ReferencedDomains->Entries &&
|
|
ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length > 0 &&
|
|
ScepIsSidFromAccountDomain( ReferencedDomains->Domains[Names[0].DomainIndex].Sid ) ) {
|
|
|
|
// For migrated accounts, sid will map to the new account and we'll lose
|
|
// permissions for the original account. Detect this case by doing a reverse
|
|
// lookup and comparing the SIDs
|
|
// If sid -> name -> sid returns a different sid, then it's a sid history
|
|
// name lookup and the account is from a different domain. Converting to current
|
|
// name will cause it to lose the original sid from the policy. We'll hold on
|
|
// to the original SID.
|
|
|
|
bool bMigratedAccount = false;
|
|
|
|
NtStatus = ScepIsMigratedAccount(
|
|
LsaPolicy,
|
|
&Names[0].Name,
|
|
&ReferencedDomains->Domains[Names[0].DomainIndex].Name,
|
|
pTmpSid,
|
|
&bMigratedAccount);
|
|
|
|
if(NT_SUCCESS(NtStatus) && bMigratedAccount) {
|
|
|
|
// return SID string
|
|
|
|
NtStatus = ScepConvertSidToPrefixStringSid(pTmpSid, AccountName);
|
|
|
|
Len = wcslen(*AccountName);
|
|
|
|
} else {
|
|
|
|
NtStatus = STATUS_SUCCESS; // ignore failure to detect migrated account
|
|
|
|
//
|
|
// build domain name\account name
|
|
//
|
|
|
|
Len = Names[0].Name.Length + ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length + 2;
|
|
|
|
*AccountName = (PWSTR)LocalAlloc(LPTR, Len+sizeof(TCHAR));
|
|
|
|
if ( *AccountName ) {
|
|
wcsncpy(*AccountName, ReferencedDomains->Domains[Names[0].DomainIndex].Name.Buffer,
|
|
ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length/2);
|
|
(*AccountName)[ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length/2] = L'\\';
|
|
wcsncpy((*AccountName)+ReferencedDomains->Domains[Names[0].DomainIndex].Name.Length/2+1,
|
|
Names[0].Name.Buffer, Names[0].Name.Length/2);
|
|
} else {
|
|
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
Len /= 2;
|
|
}
|
|
|
|
} else {
|
|
|
|
Len = Names[0].Name.Length/2;
|
|
|
|
*AccountName = (PWSTR)LocalAlloc(LPTR, Names[0].Name.Length+2);
|
|
|
|
if ( *AccountName ) {
|
|
|
|
wcsncpy(*AccountName, Names[0].Name.Buffer, Len);
|
|
|
|
} else {
|
|
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
NtStatus = STATUS_NONE_MAPPED;
|
|
}
|
|
|
|
}
|
|
|
|
if ( ReferencedDomains ) {
|
|
LsaFreeMemory(ReferencedDomains);
|
|
ReferencedDomains = NULL;
|
|
}
|
|
|
|
if ( Names ) {
|
|
LsaFreeMemory(Names);
|
|
Names = NULL;
|
|
}
|
|
|
|
if ( NT_SUCCESS(NtStatus) && Length ) {
|
|
*Length = Len;
|
|
}
|
|
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
ScepConvertNameToSid(
|
|
IN LSA_HANDLE LsaPolicy,
|
|
IN PWSTR AccountName,
|
|
OUT PSID *AccountSid
|
|
)
|
|
{
|
|
if ( LsaPolicy == NULL || AccountName == NULL ||
|
|
AccountSid == NULL ) {
|
|
return(STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
|
|
PLSA_TRANSLATED_SID2 Sids=NULL;
|
|
|
|
NTSTATUS NtStatus = ScepLsaLookupNames2(
|
|
LsaPolicy,
|
|
LSA_LOOKUP_ISOLATED_AS_LOCAL,
|
|
AccountName,
|
|
&RefDomains,
|
|
&Sids
|
|
);
|
|
|
|
if ( NT_SUCCESS(NtStatus) && Sids ) {
|
|
|
|
//
|
|
// build the account sid
|
|
//
|
|
if ( Sids[0].Use != SidTypeInvalid &&
|
|
Sids[0].Use != SidTypeUnknown &&
|
|
Sids[0].Sid != NULL ) {
|
|
|
|
//
|
|
// this name is mapped, the SID is in Sids[0].Sid
|
|
//
|
|
|
|
DWORD SidLength = RtlLengthSid(Sids[0].Sid);
|
|
|
|
if ( (*AccountSid = (PSID) ScepAlloc( (UINT)0, SidLength)) == NULL ) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
} else {
|
|
|
|
//
|
|
// copy the SID
|
|
//
|
|
|
|
NtStatus = RtlCopySid( SidLength, *AccountSid, Sids[0].Sid );
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
ScepFree( *AccountSid );
|
|
*AccountSid = NULL;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
|
|
NtStatus = STATUS_NONE_MAPPED;
|
|
}
|
|
}
|
|
|
|
if ( Sids ) {
|
|
|
|
LsaFreeMemory(Sids);
|
|
}
|
|
|
|
if ( RefDomains ) {
|
|
|
|
LsaFreeMemory(RefDomains);
|
|
}
|
|
|
|
return(NtStatus);
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
ScepLsaLookupNames2(
|
|
IN LSA_HANDLE PolicyHandle,
|
|
IN ULONG Flags,
|
|
IN PWSTR pszAccountName,
|
|
OUT PLSA_REFERENCED_DOMAIN_LIST *ReferencedDomains,
|
|
OUT PLSA_TRANSLATED_SID2 *Sids
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Similar to LsaLookupNames2 except that on local lookup
|
|
failures, it resolves free text accounts to the domain
|
|
this machine is joined to
|
|
|
|
Arguments:
|
|
|
|
PolicyHandle - handle to LSA
|
|
|
|
Flags - usually LSA_LOOKUP_ISOLATED_AS_LOCAL
|
|
|
|
pszAccountName - name of account to lookup
|
|
|
|
ReferencedDomains - returns the reference domain id
|
|
(to be freed by caller)
|
|
|
|
Sids - returns the SID looked up
|
|
(to be freed by caller)
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
--*/
|
|
{
|
|
PWSTR pszScopedName = NULL;
|
|
UNICODE_STRING UnicodeName;
|
|
PPOLICY_ACCOUNT_DOMAIN_INFO pDomainInfo = NULL;
|
|
|
|
RtlInitUnicodeString(&UnicodeName, pszAccountName);
|
|
|
|
NTSTATUS NtStatus = LsaLookupNames2(
|
|
PolicyHandle,
|
|
Flags,
|
|
1,
|
|
&UnicodeName,
|
|
ReferencedDomains,
|
|
Sids
|
|
);
|
|
|
|
if ((NtStatus == STATUS_SOME_NOT_MAPPED ||
|
|
NtStatus == STATUS_NONE_MAPPED) &&
|
|
NULL == wcschr(pszAccountName, L'\\') ) {
|
|
|
|
if ( NULL != *Sids) {
|
|
LsaFreeMemory(*Sids);
|
|
*Sids = NULL;
|
|
}
|
|
|
|
if ( NULL != *ReferencedDomains) {
|
|
LsaFreeMemory(*ReferencedDomains);
|
|
*ReferencedDomains = NULL;
|
|
}
|
|
|
|
NtStatus = LsaQueryInformationPolicy(PolicyHandle,
|
|
PolicyDnsDomainInformation,
|
|
( PVOID * )&pDomainInfo );
|
|
|
|
if (!NT_SUCCESS(NtStatus) ||
|
|
pDomainInfo == NULL ||
|
|
pDomainInfo->DomainName.Buffer == NULL ||
|
|
pDomainInfo->DomainName.Length <= 0) {
|
|
|
|
NtStatus = STATUS_SOME_NOT_MAPPED;
|
|
goto ExitHandler;
|
|
}
|
|
|
|
pszScopedName = (PWSTR) LocalAlloc(LMEM_ZEROINIT,
|
|
(pDomainInfo->DomainName.Length/2 + wcslen(pszAccountName) + 2) * sizeof(WCHAR));
|
|
|
|
if (pszScopedName == NULL) {
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
goto ExitHandler;
|
|
}
|
|
|
|
wcsncpy(pszScopedName, pDomainInfo->DomainName.Buffer, pDomainInfo->DomainName.Length/2);
|
|
wcscat(pszScopedName, L"\\");
|
|
wcscat(pszScopedName, pszAccountName);
|
|
|
|
RtlInitUnicodeString(&UnicodeName, pszScopedName);
|
|
|
|
NtStatus = LsaLookupNames2(
|
|
PolicyHandle,
|
|
Flags,
|
|
1,
|
|
&UnicodeName,
|
|
ReferencedDomains,
|
|
Sids
|
|
);
|
|
|
|
}
|
|
|
|
ExitHandler:
|
|
|
|
if (pszScopedName) {
|
|
LocalFree(pszScopedName);
|
|
}
|
|
|
|
if (pDomainInfo) {
|
|
LsaFreeMemory( pDomainInfo );
|
|
}
|
|
|
|
if(!NT_SUCCESS(NtStatus))
|
|
{
|
|
if ( NULL != *Sids) {
|
|
LsaFreeMemory(*Sids);
|
|
*Sids = NULL;
|
|
}
|
|
|
|
if ( NULL != *ReferencedDomains) {
|
|
LsaFreeMemory(*ReferencedDomains);
|
|
*ReferencedDomains = NULL;
|
|
}
|
|
}
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepConvertNameToSidString(
|
|
IN LSA_HANDLE LsaHandle,
|
|
IN PWSTR Name,
|
|
IN BOOL bAccountDomainOnly,
|
|
OUT PWSTR *SidString,
|
|
OUT DWORD *SidStrLen
|
|
)
|
|
{
|
|
if ( LsaHandle == NULL || Name == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( Name[0] == L'\0' ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( SidString == NULL || SidStrLen == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
//
|
|
// convert the sid string to a real sid
|
|
//
|
|
PSID pSid=NULL;
|
|
NTSTATUS NtStatus;
|
|
DWORD rc;
|
|
PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
|
|
PLSA_TRANSLATED_SID2 Sids=NULL;
|
|
|
|
|
|
NtStatus = ScepLsaLookupNames2(
|
|
LsaHandle,
|
|
LSA_LOOKUP_ISOLATED_AS_LOCAL,
|
|
Name,
|
|
&RefDomains,
|
|
&Sids
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( ERROR_SUCCESS == rc && Sids ) {
|
|
|
|
//
|
|
// name is found, make domain\account format
|
|
//
|
|
if ( Sids[0].Use != SidTypeInvalid &&
|
|
Sids[0].Use != SidTypeUnknown &&
|
|
Sids[0].Sid != NULL ) {
|
|
|
|
//
|
|
// this name is mapped
|
|
//
|
|
|
|
if ( !bAccountDomainOnly ||
|
|
ScepIsSidFromAccountDomain( Sids[0].Sid ) ) {
|
|
|
|
//
|
|
// convert to a sid string, note: a prefix "*" should be added
|
|
//
|
|
UNICODE_STRING UnicodeStringSid;
|
|
|
|
rc = RtlNtStatusToDosError(
|
|
RtlConvertSidToUnicodeString(&UnicodeStringSid,
|
|
Sids[0].Sid,
|
|
TRUE ));
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
*SidStrLen = UnicodeStringSid.Length/2 + 1;
|
|
*SidString = (PWSTR)ScepAlloc(LPTR, UnicodeStringSid.Length + 2*sizeof(WCHAR));
|
|
|
|
if ( *SidString ) {
|
|
|
|
(*SidString)[0] = L'*';
|
|
wcsncpy((*SidString)+1, UnicodeStringSid.Buffer, (*SidStrLen)-1);
|
|
|
|
} else {
|
|
*SidStrLen = 0;
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
RtlFreeUnicodeString( &UnicodeStringSid );
|
|
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// add only the account name
|
|
//
|
|
rc = ERROR_NONE_MAPPED;
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = ERROR_NONE_MAPPED;
|
|
}
|
|
|
|
}
|
|
|
|
if ( Sids ) {
|
|
|
|
LsaFreeMemory(Sids);
|
|
}
|
|
|
|
if ( RefDomains ) {
|
|
|
|
LsaFreeMemory(RefDomains);
|
|
}
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepLookupSidStringAndAddToNameList(
|
|
IN LSA_HANDLE LsaHandle,
|
|
IN OUT PSCE_NAME_LIST *pNameList,
|
|
IN PWSTR LookupString,
|
|
IN ULONG Len
|
|
)
|
|
{
|
|
if ( LsaHandle == NULL || LookupString == NULL ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( LookupString[0] == L'\0' ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( Len <= 3 ||
|
|
(LookupString[1] != L'S' && LookupString[1] != L's') ||
|
|
LookupString[2] != L'-' ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// convert the sid string to a real sid
|
|
//
|
|
PSID pSid=NULL;
|
|
NTSTATUS NtStatus;
|
|
DWORD rc;
|
|
PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
|
|
PLSA_TRANSLATED_NAME Names=NULL;
|
|
|
|
if ( ConvertStringSidToSid(LookupString+1, &pSid) ) {
|
|
|
|
NtStatus = LsaLookupSids(
|
|
LsaHandle,
|
|
1,
|
|
&pSid,
|
|
&RefDomains,
|
|
&Names
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
} else {
|
|
rc = GetLastError();
|
|
}
|
|
|
|
if ( ERROR_SUCCESS == rc && Names && RefDomains ) {
|
|
|
|
//
|
|
// name is found, make domain\account format
|
|
//
|
|
if ( ( Names[0].Use != SidTypeInvalid &&
|
|
Names[0].Use != SidTypeUnknown ) ) {
|
|
|
|
//
|
|
// this name is mapped
|
|
//
|
|
|
|
if ( RefDomains->Entries > 0 && Names[0].Use != SidTypeWellKnownGroup &&
|
|
RefDomains->Domains != NULL &&
|
|
Names[0].DomainIndex != -1 &&
|
|
(ULONG)(Names[0].DomainIndex) < RefDomains->Entries &&
|
|
RefDomains->Domains[Names[0].DomainIndex].Name.Length > 0 &&
|
|
ScepIsSidFromAccountDomain( RefDomains->Domains[Names[0].DomainIndex].Sid ) ) {
|
|
|
|
// For migrated accounts, sid will map to the new account and we'll lose
|
|
// permissions for the original account. Detect this case by doing a reverse
|
|
// lookup and comparing the SIDs
|
|
// If sid -> name -> sid returns a different sid, then it's a sid history
|
|
// name lookup and the account is from a different domain. Converting to current
|
|
// name will cause it to lose the original sid from the policy. We'll hold on
|
|
// to the original SID.
|
|
|
|
bool bMigratedAccount = false;
|
|
|
|
NtStatus = ScepIsMigratedAccount(
|
|
LsaHandle,
|
|
&Names[0].Name,
|
|
&RefDomains->Domains[Names[0].DomainIndex].Name,
|
|
pSid,
|
|
&bMigratedAccount);
|
|
|
|
if(NT_SUCCESS(NtStatus) && bMigratedAccount) {
|
|
|
|
// add SID string to list
|
|
|
|
rc = ScepAddToNameList(
|
|
pNameList,
|
|
LookupString,
|
|
Len);
|
|
|
|
} else {
|
|
|
|
NtStatus = STATUS_SUCCESS; // ignore failure to detect migrated account
|
|
|
|
//
|
|
// add both domain name and account name
|
|
//
|
|
rc = ScepAddTwoNamesToNameList(
|
|
pNameList,
|
|
TRUE,
|
|
RefDomains->Domains[Names[0].DomainIndex].Name.Buffer,
|
|
RefDomains->Domains[Names[0].DomainIndex].Name.Length/2,
|
|
Names[0].Name.Buffer,
|
|
Names[0].Name.Length/2);
|
|
}
|
|
|
|
} else {
|
|
//
|
|
// add only the account name
|
|
//
|
|
rc = ScepAddToNameList(
|
|
pNameList,
|
|
Names[0].Name.Buffer,
|
|
Names[0].Name.Length/2);
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = ERROR_NONE_MAPPED;
|
|
}
|
|
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
//
|
|
// either invalid sid string, or not found a name map, or
|
|
// failed to add to the name list, just simply add the sid string to the name list
|
|
//
|
|
|
|
rc = ScepAddToNameList(
|
|
pNameList,
|
|
LookupString,
|
|
Len);
|
|
}
|
|
|
|
if ( Names ) {
|
|
|
|
LsaFreeMemory(Names);
|
|
}
|
|
|
|
if ( RefDomains ) {
|
|
|
|
LsaFreeMemory(RefDomains);
|
|
}
|
|
|
|
if ( pSid ) {
|
|
|
|
LocalFree(pSid);
|
|
}
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
|
|
}
|
|
|
|
|
|
|
|
SCESTATUS
|
|
ScepLookupNameAndAddToSidStringList(
|
|
IN LSA_HANDLE LsaHandle,
|
|
IN OUT PSCE_NAME_LIST *pNameList,
|
|
IN PWSTR LookupString,
|
|
IN ULONG Len
|
|
)
|
|
{
|
|
if ( LsaHandle == NULL || LookupString == NULL || Len == 0 ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if ( LookupString[0] == L'\0' ) {
|
|
return(SCESTATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
//
|
|
// convert the sid string to a real sid
|
|
//
|
|
PSID pSid=NULL;
|
|
NTSTATUS NtStatus;
|
|
DWORD rc;
|
|
PLSA_REFERENCED_DOMAIN_LIST RefDomains=NULL;
|
|
PLSA_TRANSLATED_SID2 Sids=NULL;
|
|
UNICODE_STRING UnicodeName;
|
|
|
|
NtStatus = ScepLsaLookupNames2(
|
|
LsaHandle,
|
|
LSA_LOOKUP_ISOLATED_AS_LOCAL,
|
|
LookupString,
|
|
&RefDomains,
|
|
&Sids
|
|
);
|
|
|
|
rc = RtlNtStatusToDosError(NtStatus);
|
|
|
|
if ( ERROR_SUCCESS == rc && Sids ) {
|
|
|
|
//
|
|
// name is found, make domain\account format
|
|
//
|
|
if ( Sids[0].Use != SidTypeInvalid &&
|
|
Sids[0].Use != SidTypeUnknown &&
|
|
Sids[0].Sid ) {
|
|
|
|
//
|
|
// this name is mapped
|
|
// convert to a sid string, note: a prefix "*" should be added
|
|
//
|
|
|
|
UNICODE_STRING UnicodeStringSid;
|
|
|
|
rc = RtlNtStatusToDosError(
|
|
RtlConvertSidToUnicodeString(&UnicodeStringSid,
|
|
Sids[0].Sid,
|
|
TRUE ));
|
|
|
|
if ( ERROR_SUCCESS == rc ) {
|
|
|
|
rc = ScepAddTwoNamesToNameList(
|
|
pNameList,
|
|
FALSE,
|
|
TEXT("*"),
|
|
1,
|
|
UnicodeStringSid.Buffer,
|
|
UnicodeStringSid.Length/2);
|
|
|
|
RtlFreeUnicodeString( &UnicodeStringSid );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rc = ERROR_NONE_MAPPED;
|
|
}
|
|
|
|
}
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
|
|
//
|
|
// either invalid sid string, or not found a name map, or
|
|
// failed to add to the name list, just simply add the sid string to the name list
|
|
//
|
|
|
|
rc = ScepAddToNameList(
|
|
pNameList,
|
|
LookupString,
|
|
Len);
|
|
}
|
|
|
|
if ( Sids ) {
|
|
|
|
LsaFreeMemory(Sids);
|
|
}
|
|
|
|
if ( RefDomains ) {
|
|
|
|
LsaFreeMemory(RefDomains);
|
|
}
|
|
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScepOpenLsaPolicy(
|
|
IN ACCESS_MASK access,
|
|
OUT PLSA_HANDLE pPolicyHandle,
|
|
IN BOOL bDoNotNotify
|
|
)
|
|
/* ++
|
|
Routine Description:
|
|
|
|
This routine opens the LSA policy with the desired access.
|
|
|
|
Arguments:
|
|
|
|
access - the desired access to the policy
|
|
|
|
pPolicyHandle - returned address of the Policy Handle
|
|
|
|
Return value:
|
|
|
|
NTSTATUS
|
|
-- */
|
|
{
|
|
|
|
NTSTATUS NtStatus;
|
|
LSA_OBJECT_ATTRIBUTES attributes;
|
|
SECURITY_QUALITY_OF_SERVICE service;
|
|
|
|
|
|
memset( &attributes, 0, sizeof(attributes) );
|
|
attributes.Length = sizeof(attributes);
|
|
attributes.SecurityQualityOfService = &service;
|
|
service.Length = sizeof(service);
|
|
service.ImpersonationLevel= SecurityImpersonation;
|
|
service.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
service.EffectiveOnly = TRUE;
|
|
|
|
//
|
|
// open the lsa policy first
|
|
//
|
|
|
|
NtStatus = LsaOpenPolicy(
|
|
NULL,
|
|
&attributes,
|
|
access,
|
|
pPolicyHandle
|
|
);
|
|
/*
|
|
if ( NT_SUCCESS(NtStatus) &&
|
|
bDoNotNotify &&
|
|
*pPolicyHandle ) {
|
|
|
|
NtStatus = LsaSetPolicyReplicationHandle(pPolicyHandle);
|
|
|
|
if ( !NT_SUCCESS(NtStatus) ) {
|
|
LsaClose( *pPolicyHandle );
|
|
*pPolicyHandle = NULL;
|
|
}
|
|
}
|
|
*/
|
|
return(NtStatus);
|
|
}
|
|
|
|
|
|
|
|
BOOL
|
|
ScepIsSidFromAccountDomain(
|
|
IN PSID pSid
|
|
)
|
|
{
|
|
if ( pSid == NULL ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
if ( !RtlValidSid(pSid) ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
PSID_IDENTIFIER_AUTHORITY pia = RtlIdentifierAuthoritySid ( pSid );
|
|
|
|
if ( pia ) {
|
|
|
|
if ( pia->Value[5] != 5 ||
|
|
pia->Value[0] != 0 ||
|
|
pia->Value[1] != 0 ||
|
|
pia->Value[2] != 0 ||
|
|
pia->Value[3] != 0 ||
|
|
pia->Value[4] != 0 ) {
|
|
//
|
|
// this is not a account from account domain
|
|
//
|
|
return(FALSE);
|
|
}
|
|
|
|
|
|
if ( RtlSubAuthorityCountSid( pSid ) == 0 ||
|
|
*RtlSubAuthoritySid ( pSid, 0 ) != SECURITY_NT_NON_UNIQUE ) {
|
|
return(FALSE);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: SetupINFAsUCS2
|
|
//
|
|
// Synopsis: Dumps some UCS-2 to the specified INF file if it
|
|
// doesn't already exist; this makes the .inf/.ini manipulation code
|
|
// use UCS-2.
|
|
//
|
|
// Arguments: The file to create and dump to
|
|
//
|
|
// Returns: 0 == failure, non-zero == success; use GetLastError()
|
|
// to retrieve the error code (same as WriteFile).
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
BOOL
|
|
SetupINFAsUCS2(LPCTSTR szName)
|
|
{
|
|
HANDLE file;
|
|
BOOL status;
|
|
|
|
file = CreateFile(szName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL);
|
|
if (file == INVALID_HANDLE_VALUE) {
|
|
if (GetLastError() != ERROR_ALREADY_EXISTS)
|
|
// Well, this isn't good -- we lose.
|
|
status = FALSE;
|
|
else
|
|
// Otherwise, the file already existed, which is just fine.
|
|
// We'll just let the .inf/.ini manipulation code keep using
|
|
// the same charset&encoding...
|
|
status = TRUE;
|
|
} else {
|
|
// We created the file -- it didn't exist.
|
|
// So we need to spew a little UCS-2 into it.
|
|
static WCHAR str[] = L"0[Unicode]\r\nUnicode=yes\r\n";
|
|
DWORD n_written;
|
|
BYTE *pbStr = (BYTE *)str;
|
|
|
|
pbStr[0] = 0xFF;
|
|
pbStr[1] = 0xFE;
|
|
|
|
status = WriteFile(file,
|
|
(LPCVOID)str,
|
|
sizeof(str) - sizeof(UNICODE_NULL),
|
|
&n_written,
|
|
NULL);
|
|
CloseHandle(file);
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ScepStripPrefix
|
|
//
|
|
// Arguments: pwszPath to look in
|
|
//
|
|
// Returns: Returns ptr to stripped path (same if no stripping)
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
WCHAR *
|
|
ScepStripPrefix(
|
|
IN LPTSTR pwszPath
|
|
)
|
|
{
|
|
WCHAR wszMachPrefix[] = TEXT("LDAP://CN=Machine,");
|
|
INT iMachPrefixLen = lstrlen( wszMachPrefix );
|
|
WCHAR wszUserPrefix[] = TEXT("LDAP://CN=User,");
|
|
INT iUserPrefixLen = lstrlen( wszUserPrefix );
|
|
WCHAR *pwszPathSuffix;
|
|
|
|
//
|
|
// Strip out prefix to get the canonical path to Gpo
|
|
//
|
|
|
|
if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
|
|
pwszPath, iUserPrefixLen, wszUserPrefix, iUserPrefixLen ) == CSTR_EQUAL ) {
|
|
pwszPathSuffix = pwszPath + iUserPrefixLen;
|
|
} else if ( CompareString( LOCALE_USER_DEFAULT, NORM_IGNORECASE,
|
|
pwszPath, iMachPrefixLen, wszMachPrefix, iMachPrefixLen ) == CSTR_EQUAL ) {
|
|
pwszPathSuffix = pwszPath + iMachPrefixLen;
|
|
} else
|
|
pwszPathSuffix = pwszPath;
|
|
|
|
return pwszPathSuffix;
|
|
}
|
|
|
|
|
|
//+--------------------------------------------------------------------------
|
|
//
|
|
// Function: ScepGenerateGuid
|
|
//
|
|
// Arguments: out: the guid string
|
|
//
|
|
// Returns: Returns guid string (has to be freed outside
|
|
//
|
|
//+--------------------------------------------------------------------------
|
|
/*
|
|
DWORD
|
|
ScepGenerateGuid(
|
|
OUT PWSTR *ppwszGuid
|
|
)
|
|
{
|
|
GUID guid;
|
|
DWORD rc = ERROR_SUCCESS;
|
|
|
|
if (ppwszGuid == NULL)
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
*ppwszGuid = (PWSTR) ScepAlloc(LMEM_ZEROINIT, (MAX_GUID_STRING_LEN + 1) * sizeof(WCHAR));
|
|
|
|
if (*ppwszGuid) {
|
|
|
|
if (ERROR_SUCCESS == (rc = ScepWbemErrorToDosError(CoCreateGuid( &guid )))) {
|
|
|
|
if (!SCEP_NULL_GUID(guid))
|
|
SCEP_GUID_TO_STRING(guid, *ppwszGuid);
|
|
else {
|
|
rc = ERROR_INVALID_PARAMETER;
|
|
|
|
}
|
|
}
|
|
} else
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
|
|
return rc;
|
|
}
|
|
*/
|
|
|
|
|
|
SCESTATUS
|
|
SceInfpGetPrivileges(
|
|
IN HINF hInf,
|
|
IN BOOL bLookupAccount,
|
|
OUT PSCE_PRIVILEGE_ASSIGNMENT *pPrivileges,
|
|
OUT PSCE_ERROR_LOG_INFO *Errlog OPTIONAL
|
|
)
|
|
/* ++
|
|
Description:
|
|
Get user right assignments from a INF template. If bLookupAccount is set
|
|
to TRUE, the accounts in user right assignments will be translated to
|
|
account names (from SID format); else the information is returned in
|
|
the same way as defined in the template.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
|
|
-- */
|
|
{
|
|
INFCONTEXT InfLine;
|
|
SCESTATUS rc=SCESTATUS_SUCCESS;
|
|
PSCE_PRIVILEGE_ASSIGNMENT pCurRight=NULL;
|
|
WCHAR Keyname[SCE_KEY_MAX_LENGTH];
|
|
PWSTR StrValue=NULL;
|
|
DWORD DataSize;
|
|
DWORD PrivValue;
|
|
DWORD i, cFields;
|
|
LSA_HANDLE LsaHandle=NULL;
|
|
|
|
//
|
|
// [Privilege Rights] section
|
|
//
|
|
|
|
if(SetupFindFirstLine(hInf,szPrivilegeRights,NULL,&InfLine)) {
|
|
|
|
//
|
|
// open lsa policy handle for sid/name lookup
|
|
//
|
|
|
|
rc = RtlNtStatusToDosError(
|
|
ScepOpenLsaPolicy(
|
|
POLICY_LOOKUP_NAMES | POLICY_VIEW_LOCAL_INFORMATION,
|
|
&LsaHandle,
|
|
TRUE
|
|
));
|
|
|
|
if ( ERROR_SUCCESS != rc ) {
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
Errlog,
|
|
SCEERR_ADD,
|
|
TEXT("LSA")
|
|
);
|
|
return(ScepDosErrorToSceStatus(rc));
|
|
}
|
|
|
|
do {
|
|
|
|
memset(Keyname, '\0', SCE_KEY_MAX_LENGTH*sizeof(WCHAR));
|
|
rc = SCESTATUS_SUCCESS;
|
|
|
|
if ( SetupGetStringField(&InfLine, 0, Keyname,
|
|
SCE_KEY_MAX_LENGTH, NULL) ) {
|
|
|
|
//
|
|
// find a key name (which is a privilege name here ).
|
|
// lookup privilege's value
|
|
//
|
|
if ( ( PrivValue = ScepLookupPrivByName(Keyname) ) == -1 ) {
|
|
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
|
|
Errlog,
|
|
SCEERR_INVALID_PRIVILEGE,
|
|
Keyname
|
|
);
|
|
// goto NextLine;
|
|
}
|
|
|
|
//
|
|
// a sm_privilege_assignment structure. allocate buffer
|
|
//
|
|
pCurRight = (PSCE_PRIVILEGE_ASSIGNMENT)ScepAlloc( LMEM_ZEROINIT,
|
|
sizeof(SCE_PRIVILEGE_ASSIGNMENT) );
|
|
if ( pCurRight == NULL ) {
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
goto Done;
|
|
}
|
|
pCurRight->Name = (PWSTR)ScepAlloc( (UINT)0, (wcslen(Keyname)+1)*sizeof(WCHAR));
|
|
if ( pCurRight->Name == NULL ) {
|
|
ScepFree(pCurRight);
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
goto Done;
|
|
}
|
|
|
|
wcscpy(pCurRight->Name, Keyname);
|
|
pCurRight->Value = PrivValue;
|
|
|
|
cFields = SetupGetFieldCount( &InfLine );
|
|
|
|
for ( i=0; i<cFields && rc==SCESTATUS_SUCCESS; i++) {
|
|
//
|
|
// read each user/group name
|
|
//
|
|
if ( SetupGetStringField( &InfLine, i+1, NULL, 0, &DataSize ) ) {
|
|
|
|
if (DataSize > 1) {
|
|
|
|
|
|
StrValue = (PWSTR)ScepAlloc( 0, (DataSize+1)*sizeof(WCHAR) );
|
|
|
|
if ( StrValue == NULL )
|
|
rc = SCESTATUS_NOT_ENOUGH_RESOURCE;
|
|
else {
|
|
StrValue[DataSize] = L'\0';
|
|
if ( SetupGetStringField( &InfLine, i+1, StrValue,
|
|
DataSize, NULL) ) {
|
|
|
|
if ( bLookupAccount && StrValue[0] == L'*' && DataSize > 0 ) {
|
|
//
|
|
// this is a SID format, should look it up
|
|
//
|
|
rc = ScepLookupSidStringAndAddToNameList(
|
|
LsaHandle,
|
|
&(pCurRight->AssignedTo),
|
|
StrValue, // +1,
|
|
DataSize // -1
|
|
);
|
|
|
|
} else {
|
|
|
|
rc = ScepAddToNameList(&(pCurRight->AssignedTo),
|
|
StrValue,
|
|
DataSize );
|
|
}
|
|
} else
|
|
rc = SCESTATUS_INVALID_DATA;
|
|
}
|
|
|
|
ScepFree( StrValue );
|
|
StrValue = NULL;
|
|
}
|
|
|
|
} else {
|
|
ScepBuildErrorLogInfo( ERROR_INVALID_DATA,
|
|
Errlog,
|
|
SCEERR_QUERY_INFO,
|
|
Keyname );
|
|
rc = SCESTATUS_INVALID_DATA;
|
|
}
|
|
}
|
|
|
|
if ( rc == SCESTATUS_SUCCESS ) {
|
|
//
|
|
// add this node to the list
|
|
//
|
|
pCurRight->Next = *pPrivileges;
|
|
*pPrivileges = pCurRight;
|
|
pCurRight = NULL;
|
|
|
|
} else
|
|
ScepFreePrivilege(pCurRight);
|
|
|
|
} else
|
|
rc = SCESTATUS_BAD_FORMAT;
|
|
|
|
//NextLine:
|
|
if (rc != SCESTATUS_SUCCESS ) {
|
|
|
|
ScepBuildErrorLogInfo( ScepSceStatusToDosError(rc),
|
|
Errlog,
|
|
SCEERR_QUERY_INFO,
|
|
szPrivilegeRights
|
|
);
|
|
goto Done;
|
|
}
|
|
|
|
} while(SetupFindNextLine(&InfLine,&InfLine));
|
|
}
|
|
|
|
Done:
|
|
|
|
if ( StrValue != NULL )
|
|
ScepFree(StrValue);
|
|
|
|
if ( LsaHandle ) {
|
|
LsaClose(LsaHandle);
|
|
}
|
|
|
|
return(rc);
|
|
}
|
|
|
|
NTSTATUS
|
|
ScepIsSystemContext(
|
|
IN HANDLE hUserToken,
|
|
OUT BOOL *pbSystem
|
|
)
|
|
{
|
|
NTSTATUS NtStatus;
|
|
DWORD nRequired;
|
|
|
|
//
|
|
// variables to determine calling context
|
|
//
|
|
|
|
PTOKEN_USER pUser=NULL;
|
|
SID_IDENTIFIER_AUTHORITY ia=SECURITY_NT_AUTHORITY;
|
|
PSID SystemSid=NULL;
|
|
BOOL b;
|
|
|
|
|
|
//
|
|
// get current user SID in the token
|
|
//
|
|
|
|
NtStatus = NtQueryInformationToken (hUserToken,
|
|
TokenUser,
|
|
NULL,
|
|
0,
|
|
&nRequired
|
|
);
|
|
|
|
if ( STATUS_BUFFER_TOO_SMALL == NtStatus ) {
|
|
|
|
pUser = (PTOKEN_USER)LocalAlloc(0,nRequired+1);
|
|
if ( pUser ) {
|
|
NtStatus = NtQueryInformationToken (hUserToken,
|
|
TokenUser,
|
|
(PVOID)pUser,
|
|
nRequired,
|
|
&nRequired
|
|
);
|
|
} else {
|
|
|
|
NtStatus = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
b = FALSE;
|
|
|
|
if ( NT_SUCCESS(NtStatus) && pUser && pUser->User.Sid ) {
|
|
|
|
//
|
|
// build system sid and compare with the current user SID
|
|
//
|
|
|
|
NtStatus = RtlAllocateAndInitializeSid (&ia,1,SECURITY_LOCAL_SYSTEM_RID,
|
|
0, 0, 0, 0, 0, 0, 0, &SystemSid);
|
|
if ( NT_SUCCESS(NtStatus) && SystemSid ) {
|
|
|
|
//
|
|
// check to see if it is system sid
|
|
//
|
|
|
|
if ( RtlEqualSid(pUser->User.Sid, SystemSid) ) {
|
|
|
|
b=TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// free memory allocated
|
|
//
|
|
|
|
if ( SystemSid ) {
|
|
FreeSid(SystemSid);
|
|
}
|
|
|
|
if ( pUser ) {
|
|
LocalFree(pUser);
|
|
}
|
|
|
|
*pbSystem = b;
|
|
|
|
return NtStatus;
|
|
}
|
|
|
|
BOOL
|
|
IsNT5()
|
|
{
|
|
WCHAR szInfName[MAX_PATH+30];
|
|
szInfName[0] = L'\0';
|
|
DWORD cNumCharsReturned = GetSystemWindowsDirectory(szInfName, MAX_PATH);
|
|
|
|
if (cNumCharsReturned)
|
|
{
|
|
wcscat(szInfName, L"\\system32\\$winnt$.inf");
|
|
}
|
|
else {
|
|
return TRUE;
|
|
}
|
|
|
|
UINT nRet = GetPrivateProfileInt( L"Networking",
|
|
L"BuildNumber",
|
|
0,
|
|
szInfName
|
|
);
|
|
if (nRet == 0) {
|
|
return TRUE;
|
|
}
|
|
else if (nRet > 1381) {
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScepVerifyTemplateName(
|
|
IN PWSTR InfTemplateName,
|
|
OUT PSCE_ERROR_LOG_INFO *pErrlog OPTIONAL
|
|
)
|
|
/*
|
|
Routine Description:
|
|
|
|
This routine verifies the template name for read protection and
|
|
invalid path
|
|
|
|
Arguments:
|
|
|
|
InfTemplateName - the full path name of the inf template
|
|
|
|
pErrlog - the error log buffer
|
|
|
|
Return Value:
|
|
|
|
WIN32 error code
|
|
*/
|
|
{
|
|
if ( !InfTemplateName ) {
|
|
|
|
return(ERROR_INVALID_PARAMETER);
|
|
}
|
|
|
|
PWSTR DefProfile;
|
|
DWORD rc;
|
|
|
|
//
|
|
// verify the InfTemplateName to generate
|
|
// if read only, or access denied, return ERROR_ACCESS_DENIED
|
|
// if invalid path, return ERROR_PATH_NOT_FOUND
|
|
//
|
|
|
|
DefProfile = InfTemplateName + wcslen(InfTemplateName)-1;
|
|
while ( DefProfile > InfTemplateName+1 ) {
|
|
|
|
if ( *DefProfile != L'\\') {
|
|
DefProfile--;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
rc = NO_ERROR;
|
|
|
|
if ( DefProfile > InfTemplateName+2 ) { // at least allow a drive letter, a colon, and a \
|
|
|
|
//
|
|
// find the directory path
|
|
//
|
|
|
|
DWORD Len=(DWORD)(DefProfile-InfTemplateName);
|
|
|
|
PWSTR TmpBuf=(PWSTR)LocalAlloc(0, (Len+1)*sizeof(WCHAR));
|
|
if ( TmpBuf ) {
|
|
|
|
wcsncpy(TmpBuf, InfTemplateName, Len);
|
|
TmpBuf[Len] = L'\0';
|
|
|
|
if ( 0xFFFFFFFF == GetFileAttributes(TmpBuf) )
|
|
rc = ERROR_PATH_NOT_FOUND;
|
|
|
|
LocalFree(TmpBuf);
|
|
|
|
} else {
|
|
rc = ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
} else if ( DefProfile == InfTemplateName+2 &&
|
|
InfTemplateName[1] == L':' ) {
|
|
//
|
|
// this is a template path off the root
|
|
//
|
|
|
|
} else {
|
|
|
|
//
|
|
// invalid directory path
|
|
//
|
|
|
|
rc = ERROR_PATH_NOT_FOUND;
|
|
}
|
|
|
|
|
|
if ( rc != NO_ERROR ) {
|
|
//
|
|
// error occurs
|
|
//
|
|
if ( ERROR_PATH_NOT_FOUND == rc ) {
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrlog,
|
|
SCEERR_INVALID_PATH,
|
|
InfTemplateName
|
|
);
|
|
}
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// make it unicode aware
|
|
// do not worry about failure
|
|
//
|
|
SetupINFAsUCS2(InfTemplateName);
|
|
|
|
//
|
|
// validate if the template is write protected
|
|
//
|
|
|
|
FILE *hTempFile;
|
|
hTempFile = _wfopen(InfTemplateName, L"a+");
|
|
|
|
if ( !hTempFile ) {
|
|
//
|
|
// can't overwrite/create the file, must be access denied
|
|
//
|
|
rc = ERROR_ACCESS_DENIED;
|
|
|
|
ScepBuildErrorLogInfo(
|
|
rc,
|
|
pErrlog,
|
|
SCEERR_ERROR_CREATE,
|
|
InfTemplateName
|
|
);
|
|
|
|
return(rc);
|
|
|
|
} else {
|
|
fclose( hTempFile );
|
|
}
|
|
|
|
return(rc);
|
|
|
|
}
|
|
|