Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

673 lines
19 KiB

/******************************************************************************
*
* FILE.C
*
* This file contains routines based off the User Profile Editor utility.
*
* Copyright Citrix Systems, Inc. 1997
* Copyright (c) 1998-1999 Microsoft Corporation
*
* Author: Brad Anderson 1/20/97
*
* $Log: M:\nt\private\utils\citrix\cprofile\VCS\file.c $
*
* Rev 1.3 Jun 26 1997 18:18:38 billm
* move to WF40 tree
*
* Rev 1.2 23 Jun 1997 16:13:20 butchd
* update
*
* Rev 1.1 28 Jan 1997 20:06:34 BradA
* Fixed up some problems related to WF 2.0 changes
*
* Rev 1.0 27 Jan 1997 20:03:44 BradA
* Initial Version
*
******************************************************************************/
/****************************** Module Header ******************************\
* Module Name: upesave.c
*
* Copyright (c) 1992, Microsoft Corporation
*
* Handles OPening and saving of Profiles: default, system, current and user
* profiles.
*
\***************************************************************************/
#include "precomp.h"
#pragma hdrstop
#ifndef RC_INVOKED
#include <winstaw.h>
#include <syslib.h>
#include <tsappcmp.h>
#include <compatfl.h>
#include <utilsub.h>
#endif
#include "cprofile.h"
HKEY hkeyCurrentUser;
PSID gSystemSid; // Initialized in 'InitializeGlobalSids'
PSID gAdminsLocalGroup; // Initialized in 'InitializeGlobalSids
SID_IDENTIFIER_AUTHORITY gNtAuthority = SECURITY_NT_AUTHORITY;
#define SYSTEM_DEFAULT_SUBKEY TEXT(".DEFAULT")
#define TEMP_USER_SUBKEY TEXT("TEMP_USER")
#define TEMP_USER_HIVE_PATH TEXT("%systemroot%\\system32\\config\\")
#define TEMP_SAVE_HIVE TEXT("%systemroot%\\system32\\config\\HiveSave")
#define CITRIX_CLASSES L"\\Registry\\Machine\\Software\\Classes"
LPTSTR lpTempUserHive = NULL;
LPTSTR lpTempUserHivePath = NULL;
LPTSTR lpTempHiveKey;
extern TCHAR szDefExt[];
extern PSID gSystemSid;
BOOL AllocAndExpandEnvironmentStrings(LPTSTR String, LPTSTR *lpExpandedString);
VOID GetRegistryKeyFromPath(LPTSTR lpPath, LPTSTR *lpKey);
NTSTATUS
CtxDeleteKeyTree( HANDLE hKeyRoot,
PKEY_BASIC_INFORMATION pKeyInfo,
ULONG ulInfoSize );
PSECURITY_DESCRIPTOR GetSecurityInfo( LPTSTR File );
void FreeSecurityInfo(PSECURITY_DESCRIPTOR);
/***************************************************************************\
* ClearTempUserProfile
*
* Purpose : unloads the temp user profile loaded from a file, and deletes
* the temp file
*
* History:
* 11-20-92 JohanneC Created.
\***************************************************************************/
BOOL APIENTRY ClearTempUserProfile()
{
BOOL bRet;
if (hkeyCurrentUser == HKEY_CURRENT_USER)
return(TRUE);
//
// Close registry keys.
//
if (hkeyCurrentUser) {
RegCloseKey(hkeyCurrentUser);
}
hkeyCurrentUser = HKEY_CURRENT_USER;
bRet = (RegUnLoadKey(HKEY_USERS, lpTempHiveKey) == ERROR_SUCCESS);
if (*lpTempUserHive) {
DeleteFile(lpTempUserHive);
lstrcat(lpTempUserHive, TEXT(".log"));
DeleteFile(lpTempUserHive);
LocalFree(lpTempUserHive);
lpTempUserHive = NULL;
}
return(bRet);
}
/***************************************************************************\
* OpenUserProfile
*
* Purpose : Load an existing profile in the registry and unload previously
* loaded profile (and delete its tmp file).
*
* History:
* 11-20-92 JohanneC Created.
\***************************************************************************/
BOOL APIENTRY OpenUserProfile(LPTSTR szFilePath, PSID *pUserSid)
{
DWORD err;
//
// Copy the profile to a temp hive before loading it in the registry.
//
if (!lpTempUserHivePath) {
if (!AllocAndExpandEnvironmentStrings(TEMP_USER_HIVE_PATH, &lpTempUserHivePath))
return(FALSE);
}
lpTempUserHive = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) *
(lstrlen(lpTempUserHivePath) + 17));
if (!lpTempUserHive) {
return(FALSE);
}
if (!GetTempFileName(lpTempUserHivePath, TEXT("tmp"), 0, lpTempUserHive)) {
lstrcpy(lpTempUserHive, lpTempUserHivePath);
lstrcat(lpTempUserHive, TEXT("\\HiveOpen"));
}
if (CopyFile(szFilePath, lpTempUserHive, FALSE)) {
GetRegistryKeyFromPath(lpTempUserHive, &lpTempHiveKey);
if ((err = RegLoadKey(HKEY_USERS, lpTempHiveKey, lpTempUserHive)) == ERROR_SUCCESS) {
if ((err = RegOpenKeyEx(HKEY_USERS, lpTempHiveKey, 0,
MAXIMUM_ALLOWED,
&hkeyCurrentUser)) != ERROR_SUCCESS) {
//
// Error, do not have access to the profile.
//
ErrorPrintf(IDS_ERROR_PROFILE_LOAD_ERR, err);
ClearTempUserProfile();
return(FALSE);
}
}
else {
DeleteFile(lpTempUserHive);
lstrcat(lpTempUserHive, TEXT(".log"));
DeleteFile(lpTempUserHive);
LocalFree(lpTempUserHive);
//
// Could not load the user profile, check the error code
//
if (err == ERROR_BADDB) {
// bad format: not a profile registry file
ErrorPrintf(IDS_ERROR_BAD_PROFILE);
return(FALSE);
}
else {
// generic error message : Failed to load profile
ErrorPrintf(IDS_ERROR_PROFILE_LOAD_ERR, err);
return(FALSE);
}
}
}
else {
//
// An error occured trying to load the profile.
//
DeleteFile(lpTempUserHive);
switch ( (err = GetLastError()) ) {
case ERROR_SHARING_VIOLATION:
ErrorPrintf(IDS_ERROR_PROFILE_INUSE);
break;
default:
ErrorPrintf(IDS_ERROR_PROFILE_LOAD_ERR, err);
break;
}
return(FALSE);
}
//
// Get the permitted user
//
*pUserSid = NULL;
return(TRUE);
}
/***************************************************************************\
* SaveUserProfile
*
* Purpose : Save the loaded profile as a file. The registry should already
* have the existing ACL's already set so nothing needs to change. The
* file ACL's do need to be copied from the original and applied to the
* saved file. This function assumes the orignal file exists.
*
\***************************************************************************/
BOOL APIENTRY SaveUserProfile(PSID pUserSid, LPTSTR lpFilePath)
{
LPTSTR lpTmpHive = NULL;
BOOL err = FALSE;
//
// Save the profile to a temp hive then copy it over.
//
if ( AllocAndExpandEnvironmentStrings(TEMP_SAVE_HIVE, &lpTmpHive) )
{
if( lpTmpHive != NULL )
{
DeleteFile(lpTmpHive);
if(RegSaveKey(hkeyCurrentUser, lpTmpHive, NULL) != ERROR_SUCCESS)
{
LocalFree(lpTmpHive);
lpTmpHive = NULL;
err = TRUE;
}
else
{
PSECURITY_DESCRIPTOR pSecDesc;
DWORD Attrib = GetFileAttributes(lpFilePath);
pSecDesc = GetSecurityInfo(lpFilePath);
SetFileAttributes(lpFilePath,FILE_ATTRIBUTE_ARCHIVE);
if(CopyFile(lpTmpHive, lpFilePath, FALSE))
{
DeleteFile(lpTmpHive);
LocalFree(lpTmpHive);
lpTmpHive = NULL;
if (pSecDesc)
{
SetFileSecurity(lpFilePath,
DACL_SECURITY_INFORMATION,
pSecDesc);
FreeSecurityInfo(pSecDesc);
}
}
else
{
if(pSecDesc)
{
FreeSecurityInfo(pSecDesc);
}
err = TRUE;
}
if(0xffffffff != Attrib)
{
SetFileAttributes(lpFilePath,Attrib);
}
}
}
}
else
{
err = TRUE;
}
if( lpTmpHive != NULL )
{
LocalFree(lpTmpHive);
}
return(!err);
}
/***************************************************************************\
* EnablePrivilege
*
* Enables/disabled the specified well-known privilege in the
* current process context
*
* Returns TRUE on success, FALSE on failure
*
* History:
* 12-05-91 Davidc Created
\***************************************************************************/
BOOL
EnablePrivilege(
DWORD Privilege,
BOOL Enable
)
{
NTSTATUS Status;
#if 0
BOOL WasEnabled;
Status = RtlAdjustPrivilege(Privilege, Enable, TRUE, (PBOOLEAN)&WasEnabled);
return(NT_SUCCESS(Status));
#else
HANDLE ProcessToken;
LUID LuidPrivilege;
PTOKEN_PRIVILEGES NewPrivileges;
DWORD Length;
//
// Open our own token
//
Status = NtOpenProcessToken(
NtCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES,
&ProcessToken
);
if (!NT_SUCCESS(Status)) {
return(FALSE);
}
//
// Initialize the privilege adjustment structure
//
LuidPrivilege = RtlConvertLongToLuid(Privilege);
NewPrivileges = (PTOKEN_PRIVILEGES) LocalAlloc(LPTR, sizeof(TOKEN_PRIVILEGES) +
(1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
if (NewPrivileges == NULL) {
NtClose(ProcessToken);
return(FALSE);
}
NewPrivileges->PrivilegeCount = 1;
NewPrivileges->Privileges[0].Luid = LuidPrivilege;
//
// WORKAROUND: because of a bug in NtAdjustPrivileges which
// returns an error when you try to enable a privilege
// that is already enabled, we first try to disable it.
// to be removed when api is fixed.
//
NewPrivileges->Privileges[0].Attributes = 0;
Status = NtAdjustPrivilegesToken(
ProcessToken, // TokenHandle
(BOOLEAN)FALSE, // DisableAllPrivileges
NewPrivileges, // NewPrivileges
0, // BufferLength
NULL, // PreviousState (OPTIONAL)
&Length // ReturnLength
);
NewPrivileges->Privileges[0].Attributes = Enable ? SE_PRIVILEGE_ENABLED : 0;
//
// Enable the privilege
//
Status = NtAdjustPrivilegesToken(
ProcessToken, // TokenHandle
(BOOLEAN)FALSE, // DisableAllPrivileges
NewPrivileges, // NewPrivileges
0, // BufferLength
NULL, // PreviousState (OPTIONAL)
&Length // ReturnLength
);
LocalFree(NewPrivileges);
NtClose(ProcessToken);
if (Status) {
return(FALSE);
}
return(TRUE);
#endif
}
BOOL AllocAndExpandEnvironmentStrings(LPTSTR String, LPTSTR *lpExpandedString)
{
LPTSTR lptmp = NULL;
DWORD cchBuffer;
// Get the number of characters needed.
cchBuffer = ExpandEnvironmentStrings(String, lptmp, 0);
if (cchBuffer) {
cchBuffer++; // for NULL terminator
lptmp = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * cchBuffer);
if (!lptmp) {
return(FALSE);
}
cchBuffer = ExpandEnvironmentStrings(String, lptmp, cchBuffer);
}
*lpExpandedString = lptmp;
return(TRUE);
}
VOID GetRegistryKeyFromPath(LPTSTR lpPath, LPTSTR *lpKey)
{
LPTSTR lptmp;
*lpKey = lpPath;
for (lptmp = lpPath; *lptmp; lptmp++) {
if (*lptmp == TEXT('\\')) {
*lpKey = lptmp+1;
}
}
}
/***************************************************************************\
* InitializeGlobalSids
*
* Initializes the various global Sids used in this module.
*
* History:
* 04-28-93 JohanneC Created
\***************************************************************************/
VOID InitializeGlobalSids()
{
NTSTATUS Status;
//
// Build the admins local group SID
//
Status = RtlAllocateAndInitializeSid(
&gNtAuthority,
2,
SECURITY_BUILTIN_DOMAIN_RID,
DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&gAdminsLocalGroup
);
//
// create System Sid
//
Status = RtlAllocateAndInitializeSid(
&gNtAuthority,
1,
SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0,
&gSystemSid
);
}
/*****************************************************************************
*
* ClearDisabledClasses
*
* This routine will check the compatibility flags for the user's Classes
* registry key, and remove the keys if mapping is disabled.
*
* ENTRY:
*
* EXIT:
* No return value.
*
****************************************************************************/
void ClearDisabledClasses(void)
{
NTSTATUS Status = STATUS_SUCCESS;
ULONG ulcnt = 0, ultemp = 0;
UNICODE_STRING UniPath;
OBJECT_ATTRIBUTES ObjAttr;
PKEY_BASIC_INFORMATION pKeyUserInfo = NULL;
HANDLE hKeyUser = NULL;
NTSTATUS Status2;
HANDLE hClassesKey;
WCHAR wcuser[MAX_PATH];
if ( ! hkeyCurrentUser) {
return;
}
GetTermsrCompatFlags(CITRIX_CLASSES, &ultemp, CompatibilityRegEntry);
if ( (ultemp & (TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) !=
(TERMSRV_COMPAT_WIN32 | TERMSRV_COMPAT_NOREGMAP)) {
return;
}
// Get a buffer for the key info
ulcnt = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH*sizeof(WCHAR) + sizeof(WCHAR);
pKeyUserInfo = RtlAllocateHeap(RtlProcessHeap(),
0,
ulcnt);
if (!pKeyUserInfo) {
Status = STATUS_NO_MEMORY;
}
// We have the necessary buffers, start checking the keys
if (NT_SUCCESS(Status)) {
// Build up a string for this user's software section
wcscpy(wcuser, L"Software");
// Create a unicode string for the user key path
RtlInitUnicodeString(&UniPath, wcuser);
InitializeObjectAttributes(&ObjAttr,
&UniPath,
OBJ_CASE_INSENSITIVE,
hkeyCurrentUser,
NULL);
Status = NtOpenKey(&hKeyUser,
KEY_READ | DELETE,
&ObjAttr);
RtlInitUnicodeString(&UniPath, L"Classes");
InitializeObjectAttributes(&ObjAttr,
&UniPath,
OBJ_CASE_INSENSITIVE,
hKeyUser,
NULL);
Status2 = NtOpenKey(&hClassesKey, KEY_READ | DELETE, &ObjAttr);
if ( NT_SUCCESS(Status2) ) {
Status2 = CtxDeleteKeyTree(hClassesKey, pKeyUserInfo, ulcnt);
if ( !NT_SUCCESS(Status2)) {
}
NtClose(hClassesKey);
}
// If we allocated the system key, close it
if (hKeyUser) {
NtClose(hKeyUser);
}
}
// Free up any memory we allocated
if (pKeyUserInfo) {
RtlFreeHeap( RtlProcessHeap(), 0, pKeyUserInfo);
}
}
/*****************************************************************************
*
* CtxDeleteKeyTree
*
* Delete a subtree of registry keys
*
* ENTRY:
* hKeyRoot is a handle to the root key that will be deleted along with
* its children
* pKeyInfo is a pointer to a KEY_BASIC_INFORMATION buffer that is
* large enough to hold a MAX_PATH WCHAR string. It is
* reused and destroyed by each recursive call.
* ulInfoSize is the size of the pKeyInfo buffer
*
* EXIT:
* Status
*
****************************************************************************/
NTSTATUS
CtxDeleteKeyTree( HANDLE hKeyRoot,
PKEY_BASIC_INFORMATION pKeyInfo,
ULONG ulInfoSize )
{
NTSTATUS Status = STATUS_SUCCESS, Status2;
UNICODE_STRING UniPath;
OBJECT_ATTRIBUTES ObjAttr;
ULONG ulcnt = 0;
ULONG ultemp;
HANDLE hKey;
// Go through each of the subkeys
while (NT_SUCCESS(Status)) {
Status = NtEnumerateKey(hKeyRoot,
ulcnt,
KeyBasicInformation,
pKeyInfo,
ulInfoSize,
&ultemp);
// Delete sub keys
if (NT_SUCCESS(Status)) {
// Null terminate the key name
pKeyInfo->Name[pKeyInfo->NameLength/sizeof(WCHAR)] = L'\0';
// Create a unicode string for the key name
RtlInitUnicodeString(&UniPath, pKeyInfo->Name);
InitializeObjectAttributes(&ObjAttr,
&UniPath,
OBJ_CASE_INSENSITIVE,
hKeyRoot,
NULL);
// Open up the child key
Status2 = NtOpenKey(&hKey,
MAXIMUM_ALLOWED,
&ObjAttr);
if ( NT_SUCCESS(Status2) ) {
Status2 = CtxDeleteKeyTree ( hKey, pKeyInfo, ulInfoSize );
NtClose(hKey);
// If the key was not successfully deleted, we need
// to increment the enumerate index to guarantee
// that the alogorithm will complete.
if ( !NT_SUCCESS(Status2) ) {
++ulcnt;
}
}
}
}
// If we deleted all the sub-keys delete the curent key
if ( !ulcnt ) {
Status = NtDeleteKey(hKeyRoot);
}
else {
Status = STATUS_CANNOT_DELETE;
}
return ( Status );
}
PSECURITY_DESCRIPTOR
GetSecurityInfo(LPTSTR lpFilePath)
{
int SizeReq = 0;
PSECURITY_DESCRIPTOR pSecDesc = NULL;
GetFileSecurity(lpFilePath, DACL_SECURITY_INFORMATION, pSecDesc, 0,
&SizeReq);
if ( !SizeReq ) {
return (NULL);
}
pSecDesc = LocalAlloc(LPTR, SizeReq);
if ( pSecDesc ) {
if ( !GetFileSecurity(lpFilePath, DACL_SECURITY_INFORMATION, pSecDesc,
SizeReq, &SizeReq) ) {
LocalFree(pSecDesc);
pSecDesc = NULL;
}
}
return (pSecDesc);
}
void
FreeSecurityInfo(PSECURITY_DESCRIPTOR pSecDesc)
{
LocalFree(pSecDesc);
}