Leaked source code of windows server 2003
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

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