|
|
/*++
Copyright (c) 1999 Microsoft Corporation
Module Name :
setup.c
Abstract :
Setup program for the AppSec tool. Setup the Registry keys and gives Read Permission for 'Everyone' to these keys. Also copies the AppSec.dll file to the %SystemRoot%\system32 directory
Revision history :
09.02.2000 - Adding support for command line arguments - taking a text file containing Authorized Applications and a integer for Enabling Appsec - SriramSa Returns :
TRUE if success FALSE if failed Author :
Sriram (t-srisam) July 1999
--*/
#include "pch.h"
#pragma hdrstop
#include "setup.h"
#include "aclapi.h"
#include <accctrl.h>
WCHAR g_szSystemRoot[MAX_PATH] ;
INT _cdecl main ( INT argc, CHAR *argv[] ) {
DWORD Disp, size, error_code ; HKEY AppCertKey, AppsKey ; WCHAR *AppSecDllPath = L"%SystemRoot%\\system32\\appsec.dll" ; WCHAR *OldFileName = L".\\appsec.dll" ; WCHAR NewFileName[MAX_PATH] ;
WCHAR HelpMessage[HELP_MSG_SIZE]; WCHAR szTitle[MAX_PATH]; WCHAR szMsg[MAX_PATH]; CHAR FileName[MAX_PATH] ; INT IsEnabled = 0; // by default AppSec is disabled initially
BOOL IsInitialFile = FALSE; // assume no initial file was provided
BOOL status, IsNoGUI = FALSE ;
// Process the command line arguments
if (argc > 1) { IsInitialFile = TRUE ; strcpy(FileName, argv[1]) ; if (argc > 2) { IsEnabled = atoi(argv[2]) ; } // Check if user does not want any GUI
if ((argc > 3) && (_stricmp(argv[3], "/N") == 0)) { IsNoGUI = TRUE ; } }
// Display Help Message if asked for
if (strcmp(FileName,"/?") == 0) { LoadString( NULL, IDS_HELP_MESSAGE ,HelpMessage, HELP_MSG_SIZE ); LoadString( NULL, IDS_HELP_TITLE ,szTitle, MAX_PATH ); MessageBox( NULL, HelpMessage, szTitle, MB_OK); return TRUE ; }
// Check the second argument
if ((IsEnabled != 0) && (IsEnabled != 1)) { LoadString( NULL, IDS_ARGUMENT_ERROR, szMsg, MAX_PATH ); LoadString( NULL, IDS_ERROR, szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); return TRUE ; }
// Display warning message regarding authorized apps already in the Registry
if (IsNoGUI == FALSE) { LoadString( NULL, IDS_WARNING, szMsg, MAX_PATH ); LoadString( NULL, IDS_WARNING_TITLE ,szTitle, MAX_PATH ); if ( MessageBox( NULL, szMsg, szTitle, MB_OKCANCEL) == IDCANCEL ) { return TRUE ; } }
// Create the AppCertDlls Key
if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, APPCERTDLLS_REG_NAME, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &AppCertKey, &Disp ) != ERROR_SUCCESS ) { LoadString( NULL, IDS_REG_ERROR ,szMsg, MAX_PATH ); LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); return FALSE ; }
// After creating the key, give READ access to EVERYONE
AddEveryoneToRegKey( APPCERTDLLS_REG_NAME ) ;
// Set the AppSecDll value to the path of the AppSec.dll
size = wcslen(AppSecDllPath) ;
RegSetValueEx( AppCertKey, APPSECDLL_VAL, 0, REG_EXPAND_SZ, (CONST BYTE *)AppSecDllPath, (size + 1) * sizeof(WCHAR) ) ;
// Create the AuthorizedApplications Key and give Read access to Evereone
if (RegCreateKeyEx( HKEY_LOCAL_MACHINE, AUTHORIZEDAPPS_REG_NAME, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &AppsKey, &Disp ) != ERROR_SUCCESS ) { LoadString( NULL, IDS_REG_ERROR ,szMsg, MAX_PATH ); LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); RegCloseKey(AppCertKey) ; return FALSE ; }
// After creating the key, give READ access to EVERYONE
AddEveryoneToRegKey( AUTHORIZEDAPPS_REG_NAME ) ;
RegCloseKey(AppCertKey) ; GetEnvironmentVariable( L"SystemRoot", g_szSystemRoot, MAX_PATH ) ;
// Load the initial set of authorized apps into the Registry
status = LoadInitApps( AppsKey, IsInitialFile, FileName) ; if (status == FALSE) { LoadString( NULL, IDS_APPS_WARNING, szMsg, MAX_PATH ); LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); }
// Set the fEnabled key now
RegSetValueEx( AppsKey, FENABLED_KEY, 0, REG_DWORD, (BYTE *) &IsEnabled, sizeof(DWORD) );
RegCloseKey(AppsKey) ;
// Copy the appsec.dll file to %SystemRoot%\system32 directory
swprintf(NewFileName, L"%s\\system32\\appsec.dll", g_szSystemRoot ) ;
if ( CopyFile( OldFileName, NewFileName, TRUE ) == 0 ) {
error_code = GetLastError() ;
// If AppSec.dll already exists in Target Directory, print appropriate Message
if (error_code == ERROR_FILE_EXISTS) { if (IsNoGUI == FALSE) { LoadString( NULL, IDS_FILE_ALREADY_EXISTS ,szMsg, MAX_PATH ); LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); } return FALSE ; }
// If AppSec.dll does not exist in the current directory, print appropriate Message
if (error_code == ERROR_FILE_NOT_FOUND) { LoadString( NULL, IDS_FILE_NOT_FOUND ,szMsg, MAX_PATH ); LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); return FALSE ;
}
LoadString( NULL, IDS_ERROR_TEXT ,szMsg, MAX_PATH ); LoadString( NULL, IDS_ERROR ,szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK);
return FALSE ; } // File was copied successfully - Installation was successful
if (IsNoGUI == FALSE) { LoadString( NULL, IDS_SUCCESS_TEXT ,szMsg, MAX_PATH ); LoadString( NULL, IDS_SUCCESS ,szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); }
return TRUE ;
}
/*++
The following two functions are used to change the permissions of the relevant Regsitry Keys, to give READ access to everyone, to take care of Guest users.
--*/
BOOL AddSidToObjectsSecurityDescriptor( HANDLE hObject, SE_OBJECT_TYPE ObjectType, PSID pSid, DWORD dwNewAccess, ACCESS_MODE AccessMode, DWORD dwInheritance ) { BOOL fReturn = FALSE; DWORD dwRet; EXPLICIT_ACCESS ExpAccess; PACL pOldDacl = NULL, pNewDacl = NULL; PSECURITY_DESCRIPTOR pSecDesc = NULL;
//
// pSid cannot be NULL.
//
if (pSid == NULL) { SetLastError(ERROR_INVALID_PARAMETER); return(FALSE); }
//
// Get the objects security descriptor and current DACL.
//
dwRet = GetSecurityInfo( hObject, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, &pOldDacl, NULL, &pSecDesc );
if (dwRet != ERROR_SUCCESS) { return(FALSE); }
//
// Initialize an EXPLICIT_ACCESS structure for the new ACE.
//
ZeroMemory(&ExpAccess, sizeof(EXPLICIT_ACCESS)); ExpAccess.grfAccessPermissions = dwNewAccess; ExpAccess.grfAccessMode = AccessMode; ExpAccess.grfInheritance = dwInheritance; ExpAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID; ExpAccess.Trustee.ptstrName = (PTSTR)pSid;
//
// Merge the new ACE into the existing DACL.
//
dwRet = SetEntriesInAcl( 1, &ExpAccess, pOldDacl, &pNewDacl );
if (dwRet != ERROR_SUCCESS) { goto ErrorCleanup; }
//
// Set the new security for the object.
//
dwRet = SetSecurityInfo( hObject, ObjectType, DACL_SECURITY_INFORMATION, NULL, NULL, pNewDacl, NULL );
if (dwRet != ERROR_SUCCESS) { goto ErrorCleanup; }
fReturn = TRUE;
ErrorCleanup: if (pNewDacl != NULL) { LocalFree(pNewDacl); }
if (pSecDesc != NULL) { LocalFree(pSecDesc); }
return(fReturn); }
VOID AddEveryoneToRegKey( WCHAR *RegPath ) { HKEY hKey; PSID pSid = NULL; SID_IDENTIFIER_AUTHORITY SepWorldAuthority = SECURITY_WORLD_SID_AUTHORITY; LONG status ;
status = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RegPath, 0, KEY_ALL_ACCESS, &hKey );
if (status != ERROR_SUCCESS) { return ; }
AllocateAndInitializeSid( &SepWorldAuthority, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSid );
AddSidToObjectsSecurityDescriptor( hKey, SE_REGISTRY_KEY, pSid, KEY_READ, GRANT_ACCESS, CONTAINER_INHERIT_ACE );
LocalFree(pSid); RegCloseKey(hKey); }
/*++
Routine Description : This function loads a initial set of authorized applications to the registry. Arguments : AppsecKey - Key to the registry entry where authorized applications are stored IsInitialFile - Was a initial file given as command line argument to load applications other than the default ones FileName - Name of the file given as command line argument Return Value : A BOOL indicating if the desired task succeeded or not.
--*/
BOOL LoadInitApps( HKEY AppsecKey, BOOL IsInitialFile, CHAR *FileName ) {
FILE *fp ; INT MaxInitApps ; WCHAR *BufferWritten ; INT BufferLength = 0 ; WCHAR AppsInFile[MAX_FILE_APPS][MAX_PATH] ; CHAR FileRead[MAX_PATH] ; INT size, count = 0, NumOfApps = 0 ; INT i, j, k ; BOOL IsFileExist = TRUE ; WCHAR InitApps[MAX_FILE_APPS][MAX_PATH]; WCHAR szMsg[MAX_PATH], szTitle[MAX_PATH]; WCHAR ResolvedAppName[MAX_PATH]; DWORD RetValue;
// Below is the list of default (necessary) applications
LPWSTR DefaultInitApps[] = { L"system32\\loadwc.exe", L"system32\\cmd.exe", L"system32\\subst.exe", L"system32\\xcopy.exe", L"system32\\net.exe", L"system32\\regini.exe", L"system32\\systray.exe", L"explorer.exe", L"system32\\attrib.exe", L"Application Compatibility Scripts\\ACRegL.exe", L"Application Compatibility Scripts\\ACsr.exe", L"system32\\ntsd.exe", L"system32\\userinit.exe", L"system32\\wfshell.exe", L"system32\\chgcdm.exe", L"system32\\nddeagnt.exe",
};
MaxInitApps = sizeof(DefaultInitApps)/sizeof(DefaultInitApps[0]) ; // Prefix the default apps with %SystemRoot%
for (i = 0; i < MaxInitApps; i++) { swprintf(InitApps[i], L"%ws\\%ws", g_szSystemRoot, DefaultInitApps[i]); }
// Calculate the size of buffer to allocate to hold initial apps
for (i = 0; i < MaxInitApps; i++) { BufferLength += wcslen(InitApps[i]) ; }
BufferLength += MaxInitApps ; // for the terminating NULLS
if (IsInitialFile == FALSE) { BufferLength += 1 ; //last terminating NULL in REG_MULTI_SZ
} else { // A initial file was given to us
fp = fopen(FileName, "r") ; if (fp == NULL) { // Display a Message Box saying Unable to open the file
// Just load the default apps and return
LoadString( NULL, IDS_APPFILE_NOT_FOUND ,szMsg, MAX_PATH ); LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); IsFileExist = FALSE ; } else { // build the array AppsInFile after UNICODE conversion
while( fgets( FileRead, MAX_PATH, fp) != NULL ) { FileRead[strlen(FileRead)- 1] = '\0' ; // Convert from Short to Long name
if ( GetLongPathNameA((LPCSTR)FileRead, FileRead, MAX_PATH) == 0 ) { // GetLongPathName returns error
// some problem with the app listed in the file
// Terminate further handling of apps in the file
LoadString( NULL, IDS_ERROR_LOAD, szMsg, MAX_PATH ); LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); break; } // Convert to UNICODE format
// Get the size of the buffer required first
size = MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, FileRead, -1, NULL, 0) ; if (size > MAX_PATH) { // Something is wrong in the list of apps in the File
// Terminate further handling of apps in the file
LoadString( NULL, IDS_ERROR_LOAD, szMsg, MAX_PATH ); LoadString( NULL, IDS_WARNING_TITLE, szTitle, MAX_PATH ); MessageBox( NULL, szMsg, szTitle, MB_OK); break; } else { MultiByteToWideChar( CP_ACP, MB_PRECOMPOSED, FileRead, -1, AppsInFile[count], MAX_PATH) ; count++ ; } } fclose(fp) ; NumOfApps = count ; // Now any of these apps may be in remote Server and Share - so resolve them into UNC names
// Copy the resolved names back into the same buffer
for(i = 0; i < NumOfApps; i++) { ResolveName((LPCWSTR)AppsInFile[i], ResolvedAppName) ; wcscpy(AppsInFile[i], ResolvedAppName); }
// Continue calculation of BufferLength
for (i = 0; i < NumOfApps; i++) { BufferLength += wcslen(AppsInFile[i]) ; } BufferLength += NumOfApps ; // for the Terminating NULLs in REG_MULTI_SZ
BufferLength += 1 ; // for the last NULL char in REG_MULTI_SZ
} } BufferWritten = (WCHAR *) malloc (BufferLength * sizeof(WCHAR)) ; if (BufferWritten == NULL) { return FALSE ; } memset(BufferWritten, 0, BufferLength * sizeof(WCHAR)) ;
// Build the LPWSTR BufferWritten with Initial Default Apps
j = 0 ; for (i = 0; i < MaxInitApps; i++) { for(k = 0 ; k < (int) wcslen(InitApps[i]); k++) { BufferWritten[j++] = InitApps[i][k]; } BufferWritten[j++] = L'\0' ; } if (IsInitialFile && IsFileExist ) { for (i = 0; i < NumOfApps; i++) { for(k = 0 ; k < (int) wcslen(AppsInFile[i]); k++) { BufferWritten[j++] = AppsInFile[i][k]; } BufferWritten[j++] = L'\0' ; } } BufferWritten[j] = L'\0' ; // Last NULL char in REG_MULTI_SZ
// Write this Buffer into the Registry Key
if ( RegSetValueEx( AppsecKey, AUTHORIZED_APPS_KEY, 0, REG_MULTI_SZ, (CONST BYTE *) BufferWritten, (j+1) * sizeof(WCHAR) ) != ERROR_SUCCESS ) { // Free all the buffers which were allocated
free(BufferWritten) ; return FALSE ; }
free(BufferWritten) ; return TRUE ;
}// end of function LoadInitApps
/*++
Routine Description :
This Routine checks if the application resides in a local drive or a remote network share. If it is a remote share, the UNC path of the application is returned. Arguments : appname - name of the application
Return Value :
The UNC path of the appname if it resides in a remote server share. The same appname if it resides in a local drive. --*/
VOID ResolveName( LPCWSTR appname, WCHAR *ResolvedName ) {
UINT i ; INT length ; WCHAR LocalName[3] ; WCHAR RootPathName[4] ; WCHAR RemoteName[MAX_PATH] ; DWORD size = MAX_PATH ; DWORD DriveType, error_status ; //
// ResolvedName will hold the name of the UNC path of the appname if it is in
// a remote server and share
memset(ResolvedName, 0, MAX_PATH * sizeof(WCHAR)) ; // check if appname is a app in local drive or remote server share
// Parse the first 3 chars in appname to get the root directory of the drive
// where it resides
wcsncpy(RootPathName, appname, 3 ) ; RootPathName[3] = L'\0'; // Find the type of the Drive where the app is
DriveType = GetDriveType(RootPathName) ;
if (DriveType == DRIVE_REMOTE) { // Use WNetGetConnection to get the name of the remote share
// Parse the first two chars of the appname to get the local drive
// which is mapped onto the remote server and share
wcsncpy(LocalName, appname, 2 ) ; LocalName[2] = L'\0' ;
error_status = WNetGetConnection ( LocalName, RemoteName, &size ) ;
if (error_status != NO_ERROR) { wcscpy(ResolvedName,appname) ; return ; }
//
// Prepare ResolvedName - it will contain the Remote Server and Share name
// followed by a \ and then the appname
//
wcscpy( ResolvedName, RemoteName ) ; length = wcslen(ResolvedName) ;
ResolvedName[length++] = L'\\' ; for (i = 3 ; i <= wcslen(appname) ; i++ ) { ResolvedName[length++] = appname[i] ; } ResolvedName[length] = L'\0' ; return ;
} else { // This application is in local drive and not in a remote server and share
// Just send the appname back to the calling function
wcscpy(ResolvedName,appname) ; return ; } }
|