//////////////////////////////////////////////////////////////// // // Refgp.cxx // // Refresh Group Policy exe // // //////////////////////////////////////////////////////////////// #include "refgp.h" #define USER_POLICY_APPLIED_EVENT TEXT("userenv: User Group Policy has been applied") #define MACHINE_POLICY_APPLIED_EVENT TEXT("Global\\userenv: Machine Group Policy has been applied") #define USER_POLICY_DONE_EVENT TEXT("userenv: User Group Policy Processing is done") #define MACHINE_POLICY_DONE_EVENT TEXT("Global\\userenv: Machine Group Policy Processing is done") #define USER_POLICY_REFRESH_NEEDFG_EVENT TEXT("userenv: User Group Policy ForcedRefresh Needs Foreground Processing") #define MACHINE_POLICY_REFRESH_NEEDFG_EVENT TEXT("Global\\userenv: Machine Group Policy ForcedRefresh Needs Foreground Processing") #define REFRESH_MACHINE 1 #define REFRESH_USER 2 HINSTANCE hInst; typedef enum _FAILSTATES { NO_FAILURE, REFRESH_FAILED, POLWAIT_FAILED, POLWAIT_TIMEDOUT } FAILSTATES; typedef struct _REFSTRUCT { BOOL bMachine; DWORD dwOption; DWORD dwTimeOut; DWORD dwError; FAILSTATES fState; BOOL bFGNeeded; } REFSTRUCT, *LPREFSTRUCT; REFSTRUCT refMach; REFSTRUCT refUser; WCHAR szUser[200]; WCHAR szMach[200]; WCHAR szErr[MAX_PATH*2]; // Process arg. checks whether argument is present BOOL ProcessArg(int *pargc, LPWSTR **pargv, DWORD dwStringId, BOOL *bValue) { WCHAR szStr[200]; LPWSTR *argv = *pargv; if (*pargc == 0) return TRUE; if (!LoadString (hInst, dwStringId, szStr, 200)) { return FALSE; } for (; (*argv); *argv++) { if (_wcsicmp(*argv, szStr) == 0) { *bValue = TRUE; (*pargc)--; return TRUE; } } return TRUE; } // Process arg. checks whether argument is present and what the value is after the ":" in string format BOOL ProcessArg(int *pargc, WCHAR ***pargv, DWORD dwStringId, WCHAR **szValue) { WCHAR szStr[200]; LPWSTR *argv = *pargv, szJunk=NULL; if (*pargc == 0) return TRUE; if (!LoadString (hInst, dwStringId, szStr, 200)) { return FALSE; } for (; (*argv); *argv++) { if (_wcsnicmp(*argv, szStr, lstrlen(szStr)) == 0) { *szValue = (*argv)+lstrlen(szStr); (*pargc)--; return TRUE; } } *szValue = NULL; return TRUE; } // Process arg. checks whether argument is present and what the value is after the ":" in long format BOOL ProcessArg(int *pargc, WCHAR ***pargv, DWORD dwStringId, long *plValue) { WCHAR szStr[200]; LPWSTR *argv = *pargv, szJunk=NULL; if (*pargc == 0) return TRUE; if (!LoadString (hInst, dwStringId, szStr, 200)) { return FALSE; } for (; (*argv); *argv++) { if (_wcsnicmp(*argv, szStr, lstrlen(szStr)) == 0) { *plValue = wcstol((*argv)+lstrlen(szStr), &szJunk, 10); (*pargc)--; return TRUE; } } return TRUE; } BOOL CompareOptions(WCHAR *szValue, DWORD dwOptionId) { WCHAR szStr[200]; if (!szValue) return FALSE; if (!LoadString (hInst, dwOptionId, szStr, 200)) { return FALSE; } if (_wcsicmp(szValue, szStr) == 0) return TRUE; return FALSE; } BOOL GetValue(WCHAR *szValue, DWORD dwOptionId) { if (!LoadString (hInst, dwOptionId, szValue, 200)) { return FALSE; } return TRUE; } void PrintMsg(DWORD dwMsgId, ...) { WCHAR szFmt[200]; WCHAR szMsg[200]; va_list marker; if (!LoadString (hInst, dwMsgId, szFmt, 200)) { return; } va_start(marker, dwMsgId); wvnsprintf(szMsg, 200, szFmt, marker); va_end(marker); wprintf(szMsg); return; } void PrintUsage() { for (DWORD dwMsgId = IDS_USAGE_FIRST; dwMsgId <= IDS_USAGE_LAST; dwMsgId++) { PrintMsg(dwMsgId); } return; } BOOL PromptUserForFG(BOOL bMachine) { WCHAR tTemp, tChar; WCHAR Yes[20], No[20]; if (!LoadString (hInst, IDS_YES, Yes, 20)) { return FALSE; // safe } if (!LoadString (hInst, IDS_NO, No, 20)) { return FALSE; // safe } for (;;) { if (bMachine) PrintMsg(IDS_PROMPT_REBOOT); else PrintMsg(IDS_PROMPT_LOGOFF); tChar = getwchar(); tTemp = tChar; while (tTemp != TEXT('\n')) { tTemp = getwchar(); } if (towupper(tChar) == towupper(Yes[0])) return TRUE; if (towupper(tChar) == towupper(No[0])) return FALSE; } return FALSE; } //*************************************************************************** // // GetErrString // // Purpose: Calls FormatMessage to Get the error string corresp. to a error // code // // // Parameters: dwErr - Error Code // szErr - Buffer to return the error string (MAX_PATH) // is assumed.!!! // // Return: szErr // //*************************************************************************** LPTSTR GetErrString(DWORD dwErr, LPTSTR szErr) { szErr[0] = TEXT('\0'); FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK, NULL, dwErr, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), szErr, MAX_PATH, NULL); return szErr; } void RefreshPolicyAndWait(LPREFSTRUCT lpRef) { HANDLE hNotifyEvent=NULL, hFGProcessingEvent=NULL; DWORD dwRet=0; lpRef->fState = REFRESH_FAILED; lpRef->dwError = E_FAIL; lpRef->bFGNeeded = FALSE; if (!RefreshPolicyEx(lpRef->bMachine, lpRef->dwOption)) { lpRef->fState = REFRESH_FAILED; lpRef->dwError = GetLastError(); goto Exit; } if (lpRef->dwTimeOut != 0) { lpRef->fState = POLWAIT_FAILED; lpRef->dwError = E_FAIL; hNotifyEvent = OpenEvent(SYNCHRONIZE, FALSE, lpRef->bMachine ? MACHINE_POLICY_DONE_EVENT : USER_POLICY_DONE_EVENT ); if (!hNotifyEvent) { lpRef->fState = POLWAIT_FAILED; lpRef->dwError = GetLastError(); goto Exit; } hFGProcessingEvent = OpenEvent(SYNCHRONIZE, FALSE, lpRef->bMachine ? MACHINE_POLICY_REFRESH_NEEDFG_EVENT : USER_POLICY_REFRESH_NEEDFG_EVENT); if (!hNotifyEvent) { lpRef->fState = POLWAIT_FAILED; lpRef->dwError = GetLastError(); goto Exit; } dwRet = WaitForSingleObject(hNotifyEvent, (lpRef->dwTimeOut == INFINITE) ? INFINITE : 1000*(lpRef->dwTimeOut)); if (dwRet == WAIT_FAILED) { lpRef->fState = POLWAIT_FAILED; lpRef->dwError = GetLastError(); goto Exit; } else if (dwRet == WAIT_ABANDONED) { lpRef->fState = POLWAIT_FAILED; lpRef->dwError = E_UNEXPECTED; goto Exit; } else if (dwRet == WAIT_TIMEOUT) { lpRef->fState = POLWAIT_TIMEDOUT; lpRef->dwError = 0; goto Exit; } lpRef->bFGNeeded = (lpRef->dwOption == RP_FORCE) && (WaitForSingleObject(hFGProcessingEvent, 0) == WAIT_OBJECT_0); } lpRef->fState = NO_FAILURE; Exit: if (hNotifyEvent) CloseHandle(hNotifyEvent); if (hFGProcessingEvent) CloseHandle(hFGProcessingEvent); return; } void PrintRefreshError(LPREFSTRUCT lpRef) { LPWSTR szTarget = (lpRef->bMachine) ? szMach: szUser; switch (lpRef->fState) { case REFRESH_FAILED: PrintMsg(IDS_REFRESH_FAILED, szTarget, GetErrString(lpRef->dwError, szErr)); break; case POLWAIT_FAILED: PrintMsg(IDS_POLWAIT_FAILED, szTarget, GetErrString(lpRef->dwError, szErr)); break; case POLWAIT_TIMEDOUT: PrintMsg(IDS_POLWAIT_TIMEDOUT, szTarget); case NO_FAILURE: if (lpRef->dwTimeOut == 0) PrintMsg(IDS_REFRESH_BACKGND_TRIGGERED, szTarget); else PrintMsg(IDS_REFRESH_BACKGND_SUCCESS, szTarget); break; default: break; } } void __cdecl main (int argc, char **argv) { DWORD uTarget=0; BOOL bArgValid = TRUE; LONG lTime = 600; DWORD dwTime = 600, dwRet = 0, dwOption = 0, dwThread = 0; HANDLE hNotifyEvent=NULL, hFGProcessingEvent=NULL, hToken = NULL; BOOL bNeedFG = FALSE; LPWSTR lpCommandLine=0, szTarget=0; int wargc=0; LPWSTR *wargv=NULL, *wargv1=NULL; BOOL bForce=FALSE, bOkToLogoff=FALSE, bOkToBoot=FALSE, bNextFgSync = FALSE; BOOL bNeedBoot = FALSE, bNeedLogoff = FALSE; BOOL bError = FALSE; HANDLE hThreads[2] = {0, 0}; setlocale( LC_ALL, ".OCP" ); SetThreadUILanguage(0); lpCommandLine = GetCommandLine(); wargv1 = CommandLineToArgvW(lpCommandLine, &wargc); wargv = (LPWSTR *)LocalAlloc(LPTR, (1+wargc)*sizeof(LPWSTR)); if (!wargv) { PrintMsg(IDS_OUT_OF_MEMORY); goto Exit; } memcpy(wargv, wargv1, wargc*sizeof(LPWSTR)); hInst = GetModuleHandle(wargv[0]); if ((!GetValue(szUser, IDS_USER)) || (!GetValue(szMach, IDS_MACHINE))) { // we cannot read the resource strings. no point continuing return; } // // Ignore the first argument // wargc--; wargv++; // // Get the args // bArgValid = bArgValid && ProcessArg(&wargc, &wargv, IDS_TARGET, &szTarget); bArgValid = bArgValid && ProcessArg(&wargc, &wargv, IDS_TIME, &lTime); bArgValid = bArgValid && ProcessArg(&wargc, &wargv, IDS_FORCE, &bForce); bArgValid = bArgValid && ProcessArg(&wargc, &wargv, IDS_LOGOFF, &bOkToLogoff); bArgValid = bArgValid && ProcessArg(&wargc, &wargv, IDS_BOOT, &bOkToBoot); bArgValid = bArgValid && ProcessArg(&wargc, &wargv, IDS_SYNC, &bNextFgSync); bArgValid = bArgValid && (wargc == 0); // // Get the target correctly // uTarget = 0; if (bArgValid ) { if (!szTarget) { uTarget |= REFRESH_MACHINE; uTarget |= REFRESH_USER; } else if ( CompareOptions(szTarget, IDS_MACHINE) ) uTarget |= REFRESH_MACHINE; else if ( CompareOptions(szTarget, IDS_USER) ) uTarget |= REFRESH_USER; else { bArgValid = FALSE; } } // // Get the options correctly // if (bArgValid) { if ( bForce ) dwOption = RP_FORCE; else dwOption = 0; } if (lTime == -1) dwTime = INFINITE; else dwTime = lTime; if (!bArgValid) { PrintUsage(); goto Exit; } if (bOkToBoot) bOkToLogoff = TRUE; if (bNextFgSync) { if (uTarget & REFRESH_MACHINE) { dwRet = ForceSyncFgPolicy( 0 ); if (dwRet != ERROR_SUCCESS) { PrintMsg(IDS_SET_MODE_FAILED, GetErrString(dwRet, szErr)); goto Exit; } } if (uTarget & REFRESH_USER) { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { PrintMsg(IDS_SET_MODE_FAILED, GetErrString(GetLastError(), szErr)); goto Exit; } LPWSTR szSid = GetSidString( hToken ); if (!szSid) { PrintMsg(IDS_SET_MODE_FAILED, GetErrString(GetLastError(), szErr)); goto Exit; } dwRet = ForceSyncFgPolicy( szSid ); if (dwRet != ERROR_SUCCESS) { LocalFree (szSid); PrintMsg(IDS_SET_MODE_FAILED, GetErrString(dwRet, szErr)); goto Exit; } LocalFree (szSid); CloseHandle (hToken); hToken = 0; } } else { if (uTarget & REFRESH_MACHINE) { refMach.bMachine = TRUE; refMach.dwOption = dwOption; refMach.dwTimeOut = dwTime; if ((hThreads[dwThread] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RefreshPolicyAndWait, &refMach, 0, 0)) == NULL) { PrintMsg(IDS_REFRESH_POLICY_FAILED, GetErrString(GetLastError(), szErr)); goto Exit; } dwThread++; } if (uTarget & REFRESH_USER) { refUser.bMachine = FALSE; refUser.dwOption = dwOption; refUser.dwTimeOut = dwTime; if ((hThreads[dwThread] = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)RefreshPolicyAndWait, &refUser, 0, 0)) == NULL) { PrintMsg(IDS_REFRESH_POLICY_FAILED, GetErrString(GetLastError(), szErr)); goto Exit; } dwThread++; } PrintMsg(IDS_REFRESH_LAUNCHED); dwRet = WaitForMultipleObjects(dwThread, hThreads, TRUE, INFINITE); if ((dwRet != WAIT_OBJECT_0) && (dwRet != (WAIT_OBJECT_0 + 1))) { // our threads didn't terminate properly.. PrintMsg(IDS_REFRESH_POLICY_FAILED, GetErrString(GetLastError(), szErr)); goto Exit; } if (uTarget & REFRESH_USER) { PrintRefreshError(&refUser); if (refUser.fState != NO_FAILURE) bError = TRUE; } if (uTarget & REFRESH_MACHINE) { PrintRefreshError(&refMach); if (refMach.fState != NO_FAILURE) bError = TRUE; } if (bError) { goto Exit; } } PrintMsg(IDS_SPACE); if ((uTarget & REFRESH_USER) && (bNextFgSync || refUser.bFGNeeded)) { if ( bNextFgSync ) PrintMsg(IDS_NEED_LOGOFF_SYNC); else PrintMsg(IDS_NEED_LOGOFF); bNeedLogoff = TRUE; } if ((uTarget & REFRESH_MACHINE) && (bNextFgSync || refMach.bFGNeeded)) { if ( bNextFgSync ) PrintMsg(IDS_NEED_REBOOT_SYNC); else PrintMsg(IDS_NEED_REBOOT); bNeedBoot = TRUE; } if ( !bNeedBoot && !bNeedLogoff) { goto Exit; } PrintMsg(IDS_SPACE); if (bNeedBoot && !bOkToBoot) { bOkToBoot = PromptUserForFG(TRUE); } if (bNeedBoot && bOkToBoot) { if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken)) { PrintMsg(IDS_COULDNT_REBOOT, GetErrString(GetLastError(), szErr)); goto Exit; } BYTE bytesTokenPrivNew[sizeof(DWORD)+sizeof(LUID_AND_ATTRIBUTES)]; PTOKEN_PRIVILEGES pTokenPrivNew = (PTOKEN_PRIVILEGES)bytesTokenPrivNew; BYTE bytesTokenPrivOld[sizeof(DWORD)+sizeof(LUID_AND_ATTRIBUTES)]; PTOKEN_PRIVILEGES pTokenPrivOld = (PTOKEN_PRIVILEGES)bytesTokenPrivOld; DWORD dwSize=sizeof(DWORD)+sizeof(LUID_AND_ATTRIBUTES); DWORD dwRetSize=0; pTokenPrivNew->PrivilegeCount = 1; pTokenPrivNew->Privileges->Attributes = SE_PRIVILEGE_ENABLED; if (!LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &(pTokenPrivNew->Privileges->Luid))) { PrintMsg(IDS_COULDNT_REBOOT, GetErrString(GetLastError(), szErr)); goto Exit; } if (!AdjustTokenPrivileges(hToken, FALSE, pTokenPrivNew, dwSize, pTokenPrivOld, &dwRetSize)) { PrintMsg(IDS_COULDNT_REBOOT, GetErrString(GetLastError(), szErr)); goto Exit; } PrintMsg(IDS_NOTIFY_MACHINE_FG); if (!ExitWindowsEx(EWX_REBOOT, 0)) { PrintMsg(IDS_COULDNT_REBOOT, GetErrString(GetLastError(), szErr)); } else { PrintMsg(IDS_REBOOTING); } if (!AdjustTokenPrivileges(hToken, FALSE, pTokenPrivOld, 0, NULL, 0)) { PrintMsg(IDS_COULDNT_REBOOT, GetErrString(GetLastError(), szErr)); goto Exit; } // if we are rebooting no need to call logoff code goto Exit; } if (bNeedLogoff && !bOkToLogoff) { bOkToLogoff = PromptUserForFG(FALSE); } if (bNeedLogoff && bOkToLogoff) { PrintMsg(IDS_NOTIFY_USER_FG); if (!ExitWindowsEx(EWX_LOGOFF, 0)) { PrintMsg(IDS_COULDNT_LOGOFF, GetErrString(GetLastError(), szErr)); } else { PrintMsg(IDS_LOGGING_OFF); } } Exit: if (hToken) CloseHandle(hToken); for (;dwThread;dwThread--) if (hThreads[dwThread-1]) { CloseHandle(hThreads[dwThread-1]); } if (wargv1) GlobalFree(wargv1); if (wargv) LocalFree(wargv); return; }