1068 lines
31 KiB
C
1068 lines
31 KiB
C
|
||
/*************************************************************************
|
||
*
|
||
* inipath.c
|
||
*
|
||
* Routines to manage per user mapping of Ini file paths
|
||
*
|
||
* copyright notice: Copyright 1998, Microsoft Corporation
|
||
*
|
||
*
|
||
*
|
||
*************************************************************************/
|
||
#include "precomp.h"
|
||
#pragma hdrstop
|
||
|
||
|
||
//*** Instance data
|
||
ULONG ulWinDirFlags = 0; // State of user's Windows directory
|
||
|
||
#define WINDIR_FLAGS_VALID 0x01 // The flags are initialized
|
||
#define WINDIR_USER_WINDIR_OK 0x02 // User's Windows dir exists
|
||
|
||
#define WINDOWS_DIR L"WINDOWS"
|
||
UNICODE_STRING WindowsDir = { sizeof(WINDOWS_DIR) - sizeof(UNICODE_NULL) , sizeof(WINDOWS_DIR) + sizeof(UNICODE_NULL), WINDOWS_DIR };
|
||
|
||
WCHAR gpwszDefaultUserName[MAX_PATH+1];
|
||
|
||
/******************************************************************************
|
||
*
|
||
* TermsrvPerUserWinDirMapping
|
||
*
|
||
*
|
||
/******************************************************************************/
|
||
BOOLEAN TermsrvPerUserWinDirMapping() {
|
||
|
||
#ifdef PERUSERBYREQUEST
|
||
PRTL_USER_PROCESS_PARAMETERS pUserParam;
|
||
PWCHAR pwch, pwchext;
|
||
WCHAR pwcAppName[MAX_PATH+1];
|
||
ULONG ulCompat=0, ulAppType=0;
|
||
|
||
// Get the path of the executable name
|
||
pUserParam = NtCurrentPeb()->ProcessParameters;
|
||
|
||
// Get the executable name, if there's no \ just use the name as it is
|
||
pwch = wcsrchr(pUserParam->ImagePathName.Buffer, L'\\');
|
||
if (pwch) {
|
||
pwch++;
|
||
} else {
|
||
pwch = pUserParam->ImagePathName.Buffer;
|
||
}
|
||
wcscpy(pwcAppName, pwch);
|
||
pwch = pwcAppName;
|
||
|
||
if (_wcsicmp(pwch, L"ntvdm.exe")) {
|
||
|
||
// If not a 16 bit app
|
||
// Check if we should return the per user windows dir for this app
|
||
GetCtxAppCompatFlags(&ulCompat, &ulAppType);
|
||
if (!(ulCompat & TERMSRV_COMPAT_PERUSERWINDIR) ||
|
||
!(ulCompat & ulAppType)) {
|
||
//
|
||
// Let the standard GetWindowsDirectory call return the actual path
|
||
//
|
||
return FALSE;
|
||
|
||
}
|
||
}
|
||
|
||
return TRUE;
|
||
#else
|
||
ULONG ulCompat=0, ulAppType = 0;
|
||
|
||
|
||
// Check if we should return the system windows dir for this app
|
||
GetCtxAppCompatFlags(&ulCompat, &ulAppType);
|
||
if ((ulCompat & CITRIX_COMPAT_SYSWINDIR) &&
|
||
(ulCompat & ulAppType)) {
|
||
return FALSE;
|
||
} else {
|
||
return TRUE;
|
||
}
|
||
|
||
#endif
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* TermsrvBuildIniFileName
|
||
*
|
||
* Build the INI file name based on the INIPATH or HOMEPATH (if no INIPATH)
|
||
*
|
||
* ENTRY:
|
||
* pFQName (output)
|
||
* Buffer to place fully qualified INI file name
|
||
* pBaseFileName (input)
|
||
* pointer to buffer containing base INI file name
|
||
*
|
||
* EXIT:
|
||
* NTSTATUS
|
||
*
|
||
*****************************************************************************/
|
||
NTSTATUS
|
||
TermsrvBuildIniFileName(
|
||
OUT PUNICODE_STRING pFQName,
|
||
IN PUNICODE_STRING pBaseFileName
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
USHORT indexLastWChar;
|
||
ULONG ulCompat, ulAppType=0;
|
||
|
||
|
||
//Added By SalimC
|
||
/*
|
||
* If in install mode, use the base windows directory
|
||
* like a stock NT.
|
||
*/
|
||
if( IsSystemLUID() || TermsrvAppInstallMode() ) {
|
||
|
||
return( STATUS_UNSUCCESSFUL );
|
||
}
|
||
//END SalimC
|
||
|
||
if (!TermsrvPerUserWinDirMapping()) {
|
||
return( STATUS_UNSUCCESSFUL );
|
||
}
|
||
#if 0
|
||
GetCtxAppCompatFlags(&ulCompat, &ulAppType);
|
||
if (((ulCompat & TERMSRV_COMPAT_SYSWINDIR) && (ulCompat & ulAppType))) {
|
||
|
||
return STATUS_UNSUCCESSFUL;
|
||
|
||
}
|
||
#endif
|
||
|
||
Status = GetPerUserWindowsDirectory( pFQName );
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
/*
|
||
* Add a '\' if one's not already there
|
||
*/
|
||
if ( indexLastWChar = pFQName->Length / sizeof( WCHAR ) ) {
|
||
if ( pFQName->Buffer[--indexLastWChar] != L'\\' ) {
|
||
Status = RtlAppendUnicodeToString( pFQName, L"\\" );
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Append the base file name to the fully qualified directory name
|
||
*/
|
||
if ( NT_SUCCESS( Status ) ) {
|
||
Status = RtlAppendUnicodeStringToString( pFQName, pBaseFileName );
|
||
}
|
||
}
|
||
|
||
return( Status );
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* GetPerUserWindowsDirectory
|
||
*
|
||
* Get the user's INI file directory
|
||
*
|
||
* ENTRY:
|
||
* pFQName (output)
|
||
* Buffer to place fully qualified INI file name
|
||
*
|
||
* EXIT:
|
||
* NTSTATUS
|
||
*
|
||
*****************************************************************************/
|
||
NTSTATUS
|
||
GetPerUserWindowsDirectory(
|
||
OUT PUNICODE_STRING pFQName
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
int indexLastWChar;
|
||
USHORT Length;
|
||
#if 0 //Bug fix #340691: Inherit the security
|
||
PSECURITY_ATTRIBUTES psa = NULL;
|
||
#endif //Bug fix #340691: Inherit the security
|
||
UNICODE_STRING UserProfilePath;
|
||
WCHAR* pwszFQProfileName;
|
||
#if DBG
|
||
char pszFile[MAX_PATH+1];
|
||
#endif
|
||
|
||
UNICODE_STRING BaseHomePathVariableName, BaseHomeDriveVariableName;
|
||
|
||
/*
|
||
* If in install mode, use the base windows directory
|
||
* like a stock NT.
|
||
*/
|
||
if( IsSystemLUID() || TermsrvAppInstallMode() ) {
|
||
//Status = GetEnvPath( pFQName, NULL, &BaseWindowsDirectory );
|
||
return( STATUS_UNSUCCESSFUL );
|
||
}
|
||
|
||
/*
|
||
* Check for HOMEDRIVE and HOMEPATH
|
||
*/
|
||
RtlInitUnicodeString(&BaseHomeDriveVariableName,L"HOMEDRIVE");
|
||
RtlInitUnicodeString(&BaseHomePathVariableName,L"HOMEPATH");
|
||
|
||
if (!NT_SUCCESS(Status = GetEnvPath( pFQName, &BaseHomeDriveVariableName,
|
||
&BaseHomePathVariableName ))){
|
||
|
||
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
|
||
// Need 2 bytes for the "\" character to cat FQN and WindowsDir
|
||
Length = pFQName->Length + sizeof(WCHAR) + WindowsDir.Length;
|
||
|
||
#if DBG
|
||
DbgPrint("pFQName->Length = %u WindowsDir.Length = %u Length = %u\n",
|
||
pFQName->Length, WindowsDir.Length, Length);
|
||
#endif
|
||
|
||
|
||
pFQName->Length = Length;
|
||
#if DBG
|
||
DbgPrint("\nGetEnvPath return STATUS_BUFFER_TOO_SMALL\n");
|
||
#endif
|
||
} else {
|
||
#if DBG
|
||
DbgPrint("GetEnvPath failed with Status %lx\n",Status);
|
||
#endif
|
||
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
/*
|
||
* If the user profile is Default User then use the
|
||
* base windows directory.
|
||
*/
|
||
|
||
if (pwszFQProfileName = wcsrchr( pFQName->Buffer, L'\\' )) {
|
||
|
||
if (_wcsnicmp(pwszFQProfileName+1, gpwszDefaultUserName, MAX_PATH+1) == 0) {
|
||
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* Check buffer length
|
||
*/
|
||
Length = pFQName->Length + sizeof(WCHAR) + WindowsDir.Length;
|
||
|
||
// take into account the NULL terminator character
|
||
if (pFQName->MaximumLength < Length + 1) {
|
||
// Need 2 bytes for the NULL terminator
|
||
Length += sizeof(WCHAR);
|
||
pFQName->Length = Length;
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
goto done;
|
||
}
|
||
|
||
|
||
/*
|
||
* Add a trailing backslash if one's not already there
|
||
*/
|
||
if ( indexLastWChar = pFQName->Length / sizeof( WCHAR ) ) {
|
||
|
||
if ( pFQName->Buffer[--indexLastWChar] != L'\\' ) {
|
||
|
||
if (NT_SUCCESS(RtlAppendUnicodeToString( pFQName, L"\\" ))) {
|
||
|
||
/*
|
||
* Append "WINDOWS" to home dir
|
||
*/
|
||
Status = RtlAppendUnicodeStringToString( pFQName, &WindowsDir );
|
||
}
|
||
|
||
} else {
|
||
|
||
Status = RtlAppendUnicodeStringToString( pFQName, &WindowsDir );
|
||
}
|
||
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
// Check if we've already tried to create the user's windows path
|
||
if (ulWinDirFlags & WINDIR_FLAGS_VALID) {
|
||
if (ulWinDirFlags & WINDIR_USER_WINDIR_OK) {
|
||
goto done;
|
||
} else {
|
||
Status = STATUS_OBJECT_PATH_INVALID;
|
||
}
|
||
}
|
||
}
|
||
|
||
if ( NT_SUCCESS(Status) ) {
|
||
|
||
WCHAR Buffer[MAX_PATH+1];
|
||
SECURITY_ATTRIBUTES sa;
|
||
BOOL fDirCreated = FALSE;
|
||
|
||
// Mark this process's windows directory flags as valid
|
||
ulWinDirFlags |= WINDIR_FLAGS_VALID;
|
||
#if 0 //Bug fix #340691: Inherit the security
|
||
/*
|
||
* Since creating a security descriptor calls LookupAccountName,
|
||
* which is very time consuming, we only do that if we have to
|
||
* create the directory (which should rarely happen anyway).
|
||
*/
|
||
if ( CreateDirectoryW( (LPCWSTR)pFQName->Buffer, NULL ) &&
|
||
RemoveDirectoryW( (LPCWSTR)pFQName->Buffer ) &&
|
||
CtxCreateSecurityDescriptor( &sa ) ) {
|
||
psa = &sa;
|
||
}
|
||
/*
|
||
* Create windows directory if it doesn't exist
|
||
*/
|
||
if ( !CreateDirectoryW( (LPCWSTR)pFQName->Buffer, psa ) ) {
|
||
#endif //Bug fix #340691: Inherit the security
|
||
if ( !CreateDirectoryW( (LPCWSTR)pFQName->Buffer, NULL ) ) {
|
||
|
||
if ( (Status = GetLastError()) == ERROR_ALREADY_EXISTS ) {
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
|
||
#if DBG
|
||
else {
|
||
wcstombs( pszFile, pFQName->Buffer, sizeof(pszFile) );
|
||
DbgPrint( "KERNEL32: Error (%d) creating dir '%s'\n",
|
||
Status, pszFile );
|
||
}
|
||
#endif
|
||
} else {
|
||
fDirCreated = TRUE;
|
||
}
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
|
||
|
||
/*
|
||
* Create system directory if it doesn't exist
|
||
* (ignore return code)
|
||
*/
|
||
wcscpy( Buffer, pFQName->Buffer );
|
||
wcscat( Buffer, L"\\system" );
|
||
|
||
/*
|
||
* If the user's WINDOWS directory already existed but the
|
||
* WINDOWS\SYSTEM directory didn't, we need to create the
|
||
* security descriptor (this scenario is even rarer).
|
||
*/
|
||
#if 0 //Bug fix #340691: Inherit the security
|
||
if ( !psa && !fDirCreated &&
|
||
CreateDirectoryW( (LPCWSTR)Buffer, NULL ) &&
|
||
RemoveDirectoryW( (LPCWSTR)Buffer ) &&
|
||
CtxCreateSecurityDescriptor( &sa ) ) {
|
||
psa = &sa;
|
||
}
|
||
|
||
|
||
if ( !CreateDirectoryW( (LPCWSTR)Buffer, psa ) ) {
|
||
#endif
|
||
if ( !CreateDirectoryW( (LPCWSTR)Buffer, NULL ) ) {
|
||
#if DBG
|
||
if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
|
||
wcstombs( pszFile, Buffer, sizeof(pszFile) );
|
||
DbgPrint( "KERNEL32: Error (%d) creating dir '%s'\n",
|
||
GetLastError(), pszFile );
|
||
}
|
||
#endif
|
||
}
|
||
|
||
ulWinDirFlags |= WINDIR_USER_WINDIR_OK;
|
||
}
|
||
}
|
||
|
||
|
||
done:
|
||
#if 0 //Bug fix #340691: Inherit the security
|
||
if ( psa ) {
|
||
CtxFreeSecurityDescriptor( psa );
|
||
}
|
||
#endif //Bug fix #340691: Inherit the security
|
||
#if DDBG
|
||
wcstombs( pszFile, pFQName->Buffer, sizeof(pszFile) );
|
||
DbgPrint( "KERNEL32: ctxwindir='%s'\n", Status ? "Error" : pszFile );
|
||
#endif
|
||
|
||
return( Status );
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* GetEnvPath
|
||
*
|
||
* Retrieve a fully qualified path derived from a drive and dir env variable
|
||
*
|
||
* ENTRY:
|
||
* pFQPath (output)
|
||
* Buffer to place fully qualified path name
|
||
* pDriveVariableName (input)
|
||
* pointer to buffer containing env variable name for drive
|
||
* if NULL, pPathVariableName is a FQPath and no env vars are used
|
||
* pPathVariableName (input)
|
||
* pointer to buffer containing env variable name for dir
|
||
*
|
||
* EXIT:
|
||
* NTSTATUS
|
||
*
|
||
* If NTSTATUS is STATUS_BUFFER_TOO_SMALL, pFQPath->Length will be set
|
||
* to the buffer size needed.
|
||
*
|
||
*****************************************************************************/
|
||
NTSTATUS
|
||
GetEnvPath(
|
||
OUT PUNICODE_STRING pFQPath,
|
||
IN PUNICODE_STRING pDriveVariableName,
|
||
IN PUNICODE_STRING pPathVariableName
|
||
)
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
UNICODE_STRING Path;
|
||
USHORT Length;
|
||
|
||
if ( pDriveVariableName ) {
|
||
/*
|
||
* First let's figure out how big the buffer needs to be
|
||
* We need to do this in case the buffer is too small and we
|
||
* need to return the required size
|
||
*/
|
||
RtlInitUnicodeString( &Path, NULL );
|
||
|
||
/*
|
||
* See if an env variable is defined for the drive
|
||
*/
|
||
Status = RtlQueryEnvironmentVariable_U( NULL, pDriveVariableName,
|
||
&Path);
|
||
switch ( Status ) {
|
||
case STATUS_BUFFER_TOO_SMALL:
|
||
Length = Path.Length; // Count how big this the drive spec is
|
||
break;
|
||
case STATUS_SUCCESS:
|
||
Status = STATUS_OBJECT_NAME_NOT_FOUND; // Something's wrong!
|
||
default:
|
||
goto done;
|
||
break;
|
||
}
|
||
|
||
/*
|
||
* See if an env variable is defined for the directory
|
||
*/
|
||
Path.Length = 0;
|
||
Status = RtlQueryEnvironmentVariable_U( NULL, pPathVariableName,
|
||
&Path);
|
||
switch ( Status ) {
|
||
case STATUS_BUFFER_TOO_SMALL:
|
||
Length += Path.Length; // Count how big this the dir spec is
|
||
break;
|
||
case STATUS_SUCCESS:
|
||
Status = STATUS_OBJECT_NAME_NOT_FOUND; // Something's wrong!
|
||
default:
|
||
goto done;
|
||
break;
|
||
}
|
||
|
||
/*
|
||
* If the buffer is too small, return the max size needed
|
||
*/
|
||
if ( Length + sizeof(WCHAR) > pFQPath->MaximumLength ) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
pFQPath->Length = Length + sizeof(WCHAR); // return size
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Get the env variable for the drive - should work if we got this far
|
||
*/
|
||
if ( Status = RtlQueryEnvironmentVariable_U( NULL, pDriveVariableName,
|
||
pFQPath) ) {
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Setup a receive buffer that points to the proper spot in pFQPath
|
||
*/
|
||
Length = pFQPath->Length; // Save the drive length
|
||
Path.Length = 0;
|
||
Path.MaximumLength = pFQPath->MaximumLength - Length;
|
||
(ULONG_PTR)Path.Buffer = (ULONG_PTR)pFQPath->Buffer + (ULONG)Length;
|
||
|
||
/*
|
||
* Get the env variable for the directory - should work if we got this far
|
||
* Then append it to the end of the drive spec
|
||
*/
|
||
if ( Status = RtlQueryEnvironmentVariable_U( NULL, pPathVariableName,
|
||
&Path) ) {
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Fix up the structure and we're done
|
||
*/
|
||
pFQPath->Length = Path.Length + Length;
|
||
|
||
} else {
|
||
|
||
/*
|
||
* pPathVariableName is really the FQ directory name
|
||
*/
|
||
if ( (pPathVariableName->Length + sizeof(WCHAR)) > pFQPath->MaximumLength ) {
|
||
Status = STATUS_BUFFER_TOO_SMALL;
|
||
pFQPath->Length = pPathVariableName->Length + sizeof(WCHAR); // return size
|
||
} else {
|
||
RtlCopyUnicodeString( pFQPath, pPathVariableName );
|
||
}
|
||
}
|
||
|
||
done:
|
||
return( Status );
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* TermsrvConvertSysRootToUserDir
|
||
*
|
||
* People who use INI files should never have to fully qualify them, but some
|
||
* people do anyway. What's more, some people do it wrong. For example,
|
||
* Microsoft PowerPoint 4.0 will call GetSystemDir (not GetWindowsDir) and
|
||
* will strip off "\system" to build a fully qualified path.
|
||
*
|
||
* ENTRY:
|
||
* pFQPath (input/output)
|
||
* Buffer containing fully qualified path name
|
||
*
|
||
* EXIT:
|
||
* NTSTATUS
|
||
*
|
||
* If NTSTATUS is not STATUS_SUCCESS, the directory was not converted
|
||
*
|
||
*****************************************************************************/
|
||
NTSTATUS
|
||
TermsrvConvertSysRootToUserDir(
|
||
OUT PUNICODE_STRING pFQPath,
|
||
IN PUNICODE_STRING BaseWindowsDirectory
|
||
)
|
||
{
|
||
NTSTATUS Status = STATUS_UNSUCCESSFUL;
|
||
PWSTR p;
|
||
INT_PTR c;
|
||
WCHAR buffer[MAX_PATH+1];
|
||
UNICODE_STRING BaseFileName;
|
||
#if DDBG
|
||
char pszFile[MAX_PATH+1];
|
||
#endif
|
||
|
||
ULONG ulCompat, ulAppType=0;
|
||
|
||
/*
|
||
* If in install mode, use the base windows directory
|
||
* like a stock NT.
|
||
*/
|
||
if( IsSystemLUID() || TermsrvAppInstallMode() ) {
|
||
goto done;
|
||
}
|
||
|
||
|
||
#if 0
|
||
GetCtxAppCompatFlags(&ulCompat, &ulAppType);
|
||
if (((ulCompat & TERMSRV_COMPAT_SYSWINDIR) && (ulCompat & ulAppType))) {
|
||
goto done;
|
||
}
|
||
#endif
|
||
if (!TermsrvPerUserWinDirMapping()) {
|
||
goto done;
|
||
}
|
||
|
||
|
||
/*
|
||
* Check for NULL pointers
|
||
*/
|
||
if ( !pFQPath || !pFQPath->Buffer ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Bogus ini path\n" );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Validate and isolate the path
|
||
*/
|
||
if ( !(p = wcsrchr( pFQPath->Buffer, L'\\' ) ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: No backslash in ini path\n" );
|
||
#endif
|
||
goto done;
|
||
}
|
||
c = (INT_PTR)((ULONG_PTR)p - (ULONG_PTR)pFQPath->Buffer);
|
||
|
||
#if DDBG
|
||
wcstombs( pszFile, BaseWindowsDirectory->Buffer, sizeof(pszFile) );
|
||
DbgPrint( "KERNEL32: c(%d) c2(%d) BaseWinDir: '%s'\n",
|
||
c, (int)BaseWindowsDirectory->Length, pszFile );
|
||
wcstombs( pszFile, p, sizeof(pszFile) );
|
||
DbgPrint( "KERNEL32: BaseFileName: '%s'\n", pszFile );
|
||
#endif
|
||
|
||
if ( c != (INT_PTR)BaseWindowsDirectory->Length ) {
|
||
#if DDBG
|
||
DbgPrint( "KERNEL32: Path length diff from BaseWinDir length\n" );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* See if the path is the same as the base windows directory
|
||
*/
|
||
c /= sizeof(WCHAR);
|
||
if ( _wcsnicmp( BaseWindowsDirectory->Buffer, pFQPath->Buffer, (size_t)c ) ) {
|
||
#if DDBG
|
||
DbgPrint( "KERNEL32: Path diff from BaseWinDir\n" );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Use the user's directory instead
|
||
*/
|
||
wcscpy( buffer, ++p );
|
||
RtlInitUnicodeString( &BaseFileName, buffer );
|
||
Status = TermsrvBuildIniFileName( pFQPath, &BaseFileName );
|
||
|
||
done:
|
||
|
||
#if DDBG
|
||
wcstombs( pszFile, pFQPath->Buffer, sizeof(pszFile) );
|
||
DbgPrint( "KERNEL32: Exit(%x) ConvertSystemRootToUserDir: '%s'\n",
|
||
Status, pszFile );
|
||
#endif
|
||
|
||
return( Status );
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* CtxCreateSecurityDescriptor
|
||
*
|
||
* This routine will create a security descriptor based on the specified
|
||
* generic flags. If this function succeeds, the caller needs to call
|
||
* CtxFreeSecurityDescriptor() when it is done using the descriptor.
|
||
*
|
||
* ENTRY:
|
||
* psa (output)
|
||
* Pointer to uninitialized security attributes structure
|
||
*
|
||
* EXIT:
|
||
* TRUE if successful, FALSE if error occurred
|
||
*
|
||
* (GetLastError() can be called to retrieve error code)
|
||
*
|
||
*****************************************************************************/
|
||
#if 0 //Bug fix #340691: Inherit the security
|
||
BOOL CtxCreateSecurityDescriptor( PSECURITY_ATTRIBUTES psa )
|
||
{
|
||
BOOL fSuccess = FALSE;
|
||
NTSTATUS Status;
|
||
PSID psidAdmin, psidUser;
|
||
UINT cb = sizeof( SECURITY_DESCRIPTOR ) + 2 * sizeof(PSID);
|
||
UINT cbAcl = sizeof(ACL);
|
||
PACL pAcl;
|
||
PSID *ppsidAdmin, *ppsidUser;
|
||
SID_IDENTIFIER_AUTHORITY gSystemSidAuthority = SECURITY_NT_AUTHORITY;
|
||
HANDLE hUserToken;
|
||
PTOKEN_USER pTokenUser = NULL;
|
||
DWORD cbNeeded;
|
||
|
||
/*
|
||
* Initialize pointers to dynamic memory blocks
|
||
*/
|
||
psa->lpSecurityDescriptor = NULL;
|
||
psidAdmin = NULL;
|
||
psidUser = NULL;
|
||
|
||
/*
|
||
* Get the SID of the bult-in Administrators group
|
||
*/
|
||
Status = RtlAllocateAndInitializeSid(
|
||
&gSystemSidAuthority,
|
||
2,
|
||
SECURITY_BUILTIN_DOMAIN_RID,
|
||
DOMAIN_ALIAS_RID_ADMINS,
|
||
0,0,0,0,0,0,
|
||
&psidAdmin);
|
||
if (!NT_SUCCESS(Status)) {
|
||
#if DBG
|
||
DbgPrint("KERNEL32: Couldn't allocate Administrators SID (0x%x)\n", Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Get the SID for the current user from their process token
|
||
*/
|
||
Status = NtOpenThreadToken(
|
||
NtCurrentThread(),
|
||
TOKEN_QUERY,
|
||
TRUE,
|
||
&hUserToken);
|
||
if (Status == STATUS_NO_TOKEN) {
|
||
Status = NtOpenProcessToken(
|
||
NtCurrentProcess(),
|
||
TOKEN_QUERY,
|
||
&hUserToken);
|
||
}
|
||
if (!NT_SUCCESS(Status)) {
|
||
#if DBG
|
||
DbgPrint("KERNEL32: Couldn't access process' token (0x%x)\n", Status );
|
||
#endif
|
||
RtlFreeHeap( RtlProcessHeap(), 0, psidAdmin );
|
||
goto done;
|
||
}
|
||
Status = NtQueryInformationToken(
|
||
hUserToken,
|
||
TokenUser,
|
||
NULL,
|
||
0,
|
||
&cbNeeded );
|
||
if (Status == STATUS_BUFFER_TOO_SMALL) {
|
||
pTokenUser = (PTOKEN_USER)RtlAllocateHeap( RtlProcessHeap(), 0, cbNeeded );
|
||
if (pTokenUser != NULL) {
|
||
Status = NtQueryInformationToken(
|
||
hUserToken,
|
||
TokenUser,
|
||
(LPVOID)pTokenUser,
|
||
cbNeeded,
|
||
&cbNeeded );
|
||
if (NT_SUCCESS(Status)) {
|
||
/*
|
||
* Make a copy of the user's SID
|
||
*/
|
||
psidUser = RtlAllocateHeap( RtlProcessHeap(), 0, RtlLengthSid(pTokenUser->User.Sid) );
|
||
if (psidUser != NULL) {
|
||
Status = RtlCopySid( RtlLengthSid(pTokenUser->User.Sid), psidUser, pTokenUser->User.Sid );
|
||
} else {
|
||
Status = STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
} else {
|
||
Status = STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
|
||
if (pTokenUser != NULL) {
|
||
RtlFreeHeap( RtlProcessHeap(), 0, pTokenUser );
|
||
}
|
||
NtClose(hUserToken);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
#if DBG
|
||
DbgPrint("KERNEL32: Couldn't query user's token (0x%x)\n", Status );
|
||
#endif
|
||
RtlFreeHeap( RtlProcessHeap(), 0, psidAdmin );
|
||
if (psidUser != NULL) {
|
||
RtlFreeHeap( RtlProcessHeap(), 0, psidUser );
|
||
}
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Figure out how much memory we need to allocate for the SD
|
||
*/
|
||
cbAcl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid( psidUser ) - sizeof(DWORD);
|
||
cbAcl += sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid( psidAdmin ) - sizeof(DWORD);
|
||
|
||
/*
|
||
* Allocate all the memory we need for the security descriptor
|
||
*/
|
||
if ( !(psa->lpSecurityDescriptor =
|
||
(PSECURITY_DESCRIPTOR)LocalAlloc( LPTR, cb + cbAcl ) ) ) {
|
||
#if DBG
|
||
DbgPrint("KERNEL32: No memory to create security descriptor (%d)\n",
|
||
cb + cbAcl);
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Divvy up our memory block to include SIDs and ACLs
|
||
*/
|
||
ppsidAdmin = (PSID*)((ULONG_PTR)psa->lpSecurityDescriptor + sizeof(SECURITY_DESCRIPTOR));
|
||
ppsidUser = (PSID*)((ULONG_PTR)ppsidAdmin + sizeof(PSID));
|
||
pAcl = (PACL)((ULONG_PTR)ppsidUser + sizeof(PSID));
|
||
/*
|
||
* Save the SIDs - the SIDs must not be freed until we're done
|
||
* using the security descriptor
|
||
*/
|
||
*ppsidAdmin = psidAdmin;
|
||
*ppsidUser = psidUser;
|
||
|
||
/*
|
||
* Initialize the rest of the security attributes structure
|
||
*/
|
||
psa->nLength = sizeof( SECURITY_ATTRIBUTES );
|
||
psa->bInheritHandle = FALSE;
|
||
|
||
/*
|
||
* Initialize the security descriptor
|
||
*/
|
||
if ( Status = RtlCreateSecurityDescriptor(
|
||
psa->lpSecurityDescriptor,
|
||
SECURITY_DESCRIPTOR_REVISION ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) initializing security descriptor\n",
|
||
Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Set the owner
|
||
*/
|
||
if ( Status = RtlSetOwnerSecurityDescriptor( psa->lpSecurityDescriptor,
|
||
NULL, FALSE ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) setting security descriptor owner\n",
|
||
Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Set the group
|
||
*/
|
||
if ( Status = RtlSetGroupSecurityDescriptor( psa->lpSecurityDescriptor,
|
||
psidAdmin, FALSE ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) setting security descriptor owner\n",
|
||
Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Initialize the ACL
|
||
*/
|
||
if ( Status = RtlCreateAcl( pAcl, cbAcl, ACL_REVISION ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) initializing ACL\n",
|
||
Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Add user ACE
|
||
*/
|
||
if ( Status = CtxAddAccessAllowedAce( pAcl, ACL_REVISION, GENERIC_ALL, psidUser, 0 ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) adding user ACE\n", Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Add Administrators ACE
|
||
*/
|
||
if ( Status = CtxAddAccessAllowedAce( pAcl, ACL_REVISION, GENERIC_ALL, psidAdmin, 1 ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) adding admin ACE\n", Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Set the discretionary ACL
|
||
*/
|
||
if ( Status = RtlSetDaclSecurityDescriptor( psa->lpSecurityDescriptor,
|
||
TRUE, pAcl, FALSE ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%08X) setting security descriptor owner\n",
|
||
Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
fSuccess = TRUE;
|
||
|
||
done:
|
||
if ( !fSuccess && psa->lpSecurityDescriptor ) {
|
||
CtxFreeSecurityDescriptor( psa );
|
||
}
|
||
return( fSuccess );
|
||
}
|
||
|
||
/******************************************************************************
|
||
*
|
||
* CtxFreeSecurityDescriptor
|
||
*
|
||
* This routine will free resources allocated in a corresponding
|
||
* CtxCreateSecurityDescriptor() call.
|
||
*
|
||
* ENTRY:
|
||
* psa (input)
|
||
* Pointer to security attributes
|
||
*
|
||
* EXIT:
|
||
* TRUE if successful, FALSE if error occurred
|
||
*
|
||
* (GetLastError() can be called to retrieve error code)
|
||
*
|
||
*****************************************************************************/
|
||
BOOL CtxFreeSecurityDescriptor( PSECURITY_ATTRIBUTES psa )
|
||
{
|
||
BOOL fSuccess = TRUE;
|
||
PSID *ppsidAdmin, *ppsidUser;
|
||
|
||
if ( psa->lpSecurityDescriptor ) {
|
||
ppsidAdmin = (PSID*)((ULONG_PTR)psa->lpSecurityDescriptor + sizeof(SECURITY_DESCRIPTOR));
|
||
ppsidUser = (PSID*)((ULONG_PTR)ppsidAdmin + sizeof(PSID));
|
||
if ( *ppsidUser ) {
|
||
CtxFreeSID( *ppsidUser );
|
||
}
|
||
if ( *ppsidAdmin ) {
|
||
CtxFreeSID( *ppsidAdmin );
|
||
}
|
||
fSuccess = !LocalFree( psa->lpSecurityDescriptor );
|
||
#if DDBG
|
||
DbgPrint( "KERNEL32: fSuccess(%d) freeing security descriptor (%08X)\n",
|
||
fSuccess, psa->lpSecurityDescriptor );
|
||
#endif
|
||
}
|
||
|
||
return( fSuccess );
|
||
}
|
||
|
||
NTSTATUS
|
||
CtxAddAccessAllowedAce (
|
||
IN OUT PACL Acl,
|
||
IN ULONG AceRevision,
|
||
IN ACCESS_MASK AccessMask,
|
||
IN PSID Sid,
|
||
IN DWORD index
|
||
)
|
||
{
|
||
NTSTATUS Status;
|
||
ACE_HEADER *pHeader;
|
||
|
||
/*
|
||
* First add the ACL
|
||
*/
|
||
if ( !(Status = RtlAddAccessAllowedAce( Acl, AceRevision,
|
||
AccessMask, Sid ) ) ) {
|
||
/*
|
||
* Get the ACE
|
||
*/
|
||
if ( Status = RtlGetAce( Acl, index, &pHeader ) ) {
|
||
#if DBG
|
||
DbgPrint( "KERNEL32: Error (%X) from RtlGetAce\n", Status );
|
||
#endif
|
||
goto done;
|
||
}
|
||
|
||
/*
|
||
* Now set the inheritence bits
|
||
*/
|
||
pHeader->AceFlags |= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
|
||
}
|
||
|
||
done:
|
||
return( Status );
|
||
}
|
||
#endif //Bug fix #340691: Inherit the security
|
||
|
||
// from \nt\private\windows\gina\userenv\globals.h
|
||
#define PROFILE_LIST_PATH L"\\Registry\\Machine\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
|
||
#define DEFAULT_USER_PROFILE L"DefaultUserProfile"
|
||
#define DEFAULT_USER L"Default User"
|
||
|
||
BOOL GetDefaultUserProfileName(
|
||
LPWSTR lpProfileDir,
|
||
LPDWORD lpcchSize
|
||
)
|
||
{
|
||
WCHAR* pwszProfileName;
|
||
BYTE pKeyValueInfo[sizeof(KEY_VALUE_PARTIAL_INFORMATION)+(MAX_PATH+1)*sizeof(WCHAR)];
|
||
ULONG ulSize;
|
||
DWORD dwLength;
|
||
BOOL bRetVal = FALSE;
|
||
HKEY hKey;
|
||
NTSTATUS Status;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
UNICODE_STRING UnicodeString;
|
||
|
||
|
||
//
|
||
// Query for the Default User profile name
|
||
//
|
||
|
||
RtlInitUnicodeString(&UnicodeString, PROFILE_LIST_PATH);
|
||
|
||
InitializeObjectAttributes(&ObjectAttributes,
|
||
&UnicodeString,
|
||
OBJ_CASE_INSENSITIVE,
|
||
NULL,
|
||
NULL);
|
||
|
||
|
||
Status = NtOpenKey( &hKey,
|
||
KEY_READ,
|
||
&ObjectAttributes );
|
||
|
||
//lResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, PROFILE_LIST_PATH,
|
||
// 0, KEY_READ, &hKey);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
#if DBG
|
||
DbgPrint("TSAppCmp:GetDefaultUserProfileName: Failed to open profile list key with 0x%x.",Status);
|
||
#endif
|
||
SetLastError(RtlNtStatusToDosError(Status));
|
||
return FALSE;
|
||
}
|
||
|
||
//lResult = RegQueryValueExW(hKey, DEFAULT_USER_PROFILE, NULL, &dwType,
|
||
// (LPBYTE) wszProfileName, &dwSize);
|
||
|
||
RtlInitUnicodeString(&UnicodeString, DEFAULT_USER_PROFILE);
|
||
|
||
Status = NtQueryValueKey( hKey,
|
||
&UnicodeString,
|
||
KeyValuePartialInformation,
|
||
pKeyValueInfo,
|
||
sizeof(pKeyValueInfo),
|
||
&ulSize);
|
||
|
||
pwszProfileName = (WCHAR*)(((PKEY_VALUE_PARTIAL_INFORMATION)pKeyValueInfo)->Data);
|
||
|
||
if (!NT_SUCCESS(Status)) {
|
||
lstrcpy (pwszProfileName, DEFAULT_USER);
|
||
}
|
||
|
||
NtClose(hKey);
|
||
|
||
|
||
//
|
||
// Save the result if possible
|
||
dwLength = lstrlen(pwszProfileName) + 1;
|
||
|
||
if (lpProfileDir) {
|
||
|
||
if (*lpcchSize >= dwLength) {
|
||
lstrcpy (lpProfileDir, pwszProfileName);
|
||
bRetVal = TRUE;
|
||
|
||
} else {
|
||
SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||
}
|
||
|
||
} else {
|
||
SetLastError(ERROR_INVALID_PARAMETER);
|
||
}
|
||
|
||
|
||
*lpcchSize = dwLength;
|
||
|
||
return bRetVal;
|
||
}
|
||
|
||
|