/****************************************************************************** * * CPROFILE.C * * Text based utility to clean user profiles. This utility will remove user * file associations if they are disabled for the system and re-write * the user profile truncating unused space. * * Copyright Citrix Systems Inc. 1995 * Copyright (c) 1998-1999 Microsoft Corporation * * Author: Brad Anderson 01/20/97 * * $Log: U:\NT\PRIVATE\UTILS\citrix\cprofile\VCS\cprofile.c $ * * Rev 1.7 May 04 1998 18:06:14 bills * Fixes for MS bug #2109, OEM->ANSI conversion and moving strings to the rc file. * * Rev 1.6 Feb 09 1998 19:37:00 yufengz * change user profile from directory to file * * Rev 1.5 09 Oct 1997 19:04:14 scottn * Make help like MS. * * Rev 1.4 Jun 26 1997 18:18:32 billm * move to WF40 tree * * Rev 1.3 23 Jun 1997 16:13:18 butchd * update * * Rev 1.2 19 Feb 1997 15:55:32 BradA * Allow only administrators to run CPROFILE * * Rev 1.1 28 Jan 1997 20:06:28 BradA * Fixed up some problems related to WF 2.0 changes * * Rev 1.0 27 Jan 1997 20:37:46 BradA * Initial Versions * * Rev 1.0 27 Jan 1997 20:02:46 BradA * Initial Version * * Rev 1.0 Jan 27 1997 19:51:12 KenB * Initial version * * *******************************************************************************/ #include "precomp.h" #pragma hdrstop #include #include #include #include #include #include #include #include #include #include #include "cprofile.h" #include #define REG_PROFILELIST \ L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList" #define USER_PROFILE L"NTUSER.DAT" FILELIST Files; int LocalProfiles_flag = FALSE; int Verbose_flag = FALSE; int Query_flag; int Help_flag = FALSE; TOKMAP ptm[] = { {L"/L", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &LocalProfiles_flag}, {L"/V", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &Verbose_flag}, {L"/I", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &Query_flag}, {L"/?", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &Help_flag}, {L"/H", TMFLAG_OPTIONAL, TMFORM_BOOLEAN, sizeof(USHORT), &Help_flag}, {L" ", TMFLAG_OPTIONAL, TMFORM_FILES, sizeof(Files), &Files}, {0, 0, 0, 0, 0} }; #define INPUT_CONT 0 #define INPUT_SKIP 1 #define INPUT_QUIT 2 int QueryUserInput(); int ProcessFile( PWCHAR pFile ); void Usage( BOOL ErrorOccured ); /******************************************************************************* * * main * ******************************************************************************/ int __cdecl main(INT argc, CHAR **argv) { WCHAR *CmdLine; WCHAR **argvW; ULONG rc; int i; BOOL Result; HANDLE hWin; int CurFile; int Abort_flag; setlocale(LC_ALL, ".OCP"); /* * Massage the command line. */ argvW = MassageCommandLine((DWORD)argc); if (argvW == NULL) { ErrorPrintf(IDS_ERROR_MALLOC); return(FAILURE); } /* * parse the cmd line without parsing the program name (argc-1, argv+1) */ rc = ParseCommandLine(argc-1, argvW+1, ptm, 0); /* * Check for error from ParseCommandLine */ if ( Help_flag || (rc & ~PARSE_FLAG_NO_PARMS) || (!LocalProfiles_flag && (Files.argc == 0)) ) { if ( !Help_flag ) { Usage(TRUE); return(FAILURE); } else { Usage(FALSE); return(SUCCESS); } } if (!TestUserForAdmin(FALSE)) { ErrorPrintf(IDS_ERROR_NOT_ADMIN); return(FAILURE); } InitializeGlobalSids(); /* * Verify if the user has the privilege to save the profile i.e. * SeBackupPrivilege */ if (!EnablePrivilege(SE_BACKUP_PRIVILEGE, TRUE) || !EnablePrivilege(SE_RESTORE_PRIVILEGE, TRUE)) { ErrorPrintf(IDS_ERROR_PRIVILEGE_NOT_AVAILABLE); return(FAILURE); } CurFile = 0; Abort_flag = FALSE; while ( !Abort_flag && Files.argc && (CurFile < Files.argc) ) { if ( ProcessFile(Files.argv[CurFile]) ) { Abort_flag = TRUE; break; } CurFile++; } if ( !Abort_flag && LocalProfiles_flag ) { // Enumerate local profiles LONG Status; HKEY hkeyProfileList; DWORD indx = 0; WCHAR wSubKeyName[MAX_PATH+sizeof(WCHAR)]; DWORD Size; Status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REG_PROFILELIST, 0, KEY_READ, &hkeyProfileList); if ( Status != ERROR_SUCCESS ) { ErrorPrintf(IDS_ERROR_MISSING_PROFILE_LIST); Abort_flag = TRUE; hkeyProfileList = 0; } while ( !Abort_flag && (Status == ERROR_SUCCESS) ) { LONG Status2; Size = sizeof(wSubKeyName)/sizeof( WCHAR ); Status = RegEnumKeyEx(hkeyProfileList, indx++, wSubKeyName, &Size, 0, NULL, NULL, NULL ); if ( Status == ERROR_SUCCESS ) { HKEY hkeyProfile; Status2 = RegOpenKeyEx(hkeyProfileList, wSubKeyName, 0, KEY_READ, &hkeyProfile); if ( Status2 == ERROR_SUCCESS ) { DWORD type; WCHAR file[MAX_PATH], expandedFile[MAX_PATH]; DWORD filelen = sizeof(file); Status2 = RegQueryValueExW(hkeyProfile, L"ProfileImagePath", 0, &type, (PBYTE)file, &filelen ); if ( Status2 == ERROR_SUCCESS ) { if ( ExpandEnvironmentStrings(file, expandedFile, MAX_PATH) > 0) { // // Append the User Profile file "NTUSER.DAT" // to the end of the profile path. // Added by Yufeng Zheng // PWCHAR c; // // Find the trailing backslash '\' and // handle the appending according to the backslash. // if ((c = wcsrchr(expandedFile, L'\\')) == NULL) { wcscat(expandedFile, L"\\"); wcscat(expandedFile, USER_PROFILE); } else if (c[1] == L'\0') { wcscat(expandedFile, USER_PROFILE); } else { wcscat(expandedFile, L"\\"); wcscat(expandedFile, USER_PROFILE); } if ( ProcessFile(expandedFile) ) { Abort_flag = TRUE; } } } else { StringErrorPrintf(IDS_ERROR_MISSING_LPROFILE, wSubKeyName); } RegCloseKey(hkeyProfile); } else { StringErrorPrintf(IDS_ERROR_BAD_LPROFILE, wSubKeyName); } } } if ( hkeyProfileList ) { RegCloseKey(hkeyProfileList); } } return( Abort_flag ); } /**************************************************************************** * * ProcessFile( PWCHAR pFile ) * Read the specified profile, eliminate the Software\Classes registry * key if Classes are disabled, and resave the profile such that it * is truncated. * * Arguments: * pFile Filename to process * * Returns: * FALSE If completed successfully * TRUE If there was an error, and the program should terminate. * ****************************************************************************/ int ProcessFile( PWCHAR pFile ) { PSID pUserSid; WCHAR tempbuf[100]; int UserInput = INPUT_CONT; if ( Verbose_flag || Query_flag ) { StringMessage(IDS_MSG_PROCESSING, pFile ); } if ( Query_flag ) { UserInput = QueryUserInput(); } if ( UserInput == INPUT_CONT ) { if ( OpenUserProfile(pFile, &pUserSid) ) { ClearDisabledClasses(); if ( ! SaveUserProfile(pUserSid, pFile) ) { StringErrorPrintf(IDS_ERROR_SAVING_PROFILE, pFile); } ClearTempUserProfile(); } else { StringErrorPrintf(IDS_ERROR_OPENING_PROFILE, pFile); } } return ( UserInput == INPUT_QUIT ); } int QueryUserInput() { WCHAR c, firstc; int Valid_flag = FALSE; int rc = INPUT_CONT; static int FirstTime = TRUE; static WCHAR yes[10], no[10], quit[10]; if (FirstTime) { BOOLEAN error = FALSE; if ( !LoadString(NULL, IDS_UI_NO_CHAR, no, 2) ) { error = TRUE; } if ( !LoadString(NULL, IDS_UI_YES_CHAR, yes, 2) ) { error = TRUE; } if ( !LoadString(NULL, IDS_UI_QUIT_CHAR, quit, 2) ) { error = TRUE; } if ( error ) { ErrorPrintf(IDS_ERROR_MISSING_RESOURCES); return ( INPUT_QUIT ); } FirstTime = FALSE; } fflush(stdin); Message(IDS_MSG_MODIFY_PROMPT); do { firstc = L'\0'; while ( ((c = getwchar()) != L'\n') && (c != EOF) ) { if ( !firstc && !iswspace(c)) { firstc = c; } } if ( _wcsnicmp(yes, &firstc, 1) == 0 ) { Valid_flag = TRUE; } else if ( _wcsnicmp(quit, &firstc, 1) == 0 ) { Valid_flag = TRUE; rc = INPUT_QUIT; } else if ( (_wcsnicmp(no, &firstc, 1) == 0) || (firstc == '\0') ) { rc = INPUT_SKIP; Valid_flag = TRUE; } else { ErrorPrintf(IDS_ERROR_INVALID_USER_RESP); } } while ( ! Valid_flag ); return ( rc ); } void Usage ( BOOL ErrorOccurred ) { if ( ErrorOccurred ) { ErrorPrintf(IDS_ERROR_INVALID_PARAMETERS); ErrorPrintf(IDS_USAGE_CMDLINE); } else { Message(IDS_USAGE_DESCR1); Message(IDS_USAGE_CMDLINE); Message(IDS_USAGE_DESCR2); Message(IDS_USAGE_OPTION_LIST); Message(IDS_USAGE_LOPTION); Message(IDS_USAGE_IOPTION); Message(IDS_USAGE_VOPTION); Message(IDS_USAGE_HOPTION); } }