You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
328 lines
8.6 KiB
328 lines
8.6 KiB
// Copyright (c) 1998-1999 Microsoft Corporation
|
|
/*************************************************************************
|
|
*
|
|
* LOGOFF.C
|
|
*
|
|
* This module is the LOGOFF utility code.
|
|
*
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
//#include <ntddkbd.h>
|
|
//#include <ntddmou.h>
|
|
#include <winstaw.h>
|
|
#include <stdlib.h>
|
|
#include <utilsub.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#include <locale.h>
|
|
#include <winnlsp.h>
|
|
|
|
#include "logoff.h"
|
|
#include "printfoa.h"
|
|
|
|
|
|
// max length of the locale string
|
|
#define MAX_LOCALE_STRING 64
|
|
|
|
|
|
WINSTATIONNAME WSName;
|
|
USHORT help_flag = FALSE;
|
|
USHORT v_flag = FALSE;
|
|
HANDLE hServerName = SERVERNAME_CURRENT;
|
|
WCHAR ServerName[MAX_IDS_LEN+1];
|
|
|
|
TOKMAP ptm[] =
|
|
{
|
|
#define TERM_PARM 0
|
|
{TOKEN_WS, TMFLAG_OPTIONAL, TMFORM_STRING,
|
|
WINSTATIONNAME_LENGTH, WSName},
|
|
|
|
{TOKEN_SERVER, TMFLAG_OPTIONAL, TMFORM_STRING,
|
|
MAX_IDS_LEN, ServerName},
|
|
|
|
{TOKEN_HELP, TMFLAG_OPTIONAL, TMFORM_BOOLEAN,
|
|
sizeof(USHORT), &help_flag},
|
|
|
|
{TOKEN_VERBOSE, TMFLAG_OPTIONAL, TMFORM_BOOLEAN,
|
|
sizeof(USHORT), &v_flag},
|
|
|
|
{0, 0, 0, 0, 0}
|
|
};
|
|
|
|
|
|
/*
|
|
* Local function prototypes.
|
|
*/
|
|
void Usage( BOOLEAN bError );
|
|
BOOL ProceedWithLogoff(HANDLE hServerName,ULONG LogonId,PWINSTATIONNAME pWSName);
|
|
|
|
|
|
/*************************************************************************
|
|
*
|
|
* main
|
|
* Main function and entry point of the LOGOFF
|
|
* utility.
|
|
*
|
|
* ENTRY:
|
|
* argc - count of the command line arguments.
|
|
* argv - vector of strings containing the command line arguments.
|
|
*
|
|
* EXIT
|
|
* Nothing.
|
|
*
|
|
*************************************************************************/
|
|
|
|
int __cdecl
|
|
main(INT argc, CHAR **argv)
|
|
{
|
|
BOOLEAN bCurrent = FALSE;
|
|
int rc, i;
|
|
WCHAR *CmdLine;
|
|
WCHAR **argvW, *endptr;
|
|
ULONG LogonId;
|
|
WCHAR wszString[MAX_LOCALE_STRING + 1];
|
|
|
|
setlocale(LC_ALL, ".OCP");
|
|
|
|
// We don't want LC_CTYPE set the same as the others or else we will see
|
|
// garbage output in the localized version, so we need to explicitly
|
|
// set it to correct console output code page
|
|
_snwprintf(wszString, sizeof(wszString)/sizeof(WCHAR), L".%d", GetConsoleOutputCP());
|
|
wszString[sizeof(wszString)/sizeof(WCHAR) - 1] = L'\0';
|
|
_wsetlocale(LC_CTYPE, wszString);
|
|
|
|
SetThreadUILanguage(0);
|
|
|
|
/*
|
|
* 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 && !(rc & PARSE_FLAG_NO_PARMS)) ) {
|
|
|
|
if ( !help_flag ) {
|
|
|
|
Usage(TRUE);
|
|
return(FAILURE);
|
|
|
|
} else {
|
|
|
|
Usage(FALSE);
|
|
return(SUCCESS);
|
|
}
|
|
}
|
|
|
|
// If no remote server was specified, then check if we are running under Terminal Server
|
|
if ((!IsTokenPresent(ptm, TOKEN_SERVER) ) && (!AreWeRunningTerminalServices()))
|
|
{
|
|
ErrorPrintf(IDS_ERROR_NOT_TS);
|
|
return(FAILURE);
|
|
}
|
|
|
|
/*
|
|
* Open the specified server
|
|
*/
|
|
if( ServerName[0] ) {
|
|
hServerName = WinStationOpenServer( ServerName );
|
|
if( hServerName == NULL ) {
|
|
StringErrorPrintf(IDS_ERROR_SERVER,ServerName);
|
|
PutStdErr( GetLastError(), 0 );
|
|
return(FAILURE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Validate input string for WinStation or LogonId.
|
|
*/
|
|
if ( !IsTokenPresent(ptm, TOKEN_WS) ) {
|
|
|
|
/*
|
|
* No string specified; use current WinStation / LogonId.
|
|
*/
|
|
bCurrent = TRUE;
|
|
LogonId = GetCurrentLogonId();
|
|
|
|
if( ServerName[0] ) {
|
|
ErrorPrintf(IDS_ERROR_NEED_A_SESSIONID);
|
|
return(FAILURE);
|
|
}
|
|
|
|
} else if ( !iswdigit(*WSName) ) {
|
|
|
|
/*
|
|
* Treat the string as a WinStation name.
|
|
*/
|
|
if ( !LogonIdFromWinStationName(hServerName, WSName, &LogonId) ) {
|
|
StringErrorPrintf(IDS_ERROR_WINSTATION_NOT_FOUND, WSName);
|
|
return(FAILURE);
|
|
}
|
|
|
|
} else {
|
|
|
|
/*
|
|
* Treat the string as a LogonId.
|
|
*/
|
|
LogonId = wcstoul(WSName, &endptr, 10);
|
|
|
|
if ( *endptr || LogonId == ( ULONG )-1 )
|
|
{
|
|
StringErrorPrintf(IDS_ERROR_INVALID_LOGONID, WSName);
|
|
return(FAILURE);
|
|
}
|
|
if ( !WinStationNameFromLogonId(hServerName, LogonId, WSName) ) {
|
|
ErrorPrintf(IDS_ERROR_LOGONID_NOT_FOUND, LogonId);
|
|
return(FAILURE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Perform the logoff.
|
|
*/
|
|
if ( bCurrent ) {
|
|
|
|
if ( !ExitWindowsEx(EWX_LOGOFF, (DWORD)-1) ) {
|
|
|
|
ErrorPrintf(IDS_ERROR_LOGOFF_CURRENT,
|
|
GetLastError());
|
|
PutStdErr( GetLastError(), 0 );
|
|
return(FAILURE);
|
|
}
|
|
|
|
} else{
|
|
|
|
if (!ProceedWithLogoff(hServerName,LogonId,WSName))
|
|
return (SUCCESS);
|
|
|
|
if ( v_flag )
|
|
Message(IDS_WINSTATION_LOGOFF, LogonId);
|
|
|
|
/*
|
|
* RESOLVED: we need to expose the session manager's "logoff winstation"
|
|
* API and call it here for the specified LogonId. Till then, we'll
|
|
* do a WinStationReset (nasty, but does the job).
|
|
*
|
|
* - Reset and logoff are synonymous
|
|
*/
|
|
|
|
if ( !WinStationReset(hServerName, LogonId, TRUE) ) {
|
|
|
|
ErrorPrintf(IDS_ERROR_LOGOFF, LogonId, GetLastError());
|
|
PutStdErr( GetLastError(), 0 );
|
|
return(FAILURE);
|
|
}
|
|
}
|
|
|
|
return(SUCCESS);
|
|
|
|
} /* main() */
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* Usage
|
|
*
|
|
* If LogonId does not have a corresponding UserName then a warning
|
|
* message is displayed.
|
|
*
|
|
* ENTRY:
|
|
* hServerName : Handle to server
|
|
* LogonId : ID as shown in qwinsta
|
|
* pWSName : Session Name
|
|
*
|
|
* EXIT:
|
|
* TRUE : User wants to logoff
|
|
* FALSE: User does not want to proceed with logoff
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
BOOL ProceedWithLogoff(HANDLE hServerName,ULONG LogonId,PWINSTATIONNAME pWSName)
|
|
{
|
|
#ifdef UNICODE
|
|
#define GetStdInChar getwchar
|
|
wint_t ch;
|
|
#else
|
|
#define GetStdInChar getchar
|
|
int ch;
|
|
#endif
|
|
|
|
WINSTATIONINFORMATION WinInfo;
|
|
ULONG ReturnLength;
|
|
int rc;
|
|
|
|
// No-session Name, No-Problem
|
|
if(lstrlen(pWSName) == 0) return (TRUE);
|
|
|
|
memset(&WinInfo,0,sizeof(WINSTATIONINFORMATION));
|
|
rc = WinStationQueryInformation( hServerName,
|
|
LogonId,
|
|
WinStationInformation,
|
|
(PVOID)&WinInfo,
|
|
sizeof(WINSTATIONINFORMATION),
|
|
&ReturnLength);
|
|
|
|
// Try to show message only if necessary
|
|
if( rc && (sizeof(WINSTATIONINFORMATION) == ReturnLength) ) {
|
|
if(lstrlen(WinInfo.UserName) == 0) {
|
|
ErrorPrintf(IDS_WARNING_LOGOFF);
|
|
rc = GetStdInChar();
|
|
if(rc == L'n') return(FALSE);
|
|
}
|
|
}
|
|
// Failed on call - assume nothing and prompt with message
|
|
else{
|
|
ErrorPrintf(IDS_WARNING_LOGOFF_QUESTIONABLE);
|
|
rc = GetStdInChar();
|
|
if(rc == L'n') return(FALSE);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* Usage
|
|
*
|
|
* Output the usage message for this utility.
|
|
*
|
|
* ENTRY:
|
|
* bError (input)
|
|
* TRUE if the 'invalid parameter(s)' message should preceed the usage
|
|
* message and the output go to stderr; FALSE for no such error
|
|
* string and output goes to stdout.
|
|
*
|
|
* EXIT:
|
|
*
|
|
*
|
|
******************************************************************************/
|
|
|
|
void
|
|
Usage( BOOLEAN bError )
|
|
{
|
|
if ( bError ) {
|
|
|
|
ErrorPrintf(IDS_ERROR_INVALID_PARAMETERS);
|
|
}
|
|
ErrorPrintf(IDS_USAGE1);
|
|
ErrorPrintf(IDS_USAGE2);
|
|
ErrorPrintf(IDS_USAGE3);
|
|
ErrorPrintf(IDS_USAGE4);
|
|
ErrorPrintf(IDS_USAGE5);
|
|
ErrorPrintf(IDS_USAGE6);
|
|
ErrorPrintf(IDS_USAGE7);
|
|
} /* Usage() */
|
|
|