679 lines
17 KiB
C++
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;
|
|
}
|
|
|