summaryrefslogtreecommitdiffstats
path: root/private/ole32/olecnfg
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ole32/olecnfg
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ole32/olecnfg')
-rw-r--r--private/ole32/olecnfg/clshive.c310
-rw-r--r--private/ole32/olecnfg/main.c374
-rw-r--r--private/ole32/olecnfg/makefile6
-rw-r--r--private/ole32/olecnfg/olecnfg.c996
-rw-r--r--private/ole32/olecnfg/olecnfg.h121
-rw-r--r--private/ole32/olecnfg/olecnfg.rc50
-rw-r--r--private/ole32/olecnfg/sid.c255
-rw-r--r--private/ole32/olecnfg/sources74
-rw-r--r--private/ole32/olecnfg/treemgmt.c882
-rw-r--r--private/ole32/olecnfg/uenv.h26
10 files changed, 3094 insertions, 0 deletions
diff --git a/private/ole32/olecnfg/clshive.c b/private/ole32/olecnfg/clshive.c
new file mode 100644
index 000000000..08a134d8f
--- /dev/null
+++ b/private/ole32/olecnfg/clshive.c
@@ -0,0 +1,310 @@
+//*************************************************************
+//
+// Personal Classes Profile management routines
+//
+// Microsoft Confidential
+// Copyright (c) Microsoft Corporation 1995
+// All rights reserved
+//
+//*************************************************************
+
+#include "uenv.h"
+
+LPTSTR GetSidString(HANDLE UserToken);
+VOID DeleteSidString(LPTSTR SidString);
+PSID GetUserSid (HANDLE UserToken);
+VOID DeleteUserSid(PSID Sid);
+
+BOOL
+MergeUserClasses(
+ HKEY UserClassStore,
+ HKEY CommonClassStore,
+ HKEY MergedClassStore,
+ BOOL ForceNew);
+
+BOOL
+CloneRegistryTree(
+ HKEY hkSourceTree,
+ HKEY hkDestinationTree,
+ LPTSTR lpDestTreeName );
+
+BOOL
+AddSharedValuesToSubkeys( HKEY hkShared, LPTSTR pszSubtree );
+
+BOOL
+AddSharedValues( HKEY hkShared );
+void CreateMachineClassHive( )
+{
+ HKEY hkUser;
+ HKEY hkMachine;
+ LONG result;
+ DWORD dwDisp;
+
+ result =
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("Software\\Classes"),
+ 0,
+ KEY_READ,
+ &hkUser);
+ result =
+ RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("Software\\MachineClasses"),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkMachine,
+ &dwDisp );
+
+ CloneRegistryTree(hkUser, hkMachine, NULL);
+
+ AddSharedValues( hkMachine );
+
+ RegCloseKey( hkUser );
+ RegCloseKey( hkMachine );
+}
+
+
+LPTSTR
+GetUserMergedHivePath(
+ LPTSTR SidString )
+{
+ // open HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\ProfileList
+ // open ...\SidString
+ // get value for ProfileImagePath, and if it is reg_expand_sz, expand it
+ // append Classes as the last component of the hive file name
+ long result;
+ HKEY hkProfileListKey;
+ HKEY hkProfileKey;
+ TCHAR ProfilePath[256];
+ TCHAR ExpandedProfilePath[256];
+ LPTSTR pszProfileDirectory = NULL;
+ LPTSTR pszReturnedHivePath = NULL;
+ DWORD dwType;
+ DWORD dwSize = sizeof( ProfilePath );
+
+
+ result = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList",
+ 0,
+ KEY_READ,
+ &hkProfileListKey );
+
+ // TBD: errors?
+
+ result = RegOpenKeyEx( hkProfileListKey,
+ SidString,
+ 0,
+ KEY_READ,
+ &hkProfileKey );
+
+ result = RegQueryValueEx( hkProfileKey,
+ L"ProfileImagePath",
+ NULL,
+ &dwType,
+ (BYTE*)&ProfilePath,
+ &dwSize );
+
+ if ( dwType == REG_EXPAND_SZ )
+ {
+ ExpandEnvironmentStrings( ProfilePath,
+ ExpandedProfilePath,
+ sizeof(ExpandedProfilePath)/sizeof(TCHAR) );
+ pszProfileDirectory = ExpandedProfilePath;
+ }
+ else
+ {
+ pszProfileDirectory = ProfilePath;
+ }
+
+ pszReturnedHivePath = (LPTSTR) LocalAlloc( LPTR,
+ (lstrlenW( pszProfileDirectory )+1) * sizeof(TCHAR) +
+ sizeof( L"\\ClsRoot" ) );
+ // make up the returned string as the profile directory with \ClsRoot on the end
+ lstrcpyW( pszReturnedHivePath, pszProfileDirectory );
+ lstrcatW( pszReturnedHivePath, L"\\ClsRoot" );
+
+ return pszReturnedHivePath;
+}
+
+void
+FreeUserMergedHivePath( LPTSTR hivepath )
+{
+ LocalFree( hivepath );
+}
+
+// see if the desired hive file already exists. If so, load it and return
+// otherwise, create a hive containing a single key, load it and return
+BOOL
+CreateUserMergedClasses(
+ LPTSTR SidString,
+ LPTSTR MergedClassesString,
+ HKEY * phkMerged )
+{
+ LPTSTR HivePath;
+ long result;
+ HKEY DummyKey;
+ DWORD dwDisp;
+ NTSTATUS Status;
+ BOOLEAN WasEnabled;
+
+ if (!NT_SUCCESS(Status)) {
+ // TBD: report error
+ }
+
+ HivePath = GetUserMergedHivePath( SidString );
+
+ // see if the desired hive file already exists. If so, load it and return
+ if ( 0xFFFFFFFF == GetFileAttributes( HivePath ) )
+ {
+ // create a hive containing a single key, load it and return
+ result = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
+ L"Software\\Microsoft\\DummyKey",
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &DummyKey,
+ &dwDisp );
+
+ //
+ // Enable the backup privilege
+ //
+
+ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, TRUE, FALSE, &WasEnabled);
+
+ // do this by doing a RegSaveKey of a small subtree
+ result = RegSaveKey( DummyKey,
+ HivePath,
+ NULL );
+
+ result = RegCloseKey( DummyKey );
+ //
+ // Restore the privilege to its previous state
+ //
+
+ Status = RtlAdjustPrivilege(SE_BACKUP_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
+ }
+
+ //
+ // Enable the restore privilege
+ //
+
+ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, TRUE, FALSE, &WasEnabled);
+
+
+ result = RegLoadKey( HKEY_USERS,
+ MergedClassesString,
+ HivePath );
+
+ // if result is OK, then open the subkey and return it
+ result = RegOpenKeyEx( HKEY_USERS,
+ MergedClassesString,
+ 0,
+ KEY_ALL_ACCESS,
+ phkMerged );
+
+ FreeUserMergedHivePath( HivePath );
+ // close keys?
+
+ //
+ // Restore the privilege to its previous state
+ //
+
+ Status = RtlAdjustPrivilege(SE_RESTORE_PRIVILEGE, WasEnabled, FALSE, &WasEnabled);
+
+ return TRUE;
+}
+
+
+
+
+void MergeUserClassHives( HANDLE Token )
+{
+ HKEY hkUser;
+ HKEY hkMachine;
+ HKEY hkMerged;
+ LONG result;
+ LPTSTR SidString;
+ LPTSTR MergedClassesString;
+ DWORD dwDisp;
+ BOOL ForceNew = FALSE;
+
+ result =
+ RegCreateKeyEx(HKEY_CURRENT_USER,
+ TEXT("Software\\Classes"),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ,
+ NULL,
+ &hkUser,
+ &dwDisp);
+
+ result =
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("Software\\MachineClasses"),
+ 0,
+ KEY_READ,
+ &hkMachine);
+
+ if ( result == ERROR_FILE_NOT_FOUND )
+ {
+ CreateMachineClassHive();
+ result =
+ RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("Software\\MachineClasses"),
+ 0,
+ KEY_READ,
+ &hkMachine);
+
+ }
+
+ SidString = GetSidString( Token );
+
+ MergedClassesString = (LPTSTR) LocalAlloc( LPTR,
+ (lstrlenW( SidString ) + 1) * sizeof(WCHAR) +
+ sizeof(L"_MergedClasses" ) );
+ // TBD: check for NULL
+
+ lstrcpyW( MergedClassesString, SidString );
+ lstrcatW( MergedClassesString, L"_MergedClasses" );
+
+ result = RegOpenKeyEx( HKEY_USERS,
+ MergedClassesString,
+ 0,
+ KEY_ALL_ACCESS,
+ &hkMerged );
+
+ if ( result == ERROR_FILE_NOT_FOUND )
+ {
+ CreateUserMergedClasses(SidString, MergedClassesString, &hkMerged );
+ ForceNew = TRUE;
+ }
+
+ MergeUserClasses(hkUser, hkMachine, hkMerged, ForceNew );
+
+ RegCloseKey( hkUser );
+ RegCloseKey( hkMachine );
+ RegCloseKey( hkMerged );
+
+ LocalFree( MergedClassesString );
+
+ DeleteSidString( SidString );
+}
+
+void MergeHives( )
+{
+ HANDLE Token;
+ NTSTATUS Status;
+
+ Status = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY, &Token );
+
+ MergeUserClassHives( Token );
+
+ NtClose( Token );
+
+}
+
diff --git a/private/ole32/olecnfg/main.c b/private/ole32/olecnfg/main.c
new file mode 100644
index 000000000..45507397b
--- /dev/null
+++ b/private/ole32/olecnfg/main.c
@@ -0,0 +1,374 @@
+//
+//
+//
+
+#include "olecnfg.h"
+
+const char * GlobalKeyNames[] =
+ {
+ 0,
+ "EnableDCOM",
+ "DefaultLaunchPermission",
+ "DefaultAccessPermission",
+ "LegacyAuthenticationLevel"
+ };
+
+const char * ClsidKeyNames[] =
+ {
+ 0,
+ "InprocHandler32",
+ "InprocServer32",
+ "LocalServer32",
+ "LocalService",
+ "RemoteServerName",
+ "RunAs",
+ "ActivateAtStorage",
+ "LaunchPermission",
+ "AccessPermission"
+ };
+
+int ArgsLeft;
+char ** Args;
+
+HKEY hRegOle = 0;
+HKEY hRegClsid = 0;
+
+#define IsDigit(c) (IsCharAlphaNumeric(c) && !IsCharAlpha(c))
+
+void __cdecl main(int argc, char **argv)
+{
+ int GlobalKeys[GLOBAL_KEYS+1];
+ int Key;
+ int n;
+ DWORD Disposition;
+ long RegStatus;
+
+ memset( GlobalKeys, 0, sizeof(GlobalKeys) );
+
+ ArgsLeft = argc - 1;
+ Args = argv + 1;
+
+ if ( (argc > 1) &&
+ ((strcmp( "/?", argv[1] ) == 0) || (strcmp( "-?", argv[1] ) == 0)) )
+ {
+ DisplayHelp();
+ return;
+ }
+
+ //
+ // With no arguments, display the global registry activation values.
+ //
+ if ( ArgsLeft == 0 )
+ {
+ DisplayGlobalSettings();
+ return;
+ }
+
+ //
+ // Look for specified global registry keys and operations
+ //
+ for ( ; ArgsLeft > 0; )
+ {
+ if ( _stricmp( *Args, "EnableDCOM" ) == 0 )
+ Key = ENABLE_NETWORK_OLE;
+ else if ( _stricmp( *Args, "DefaultLaunchPermission" ) == 0 )
+ Key = DEFAULT_LAUNCH_PERMISSION;
+ else if ( _stricmp( *Args, "DefaultAccessPermission" ) == 0 )
+ Key = DEFAULT_ACCESS_PERMISSION;
+ else if ( _stricmp( *Args, "LegacyAuthenticationLevel" ) == 0 )
+ Key = LEGACY_AUTHENTICATION_LEVEL;
+ else
+ break;
+
+ EAT_ARG();
+
+ if ( Key >= 100 )
+ {
+ if ( Key == MERGE )
+ {
+ MergeHives( );
+ }
+ else if ( Key == SAVE_USER )
+ {
+ SaveChangesToUser( );
+ }
+ else if ( Key == SAVE_COMMON )
+ {
+ SaveChangesToCommon( );
+ }
+ continue;
+ }
+
+ if ( Key == DEFAULT_ACCESS_PERMISSION )
+ {
+ GlobalKeys[Key] = YES;
+ continue;
+ }
+
+ if ( Key == LEGACY_AUTHENTICATION_LEVEL )
+ {
+ if ( ! IsDigit(**Args) || (**Args < '1') || (**Args > '6') )
+ {
+ printf( "LegacyAuthenticationLevel must be followed by a 1 to 6.\n" );
+ return;
+ }
+
+ GlobalKeys[Key] = **Args;
+ }
+ else if ( (GlobalKeys[Key] = ReadYesOrNo()) == INVALID )
+ {
+ printf( "%s must be followed by 'y' or 'n'\n", Args[-1] );
+ return;
+ }
+
+ EAT_ARG();
+ }
+
+ //
+ // Set global keys on or off.
+ //
+ for ( Key = 1; Key < sizeof(GlobalKeys)/sizeof(int); Key++ )
+ {
+ if ( (Key == LEGACY_AUTHENTICATION_LEVEL) && (GlobalKeys[Key] != 0) )
+ {
+ if ( ! SetGlobalKey( Key, GlobalKeys[Key] - '0' ) )
+ return;
+ continue;
+ }
+
+ if ( (GlobalKeys[Key] == YES) || (GlobalKeys[Key] == NO) )
+ if ( ! SetGlobalKey( Key, GlobalKeys[Key] ) )
+ return;
+ }
+
+ //
+ // Process any CLSID/ProgID specification.
+ //
+ ParseClsidProgId();
+
+ if ( hRegOle )
+ RegCloseKey( hRegOle );
+ if ( hRegClsid )
+ RegCloseKey( hRegClsid );
+}
+
+void ParseClsidProgId()
+{
+ CLSID_INFO ClsidInfo;
+ BOOL NoKeys;
+ int ClsidKey;
+
+ if ( ArgsLeft == 0 )
+ return;
+
+ memset( &ClsidInfo, 0, sizeof(CLSID_INFO) );
+
+ NoKeys = TRUE;
+
+ if ( (ArgsLeft > 0) && (**Args != '{') )
+ {
+ ClsidInfo.ProgId = *Args;
+ EAT_ARG();
+
+ if ( (ArgsLeft > 0) &&
+ (**Args != '{') &&
+ (NextClsidKey() == UNKNOWN) )
+ {
+ ClsidInfo.ProgIdDescription = *Args;
+ EAT_ARG();
+ }
+ }
+
+ if ( (ArgsLeft > 0) && (**Args == '{') )
+ {
+ ClsidInfo.Clsid = *Args;
+ EAT_ARG();
+
+ if ( (ArgsLeft > 0) &&
+ (NextClsidKey() == UNKNOWN) )
+ {
+ ClsidInfo.ClsidDescription = *Args;
+ EAT_ARG();
+ }
+ }
+
+ for (; ArgsLeft > 0;)
+ {
+ ClsidKey = NextClsidKey();
+ if ( (1 <= ClsidKey) && (ClsidKey <= CLSID_KEYS) )
+ NoKeys = FALSE;
+
+ EAT_ARG();
+
+ switch ( ClsidKey )
+ {
+ case LAUNCH_PERMISSION :
+ if ( (ClsidInfo.LaunchPermission = ReadYesOrNo()) == INVALID )
+ {
+ printf( "%s must be followed by 'y' or 'n'\n",
+ ClsidKeyNames[LAUNCH_PERMISSION] );
+ goto ErrorReturn;
+ }
+ EAT_ARG();
+ break;
+
+ case ACCESS_PERMISSION :
+ ClsidInfo.AccessPermission = YES;
+ break;
+
+ case ACTIVATE_AT_STORAGE :
+ if ( (ClsidInfo.ActivateAtStorage = ReadYesOrNo()) == INVALID )
+ {
+ printf( "%s must be followed by 'y' or 'n'\n",
+ ClsidKeyNames[ACTIVATE_AT_STORAGE] );
+ goto ErrorReturn;
+ }
+ EAT_ARG();
+ break;
+
+ case INPROC_HANDLER32 :
+ case INPROC_SERVER32 :
+ case LOCAL_SERVER32 :
+ case LOCAL_SERVICE :
+ if ( NextClsidKey() == UNKNOWN )
+ {
+ ClsidInfo.ServerPaths[ClsidKey] = *Args;
+ EAT_ARG();
+ }
+ else
+ {
+ ClsidInfo.ServerPaths[ClsidKey] = "";
+ }
+ break;
+
+ case REMOTE_SERVER_NAME :
+ if ( NextClsidKey() == UNKNOWN )
+ {
+ ClsidInfo.RemoteServerName = *Args;
+ EAT_ARG();
+ }
+ else
+ {
+ ClsidInfo.RemoteServerName = "";
+ }
+ break;
+
+ case RUN_AS :
+ if ( NextClsidKey() == UNKNOWN )
+ {
+ ClsidInfo.RunAsUserName = *Args;
+ EAT_ARG();
+
+ if ( _stricmp(ClsidInfo.RunAsUserName,"Interactive User") == 0 )
+ break;
+
+ if ( _stricmp(ClsidInfo.RunAsUserName,"Interactive") == 0 )
+ {
+ if ( (ArgsLeft > 0) && (_stricmp(*Args,"User") == 0) )
+ {
+ EAT_ARG();
+ ClsidInfo.RunAsUserName = "Interactive User";
+ break;
+ }
+ }
+
+ if ( NextClsidKey() != UNKNOWN )
+ {
+ printf( "RunAs password or '*' must follow the user name.\n" );
+ goto ErrorReturn;
+ }
+
+ ClsidInfo.RunAsPassword = *Args;
+ EAT_ARG();
+ }
+ else
+ {
+ ClsidInfo.RunAsUserName = "";
+ }
+ break;
+
+ default :
+ printf( "Invalid CLSID/ProgID specification given (%s)\n", Args[-1] );
+ goto ErrorReturn;
+ break;
+ } // switch
+ } // for
+
+ //
+ // Display current CLSID/ProgID settings if no keys were specified and
+ // only a CLSID or ProgID (but not both) was given.
+ //
+ if ( NoKeys &&
+ (ClsidInfo.ProgIdDescription == 0) &&
+ (ClsidInfo.ClsidDescription == 0) &&
+ ((ClsidInfo.Clsid == 0) || (ClsidInfo.ProgId == 0)) )
+ DisplayClsidKeys( &ClsidInfo );
+ else
+ UpdateClsidKeys( &ClsidInfo );
+
+ return;
+
+ErrorReturn:
+ printf( "No CLSID/ProgID entries were modified\n" );
+}
+
+int NextClsidKey()
+{
+ if ( ArgsLeft == 0 )
+ return END_OF_ARGS;
+
+ if ( _stricmp( *Args, "InprocHandler32" ) == 0 )
+ return INPROC_HANDLER32;
+ if ( _stricmp( *Args, "InprocServer32" ) == 0 )
+ return INPROC_SERVER32;
+ if ( _stricmp( *Args, "LocalServer32" ) == 0 )
+ return LOCAL_SERVER32;
+ if ( _stricmp( *Args, "LocalService" ) == 0 )
+ return LOCAL_SERVICE;
+ if ( _stricmp( *Args, "RemoteServerName" ) == 0 )
+ return REMOTE_SERVER_NAME;
+ if ( _stricmp( *Args, "RunAs" ) == 0 )
+ return RUN_AS;
+ if ( _stricmp( *Args, "ActivateAtStorage" ) == 0 )
+ return ACTIVATE_AT_STORAGE;
+ if ( _stricmp( *Args, "LaunchPermission" ) == 0 )
+ return LAUNCH_PERMISSION;
+ if ( _stricmp( *Args, "AccessPermission" ) == 0 )
+ return ACCESS_PERMISSION;
+
+ return UNKNOWN;
+}
+
+int ReadYesOrNo()
+{
+ if ( ArgsLeft == 0 )
+ return INVALID;
+
+ if ( (char)CharUpperA((LPSTR)**Args) == 'Y' )
+ return YES;
+ if ( (char)CharUpperA((LPSTR)**Args) == 'N' )
+ return NO;
+
+ return INVALID;
+}
+
+
+void DisplayHelp()
+{
+ puts( "\nolecnfg\n"
+ "\t[EnableDCOM <y,n>]\n"
+ "\t[DefaultLaunchPermission <y,n>]\n"
+ "\t[DefaultAccessPermission]\n"
+ "\t[LegacyAuthenticationLevel <1,2,3,4,5,6>]\n" );
+ puts( "\t[[ProgID [Description]] [CLSID [Description]]\n"
+ "\t\t[InprocHandler32 [Path]]\n"
+ "\t\t[InprocServer32 [Path]]\n"
+ "\t\t[LocalServer32 [Path]]\n"
+ "\t\t[LocalService [Path]]\n"
+ "\t\t[RemoteServerName [MachineName]]\n"
+ "\t\t[RunAs [UserName Password]] ]\n"
+ "\t\t[ActivateAtStorage <y,n>]\n"
+ "\t\t[LaunchPermission <y,n>]\n"
+ "\t\t[AccessPermission]\n"
+ "\t]\n" );
+}
diff --git a/private/ole32/olecnfg/makefile b/private/ole32/olecnfg/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ole32/olecnfg/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ole32/olecnfg/olecnfg.c b/private/ole32/olecnfg/olecnfg.c
new file mode 100644
index 000000000..b34c85a99
--- /dev/null
+++ b/private/ole32/olecnfg/olecnfg.c
@@ -0,0 +1,996 @@
+//
+//
+//
+
+#include "olecnfg.h"
+
+BOOL SetGlobalKey( int Key, int Value )
+{
+ DWORD RegStatus;
+ HKEY hReg;
+ DWORD Disposition;
+ char * ValueName;
+
+ if ( hRegOle == 0 )
+ {
+ RegStatus = RegCreateKeyEx(
+ HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\OLE",
+ 0,
+ "REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hRegOle,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\OLE for writing\n" );
+ return FALSE;
+ }
+ }
+
+ // BUGBUG : Extra stuff to do for PersonalClasses and InstallCommon.
+
+ if ( (Key == DEFAULT_LAUNCH_PERMISSION) ||
+ (Key == DEFAULT_ACCESS_PERMISSION) )
+ {
+ RegStatus = RegCreateKeyEx(
+ hRegOle,
+ GlobalKeyNames[Key],
+ 0,
+ "REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hReg,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Unable to open or add global key %s (status %d)\n",
+ GlobalKeyNames[Key],
+ RegStatus );
+ return FALSE;
+ }
+
+ ValueName = NULL;
+ }
+ else
+ {
+ hReg = hRegOle;
+ ValueName = (char *)GlobalKeyNames[Key];
+ }
+
+ if ( Key == LEGACY_AUTHENTICATION_LEVEL )
+ {
+ RegStatus = RegSetValueEx(
+ hReg,
+ ValueName,
+ 0,
+ REG_DWORD,
+ (LPBYTE)&Value,
+ sizeof(DWORD) );
+ }
+ else if ( Key != DEFAULT_ACCESS_PERMISSION )
+ {
+ RegStatus = RegSetValueEx(
+ hReg,
+ ValueName,
+ 0,
+ REG_SZ,
+ (LPBYTE)(Value == YES ? "Y" : "N"),
+ 2 * sizeof(char) );
+ }
+ else
+ RegStatus = ERROR_SUCCESS;
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Unable to set value for %s (status %d)\n",
+ GlobalKeyNames[Key],
+ RegStatus );
+ return FALSE;
+ }
+
+ if ( Key == LEGACY_AUTHENTICATION_LEVEL )
+ {
+ printf( "Global setting %s set to %d.\n",
+ GlobalKeyNames[Key],
+ Value );
+ }
+ else if ( Key == DEFAULT_ACCESS_PERMISSION )
+ {
+ printf( "Global setting %s set to on.\n",
+ GlobalKeyNames[Key] );
+ }
+ else
+ {
+ printf( "Global setting %s set to %c.\n",
+ GlobalKeyNames[Key],
+ Value == YES ? 'Y' : 'N' );
+ }
+
+ return TRUE;
+}
+
+void DisplayGlobalSettings()
+{
+ HKEY hReg;
+ DWORD RegStatus;
+ int Key;
+ DWORD Type;
+ DWORD Value;
+ DWORD BufSize;
+ char * ValueName;
+
+ RegStatus = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ "SOFTWARE\\Microsoft\\OLE",
+ 0,
+ KEY_READ,
+ &hRegOle );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\OLE\n" );
+ return;
+ }
+
+ printf( "\nGlobal OLE registry settings :\n" );
+
+ for ( Key = 1; Key <= GLOBAL_KEYS; Key++ )
+ {
+ if ( (Key == DEFAULT_LAUNCH_PERMISSION) ||
+ (Key == DEFAULT_ACCESS_PERMISSION) )
+ {
+ RegStatus = RegOpenKeyEx(
+ hRegOle,
+ GlobalKeyNames[Key],
+ 0,
+ KEY_READ,
+ &hReg );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( " %-28sN (key does not exist or could not be opened)\n",
+ GlobalKeyNames[Key] );
+ continue;
+ }
+
+ ValueName = NULL;
+ }
+ else
+ {
+ hReg = hRegOle;
+ ValueName = (char *)GlobalKeyNames[Key];
+ }
+
+ if ( Key != DEFAULT_ACCESS_PERMISSION )
+ {
+ BufSize = sizeof(DWORD);
+
+ RegStatus = RegQueryValueEx(
+ hReg,
+ ValueName,
+ 0,
+ &Type,
+ (LPBYTE) &Value,
+ &BufSize );
+ }
+ else
+ RegStatus = ERROR_SUCCESS;
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ if ( Key == DEFAULT_LAUNCH_PERMISSION )
+ printf( " %-28sN (key value could not be read)\n",
+ GlobalKeyNames[Key] );
+ else
+ printf( " %-28s%c (value not present)\n",
+ GlobalKeyNames[Key],
+ (Key == LEGACY_AUTHENTICATION_LEVEL) ? '2' : 'N' );
+ continue;
+ }
+
+ if ( Key == LEGACY_AUTHENTICATION_LEVEL )
+ {
+ printf( " %-28s%d\n",
+ GlobalKeyNames[Key],
+ Value );
+ }
+ else if ( Key == DEFAULT_ACCESS_PERMISSION )
+ {
+ printf( " %-28son\n",
+ GlobalKeyNames[Key] );
+ }
+ else
+ {
+ printf( " %-28s%c\n",
+ GlobalKeyNames[Key],
+ (char)CharUpper((LPSTR)((char *)&Value)[0]) );
+ }
+ }
+}
+
+void DisplayClsidKeys(
+ CLSID_INFO * ClsidInfo )
+{
+ HKEY hProgId;
+ HKEY hClsid;
+ HKEY hProgIdClsid;
+ HKEY hKey;
+ DWORD RegStatus;
+ DWORD RegType;
+ DWORD BufSize;
+ char ProgIdClsid[64];
+ char Value[128];
+ int Key;
+ BOOL HasRunAs;
+ char Password[64];
+ LSA_HANDLE hPolicy;
+ LSA_OBJECT_ATTRIBUTES ObjAttributes;
+ LSA_UNICODE_STRING LsaKey;
+ LSA_UNICODE_STRING * LsaData;
+ WCHAR wszKey[64];
+ WCHAR wszPassword[64];
+ NTSTATUS NtStatus;
+
+ RegStatus = RegOpenKeyEx(
+ HKEY_CLASSES_ROOT,
+ "CLSID",
+ 0,
+ KEY_READ,
+ &hRegClsid );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open HKEY_CLASSES_ROOT\\CLSID for reading.\n" );
+ return;
+ }
+
+ if ( ClsidInfo->ProgId )
+ {
+ RegStatus = RegOpenKeyEx(
+ HKEY_CLASSES_ROOT,
+ ClsidInfo->ProgId,
+ 0,
+ KEY_READ,
+ &hProgId );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Couldn't open ProgID %s\n", ClsidInfo->ProgId );
+ return;
+ }
+
+ RegStatus = RegOpenKeyEx(
+ hProgId,
+ "CLSID",
+ 0,
+ KEY_READ,
+ &hProgIdClsid );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Couldn't open CLSID key for ProgID %s\n", ClsidInfo->ProgId );
+ return;
+ }
+
+ BufSize = sizeof(ProgIdClsid);
+
+ RegStatus = RegQueryValueEx(
+ hProgIdClsid,
+ NULL,
+ 0,
+ &RegType,
+ (LPBYTE) ProgIdClsid,
+ &BufSize );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Couldn't open CLSID value for ProgID %s\n", ClsidInfo->ProgId );
+ return;
+ }
+
+ if ( ClsidInfo->Clsid &&
+ (_stricmp( ClsidInfo->Clsid, ProgIdClsid ) != 0) )
+ {
+ printf( "ProgID %s CLSID key value %s differs from given CLSID %s.\n",
+ ClsidInfo->ProgId,
+ ProgIdClsid,
+ ClsidInfo->Clsid );
+ return;
+ }
+ else
+ ClsidInfo->Clsid = ProgIdClsid;
+ }
+
+
+ if ( ! ClsidInfo->Clsid )
+ {
+ printf( "Could not determine CLSID.\n" );
+ return;
+ }
+
+ RegStatus = RegOpenKeyEx(
+ hRegClsid,
+ ClsidInfo->Clsid,
+ 0,
+ KEY_READ,
+ &hClsid );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open CLSID %s\n", ClsidInfo->Clsid );
+ return;
+ }
+
+ putchar( '\n' );
+ if ( ClsidInfo->ProgId )
+ printf( "Server settings for ProgID %s, ", ClsidInfo->ProgId );
+ else
+ printf( "Server settings for " );
+
+ printf( "CLSID %s\n", ClsidInfo->Clsid );
+
+ HasRunAs = FALSE;
+
+ for ( Key = 1; Key <= CLSID_KEYS; Key++ )
+ {
+ RegStatus = RegOpenKeyEx(
+ hClsid,
+ ClsidKeyNames[Key],
+ 0,
+ KEY_READ,
+ &hKey );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ continue;
+
+ BufSize = sizeof(Value);
+
+ if ( Key != ACCESS_PERMISSION )
+ {
+ RegStatus = RegQueryValueEx(
+ hKey,
+ NULL,
+ 0,
+ &RegType,
+ (LPBYTE) Value,
+ &BufSize );
+ }
+ else
+ RegStatus = ERROR_SUCCESS;
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( " %-28s(key exists, but value could not be read)\n",
+ ClsidKeyNames[Key] );
+ continue;
+ }
+
+ printf( " %-28s%s\n",
+ ClsidKeyNames[Key],
+ (Key == ACCESS_PERMISSION) ? "on" : Value );
+
+ if ( (Key == RUN_AS) && (_stricmp(Value,"Interactive User") != 0) )
+ HasRunAs = TRUE;
+ }
+
+ if ( ! HasRunAs )
+ return;
+
+ //
+ // Give the option of verifying the RunAs password.
+ //
+
+ printf( "\nCLSID configured with RunAs. Would you like to verify the password? " );
+
+ if ( (char)CharUpper((LPSTR)getchar()) != 'Y' )
+ return;
+
+ while ( getchar() != '\n' )
+ ;
+
+ putchar( '\n' );
+
+ lstrcpyW( wszKey, L"SCM:" );
+ MultiByteToWideChar( CP_ACP,
+ MB_PRECOMPOSED,
+ ClsidInfo->Clsid,
+ -1,
+ &wszKey[lstrlenW(wszKey)],
+ sizeof(wszKey)/2 - lstrlenW(wszKey) );
+
+ LsaKey.Length = (lstrlenW(wszKey) + 1) * sizeof(WCHAR);
+ LsaKey.MaximumLength = sizeof(wszKey);
+ LsaKey.Buffer = wszKey;
+
+ InitializeObjectAttributes( &ObjAttributes, NULL, 0L, NULL, NULL );
+
+ // Open the local security policy
+ NtStatus = LsaOpenPolicy( NULL,
+ &ObjAttributes,
+ POLICY_CREATE_SECRET,
+ &hPolicy );
+
+ if ( ! NT_SUCCESS( NtStatus ) )
+ {
+ printf( "Could not open RunAs password (0x%x)\n", NtStatus );
+ return;
+ }
+
+ // Retrive private data
+ NtStatus = LsaRetrievePrivateData( hPolicy, &LsaKey, &LsaData );
+
+ if ( ! NT_SUCCESS(NtStatus) )
+ {
+ printf( "Could not open RunAs password (0x%x)\n", NtStatus );
+ return;
+ }
+
+ LsaClose(hPolicy);
+
+ for (;;)
+ {
+ printf( "Password : " );
+ ReadPassword( Password );
+
+ if ( strcmp( Password, "dcom4ever" ) == 0 )
+ {
+ printf( "\nThe RunAs password is %ws\n", LsaData->Buffer );
+ return;
+ }
+
+ MultiByteToWideChar( CP_ACP,
+ MB_PRECOMPOSED,
+ Password,
+ -1,
+ wszPassword,
+ sizeof(wszPassword) );
+
+ if ( lstrcmpW( wszPassword, LsaData->Buffer ) != 0 )
+ {
+ printf( "\nPassword does not match RunAs password.\n" );
+ printf( "Enter another password or hit Control-C to exit.\n\n" );
+ }
+ else
+ {
+ printf( "\nPasswords match.\n" );
+ return;
+ }
+ }
+}
+
+void UpdateClsidKeys( CLSID_INFO * ClsidInfo )
+{
+ HKEY hProgId;
+ HKEY hClsid;
+ HKEY hProgIdClsid;
+ HKEY hKey;
+ DWORD RegStatus;
+ DWORD Disposition;
+ DWORD RegType;
+ char ProgIdClsid[64];
+ char Response[64];
+ DWORD BufSize;
+ int n;
+
+ RegStatus = RegOpenKeyEx(
+ HKEY_CLASSES_ROOT,
+ "CLSID",
+ 0,
+ KEY_READ | KEY_WRITE,
+ &hRegClsid );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open HKEY_CLASSES_ROOT\\CLSID for writing\n" );
+ return;
+ }
+
+ hProgId = 0;
+ hClsid = 0;
+
+ if ( ClsidInfo->ProgId )
+ {
+ RegStatus = RegCreateKeyEx(
+ HKEY_CLASSES_ROOT,
+ ClsidInfo->ProgId,
+ 0,
+ "REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hProgId,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open or create ProgID key %s.\n",
+ ClsidInfo->ProgId);
+ return;
+ }
+
+ if ( Disposition == REG_CREATED_NEW_KEY )
+ printf( "ProgId key %s created.\n", ClsidInfo->ProgId );
+
+ if ( ClsidInfo->ProgIdDescription )
+ {
+ RegStatus = RegSetValueEx(
+ hProgId,
+ NULL,
+ 0,
+ REG_SZ,
+ (LPBYTE) ClsidInfo->ProgIdDescription,
+ strlen(ClsidInfo->ProgIdDescription) + sizeof(char) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not set description value for ProgID %s.\n", ClsidInfo->ProgId );
+ return;
+ }
+
+ printf( "Setting description value %s for ProgID %s.\n",
+ ClsidInfo->ProgIdDescription,
+ ClsidInfo->ProgId );
+ }
+
+ RegStatus = RegCreateKeyEx(
+ hProgId,
+ "CLSID",
+ 0,
+ "REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hProgIdClsid,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open or create CLSID key for ProgID %s.\n",
+ ClsidInfo->ProgId );
+ return;
+ }
+
+ //
+ // Check if a CLSID key value already exists for this ProgID. If so,
+ // and a CLSID was specified to us then check if they differ.
+ //
+
+ BufSize = sizeof(ProgIdClsid);
+
+ RegStatus = RegQueryValueEx(
+ hProgIdClsid,
+ NULL,
+ 0,
+ &RegType,
+ (LPBYTE) ProgIdClsid,
+ &BufSize );
+
+ if ( RegStatus == ERROR_SUCCESS )
+ {
+ if ( ClsidInfo->Clsid &&
+ (_stricmp(ClsidInfo->Clsid, ProgIdClsid) != 0) )
+ {
+ printf( "ProgID %s has existing CLSID key value %s\n",
+ ClsidInfo->ProgId,
+ ProgIdClsid );
+ printf( "which differs from given CLSID %s.\n",
+ ClsidInfo->Clsid );
+ printf( "Would you like to replace the existing CLSID value with the new CLSID value? " );
+ gets( Response );
+ if ( (char)CharUpper((LPSTR)Response[0]) != 'Y' )
+ ClsidInfo->Clsid = ProgIdClsid;
+ }
+ else
+ ClsidInfo->Clsid = ProgIdClsid;
+ }
+
+ if ( ! ClsidInfo->Clsid )
+ {
+ printf( "CLSID for ProgID %s not specified.\n",
+ ClsidInfo->ProgId );
+ return;
+ }
+
+ if ( ClsidInfo->Clsid != ProgIdClsid )
+ {
+ RegStatus = RegSetValueEx(
+ hProgIdClsid,
+ NULL,
+ 0,
+ REG_SZ,
+ (LPBYTE) ClsidInfo->Clsid,
+ strlen(ClsidInfo->Clsid) + sizeof(char) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not set CLSID value for ProgID %s.\n", ClsidInfo->ProgId );
+ return;
+ }
+
+ printf( "Setting CLSID value %s for ProgID %s.\n",
+ ClsidInfo->Clsid,
+ ClsidInfo->ProgId );
+ }
+ }
+
+ RegStatus = RegCreateKeyEx(
+ hRegClsid,
+ ClsidInfo->Clsid,
+ 0,
+ "REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hClsid,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not open or create CLSID key %s.\n", ClsidInfo->Clsid );
+ return;
+ }
+
+ if ( Disposition == REG_CREATED_NEW_KEY )
+ printf( "CLSID key %s created.\n", ClsidInfo->Clsid );
+
+ if ( ClsidInfo->ClsidDescription )
+ {
+ RegStatus = RegSetValueEx(
+ hClsid,
+ NULL,
+ 0,
+ REG_SZ,
+ (LPBYTE) ClsidInfo->ClsidDescription,
+ strlen(ClsidInfo->ClsidDescription) + sizeof(char) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not set description value for CLSID %s.\n", ClsidInfo->Clsid );
+ return;
+ }
+
+ printf( "Setting description value %s for CLSID %s.\n",
+ ClsidInfo->ClsidDescription,
+ ClsidInfo->Clsid );
+ }
+
+ //
+ // Now add and delete individual keys on this CLSID.
+ //
+
+ if ( (ClsidInfo->LaunchPermission == YES) ||
+ (ClsidInfo->LaunchPermission == NO) )
+ {
+ SetClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[LAUNCH_PERMISSION],
+ (ClsidInfo->LaunchPermission == YES) ? "Y" : "N" );
+ }
+
+ if ( ClsidInfo->AccessPermission == YES )
+ {
+ SetClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[ACCESS_PERMISSION],
+ NULL );
+ }
+
+ if ( (ClsidInfo->ActivateAtStorage == YES) ||
+ (ClsidInfo->ActivateAtStorage == NO) )
+ {
+ SetClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[ACTIVATE_AT_STORAGE],
+ (ClsidInfo->ActivateAtStorage == YES) ? "Y" : "N" );
+ }
+
+ for ( n = 1; n <= CLSID_PATH_KEYS; n++ )
+ {
+ if ( ! ClsidInfo->ServerPaths[n] )
+ continue;
+ if ( ClsidInfo->ServerPaths[n][0] == '\0' )
+ DeleteClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[n] );
+ else
+ SetClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[n],
+ ClsidInfo->ServerPaths[n] );
+ }
+
+ if ( ClsidInfo->RemoteServerName )
+ {
+ if ( ClsidInfo->RemoteServerName[0] == '\0' )
+ DeleteClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[REMOTE_SERVER_NAME] );
+ else
+ SetClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[REMOTE_SERVER_NAME],
+ ClsidInfo->RemoteServerName );
+ }
+
+ if ( ClsidInfo->RunAsUserName )
+ {
+ DWORD CharRead;
+ char Password1[64];
+ char Password2[64];
+ LSA_HANDLE hPolicy;
+ LSA_OBJECT_ATTRIBUTES ObjAttributes;
+ LSA_UNICODE_STRING LsaKey;
+ LSA_UNICODE_STRING LsaData;
+ WCHAR wszKey[64];
+ WCHAR wszPassword[64];
+ NTSTATUS NtStatus;
+ BOOL Status;
+ BOOL RunAsInteractiveUser;
+
+ RunAsInteractiveUser = (_stricmp(ClsidInfo->RunAsUserName,"Interactive User") == 0);
+
+ if ( ! RunAsInteractiveUser )
+ {
+ InitializeObjectAttributes( &ObjAttributes, NULL, 0L, NULL, NULL );
+
+ // Open the local security policy
+ NtStatus = LsaOpenPolicy( NULL,
+ &ObjAttributes,
+ POLICY_CREATE_SECRET,
+ &hPolicy );
+
+ if ( ! NT_SUCCESS( NtStatus ) )
+ {
+ printf( "Could not setup RunAs (0x%x)\n", NtStatus );
+ return;
+ }
+
+ lstrcpyW( wszKey, L"SCM:" );
+ MultiByteToWideChar( CP_ACP,
+ MB_PRECOMPOSED,
+ ClsidInfo->Clsid,
+ -1,
+ &wszKey[lstrlenW(wszKey)],
+ sizeof(wszKey)/2 - lstrlenW(wszKey) );
+
+ LsaKey.Length = (lstrlenW(wszKey) + 1) * sizeof(WCHAR);
+ LsaKey.MaximumLength = sizeof(wszKey);
+ LsaKey.Buffer = wszKey;
+ }
+
+ if ( ClsidInfo->RunAsUserName[0] == '\0' )
+ {
+ DeleteClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[RUN_AS] );
+
+ LsaStorePrivateData( hPolicy, &LsaKey, NULL );
+ }
+ else
+ {
+ Status = SetClsidKey( hClsid,
+ ClsidInfo->Clsid,
+ ClsidKeyNames[RUN_AS],
+ ClsidInfo->RunAsUserName );
+
+ if ( ! Status )
+ return;
+
+ if ( ! RunAsInteractiveUser && (ClsidInfo->RunAsPassword[0] == '*') )
+ {
+ for (;;)
+ {
+ printf( "Enter RunAs password for %s : ", ClsidInfo->RunAsUserName );
+ ReadPassword( Password1 );
+
+ printf( "Confirm password : " );
+ ReadPassword( Password2 );
+
+ if ( strcmp( Password1, Password2 ) != 0 )
+ {
+ printf( "Passwords differ, try again or hit Control-C to exit.\n" );
+ continue;
+ }
+
+ if ( Password1[0] == '\0' )
+ {
+ printf( "Do you really want a blank password? " );
+ gets( Response );
+ if ( (char)CharUpper((LPSTR)Response[0]) != 'Y' )
+ continue;
+ }
+
+ break;
+ }
+
+ ClsidInfo->RunAsPassword = Password1;
+ } // if password == "*"
+
+ // Got a good one!
+
+ if ( ! RunAsInteractiveUser )
+ {
+ MultiByteToWideChar( CP_ACP,
+ MB_PRECOMPOSED,
+ ClsidInfo->RunAsPassword,
+ -1,
+ wszPassword,
+ sizeof(wszPassword)/2 );
+
+ LsaData.Length = (lstrlenW(wszPassword) + 1) * sizeof(WCHAR);
+ LsaData.MaximumLength = sizeof(wszPassword);
+ LsaData.Buffer = wszPassword;
+
+ // Store private data
+ NtStatus = LsaStorePrivateData( hPolicy, &LsaKey, &LsaData );
+
+ if ( ! NT_SUCCESS(NtStatus) )
+ {
+ printf( "Could not store password securely (0x%x)\n", NtStatus );
+ return;
+ }
+
+ LsaClose(hPolicy);
+ }
+ }
+ }
+
+ printf( "CLSID keys updated successfully.\n" );
+}
+
+BOOL SetClsidKey(
+ HKEY hClsid,
+ char * Clsid,
+ const char * Key,
+ char * Value )
+{
+ HKEY hKey;
+ DWORD RegStatus;
+ DWORD Disposition;
+ DWORD ValueType;
+ DWORD ValueSize;
+ char OldValue[256];
+ BOOL HasOldValue;
+
+ HasOldValue = FALSE;
+
+ RegStatus = RegCreateKeyEx(
+ hClsid,
+ Key,
+ 0,
+ "REG_SZ",
+ REG_OPTION_NON_VOLATILE,
+ KEY_READ | KEY_WRITE,
+ NULL,
+ &hKey,
+ &Disposition );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not create key %s for CLSID %s\n", Key, Clsid );
+ return FALSE;
+ }
+
+ if ( Disposition == REG_CREATED_NEW_KEY )
+ {
+ printf( "Added key %s for CLSID %s\n", Key, Clsid );
+ }
+ else
+ {
+ ValueSize = sizeof(OldValue);
+
+ RegStatus = RegQueryValueEx(
+ hKey,
+ NULL,
+ 0,
+ &ValueType,
+ OldValue,
+ &ValueSize );
+
+ HasOldValue = (RegStatus == ERROR_SUCCESS);
+ }
+
+ if ( ! Value )
+ return TRUE;
+
+ RegStatus = RegSetValueEx(
+ hKey,
+ NULL,
+ 0,
+ REG_SZ,
+ (LPBYTE) Value,
+ strlen(Value) + sizeof(char) );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not set value %s for key %s\n", Value, Key );
+ return FALSE;
+ }
+
+ if ( HasOldValue )
+ printf( "Changed value from %s to %s for key %s\n", OldValue, Value, Key );
+ else
+ printf( "Added value %s for key %s\n", Value, Key );
+
+ return TRUE;
+}
+
+BOOL DeleteClsidKey(
+ HKEY hClsid,
+ char * Clsid,
+ const char * Key )
+{
+ DWORD RegStatus;
+
+ RegStatus = RegDeleteKey( hClsid, Key );
+
+ if ( RegStatus != ERROR_SUCCESS )
+ {
+ printf( "Could not delete key %s for CLSID %s\n", Key, Clsid );
+ return FALSE;
+ }
+
+ printf( "Deleted key %s for CLSID %s\n", Key, Clsid );
+ return TRUE;
+}
+
+void ReadPassword( char * Password )
+{
+ int c, n;
+
+ n = 0;
+
+ for (;;)
+ {
+ c = _getch();
+
+ // ^C
+ if ( c == 0x3 )
+ {
+ putchar( '\n' );
+ ExitProcess( 0 );
+ }
+
+ // Backspace
+ if ( c == 0x8 )
+ {
+ if ( n )
+ {
+ n--;
+ _putch( 0x8 );
+ _putch( ' ' );
+ _putch( 0x8 );
+ }
+ continue;
+ }
+
+ // Return
+ if ( c == '\r' )
+ break;
+
+ Password[n++] = c;
+ _putch( '*' );
+ }
+
+ Password[n] = 0;
+ putchar( '\n' );
+}
+
+BOOL ControlCConsoleHandler( DWORD ControlType )
+{
+ if ( (ControlType == CTRL_C_EVENT) || (ControlType == CTRL_BREAK_EVENT) )
+ {
+ printf( "RunAs password unchanged\n" );
+ ExitProcess( 0 );
+ }
+
+ return FALSE;
+}
+
+
diff --git a/private/ole32/olecnfg/olecnfg.h b/private/ole32/olecnfg/olecnfg.h
new file mode 100644
index 000000000..e7ff03f34
--- /dev/null
+++ b/private/ole32/olecnfg/olecnfg.h
@@ -0,0 +1,121 @@
+//
+//
+//
+
+#ifndef _OLECONFIG_
+#define _OLECONFIG_
+
+#include <nt.h>
+#include <ntrtl.h>
+#include <nturtl.h>
+#include <ntlsa.h>
+#include <windows.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <conio.h>
+
+#define ENABLE_NETWORK_OLE 1
+#define DEFAULT_LAUNCH_PERMISSION 2
+#define DEFAULT_ACCESS_PERMISSION 3
+#define LEGACY_AUTHENTICATION_LEVEL 4
+
+#define GLOBAL_KEYS 4
+
+#define MERGE 101
+#define SAVE_USER 102
+#define SAVE_COMMON 103
+
+#define GLOBAL_OPERATIONS 103
+
+#define INPROC_HANDLER32 1
+#define INPROC_SERVER32 2
+#define LOCAL_SERVER32 3
+#define LOCAL_SERVICE 4
+#define REMOTE_SERVER_NAME 5
+#define RUN_AS 6
+#define ACTIVATE_AT_STORAGE 7
+#define LAUNCH_PERMISSION 8
+#define ACCESS_PERMISSION 9
+
+#define CLSID_KEYS 9
+#define CLSID_PATH_KEYS 4
+
+#define UNKNOWN 0
+#define END_OF_ARGS -1
+
+#define INVALID -1
+#define NO 1
+#define YES 2
+
+#define EAT_ARG() Args++; ArgsLeft--;
+
+typedef struct
+ {
+ char * Clsid;
+ char * ClsidDescription;
+ char * ProgId;
+ char * ProgIdDescription;
+
+ int LaunchPermission;
+ int AccessPermission;
+ int ActivateAtStorage;
+
+ char * ServerPaths[CLSID_PATH_KEYS+1];
+ char * RemoteServerName;
+ char * RunAsUserName;
+ char * RunAsPassword;
+ } CLSID_INFO;
+
+extern const char * GlobalKeyNames[];
+extern const char * ClsidKeyNames[];
+
+extern int ArgsLeft;
+extern char ** Args;
+extern char * ProgramName;
+
+extern HKEY hRegOle;
+extern HKEY hRegClsid;
+
+// main.c
+void ParseClsidProgId();
+int NextClsidKey();
+int ReadYesOrNo();
+void DisplayHelp();
+
+// oleconfig.c
+BOOL SetGlobalKey(
+ int Key,
+ int Value );
+
+void DisplayGlobalSettings();
+
+void DisplayClsidKeys(
+ CLSID_INFO * ClsidInfo );
+
+void UpdateClsidKeys(
+ CLSID_INFO * ClsidInfo );
+
+BOOL SetClsidKey(
+ HKEY hClsid,
+ char * Clsid,
+ const char * Key,
+ char * Value );
+
+BOOL DeleteClsidKey(
+ HKEY hClsid,
+ char * Clsid,
+ const char * Key );
+
+void ReadPassword(
+ char * Password );
+
+BOOL ControlCConsoleHandler(
+ DWORD ControlType );
+
+void MergeHives( );
+
+void SaveChangesToUser( );
+
+void SaveChangesToCommon( );
+
+#endif
diff --git a/private/ole32/olecnfg/olecnfg.rc b/private/ole32/olecnfg/olecnfg.rc
new file mode 100644
index 000000000..5dbcc8a3a
--- /dev/null
+++ b/private/ole32/olecnfg/olecnfg.rc
@@ -0,0 +1,50 @@
+#include <windows.h>
+#include <winver.h>
+
+#define VER_FILEVERSION_STR "4.0\0"
+#define VER_FILEVERSION 4,0000,0001,0001
+
+#define VER_PRODUCTNAME_STR "Microsoft OLE 4.0 for Windows NT(TM) Operating System\0"
+#define VER_COMPANYNAME_STR "Microsoft Corporation\0"
+#define VER_LEGALTRADEMARKS_STR "Microsoft(TM) is a registered trademark of Microsoft Corporation. Windows NT(TM) is a trademark of Microsoft Corporation\0"
+#define VER_LEGALCOPYRIGHT_STR "Copyright (C) Microsoft Corp. 1992 - 1996\0"
+#define VER_PRODUCTVERSION_STR "4.0\0"
+#define VER_PRODUCTVERSION 4,0000,001,0001
+#define VER_COMMENT_STR "Microsoft OLE 4.0 for Windows NT(TM) Operating System\0"
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE 0
+#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#define VER_FILEFLAGS 0L
+#define VER_FILEOS VOS_NT_WINDOWS32
+#define VER_FILEDESCRIPTION_STR "Microsoft OLE 4.0 for Windows NT(TM) Operating System\0"
+
+
+VS_VERSION_INFO VERSIONINFO
+FILEVERSION VER_FILEVERSION
+PRODUCTVERSION VER_PRODUCTVERSION
+FILEFLAGSMASK VER_FILEFLAGSMASK
+FILEFLAGS VER_FILEFLAGS
+FILEOS VER_FILEOS
+FILETYPE VFT_APP
+FILESUBTYPE VER_FILESUBTYPE
+{
+ BLOCK "StringFileInfo"
+ {
+ BLOCK "040904E4"
+ {
+ VALUE "CompanyName", VER_COMPANYNAME_STR
+ VALUE "FileDescription", VER_FILEDESCRIPTION_STR
+ VALUE "FileVersion", VER_FILEVERSION_STR
+ VALUE "InternalName", "OLECNFG.EXE\0"
+ VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
+ VALUE "LegalTrademarks", VER_LEGALTRADEMARKS_STR
+ VALUE "ProductName", VER_PRODUCTNAME_STR
+ VALUE "ProductVersion", VER_PRODUCTVERSION_STR
+ VALUE "Comments", VER_COMMENT_STR
+ }
+ }
+ BLOCK "VarFileInfo"
+ {
+ VALUE "Translation", 0x409, 1252
+ }
+}
diff --git a/private/ole32/olecnfg/sid.c b/private/ole32/olecnfg/sid.c
new file mode 100644
index 000000000..435df4654
--- /dev/null
+++ b/private/ole32/olecnfg/sid.c
@@ -0,0 +1,255 @@
+//*************************************************************
+//
+// SID management functions.
+//
+// THESE FUNCTIONS ARE WINDOWS NT SPECIFIC!!!!!
+//
+// Microsoft Confidential
+// Copyright (c) Microsoft Corporation 1995
+// All rights reserved
+//
+//*************************************************************
+
+#include "uenv.h"
+
+LPTSTR GetSidString(HANDLE UserToken);
+VOID DeleteSidString(LPTSTR SidString);
+PSID GetUserSid (HANDLE UserToken);
+VOID DeleteUserSid(PSID Sid);
+
+#define DebugMsg(x)
+
+/***************************************************************************\
+* GetSidString
+*
+* Allocates and returns a string representing the sid of the current user
+* The returned pointer should be freed using DeleteSidString().
+*
+* Returns a pointer to the string or NULL on failure.
+*
+* History:
+* 26-Aug-92 Davidc Created
+*
+\***************************************************************************/
+LPTSTR GetSidString(HANDLE UserToken)
+{
+ NTSTATUS NtStatus;
+ PSID UserSid;
+ UNICODE_STRING UnicodeString;
+#ifndef UNICODE
+ STRING String;
+#endif
+
+ //
+ // Get the user sid
+ //
+
+ UserSid = GetUserSid(UserToken);
+ if (UserSid == NULL) {
+ DebugMsg((DM_WARNING, TEXT("GetSidString: GetUserSid returned NULL")));
+ return NULL;
+ }
+
+ //
+ // Convert user SID to a string.
+ //
+
+ NtStatus = RtlConvertSidToUnicodeString(
+ &UnicodeString,
+ UserSid,
+ (BOOLEAN)TRUE // Allocate
+ );
+ //
+ // We're finished with the user sid
+ //
+
+ DeleteUserSid(UserSid);
+
+ //
+ // See if the conversion to a string worked
+ //
+
+ if (!NT_SUCCESS(NtStatus)) {
+ DebugMsg((DM_WARNING, TEXT("GetSidString: RtlConvertSidToUnicodeString failed, status = 0x%x"),
+ NtStatus));
+ return NULL;
+ }
+
+#ifdef UNICODE
+
+
+ return(UnicodeString.Buffer);
+
+#else
+
+ //
+ // Convert the string to ansi
+ //
+
+ NtStatus = RtlUnicodeStringToAnsiString(&String, &UnicodeString, TRUE);
+ RtlFreeUnicodeString(&UnicodeString);
+ if (!NT_SUCCESS(NtStatus)) {
+ DebugMsg((DM_WARNING, TEXT("GetSidString: RtlUnicodeStringToAnsiString failed, status = 0x%x"),
+ status));
+ return NULL;
+ }
+
+
+ return(String.Buffer);
+
+#endif
+
+}
+
+
+/***************************************************************************\
+* DeleteSidString
+*
+* Frees up a sid string previously returned by GetSidString()
+*
+* Returns nothing.
+*
+* History:
+* 26-Aug-92 Davidc Created
+*
+\***************************************************************************/
+VOID DeleteSidString(LPTSTR SidString)
+{
+
+#ifdef UNICODE
+ UNICODE_STRING String;
+
+ RtlInitUnicodeString(&String, SidString);
+
+ RtlFreeUnicodeString(&String);
+#else
+ ANSI_STRING String;
+
+ RtlInitAnsiString(&String, SidString);
+
+ RtlFreeAnsiString(&String);
+#endif
+
+}
+
+
+
+/***************************************************************************\
+* GetUserSid
+*
+* Allocs space for the user sid, fills it in and returns a pointer. Caller
+* The sid should be freed by calling DeleteUserSid.
+*
+* Note the sid returned is the user's real sid, not the per-logon sid.
+*
+* Returns pointer to sid or NULL on failure.
+*
+* History:
+* 26-Aug-92 Davidc Created.
+\***************************************************************************/
+PSID GetUserSid (HANDLE UserToken)
+{
+ PTOKEN_USER pUser;
+ PSID pSid;
+ DWORD BytesRequired = 200;
+ NTSTATUS status;
+
+
+ //
+ // Allocate space for the user info
+ //
+
+ pUser = (PTOKEN_USER)LocalAlloc(LMEM_FIXED, BytesRequired);
+
+
+ if (pUser == NULL) {
+ DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"),
+ BytesRequired));
+ return NULL;
+ }
+
+
+ //
+ // Read in the UserInfo
+ //
+
+ status = NtQueryInformationToken(
+ UserToken, // Handle
+ TokenUser, // TokenInformationClass
+ pUser, // TokenInformation
+ BytesRequired, // TokenInformationLength
+ &BytesRequired // ReturnLength
+ );
+
+ if (status == STATUS_BUFFER_TOO_SMALL) {
+
+ //
+ // Allocate a bigger buffer and try again.
+ //
+
+ pUser = LocalReAlloc(pUser, BytesRequired, LMEM_MOVEABLE);
+ if (pUser == NULL) {
+ DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"),
+ BytesRequired));
+ return NULL;
+ }
+
+ status = NtQueryInformationToken(
+ UserToken, // Handle
+ TokenUser, // TokenInformationClass
+ pUser, // TokenInformation
+ BytesRequired, // TokenInformationLength
+ &BytesRequired // ReturnLength
+ );
+
+ }
+
+ if (!NT_SUCCESS(status)) {
+ DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to query user info from user token, status = 0x%x"),
+ status));
+ LocalFree(pUser);
+ return NULL;
+ }
+
+
+ BytesRequired = RtlLengthSid(pUser->User.Sid);
+ pSid = LocalAlloc(LMEM_FIXED, BytesRequired);
+ if (pSid == NULL) {
+ DebugMsg((DM_WARNING, TEXT("GetUserSid: Failed to allocate %d bytes"),
+ BytesRequired));
+ LocalFree(pUser);
+ return NULL;
+ }
+
+
+ status = RtlCopySid(BytesRequired, pSid, pUser->User.Sid);
+
+ LocalFree(pUser);
+
+ if (!NT_SUCCESS(status)) {
+ DebugMsg((DM_WARNING, TEXT("GetUserSid: RtlCopySid Failed. status = %d"),
+ status));
+ LocalFree(pSid);
+ pSid = NULL;
+ }
+
+
+ return pSid;
+}
+
+
+/***************************************************************************\
+* DeleteUserSid
+*
+* Deletes a user sid previously returned by GetUserSid()
+*
+* Returns nothing.
+*
+* History:
+* 26-Aug-92 Davidc Created
+*
+\***************************************************************************/
+VOID DeleteUserSid(PSID Sid)
+{
+ LocalFree(Sid);
+}
diff --git a/private/ole32/olecnfg/sources b/private/ole32/olecnfg/sources
new file mode 100644
index 000000000..2a1675c5b
--- /dev/null
+++ b/private/ole32/olecnfg/sources
@@ -0,0 +1,74 @@
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1989
+
+
+Revision History:
+
+!ENDIF
+
+#
+# The TARGETNAME variable is defined by the developer. It is the name of
+# the target (component) that is being built by this makefile. It
+# should NOT include any path or file extension information.
+#
+
+TARGETNAME=olecnfg
+
+#
+# The TARGETPATH and TARGETTYPE varialbes are defined by the developer.
+# The first specifies where the target is to be build. The second specifies
+# the type of target (either PROGRAM, DYNLINK or LIBRARY)
+#
+
+TARGETPATH=.
+TARGETTYPE=PROGRAM
+
+#
+# The INCLUDES variable specifies any include paths that are specific to
+# this source directory. Separate multiple directory paths with single
+# semicolons. Relative path specifications are okay.
+#
+
+INCLUDES=.
+
+#
+# The SOURCES variable is defined by the developer. It is a list of all the
+# source files for this component. Each source file should be on a separate
+# line using the line continuation character. This will minimize merge
+# conflicts if two developers adding source files to the same component.
+#
+
+SOURCES=\
+ main.c \
+ treemgmt.c \
+ clshive.c \
+ sid.c \
+ olecnfg.c \
+ olecnfg.rc
+
+# C_DEFINES=
+
+LINKLIBS=\
+ $(BASEDIR)\public\sdk\lib\*\kernel32.lib \
+ $(BASEDIR)\public\sdk\lib\*\user32.lib \
+ $(BASEDIR)\public\sdk\lib\*\advapi32.lib \
+ $(BASEDIR)\public\sdk\lib\*\ntdll.lib
+
+UMTYPE=console
diff --git a/private/ole32/olecnfg/treemgmt.c b/private/ole32/olecnfg/treemgmt.c
new file mode 100644
index 000000000..761c293b0
--- /dev/null
+++ b/private/ole32/olecnfg/treemgmt.c
@@ -0,0 +1,882 @@
+//*************************************************************
+//
+// Personal Classes Profile management routines
+//
+// Microsoft Confidential
+// Copyright (c) Microsoft Corporation 1995
+// All rights reserved
+//
+//*************************************************************
+
+#include "uenv.h"
+#include "windows.h"
+
+// Local Data Structures
+
+LPTSTR SpecialSubtrees[] =
+ {
+ TEXT("CLSID"),
+ TEXT("Interface"),
+ TEXT("TypeLib"),
+ TEXT("Licenses"),
+ TEXT("FileType")
+ };
+
+#define MAX_SPECIAL_SUBTREE (sizeof(SpecialSubtrees)/sizeof(LPTSTR))
+//
+// Local function proto-types
+//
+typedef struct _RegKeyInfo {
+ DWORD SubKeyCount;
+ DWORD MaxSubKeyLen;
+ DWORD ValueCount;
+ DWORD MaxValueNameLen;
+ DWORD MaxValueLen;
+ DWORD SDLen;
+ LPTSTR pSubKeyName;
+ LPTSTR pValueName;
+ LPTSTR pValue;
+ } REGKEYINFO, *PREGKEYINFO;
+
+//*************************************************************
+//
+// PrepForEnumRegistryTree()
+//
+// Purpose: prepare to duplicate a source bunch of keys into the destination.
+//
+// Parameters: hkSourceTree - source registry tree
+// pRegKeyInfo - info block for use doing enumeration
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// History: Date Author Comment
+// 1/30/96 GregJen Created
+//
+//*************************************************************
+BOOL
+PrepForEnumRegistryTree(
+ HKEY hkSourceTree,
+ PREGKEYINFO pRegKeyInfo
+ )
+{
+ LPTSTR pStringsBuffer;
+ LONG result;
+
+ result = RegQueryInfoKey(hkSourceTree,
+ NULL,
+ NULL,
+ 0,
+ &pRegKeyInfo->SubKeyCount,
+ &pRegKeyInfo->MaxSubKeyLen,
+ NULL,
+ &pRegKeyInfo->ValueCount,
+ &pRegKeyInfo->MaxValueNameLen,
+ &pRegKeyInfo->MaxValueLen,
+ &pRegKeyInfo->SDLen,
+ NULL);
+
+ if ( result != ERROR_SUCCESS )
+ return FALSE;
+
+ // allocate a block of memory to use for enumerating subkeys and values
+ pStringsBuffer = (LPTSTR) LocalAlloc( LPTR,
+ (pRegKeyInfo->MaxSubKeyLen +
+ pRegKeyInfo->MaxValueNameLen +
+ pRegKeyInfo->MaxValueLen + 3)
+ * sizeof( TCHAR ) );
+ if ( !pStringsBuffer )
+ return FALSE;
+
+ pRegKeyInfo->pSubKeyName = pStringsBuffer;
+ pRegKeyInfo->pValueName = pStringsBuffer + pRegKeyInfo->MaxSubKeyLen + 1;
+ pRegKeyInfo->pValue = pRegKeyInfo->pValueName +
+ pRegKeyInfo->MaxValueNameLen + 1;
+
+}
+
+//*************************************************************
+//
+// CleanupAfterEnumRegistryTree()
+//
+// Purpose: duplicate a source bunch of keys into the destination.
+//
+// Parameters: hkSourceTree - source registry tree
+// pRegKeyInfo - info block for use doing enumeration
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// History: Date Author Comment
+// 1/30/96 GregJen Created
+//
+//*************************************************************
+void
+CleanupAfterEnumRegistryTree(
+ HKEY hkSourceTree,
+ PREGKEYINFO pRegKeyInfo)
+{
+ LocalFree( pRegKeyInfo->pSubKeyName );
+}
+BOOL
+DeleteRegistrySubtree (
+ HKEY hkTree )
+{
+ HKEY hkCurrentSourceKey;
+ DWORD idx;
+ DWORD NameLen;
+ LONG result = ERROR_SUCCESS;
+ REGKEYINFO RegKeyInfo;
+ BOOL Success = FALSE;
+
+ if ( !PrepForEnumRegistryTree( hkTree, &RegKeyInfo ) )
+ return FALSE; // nothing to clean up here yet
+
+ // enumerate all the source subkeys
+ // for each: if dest subkey is older than source, delete it
+ // if dest subkey does not exist (or was deleted) clone the subkey
+ //
+ // Clone all the subkeys
+ //
+ for ( idx = 0;
+ (result == ERROR_SUCCESS) &&
+ ( result != ERROR_MORE_DATA ) &&
+ ( idx < RegKeyInfo.SubKeyCount );
+ idx++ ) {
+ NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
+ result = RegEnumKeyEx( hkTree,
+ idx,
+ RegKeyInfo.pSubKeyName,
+ &NameLen,
+ NULL,
+ NULL,
+ NULL,
+ NULL );
+
+ if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
+ goto cleanup;
+
+ // TBD: open the subkey in the source tree AS CurrentSourceKey
+ result = RegOpenKeyEx(hkTree,
+ RegKeyInfo.pSubKeyName,
+ 0,
+ KEY_ALL_ACCESS,
+ &hkCurrentSourceKey);
+
+ DeleteRegistrySubtree( hkCurrentSourceKey );
+
+ RegCloseKey( hkCurrentSourceKey );
+
+ RegDeleteKey( hkTree, RegKeyInfo.pSubKeyName );
+
+ result = ERROR_SUCCESS;
+ }
+
+cleanup:
+ CleanupAfterEnumRegistryTree( hkTree, &RegKeyInfo );
+
+ return TRUE;
+}
+
+//*************************************************************
+//
+// CloneRegistryValues()
+//
+// Purpose: copy the values from under the source key to the dest key
+//
+// Parameters: SourceTree - source registry tree
+// DestinationTree - destintation registry tree
+// RegKeyInfo - handy information from the RegEnumKeyEx call.
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// History: Date Author Comment
+// 1/14/96 GregJen Created
+//
+//*************************************************************
+BOOL
+CloneRegistryValues(
+ HKEY hkSourceTree,
+ HKEY hkDestinationTree,
+ REGKEYINFO RegKeyInfo )
+{
+ LONG result = ERROR_SUCCESS;
+ DWORD idx;
+ DWORD ValueLen;
+ DWORD ValueType;
+ DWORD DataLen;
+
+ for ( idx = 0;
+ (result == ERROR_SUCCESS) &&
+ ( result != ERROR_MORE_DATA ) &&
+ ( idx < RegKeyInfo.ValueCount );
+ idx++ )
+ {
+ DataLen = RegKeyInfo.MaxValueLen + sizeof( TCHAR );
+ ValueLen = RegKeyInfo.MaxValueNameLen + sizeof( TCHAR );
+
+ result = RegEnumValue( hkSourceTree,
+ idx,
+ RegKeyInfo.pValueName,
+ &ValueLen,
+ NULL,
+ &ValueType,
+ (BYTE*) RegKeyInfo.pValue,
+ &DataLen);
+
+ // TBD: check errors
+
+ // now add the value to the destination key
+
+ result = RegSetValueEx( hkDestinationTree,
+ RegKeyInfo.pValueName,
+ 0,
+ ValueType,
+ (BYTE*) RegKeyInfo.pValue,
+ DataLen );
+ // TBD: check errors
+ }
+ return TRUE;
+}
+//*************************************************************
+//
+// CloneRegistryTree()
+//
+// Purpose: duplicate a source bunch of keys into the destination.
+//
+// Parameters: SourceTree - source registry tree
+// DestinationTree - destintation registry tree
+// lpSubKeyName - if present this is a subkey name that
+// corresponds to the SourceTree HKEY.
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// History: Date Author Comment
+// 1/14/96 GregJen Created
+//
+//*************************************************************
+BOOL
+CloneRegistryTree(
+ HKEY hkSourceTree,
+ HKEY hkDestinationTree,
+ LPTSTR lpDestTreeName )
+{
+ HKEY hkCurrentSourceKey;
+ DWORD idx;
+ DWORD NameLen;
+ LONG result = ERROR_SUCCESS;
+ REGKEYINFO RegKeyInfo;
+ BOOL Success = FALSE;
+
+ if ( !PrepForEnumRegistryTree( hkSourceTree, &RegKeyInfo ) )
+ return FALSE; // nothing to clean up here yet
+
+ if ( lpDestTreeName ) {
+ HKEY hkNewKey;
+ DWORD dwSDLen = RegKeyInfo.SDLen;
+ DWORD dwDisp;
+ SECURITY_INFORMATION SI = DACL_SECURITY_INFORMATION; // for now...
+ PSECURITY_DESCRIPTOR pSD = (PSECURITY_DESCRIPTOR)
+ LocalAlloc( LPTR, dwSDLen );
+ // TBD: check for NULL;
+
+ // Get the registry security information from the old key
+ result = RegGetKeySecurity( hkSourceTree,
+ SI,
+ pSD,
+ &dwSDLen);
+ // TBD: check for errors, free pSD
+ // create a key with the given name, and registry info
+ result = RegCreateKeyEx( hkDestinationTree,
+ lpDestTreeName,
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ pSD,
+ &hkNewKey,
+ &dwDisp );
+ // TBD: check for errors, free pSD
+
+ // TBD: and update the hkDestinationTree variable to point to it
+
+ hkDestinationTree = hkNewKey;
+ LocalFree( pSD );
+ }
+
+ //
+ // clone the values
+ //
+
+ if ( ! CloneRegistryValues( hkSourceTree, hkDestinationTree, RegKeyInfo ) )
+ goto cleanup;
+
+ //
+ // Clone all the subkeys
+ //
+ for ( idx = 0;
+ (result == ERROR_SUCCESS) &&
+ ( result != ERROR_MORE_DATA ) &&
+ ( idx < RegKeyInfo.SubKeyCount );
+ idx++ ) {
+ NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
+ result = RegEnumKeyEx( hkSourceTree,
+ idx,
+ RegKeyInfo.pSubKeyName,
+ &NameLen,
+ NULL,
+ NULL,
+ NULL,
+ NULL );
+
+ if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
+ goto cleanup;
+
+ // TBD: open the subkey in the source tree AS CurrentSourceKey
+ result = RegOpenKeyEx(hkSourceTree,
+ RegKeyInfo.pSubKeyName,
+ 0,
+ KEY_READ,
+ &hkCurrentSourceKey);
+
+ //
+ // recurse passing the subkey name
+ //
+ CloneRegistryTree( hkCurrentSourceKey,
+ hkDestinationTree,
+ RegKeyInfo.pSubKeyName );
+
+ //
+ // close our open key
+ //
+
+ RegCloseKey( hkCurrentSourceKey );
+ }
+
+ Success = TRUE;
+
+cleanup:
+ if ( lpDestTreeName )
+ {
+ RegCloseKey( hkDestinationTree );
+ }
+
+ CleanupAfterEnumRegistryTree( hkSourceTree, &RegKeyInfo );
+
+ return Success;
+}
+
+// TBD: dummy prototypes for now
+// dummy testing code
+void TestCloneHive( )
+{
+ // for testing
+ HKEY hkSource;
+ HKEY hkDestination;
+ LONG result;
+
+ result =
+ RegOpenKeyEx(HKEY_CLASSES_ROOT,
+ TEXT(".pps"),
+ 0,
+ KEY_READ,
+ &hkSource);
+ result =
+ RegOpenKeyEx(HKEY_CLASSES_ROOT,
+ TEXT(".paa"),
+ 0,
+ KEY_ALL_ACCESS,
+ &hkDestination);
+ CloneRegistryTree(hkSource, hkDestination, NULL);
+}
+
+void SaveChangesToUser( )
+{
+}
+
+void SaveChangesToCommon( )
+{
+}
+
+BOOL
+AddSharedValuesToSubkeys( HKEY hkShared, LPTSTR pszSubtree )
+{
+ HKEY hkSourceKey;
+ HKEY hkCurrentSourceKey;
+ DWORD idx;
+ DWORD NameLen;
+ LONG result = ERROR_SUCCESS;
+ REGKEYINFO RegKeyInfo;
+ BOOL Success = FALSE;
+
+
+ // for every subkey, set "Shared" value
+ result = RegOpenKeyEx( hkShared,
+ pszSubtree,
+ 0,
+ KEY_READ,
+ &hkSourceKey );
+
+ // TBD: if no subtree in source, skip ahead to next special subtree
+ if ( result == ERROR_FILE_NOT_FOUND )
+ return TRUE;
+
+ if ( !PrepForEnumRegistryTree( hkSourceKey, &RegKeyInfo ) )
+ goto cleanup2;
+
+ // enumerate all the source subkeys
+ // for each: if dest subkey is older than source, delete it
+ // if dest subkey does not exist (or was deleted) clone the subkey
+ //
+ // Clone all the subkeys
+ //
+ for ( idx = 0;
+ (result == ERROR_SUCCESS) &&
+ ( result != ERROR_MORE_DATA ) &&
+ ( idx < RegKeyInfo.SubKeyCount );
+ idx++ )
+ {
+ NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
+ result = RegEnumKeyEx( hkSourceKey,
+ idx,
+ RegKeyInfo.pSubKeyName,
+ &NameLen,
+ NULL,
+ NULL,
+ NULL,
+ NULL );
+
+ if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
+ goto cleanup;
+
+ result = RegOpenKeyEx( hkSourceKey,
+ RegKeyInfo.pSubKeyName,
+ 0,
+ KEY_ALL_ACCESS,
+ &hkCurrentSourceKey );
+
+ // check for errors
+
+ result = RegSetValueEx( hkCurrentSourceKey,
+ L"Shared",
+ 0,
+ REG_SZ,
+ (LPBYTE) L"Y",
+ sizeof( L"Y" ) );
+
+ RegCloseKey( hkCurrentSourceKey );
+
+ }
+
+ Success = TRUE;
+
+cleanup:
+ CleanupAfterEnumRegistryTree( hkSourceKey, &RegKeyInfo );
+
+cleanup2:
+ RegCloseKey( hkSourceKey );
+
+ return Success;
+
+}
+
+BOOL
+AddSharedValues( HKEY hkShared )
+{
+ // for each of the special subtrees, add "Shared" values
+ int idx;
+
+ // now, for each of the special top-level keys, process the level below them
+ // these keys are: CLSID, Interface, TypeLib, Licenses, FileType
+
+ for ( idx = 0; idx < MAX_SPECIAL_SUBTREE; idx++ )
+ {
+ AddSharedValuesToSubkeys( hkShared, SpecialSubtrees[idx] );
+ }
+
+ // now do all the top level keys (file extensions and progids)
+ AddSharedValuesToSubkeys( hkShared, NULL );
+
+ return TRUE;
+}
+
+
+//*************************************************************
+//
+// MergeUserClasses()
+//
+// Purpose: Merges the user's class information with the
+// common class information.
+//
+// Parameters: UserClassStore - Per-user class information
+// CommonClassStore - Machine-wide class information
+// MergedClassStore - Destination for merged information.
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments: UserClassStore may be a null HKEY, implying
+// just copy the information from the common
+// portion into the merged portion
+//
+// History: Date Author Comment
+// 1/14/96 GregJen Created
+//
+//*************************************************************
+BOOL
+MergeRegistrySubKeys (
+ HKEY hkSourceTree,
+ HKEY hkDestTree )
+{
+ HKEY hkCurrentSourceKey;
+ HKEY hkCurrentDestKey;
+ DWORD idx;
+ DWORD NameLen;
+ LONG result = ERROR_SUCCESS;
+ REGKEYINFO RegKeyInfo;
+ BOOL Success = FALSE;
+ FILETIME SourceFileTime;
+ FILETIME DestFileTime;
+ LONG cmp;
+
+ if ( !PrepForEnumRegistryTree( hkSourceTree, &RegKeyInfo ) )
+ return FALSE; // nothing to clean up here yet
+
+ // enumerate all the source subkeys
+ // for each: if dest subkey is older than source, delete it
+ // if dest subkey does not exist (or was deleted) clone the subkey
+ //
+ // Clone all the subkeys
+ //
+ for ( idx = 0;
+ (result == ERROR_SUCCESS) &&
+ ( result != ERROR_MORE_DATA ) &&
+ ( idx < RegKeyInfo.SubKeyCount );
+ idx++ ) {
+ NameLen = RegKeyInfo.MaxSubKeyLen + sizeof( TCHAR );
+ result = RegEnumKeyEx( hkSourceTree,
+ idx,
+ RegKeyInfo.pSubKeyName,
+ &NameLen,
+ NULL,
+ NULL,
+ NULL,
+ &SourceFileTime );
+
+ if ( ( result != ERROR_SUCCESS ) && ( result != ERROR_MORE_DATA ) )
+ goto cleanup;
+
+ // TBD: open the subkey in the source tree AS CurrentSourceKey
+ result = RegOpenKeyEx(hkSourceTree,
+ RegKeyInfo.pSubKeyName,
+ 0,
+ KEY_READ,
+ &hkCurrentSourceKey);
+
+
+ result = RegOpenKeyEx(hkDestTree,
+ RegKeyInfo.pSubKeyName,
+ 0,
+ KEY_READ,
+ &hkCurrentDestKey);
+
+ // if current dest key does not exist,
+ if ( result == ERROR_FILE_NOT_FOUND )
+ {
+ //
+ // recurse passing the subkey name
+ //
+ CloneRegistryTree( hkCurrentSourceKey,
+ hkDestTree,
+ RegKeyInfo.pSubKeyName );
+ }
+ // if current dest key is older than current source key, delete dest
+ // then recreate new
+ else
+ {
+ RegQueryInfoKey( hkCurrentDestKey,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &DestFileTime );
+
+
+ cmp = CompareFileTime( &SourceFileTime, &DestFileTime );
+ if ( cmp > 0 )
+ {
+ // delete dest
+ //
+ DeleteRegistrySubtree( hkCurrentDestKey );
+
+ //
+ // recurse passing the subkey name
+ //
+ CloneRegistryTree( hkCurrentSourceKey,
+ hkDestTree,
+ RegKeyInfo.pSubKeyName );
+ }
+ }
+
+ //
+ // close our open key
+ //
+
+ RegCloseKey( hkCurrentSourceKey );
+
+ result = ERROR_SUCCESS;
+ }
+
+cleanup:
+ CleanupAfterEnumRegistryTree( hkSourceTree, &RegKeyInfo );
+
+ return TRUE;
+}
+
+
+
+
+//*************************************************************
+//
+// MergeUserClasses()
+//
+// Purpose: Merges the user's class information with the
+// common class information.
+//
+// Parameters: UserClassStore - Per-user class information
+// CommonClassStore - Machine-wide class information
+// MergedClassStore - Destination for merged information.
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments: UserClassStore may be a null HKEY, implying
+// just copy the information from the common
+// portion into the merged portion
+//
+// History: Date Author Comment
+// 1/14/96 GregJen Created
+//
+//*************************************************************
+BOOL
+MergeRegistrySubtree (
+ HKEY hkSourceParent,
+ HKEY hkDestParent,
+ LPTSTR pszSubtree )
+{
+ HKEY hkCurrentSourceKey;
+ HKEY hkCurrentDestKey;
+ LONG result;
+ DWORD dummy = 0;
+
+ // open the special subtree in the source tree
+ result = RegOpenKeyEx( hkSourceParent,
+ pszSubtree,
+ 0,
+ KEY_READ,
+ &hkCurrentSourceKey );
+
+ // TBD: if no subtree in source, skip ahead to next special subtree
+ if ( result == ERROR_FILE_NOT_FOUND )
+ return TRUE;
+
+ result = RegOpenKeyEx( hkDestParent,
+ pszSubtree,
+ 0,
+ KEY_ALL_ACCESS,
+ &hkCurrentDestKey );
+ // TBD: if no such subtree in dest, do CloneRegistry etc
+ if ( result == ERROR_FILE_NOT_FOUND )
+ {
+ //
+ // recurse passing the subkey name
+ //
+ CloneRegistryTree( hkCurrentSourceKey,
+ hkDestParent,
+ pszSubtree );
+ }
+ // TBD:if timestamp on source is newer than timestamp on dest,
+ // delete dest and recreate??
+
+ MergeRegistrySubKeys( hkCurrentSourceKey,
+ hkCurrentDestKey );
+
+ // make sure the timestamp on the special trees is updated
+ result = RegSetValueEx( hkCurrentDestKey,
+ TEXT("Updated"),
+ 0,
+ REG_DWORD,
+ (BYTE*) &dummy,
+ sizeof( DWORD ) );
+
+
+ // close special subtrees
+ RegCloseKey( hkCurrentSourceKey );
+ RegCloseKey( hkCurrentDestKey );
+
+ return TRUE;
+}
+
+long
+CompareRegistryTimes(
+ HKEY hkLHS,
+ HKEY hkRHS )
+{
+ FILETIME LHSTime;
+ FILETIME RHSTime;
+
+ RegQueryInfoKey( hkLHS,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &LHSTime );
+
+ RegQueryInfoKey( hkRHS,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &RHSTime );
+
+ return CompareFileTime( &LHSTime, &RHSTime );
+}
+
+//*************************************************************
+//
+// MergeUserClasses()
+//
+// Purpose: Merges the user's class information with the
+// common class information.
+//
+// Parameters: UserClassStore - Per-user class information
+// CommonClassStore - Machine-wide class information
+// MergedClassStore - Destination for merged information.
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments: UserClassStore may be a null HKEY, implying
+// just copy the information from the common
+// portion into the merged portion
+//
+// History: Date Author Comment
+// 1/14/96 GregJen Created
+//
+//*************************************************************
+BOOL
+MergeUserClasses(
+ HKEY UserClassStore,
+ HKEY CommonClassStore,
+ HKEY MergedClassStore,
+ BOOL ForceNew )
+{
+ BOOL fNotCorrectUser = FALSE;
+ HKEY hkOverridingSubtree = CommonClassStore;
+ HKEY hkMergingSubtree = UserClassStore;
+ int idx;
+
+ //TBD: check time stamps on source and destination
+ // if same user, and timestamps are in sync, do nothing
+
+ // if destination does not belong to the current user, then
+ // delete everything under it
+
+ if ( fNotCorrectUser ) {
+ DeleteRegistrySubtree( MergedClassStore );
+ }
+
+
+ if ( !ForceNew &&
+ ( CompareRegistryTimes( MergedClassStore, CommonClassStore ) > 0 ) &&
+ ( CompareRegistryTimes( MergedClassStore, UserClassStore ) > 0 ) )
+ {
+ return TRUE;
+ }
+
+ // TBD: copy everything from the overriding store into the
+ // destination store
+ // At this moment, the common store overrides the user store;
+ // this will eventually reverse.
+
+ CloneRegistryTree( hkOverridingSubtree, MergedClassStore, NULL );
+
+ // now, for each of the special top-level keys, process the level below them
+ // these keys are: CLSID, Interface, TypeLib, Licenses, FileType
+
+ for ( idx = 0; idx < MAX_SPECIAL_SUBTREE; idx++ )
+ {
+ MergeRegistrySubtree( hkMergingSubtree,
+ MergedClassStore,
+ SpecialSubtrees[idx] );
+ }
+
+ // now do all the top level keys (file extensions and progids)
+ // TBD: MergeRegistrySubtree( UserClassStore, MergedClassStore );
+ MergeRegistrySubtree( hkMergingSubtree,
+ MergedClassStore,
+ NULL );
+
+return TRUE;
+}
+// dummy testing code
+void TestMergeHives( )
+{
+ // for testing
+ HKEY hkUser;
+ HKEY hkMachine;
+ HKEY hkMerged;
+ LONG result;
+ DWORD dwCreated;
+
+ result =
+ RegOpenKeyEx(HKEY_CLASSES_ROOT,
+ TEXT(".111111\\PerUser"),
+ 0,
+ KEY_READ,
+ &hkUser);
+ result =
+ RegOpenKeyEx(HKEY_CLASSES_ROOT,
+ TEXT(".111111\\MachineClasses"),
+ 0,
+ KEY_READ,
+ &hkMachine);
+ // note: eventually, this would be created with the
+ // same security as the per-user part.
+
+ // if the per-user part is missing, just copy the machine to per-user
+ //
+ result =
+ RegCreateKeyEx(HKEY_CLASSES_ROOT,
+ TEXT(".111111\\MergedClasses"),
+ 0,
+ NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS,
+ NULL,
+ &hkMerged,
+ &dwCreated);
+ MergeUserClasses(hkUser, hkMachine, hkMerged, TRUE);
+}
+
+
diff --git a/private/ole32/olecnfg/uenv.h b/private/ole32/olecnfg/uenv.h
new file mode 100644
index 000000000..f950563ca
--- /dev/null
+++ b/private/ole32/olecnfg/uenv.h
@@ -0,0 +1,26 @@
+//*************************************************************
+//
+// Personal Classes Profile management routines
+//
+// Microsoft Confidential
+// Copyright (c) Microsoft Corporation 1995
+// All rights reserved
+//
+//*************************************************************
+
+#define UNICODE 1
+
+#include "nt.h"
+#include "ntrtl.h"
+#include "nturtl.h"
+#include "windows.h"
+#include "userenv.h"
+
+LPTSTR GetSidString(HANDLE UserToken);
+VOID DeleteSidString(LPTSTR SidString);
+PSID GetUserSid (HANDLE UserToken);
+VOID DeleteUserSid(PSID Sid);
+
+
+
+