Source code of Windows XP (NT5)
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.

317 lines
7.8 KiB

  1. // Copyright (c) 1998-1999 Microsoft Corporation
  2. /*************************************************************************
  3. *
  4. * LOGOFF.C
  5. *
  6. * This module is the LOGOFF utility code.
  7. *
  8. *
  9. *************************************************************************/
  10. #include <stdio.h>
  11. #include <windows.h>
  12. //#include <ntddkbd.h>
  13. //#include <ntddmou.h>
  14. #include <winstaw.h>
  15. #include <stdlib.h>
  16. #include <utilsub.h>
  17. #include <string.h>
  18. #include <malloc.h>
  19. #include <locale.h>
  20. #include "logoff.h"
  21. #include "printfoa.h"
  22. WINSTATIONNAME WSName;
  23. USHORT help_flag = FALSE;
  24. USHORT v_flag = FALSE;
  25. HANDLE hServerName = SERVERNAME_CURRENT;
  26. WCHAR ServerName[MAX_IDS_LEN+1];
  27. TOKMAP ptm[] =
  28. {
  29. #define TERM_PARM 0
  30. {TOKEN_WS, TMFLAG_OPTIONAL, TMFORM_STRING,
  31. WINSTATIONNAME_LENGTH, WSName},
  32. {TOKEN_SERVER, TMFLAG_OPTIONAL, TMFORM_STRING,
  33. MAX_IDS_LEN, ServerName},
  34. {TOKEN_HELP, TMFLAG_OPTIONAL, TMFORM_BOOLEAN,
  35. sizeof(USHORT), &help_flag},
  36. {TOKEN_VERBOSE, TMFLAG_OPTIONAL, TMFORM_BOOLEAN,
  37. sizeof(USHORT), &v_flag},
  38. {0, 0, 0, 0, 0}
  39. };
  40. /*
  41. * Local function prototypes.
  42. */
  43. void Usage( BOOLEAN bError );
  44. BOOL ProceedWithLogoff(HANDLE hServerName,ULONG LogonId,PWINSTATIONNAME pWSName);
  45. /*************************************************************************
  46. *
  47. * main
  48. * Main function and entry point of the LOGOFF
  49. * utility.
  50. *
  51. * ENTRY:
  52. * argc - count of the command line arguments.
  53. * argv - vector of strings containing the command line arguments.
  54. *
  55. * EXIT
  56. * Nothing.
  57. *
  58. *************************************************************************/
  59. int __cdecl
  60. main(INT argc, CHAR **argv)
  61. {
  62. BOOLEAN bCurrent = FALSE;
  63. int rc, i;
  64. WCHAR *CmdLine;
  65. WCHAR **argvW, *endptr;
  66. ULONG LogonId;
  67. setlocale(LC_ALL, ".OCP");
  68. /*
  69. * Massage the command line.
  70. */
  71. argvW = MassageCommandLine((DWORD)argc);
  72. if (argvW == NULL) {
  73. ErrorPrintf(IDS_ERROR_MALLOC);
  74. return(FAILURE);
  75. }
  76. /*
  77. * parse the cmd line without parsing the program name (argc-1, argv+1)
  78. */
  79. rc = ParseCommandLine(argc-1, argvW+1, ptm, 0);
  80. /*
  81. * Check for error from ParseCommandLine
  82. */
  83. if ( help_flag || (rc && !(rc & PARSE_FLAG_NO_PARMS)) ) {
  84. if ( !help_flag ) {
  85. Usage(TRUE);
  86. return(FAILURE);
  87. } else {
  88. Usage(FALSE);
  89. return(SUCCESS);
  90. }
  91. }
  92. // If no remote server was specified, then check if we are running under Terminal Server
  93. if ((!IsTokenPresent(ptm, TOKEN_SERVER) ) && (!AreWeRunningTerminalServices()))
  94. {
  95. ErrorPrintf(IDS_ERROR_NOT_TS);
  96. return(FAILURE);
  97. }
  98. /*
  99. * Open the specified server
  100. */
  101. if( ServerName[0] ) {
  102. hServerName = WinStationOpenServer( ServerName );
  103. if( hServerName == NULL ) {
  104. StringErrorPrintf(IDS_ERROR_SERVER,ServerName);
  105. PutStdErr( GetLastError(), 0 );
  106. return(FAILURE);
  107. }
  108. }
  109. /*
  110. * Validate input string for WinStation or LogonId.
  111. */
  112. if ( !IsTokenPresent(ptm, TOKEN_WS) ) {
  113. /*
  114. * No string specified; use current WinStation / LogonId.
  115. */
  116. bCurrent = TRUE;
  117. LogonId = GetCurrentLogonId();
  118. if( ServerName[0] ) {
  119. ErrorPrintf(IDS_ERROR_NEED_A_SESSIONID);
  120. return(FAILURE);
  121. }
  122. } else if ( !iswdigit(*WSName) ) {
  123. /*
  124. * Treat the string as a WinStation name.
  125. */
  126. if ( !LogonIdFromWinStationName(hServerName, WSName, &LogonId) ) {
  127. StringErrorPrintf(IDS_ERROR_WINSTATION_NOT_FOUND, WSName);
  128. return(FAILURE);
  129. }
  130. } else {
  131. /*
  132. * Treat the string as a LogonId.
  133. */
  134. LogonId = wcstoul(WSName, &endptr, 10);
  135. if ( *endptr || LogonId == ( ULONG )-1 )
  136. {
  137. StringErrorPrintf(IDS_ERROR_INVALID_LOGONID, WSName);
  138. return(FAILURE);
  139. }
  140. if ( !WinStationNameFromLogonId(hServerName, LogonId, WSName) ) {
  141. ErrorPrintf(IDS_ERROR_LOGONID_NOT_FOUND, LogonId);
  142. return(FAILURE);
  143. }
  144. if( ( LogonId == GetCurrentLogonId() ) )
  145. {
  146. bCurrent = TRUE;
  147. }
  148. }
  149. /*
  150. * Perform the logoff.
  151. */
  152. if ( bCurrent ) {
  153. if ( !ExitWindowsEx(EWX_LOGOFF, (DWORD)-1) ) {
  154. ErrorPrintf(IDS_ERROR_LOGOFF_CURRENT,
  155. GetLastError());
  156. PutStdErr( GetLastError(), 0 );
  157. return(FAILURE);
  158. }
  159. } else{
  160. if (!ProceedWithLogoff(hServerName,LogonId,WSName))
  161. return (SUCCESS);
  162. if ( v_flag )
  163. Message(IDS_WINSTATION_LOGOFF, LogonId);
  164. /*
  165. * RESOLVED: we need to expose the session manager's "logoff winstation"
  166. * API and call it here for the specified LogonId. Till then, we'll
  167. * do a WinStationReset (nasty, but does the job).
  168. *
  169. * - Reset and logoff are synonymous
  170. */
  171. if ( !WinStationReset(hServerName, LogonId, TRUE) ) {
  172. ErrorPrintf(IDS_ERROR_LOGOFF, LogonId, GetLastError());
  173. PutStdErr( GetLastError(), 0 );
  174. return(FAILURE);
  175. }
  176. }
  177. return(SUCCESS);
  178. } /* main() */
  179. /*******************************************************************************
  180. *
  181. * Usage
  182. *
  183. * If LogonId does not have a corresponding UserName then a warning
  184. * message is displayed.
  185. *
  186. * ENTRY:
  187. * hServerName : Handle to server
  188. * LogonId : ID as shown in qwinsta
  189. * pWSName : Session Name
  190. *
  191. * EXIT:
  192. * TRUE : User wants to logoff
  193. * FALSE: User does not want to proceed with logoff
  194. *
  195. *
  196. ******************************************************************************/
  197. BOOL ProceedWithLogoff(HANDLE hServerName,ULONG LogonId,PWINSTATIONNAME pWSName)
  198. {
  199. #ifdef UNICODE
  200. #define GetStdInChar getwchar
  201. wint_t ch;
  202. #else
  203. #define GetStdInChar getchar
  204. int ch;
  205. #endif
  206. WINSTATIONINFORMATION WinInfo;
  207. ULONG ReturnLength;
  208. int rc;
  209. // No-session Name, No-Problem
  210. if(lstrlen(pWSName) == 0) return (TRUE);
  211. memset(&WinInfo,0,sizeof(WINSTATIONINFORMATION));
  212. rc = WinStationQueryInformation( hServerName,
  213. LogonId,
  214. WinStationInformation,
  215. (PVOID)&WinInfo,
  216. sizeof(WINSTATIONINFORMATION),
  217. &ReturnLength);
  218. // Try to show message only if necessary
  219. if( rc && (sizeof(WINSTATIONINFORMATION) == ReturnLength) ) {
  220. if(lstrlen(WinInfo.UserName) == 0) {
  221. ErrorPrintf(IDS_WARNING_LOGOFF);
  222. rc = GetStdInChar();
  223. if(rc == L'n') return(FALSE);
  224. }
  225. }
  226. // Failed on call - assume nothing and prompt with message
  227. else{
  228. ErrorPrintf(IDS_WARNING_LOGOFF_QUESTIONABLE);
  229. rc = GetStdInChar();
  230. if(rc == L'n') return(FALSE);
  231. }
  232. return (TRUE);
  233. }
  234. /*******************************************************************************
  235. *
  236. * Usage
  237. *
  238. * Output the usage message for this utility.
  239. *
  240. * ENTRY:
  241. * bError (input)
  242. * TRUE if the 'invalid parameter(s)' message should preceed the usage
  243. * message and the output go to stderr; FALSE for no such error
  244. * string and output goes to stdout.
  245. *
  246. * EXIT:
  247. *
  248. *
  249. ******************************************************************************/
  250. void
  251. Usage( BOOLEAN bError )
  252. {
  253. if ( bError ) {
  254. ErrorPrintf(IDS_ERROR_INVALID_PARAMETERS);
  255. }
  256. ErrorPrintf(IDS_USAGE1);
  257. ErrorPrintf(IDS_USAGE2);
  258. ErrorPrintf(IDS_USAGE3);
  259. ErrorPrintf(IDS_USAGE4);
  260. ErrorPrintf(IDS_USAGE5);
  261. ErrorPrintf(IDS_USAGE6);
  262. ErrorPrintf(IDS_USAGE7);
  263. } /* Usage() */