windows-nt/Source/XPSP1/NT/ds/security/gina/refgp/refgp.cxx
2020-09-26 16:20:57 +08:00

679 lines
17 KiB
C++

////////////////////////////////////////////////////////////////
//
// 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;
}