windows-nt/Source/XPSP1/NT/ds/security/services/scerpc/server/misc.cpp
2020-09-26 16:20:57 +08:00

1597 lines
39 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
misc.cpp
Abstract:
SCE Engine miscellaneous APIs
Author:
Jin Huang (jinhuang) 23-Jun-1997 created
--*/
#include "headers.h"
#include "serverp.h"
#include <ntregapi.h>
#include <userenv.h>
#include <ntlsa.h>
#include <io.h>
#pragma hdrstop
extern "C" {
#include "dumpnt.h"
}
//#define SCE_DBG 1
NTSTATUS
ScepGetLsaDomainInfo(
PPOLICY_ACCOUNT_DOMAIN_INFO *PolicyAccountDomainInfo,
PPOLICY_PRIMARY_DOMAIN_INFO *PolicyPrimaryDomainInfo
);
DWORD
ScepGetEnvVarsFromProfile(
IN PWSTR UserProfileName,
IN PCWSTR VarName1,
IN PCWSTR VarName2 OPTIONAL,
OUT PWSTR *StrValue
);
NTSTATUS
ScepOpenSamDomain(
IN ACCESS_MASK ServerAccess,
IN ACCESS_MASK DomainAccess,
OUT PSAM_HANDLE pServerHandle,
OUT PSAM_HANDLE pDomainHandle,
OUT PSID *DomainSid,
OUT PSAM_HANDLE pBuiltinDomainHandle OPTIONAL,
OUT PSID *BuiltinDomainSid OPTIONAL
)
/*
Routine Description
This routine opens the local SAM server for account domain and builtin
domain. The domain handles and their SIDs are returned.
*/
{
NTSTATUS NtStatus;
PPOLICY_ACCOUNT_DOMAIN_INFO PolicyAccountDomainInfo=NULL;
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPrimaryDomainInfo=NULL;
UNICODE_STRING AccountDomainName;
OBJECT_ATTRIBUTES ObjectAttributes;
SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
if ( !pServerHandle || !pDomainHandle || !DomainSid ) {
return(SCESTATUS_INVALID_PARAMETER);
}
//
// initialize output buffers
//
*pServerHandle = NULL;
*pDomainHandle = NULL;
*DomainSid = NULL;
if ( pBuiltinDomainHandle ) {
*pBuiltinDomainHandle = NULL;
}
if ( BuiltinDomainSid ) {
*BuiltinDomainSid = NULL;
}
//
// Get information for the account domain
//
NtStatus = ScepGetLsaDomainInfo(
&PolicyAccountDomainInfo,
&PolicyPrimaryDomainInfo
);
if (!NT_SUCCESS(NtStatus)) {
return( NtStatus );
}
AccountDomainName = PolicyAccountDomainInfo->DomainName;
//
// Connect to the local SAM server
//
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, 0, NULL );
NtStatus = SamConnect(
NULL, // ServerName (Local machine)
pServerHandle,
ServerAccess,
&ObjectAttributes
);
if ( NT_SUCCESS(NtStatus) ) {
//
// Lookup the DomainSid for AccountDomainName
//
NtStatus = SamLookupDomainInSamServer(
*pServerHandle,
&AccountDomainName,
DomainSid
);
if ( NT_SUCCESS(NtStatus) ) {
//
// open the account domain
//
NtStatus = SamOpenDomain(
*pServerHandle,
DomainAccess,
*DomainSid,
pDomainHandle
);
if ( NT_SUCCESS(NtStatus) && BuiltinDomainSid != NULL ) {
//
// build the builtin domain sid
//
NtStatus = RtlAllocateAndInitializeSid(
&NtAuthority,
1,
SECURITY_BUILTIN_DOMAIN_RID,
0, 0, 0, 0, 0, 0, 0,
BuiltinDomainSid
);
if ( NT_SUCCESS(NtStatus) && pBuiltinDomainHandle != NULL ) {
//
// open the builtin domain
//
NtStatus = SamOpenDomain(
*pServerHandle,
DomainAccess,
*BuiltinDomainSid,
pBuiltinDomainHandle
);
}
}
}
}
//
// free memory and clean up
//
if ( PolicyAccountDomainInfo != NULL ) {
LsaFreeMemory( PolicyAccountDomainInfo );
}
if ( PolicyPrimaryDomainInfo != NULL ) {
LsaFreeMemory( PolicyPrimaryDomainInfo );
}
if ( !NT_SUCCESS(NtStatus)) {
SamCloseHandle( *pDomainHandle );
*pDomainHandle = NULL;
if ( pBuiltinDomainHandle ) {
SamCloseHandle( *pBuiltinDomainHandle );
*pBuiltinDomainHandle = NULL;
}
SamCloseHandle( *pServerHandle );
*pServerHandle = NULL;
SamFreeMemory(*DomainSid);
*DomainSid = NULL;
if ( BuiltinDomainSid ) {
SamFreeMemory(*BuiltinDomainSid);
*BuiltinDomainSid = NULL;
}
}
return(NtStatus);
}
NTSTATUS
ScepLookupNamesInDomain(
IN SAM_HANDLE DomainHandle,
IN PSCE_NAME_LIST NameList,
OUT PUNICODE_STRING *Names,
OUT PULONG *RIDs,
OUT PSID_NAME_USE *Use,
OUT PULONG CountOfName
)
/* ++
Routine Description:
This routine looks up one or more names in the SAM account domain and
returns the relative IDs for each name in the list. The name list may
be user list, group list, or alias list.
Arguments:
DomainHandle - SAM handle to the account domain
NameList -- The list of names
Names - Translated UNICODE_STRING names. The name list must be freed by
RIDs -- List of relative IDs for each name
Use -- List of type for each name
CoutnOfName - The number of names in the list
Return value:
NTSTATUS
-- */
{
PSCE_NAME_LIST pUser;
ULONG cnt;
NTSTATUS NtStatus=ERROR_SUCCESS;
PUNICODE_STRING pUnicodeName=NULL;
UNICODE_STRING uName;
LPTSTR pTemp;
//
// Count how many names in the list
//
for (pUser=NameList, cnt=0;
pUser != NULL;
pUser = pUser->Next) {
if ( pUser->Name == NULL ) {
continue;
}
//
// note, this may be bigger than supposed to
//
cnt++;
}
if ( cnt > 0 ) {
//
// Allocate memory for UNICODE_STRING names
//
pUnicodeName = (PUNICODE_STRING)RtlAllocateHeap(
RtlProcessHeap(),
0,
cnt * sizeof (UNICODE_STRING)
);
if ( pUnicodeName == NULL ) {
NtStatus = STATUS_NO_MEMORY;
cnt = 0;
goto Done;
}
//
// Initialize each UNICODE_STRING
//
for (pUser=NameList, cnt=0;
pUser != NULL;
pUser = pUser->Next) {
if ( pUser->Name == NULL ) {
continue;
}
pTemp = wcschr(pUser->Name, L'\\');
if ( pTemp ) {
uName.Buffer = pUser->Name;
uName.Length = ((USHORT)(pTemp-pUser->Name))*sizeof(TCHAR);
if ( !ScepIsDomainLocal(&uName) ) {
ScepLogOutput3(1, 0, SCEDLL_NO_MAPPINGS, pUser->Name);
continue;
}
pTemp++;
} else {
pTemp = pUser->Name;
}
RtlInitUnicodeString(&(pUnicodeName[cnt]), pTemp);
cnt++;
}
// lookup
NtStatus = SamLookupNamesInDomain(
DomainHandle,
cnt,
pUnicodeName,
RIDs,
Use
);
if ( !NT_SUCCESS(NtStatus) ) {
RtlFreeHeap(RtlProcessHeap(), 0, pUnicodeName);
pUnicodeName = NULL;
}
}
Done:
*CountOfName = cnt;
*Names = pUnicodeName;
return(NtStatus);
}
NTSTATUS
ScepGetLsaDomainInfo(
PPOLICY_ACCOUNT_DOMAIN_INFO *PolicyAccountDomainInfo,
PPOLICY_PRIMARY_DOMAIN_INFO *PolicyPrimaryDomainInfo
)
/*++
Routine Description:
This routine retrieves ACCOUNT domain information from the LSA
policy database.
Arguments:
PolicyAccountDomainInfo - Receives a pointer to a
POLICY_ACCOUNT_DOMAIN_INFO structure containing the account
domain info.
PolicyPrimaryDomainInfo - Receives a pointer to a
POLICY_PRIMARY_DOMAIN_INFO structure containing the Primary
domain info.
Return Value:
STATUS_SUCCESS - Succeeded.
Other status values that may be returned from:
LsaOpenPolicy()
LsaQueryInformationPolicy()
--*/
{
NTSTATUS Status, IgnoreStatus;
LSA_HANDLE PolicyHandle;
OBJECT_ATTRIBUTES PolicyObjectAttributes;
//
// Open the policy database
//
InitializeObjectAttributes( &PolicyObjectAttributes,
NULL, // Name
0, // Attributes
NULL, // Root
NULL ); // Security Descriptor
Status = LsaOpenPolicy( NULL,
&PolicyObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&PolicyHandle );
if ( NT_SUCCESS(Status) ) {
//
// Query the account domain information
//
Status = LsaQueryInformationPolicy( PolicyHandle,
PolicyAccountDomainInformation,
(PVOID *)PolicyAccountDomainInfo );
if ( NT_SUCCESS(Status) ) {
//
// Query the Primary domain information
//
Status = LsaQueryInformationPolicy( PolicyHandle,
PolicyPrimaryDomainInformation,
(PVOID *)PolicyPrimaryDomainInfo );
}
IgnoreStatus = LsaClose( PolicyHandle );
ASSERT(NT_SUCCESS(IgnoreStatus));
}
return(Status);
}
VOID
ScepConvertLogonHours(
IN PSCE_LOGON_HOUR pLogonHours,
OUT PUCHAR LogonHourBitMask
)
/* ++
Routine Description:
This routine converted the logon hour range in hours (for example, 7-20)
to logon hour bit mask (for example, 0001 1111 1111 1111 1000 0000,
for one day).
Arguments:
pLogonHours - The logon hour range (in hours)
LogonHourBitMask - The converted logon hour bit mask. Each bit represents
an hour. There are total 21 bytes (21*8 bits in this
argument, which represents a week (7 * 24 = 21 * 8).
Return value:
None
-- */
{ PSCE_LOGON_HOUR pTemp;
CHAR BitMask[3]={0,0,0};
ULONG j;
for ( pTemp=pLogonHours; pTemp != NULL; pTemp=pTemp->Next ) {
for (j=pTemp->Start; j<pTemp->End; j++)
BitMask[j / 8] |= 1 << (j % 8);
}
for ( j=0; j<7; j++ )
strncpy((CHAR *)&(LogonHourBitMask[j*3]), BitMask,3);
}
DWORD
ScepConvertToSceLogonHour(
IN PUCHAR LogonHourBitMask,
OUT PSCE_LOGON_HOUR *pLogonHours
)
/* ++
Routine Description:
This routine converted the logon hour bit mask (for example,
0001 1111 1111 1111 1000 0000 for one day) to SCE_LOGON_HOUR type,
which stores the logon hour range (start, end).
Arguments:
LogonHourBitMask - The logon hour bit mask to convert. Each bit represents
an hour. There are total 21 bytes (21*8 bits in this
argument, which represents a week (7 * 24 = 21 * 8).
pLogonHours - The logon hour range (in hours)
Return value:
None
-- */
{
BOOL findStart = TRUE;
DWORD i, j, rc=NO_ERROR;
DWORD start=0,
end=0;
LONG value;
PSCE_LOGON_HOUR pLogon=NULL;
if (pLogonHours == NULL )
return(ERROR_INVALID_PARAMETER);
for ( i=3; i<6; i++)
for ( j=0; j<8; j++) {
if ( findStart )
value = 1;
else
value = 0;
if ( (LogonHourBitMask[i] & (1 << j)) == value ) {
if ( findStart ) {
start = (i-3)*8 + j;
findStart = FALSE;
} else {
end = (i-3)*8 + j;
findStart = TRUE;
}
if ( findStart ) {
//
// find a pair
//
pLogon = (PSCE_LOGON_HOUR)ScepAlloc( (UINT)0, sizeof(SCE_LOGON_HOUR));
if ( pLogon == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
return(rc);
}
pLogon->Start = start;
pLogon->End = end;
pLogon->Next = *pLogonHours;
*pLogonHours = pLogon;
pLogon = NULL;
}
}
}
if ( findStart == FALSE ) {
// find start but not end, which means end=24
end = 24;
pLogon = (PSCE_LOGON_HOUR)ScepAlloc( (UINT)0, sizeof(SCE_LOGON_HOUR));
if ( pLogon == NULL ) {
rc = ERROR_NOT_ENOUGH_MEMORY;
return(rc);
}
pLogon->Start = start;
pLogon->End = end;
pLogon->Next = *pLogonHours;
*pLogonHours = pLogon;
pLogon = NULL;
}
return(rc);
}
NTSTATUS
ScepGetGroupsForAccount(
IN SAM_HANDLE DomainHandle,
IN SAM_HANDLE BuiltinDomainHandle,
IN SAM_HANDLE UserHandle,
IN PSID AccountSid,
OUT PSCE_NAME_LIST *GroupList
)
/* ++
Routine Description:
This routine queries the user's group membership.
Arguments:
DomainHandle - The SAM handle of the SAM account domain
BuiltindomainHandle - The SAM builtin domain handle
UserHandle - The SAM account handle for the user
AccountSid - The SID for the user
GroupList - The list of groups the user belongs to
Return value:
NTSTATUS
-- */
{
NTSTATUS NtStatus=ERROR_SUCCESS;
ULONG GroupCount=0,
AliasCount=0;
PULONG Aliases=NULL;
PGROUP_MEMBERSHIP GroupAttributes=NULL;
PULONG GroupIds=NULL;
PUNICODE_STRING Names=NULL;
PSID_NAME_USE Use=NULL;
DWORD i;
NtStatus = SamGetGroupsForUser(
UserHandle,
&GroupAttributes,
&GroupCount
);
if ( GroupCount == 0 )
NtStatus = ERROR_SUCCESS;
if ( !NT_SUCCESS(NtStatus) )
goto Done;
//
// See what local groups the account belongs to.
// account domain
//
NtStatus = SamGetAliasMembership(
DomainHandle,
1,
&AccountSid,
&AliasCount,
&Aliases );
if ( !NT_SUCCESS(NtStatus) )
goto Done;
if ( AliasCount != 0 || GroupCount != 0 ) {
//
// process each group's name in account domain
//
GroupIds = (PULONG)ScepAlloc((UINT)0,
(GroupCount+AliasCount)*sizeof(ULONG));
if ( GroupIds == NULL ) {
NtStatus = STATUS_NO_MEMORY;
goto Done;
}
for ( i=0; i<GroupCount; i++)
GroupIds[i] = GroupAttributes[i].RelativeId;
for ( i=0; i<AliasCount; i++)
GroupIds[i+GroupCount] = Aliases[i];
}
SamFreeMemory(GroupAttributes);
GroupAttributes = NULL;
SamFreeMemory(Aliases);
Aliases = NULL;
if ( AliasCount != 0 || GroupCount != 0 ) {
// lookup names
NtStatus = SamLookupIdsInDomain(
DomainHandle,
GroupCount+AliasCount,
GroupIds,
&Names,
&Use
);
if ( !NT_SUCCESS(NtStatus) )
goto Done;
}
for ( i=0; i<GroupCount+AliasCount; i++) {
if ( GroupIds[i] == DOMAIN_GROUP_RID_USERS )
continue;
switch (Use[i]) {
case SidTypeGroup:
case SidTypeAlias:
case SidTypeWellKnownGroup:
if ( ScepAddToNameList(GroupList, Names[i].Buffer, Names[i].Length/2) != NO_ERROR) {
NtStatus = STATUS_NO_MEMORY;
goto Done;
}
break;
default:
break;
}
}
if ( GroupIds ) {
ScepFree(GroupIds);
GroupIds = NULL;
}
if ( Names ) {
SamFreeMemory(Names);
Names = NULL;
}
if ( Use ) {
SamFreeMemory(Use);
Use = NULL;
}
//
// check the builtin domain for alias membership
//
AliasCount=0;
NtStatus = SamGetAliasMembership(
BuiltinDomainHandle,
1,
&AccountSid,
&AliasCount,
&Aliases );
if ( !NT_SUCCESS(NtStatus) )
goto Done;
if ( AliasCount > 0 ) {
NtStatus = SamLookupIdsInDomain(
BuiltinDomainHandle,
AliasCount,
Aliases,
&Names,
&Use
);
if ( !NT_SUCCESS(NtStatus) )
goto Done;
}
for ( i=0; i<AliasCount; i++) {
if ( Aliases[i] == DOMAIN_GROUP_RID_USERS )
continue;
switch (Use[i]) {
case SidTypeGroup:
case SidTypeAlias:
case SidTypeWellKnownGroup:
if ( ScepAddToNameList(GroupList, Names[i].Buffer, Names[i].Length/2) != NO_ERROR) {
NtStatus = STATUS_NO_MEMORY;
goto Done;
}
break;
default:
break;
}
}
Done:
if ( GroupAttributes != NULL )
SamFreeMemory(GroupAttributes);
if ( Aliases != NULL )
SamFreeMemory(Aliases);
if ( GroupIds != NULL )
ScepFree(GroupIds);
if ( Names != NULL )
SamFreeMemory(Names);
if ( Use != NULL )
SamFreeMemory(Use);
return(NtStatus);
}
ACCESS_MASK
ScepGetDesiredAccess(
IN SECURITY_OPEN_TYPE OpenType,
IN SECURITY_INFORMATION SecurityInfo
)
/*++
Routine Description:
Gets the access required to open object to be able to set or get the
specified security info.
Arguments:
OpenType - Flag indicating if the object is to be opened to read or
write the DACL
SecurityInfo - The Security information to read/write.
Return value:
Access mask
-- */
{
ACCESS_MASK DesiredAccess = 0;
if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) ||
(SecurityInfo & GROUP_SECURITY_INFORMATION) )
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_OWNER;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_OWNER;
break;
}
}
if (SecurityInfo & DACL_SECURITY_INFORMATION)
{
switch (OpenType)
{
case READ_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL;
break;
case WRITE_ACCESS_RIGHTS:
DesiredAccess |= WRITE_DAC;
break;
case MODIFY_ACCESS_RIGHTS:
DesiredAccess |= READ_CONTROL | WRITE_DAC;
break;
}
}
if (SecurityInfo & SACL_SECURITY_INFORMATION)
{
DesiredAccess |= ACCESS_SYSTEM_SECURITY;
}
return (DesiredAccess);
}
SCESTATUS
ScepGetProfileOneArea(
IN PSCECONTEXT hProfile,
IN SCETYPE ProfileType,
IN AREA_INFORMATION Area,
IN DWORD dwAccountFormat,
OUT PSCE_PROFILE_INFO *ppInfoBuffer
)
/* ++
Routine Description:
A wrapper routine for GetDatabaseInfo except it get information
for one area at a call. This routine also logs the errors occur inside
GetSecrityProfileInfo
Arguments:
hProfile - Handle to a profile
ProfileType - The type of the profile
Area - The security area to read info from
ppInfoBuffer - output buffer for the info
Return value:
SCESTATUS returned from GetDatabaseInfo
-- */
{
SCESTATUS rc;
PSCE_ERROR_LOG_INFO pErrlog=NULL;
rc = ScepGetDatabaseInfo(
hProfile,
ProfileType,
Area,
dwAccountFormat,
ppInfoBuffer,
&pErrlog
);
ScepLogWriteError( pErrlog, 1 );
ScepFreeErrorLog( pErrlog );
return(rc);
}
SCESTATUS
ScepGetOneSection(
IN PSCECONTEXT hProfile,
IN AREA_INFORMATION Area,
IN PWSTR Name,
IN SCETYPE ProfileType,
OUT PVOID *ppInfo
)
/* ++
Routine Description:
This routine reads information for one or more Area and logs errors to
the log file. This routine should be only used by the SCP engine and
the SAP engine.
Arguments:
hProfile - Handle to a profile
ProfileType - The type of the profile
Area - The security area to read info from
Subarea - The subarea to read info from
ppInfo - output buffer for the info
Return value:
SCESTATUS
-- */
{
SCESTATUS rc;
PSCE_ERROR_LOG_INFO pErrlog=NULL;
if ( Name == NULL )
return(SCESTATUS_INVALID_PARAMETER);
if ( Area == AREA_REGISTRY_SECURITY ||
Area == AREA_FILE_SECURITY ||
Area == AREA_DS_OBJECTS ) {
rc = ScepGetObjectChildren(
hProfile,
ProfileType,
Area,
Name,
SCE_ALL_CHILDREN,
ppInfo,
&pErrlog
);
} else {
rc = ScepGetUserSection(
hProfile,
ProfileType,
Name,
ppInfo,
&pErrlog
);
}
ScepLogWriteError( pErrlog, 1 );
ScepFreeErrorLog( pErrlog );
return(rc);
}
NTSTATUS
ScepGetUserAccessAddress(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN PSID AccountSid,
OUT PACCESS_MASK *pUserAccess,
OUT PACCESS_MASK *pEveryone
)
{
NTSTATUS NtStatus;
PACL pAcl;
BOOLEAN aclPresent, tFlag;
DWORD i;
PVOID pAce;
PSID pSid;
ACCESS_MASK access;
SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
PSID EveryoneSid=NULL;
if ( AccountSid == NULL || pUserAccess == NULL || pEveryone == NULL )
return(STATUS_INVALID_PARAMETER);
*pUserAccess = NULL;
*pEveryone = NULL;
if ( pSecurityDescriptor == NULL )
return(STATUS_SUCCESS);
NtStatus = RtlGetDaclSecurityDescriptor(
pSecurityDescriptor,
&aclPresent,
&pAcl,
&tFlag);
if ( NT_SUCCESS(NtStatus) )
NtStatus = RtlAllocateAndInitializeSid(
&WorldAuth,
1,
SECURITY_CREATOR_OWNER_RID,
0,
0,
0,
0,
0,
0,
0,
&EveryoneSid );
if ( NT_SUCCESS(NtStatus) ) {
if ( pAcl != NULL && aclPresent ) {
for ( i=0; i < pAcl->AceCount; i++) {
NtStatus = RtlGetAce( pAcl, i, &pAce );
if ( !NT_SUCCESS( NtStatus ) )
break;
access = 0;
pSid = NULL;
switch ( ((PACE_HEADER)pAce)->AceType ) {
case ACCESS_ALLOWED_ACE_TYPE:
pSid = (PSID)&((PACCESS_ALLOWED_ACE)pAce)->SidStart;
access = ((PACCESS_ALLOWED_ACE)pAce)->Mask;
if ( EqualSid( AccountSid, pSid ) )
*pUserAccess = &(((PACCESS_ALLOWED_ACE)pAce)->Mask);
else if ( EqualSid( EveryoneSid, pSid) )
*pEveryone = &(((PACCESS_ALLOWED_ACE)pAce)->Mask);
break;
case ACCESS_DENIED_ACE_TYPE:
// do not look for denied ace type because it is not used here
// pSid = (PSID)&((PACCESS_DENIED_ACE)pAce)->SidStart;
// access = ((PACCESS_DENIED_ACE)pAce)->Mask;
break;
default:
break;
}
if ( *pUserAccess != NULL && *pEveryone != NULL )
// stop the loop because both are found
break;
}
}
}
//
// free EveryoneSid
//
if (EveryoneSid) {
RtlFreeSid(EveryoneSid);
EveryoneSid = NULL;
}
return(NtStatus);
}
BOOL
ScepLastBackSlash(
IN PWSTR Name
)
{
if (Name == NULL )
return(FALSE);
if ( Name[wcslen(Name)-1] == L'\\')
return(TRUE);
else
return(FALSE);
}
DWORD
ScepGetUsersHomeDirectory(
IN UNICODE_STRING AssignedHomeDir,
IN PWSTR UserProfileName,
OUT PWSTR *UserHomeDir
)
/*++
Routine Description:
This routine gets user's default home directory. The home directory is
determined 1) if it is assigned in the user's object (user profile), 2)
if there is a HomePath environment variable defined for the user, and
3). Harcoded.
Arguments:
AssignedHomeDir - The home directory explicitly assigned in the user's
object.
UserProfileName - The user's environment profile name
UserHomeDir - The returned home directory for the user
Return Value:
Win32 error code.
--*/
{
DWORD Win32rc=NO_ERROR;
PWSTR StrValue=NULL;
PWSTR SystemRoot=NULL;
DWORD DirSize=0;
*UserHomeDir = NULL;
//
// if there is a home directory assigned in the user profile, use it.
//
if ( AssignedHomeDir.Length > 0 && AssignedHomeDir.Buffer != NULL ) {
*UserHomeDir = (PWSTR)ScepAlloc( LMEM_ZEROINIT, AssignedHomeDir.Length+2);
if ( *UserHomeDir == NULL )
return(ERROR_NOT_ENOUGH_MEMORY);
wcsncpy(*UserHomeDir, AssignedHomeDir.Buffer, AssignedHomeDir.Length/2);
return(NO_ERROR);
}
//
// Home directory is NULL in user profile, the HomePath environment
// is searched.
//
Win32rc = ScepGetNTDirectory( &SystemRoot, &DirSize, SCE_FLAG_WINDOWS_DIR );
if ( Win32rc != NO_ERROR ) {
ScepLogOutput3(1, Win32rc, SCEDLL_ERROR_QUERY_INFO, L"%WinDir%");
return(Win32rc);
}
Win32rc = ScepGetEnvVarsFromProfile(
UserProfileName,
L"HomePath",
NULL,
&StrValue
);
if ( Win32rc == NO_ERROR && StrValue != NULL ) {
*UserHomeDir = (PWSTR)ScepAlloc( LMEM_ZEROINIT, (wcslen(StrValue)+3)*sizeof(WCHAR));
if ( *UserHomeDir == NULL )
Win32rc = ERROR_NOT_ENOUGH_MEMORY;
else {
swprintf(*UserHomeDir+1, L":%s", StrValue);
**UserHomeDir = SystemRoot[0];
}
} else
Win32rc = NO_ERROR; // do not care if can't get environment variable's value
if ( SystemRoot != NULL )
ScepFree(SystemRoot);
if ( StrValue != NULL )
ScepFree( StrValue );
return(Win32rc);
}
DWORD
ScepGetEnvVarsFromProfile(
IN PWSTR UserProfileName,
IN PCWSTR VarName1,
IN PCWSTR VarName2 OPTIONAL,
OUT PWSTR *StrValue
)
{
DWORD rc;
DWORD RegType;
rc = SceAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, NULL);
if ( rc == ERROR_SUCCESS ) {
rc = RegLoadKey(HKEY_USERS, L"TEMP", UserProfileName);
if ( rc == ERROR_SUCCESS ) {
rc = ScepRegQueryValue(
HKEY_USERS,
L"TEMP\\Environment",
VarName1,
(PVOID *)StrValue,
&RegType
);
if ( rc != ERROR_SUCCESS && VarName2 != NULL ) {
rc = ScepRegQueryValue(
HKEY_USERS,
L"TEMP\\Environment",
VarName2,
(PVOID *)StrValue,
&RegType
);
}
RegUnLoadKey(HKEY_USERS, L"TEMP");
} else { //if ( rc == ERROR_ALREADY_IN_USE) {
//
// this profile already in use. Open the one in HKEY_CURRENT_USER
//
rc = ScepRegQueryValue(
HKEY_CURRENT_USER,
L"Environment",
VarName1,
(PVOID *)StrValue,
&RegType
);
if ( rc != ERROR_SUCCESS && VarName2 != NULL ) {
rc = ScepRegQueryValue(
HKEY_CURRENT_USER,
L"Environment",
VarName2,
(PVOID *)StrValue,
&RegType
);
}
}
SceAdjustPrivilege(SE_RESTORE_PRIVILEGE, FALSE, NULL);
}
return(rc);
}
DWORD
ScepGetUsersTempDirectory(
IN PWSTR UserProfileName,
OUT PWSTR *UserTempDir
)
/*++
Routine Description:
This routine returns the user's temp directory. Temp directory for a
user is determined 1) environment variable "TEMP" or "TMP" defined
in the user's environment profile, or 2) Harcoded to %systemDrive%\TEMP
Arguments:
UserProfileName - The user's environment profile name
UserTempDir - The returned temp directory for the user
Return Value:
Win32 error code
--*/
{
DWORD rc=NO_ERROR;
PWSTR StrValue=NULL;
PWSTR SystemRoot=NULL;
DWORD DirSize=0;
//
// query the TEMP/TMP environment variable(s)
//
if ( UserProfileName != NULL ) {
ScepGetEnvVarsFromProfile(
UserProfileName,
L"TEMP",
L"TMP",
&StrValue
);
}
if ( StrValue != NULL ) {
//
// find the setting for temp dir
//
if ( wcsstr(_wcsupr(StrValue), L"%") != NULL ) {
rc = ScepTranslateFileDirName( StrValue, UserTempDir );
}
if ( rc == NO_ERROR ) {
ScepFree(StrValue);
} else
*UserTempDir = StrValue;
StrValue = NULL;
} else {
//
// hardcoded to %SystemDrive%\TEMP
//
rc = ScepGetNTDirectory( &SystemRoot, &DirSize, SCE_FLAG_WINDOWS_DIR );
if ( rc != NO_ERROR ) {
ScepLogOutput3(1, rc, SCEDLL_ERROR_QUERY_INFO, L"%WinDir%");
return(rc);
}
*UserTempDir = (PWSTR)ScepAlloc( 0, 8*sizeof(WCHAR));
if ( *UserTempDir == NULL )
rc = ERROR_NOT_ENOUGH_MEMORY;
else {
swprintf(*UserTempDir+1, L":\\TEMP");
**UserTempDir = SystemRoot[0];
}
}
if (SystemRoot != NULL )
ScepFree(SystemRoot);
return(rc);
}
SCESTATUS
ScepGetRegKeyCase(
IN PWSTR ObjName,
IN DWORD BufOffset,
IN DWORD BufLen
)
{
DWORD Win32rc;
HKEY hKey=NULL;
PWSTR Buffer=NULL;
TCHAR Buffer1[MAX_PATH];
DWORD BufSize, index;
FILETIME LastWriteTime;
if ( BufOffset <= 0 || BufLen <= 0 ) {
_wcsupr(ObjName);
return(SCESTATUS_SUCCESS);
}
Buffer = (PWSTR)ScepAlloc(LMEM_ZEROINIT, BufOffset*sizeof(WCHAR));
if ( Buffer != NULL ) {
wcsncpy(Buffer, ObjName, BufOffset-1);
Win32rc = ScepOpenRegistryObject(
SE_REGISTRY_KEY,
Buffer,
KEY_READ,
&hKey
);
if ( Win32rc == NO_ERROR ) {
index = 0;
//
// enumerate all subkeys of the key
//
do {
memset(Buffer1, '\0', MAX_PATH*sizeof(WCHAR));
BufSize = MAX_PATH;
Win32rc = RegEnumKeyEx(hKey,
index,
Buffer1,
&BufSize,
NULL,
NULL,
NULL,
&LastWriteTime);
if ( Win32rc == ERROR_SUCCESS ) {
index++;
//
// find if the subkey matches the object name
//
if ( _wcsicmp(ObjName+BufOffset, Buffer1) == 0 )
break;
}
} while ( Win32rc != ERROR_NO_MORE_ITEMS );
RegCloseKey(hKey);
if ( Win32rc == ERROR_SUCCESS ) {
//
// find it
//
if ( BufSize > BufLen )
BufSize = BufLen;
wcsncpy(ObjName+BufOffset, Buffer1, BufSize);
*(ObjName+BufOffset+BufSize) = L'\0';
} else if ( Win32rc == ERROR_NO_MORE_ITEMS) {
//
// does not find it
//
Win32rc = ERROR_FILE_NOT_FOUND;
}
}
ScepFree(Buffer);
} else
Win32rc = ERROR_NOT_ENOUGH_MEMORY;
if ( Win32rc != NO_ERROR ) {
//
// convert everything to uppercase
//
_wcsupr(ObjName+BufOffset);
}
return(ScepDosErrorToSceStatus(Win32rc));
}
SCESTATUS
ScepGetFileCase(
IN PWSTR ObjName,
IN DWORD BufOffset,
IN DWORD BufLen
)
{
intptr_t hFile;
struct _wfinddata_t FileInfo;
hFile = _wfindfirst(ObjName, &FileInfo);
if ( hFile != -1 ) {
wcsncpy(ObjName+BufOffset, FileInfo.name, BufLen);
_findclose(hFile);
} else
return(ScepDosErrorToSceStatus(GetLastError()));
return(SCESTATUS_SUCCESS);
}
SCESTATUS
ScepGetGroupCase(
IN OUT PWSTR GroupName,
IN DWORD Length
)
{
NTSTATUS NtStatus;
SAM_HANDLE ServerHandle=NULL,
DomainHandle=NULL,
BuiltinDomainHandle=NULL,
ThisDomain=NULL,
GroupHandle=NULL;
PSID DomainSid=NULL,
BuiltinDomainSid=NULL;
UNICODE_STRING Name;
PULONG GrpId=NULL;
PSID_NAME_USE GrpUse=NULL;
PVOID pNameInfo=NULL;
NtStatus = ScepOpenSamDomain(
SAM_SERVER_READ | SAM_SERVER_EXECUTE,
DOMAIN_READ | DOMAIN_EXECUTE,
&ServerHandle,
&DomainHandle,
&DomainSid,
&BuiltinDomainHandle,
&BuiltinDomainSid
);
if ( NT_SUCCESS(NtStatus) ) {
RtlInitUnicodeString(&Name, GroupName);
NtStatus = SamLookupNamesInDomain(
DomainHandle,
1,
&Name,
&GrpId,
&GrpUse
);
ThisDomain = DomainHandle;
if ( NtStatus == STATUS_NONE_MAPPED ) {
//
// not found in account domain. Lookup in the builtin domain
//
NtStatus = SamLookupNamesInDomain(
BuiltinDomainHandle,
1,
&Name,
&GrpId,
&GrpUse
);
ThisDomain=BuiltinDomainHandle;
}
if ( NT_SUCCESS(NtStatus) ) {
switch ( GrpUse[0] ) {
case SidTypeGroup:
NtStatus = SamOpenGroup(
ThisDomain,
GROUP_READ | GROUP_EXECUTE,
GrpId[0],
&GroupHandle
);
if ( NT_SUCCESS(NtStatus) ) {
NtStatus = SamQueryInformationGroup(
GroupHandle,
GroupNameInformation,
&pNameInfo
);
}
break;
case SidTypeAlias:
NtStatus = SamOpenAlias(
ThisDomain,
ALIAS_READ | ALIAS_EXECUTE,
GrpId[0],
&GroupHandle
);
if ( NT_SUCCESS(NtStatus) ) {
NtStatus = SamQueryInformationAlias(
GroupHandle,
AliasNameInformation,
&pNameInfo
);
}
break;
default:
NtStatus = STATUS_NONE_MAPPED;
break;
}
if ( NT_SUCCESS(NtStatus) ) {
//
// get name information
//
if ( ((PGROUP_NAME_INFORMATION)pNameInfo)->Name.Buffer != NULL &&
((PGROUP_NAME_INFORMATION)pNameInfo)->Name.Length > 0 ) {
if ( Length > (DWORD)(((PGROUP_NAME_INFORMATION)pNameInfo)->Name.Length/2) ) {
wcsncpy(GroupName, ((PGROUP_NAME_INFORMATION)pNameInfo)->Name.Buffer,
((PGROUP_NAME_INFORMATION)pNameInfo)->Name.Length/2);
} else {
wcsncpy(GroupName, ((PGROUP_NAME_INFORMATION)pNameInfo)->Name.Buffer,
Length);
}
} else
NtStatus = STATUS_NONE_MAPPED;
SamFreeMemory(pNameInfo);
}
if (GroupHandle)
SamCloseHandle(GroupHandle);
SamFreeMemory(GrpId);
SamFreeMemory(GrpUse);
}
SamCloseHandle( DomainHandle );
SamCloseHandle( BuiltinDomainHandle );
SamCloseHandle( ServerHandle );
SamFreeMemory(DomainSid);
RtlFreeSid(BuiltinDomainSid);
}
return(ScepDosErrorToSceStatus( RtlNtStatusToDosError(NtStatus) ));
}
VOID
ScepPrintSecurityDescriptor(
IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
IN BOOL ToDumpSD
)
{
if (pSecurityDescriptor != NULL) {
if ( ToDumpSD )
DumpSECURITY_DESCRIPTOR(pSecurityDescriptor);
else
printf("Security Descriptor\n");
}
}