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.

429 lines
14 KiB

  1. /****************************************************************************/
  2. /* qidle.c */
  3. /* */
  4. /* QueryIdle utility source */
  5. /* */
  6. /* Copyright (c) 1999 Microsoft Corporation */
  7. /****************************************************************************/
  8. /*
  9. * Includes
  10. */
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <locale.h>
  15. #include <windows.h>
  16. #include <winsock2.h>
  17. #include <ws2tcpip.h>
  18. #include <winsta.h>
  19. #pragma warning (push, 4)
  20. #include "qidle.h"
  21. #define MAX_SERVER_NAME 120
  22. #define MAXADDR 16 // (255.255.255.255 null-terminated)
  23. #define MAX_SEND_STRING 64
  24. #define MAX_OUTPUT_STRING_LENGTH 80
  25. const int BEEP_FREQUENCY = 880;
  26. const int BEEP_DURATION = 500;
  27. const int SLEEP_DURATION = 30000;
  28. #define BEEPANDDONOTHING 0
  29. #define LOGTHEMOFF 1
  30. #define DISCONNECTTHEM 2
  31. #define DEFAULT_PORT "9878"
  32. /*
  33. * Global variables
  34. */
  35. SOCKET g_sockRoboServer = INVALID_SOCKET;
  36. HANDLE g_hServer = NULL;
  37. BOOL g_WinSockActivated = FALSE;
  38. char g_SendString[MAX_SEND_STRING];
  39. int g_DoToBadSessions = BEEPANDDONOTHING;
  40. int g_Silent = FALSE;
  41. /*
  42. * Private function prototypes.
  43. */
  44. typedef struct _ELAPSEDTIME {
  45. USHORT days;
  46. USHORT hours;
  47. USHORT minutes;
  48. USHORT seconds;
  49. } ELAPSEDTIME, * PELAPSEDTIME;
  50. int GetSMCNumber(wchar_t *psSmcName);
  51. int SendToRS(char *senddata);
  52. LARGE_INTEGER WINAPI
  53. CalculateDiffTime( LARGE_INTEGER FirstTime, LARGE_INTEGER SecondTime )
  54. {
  55. LARGE_INTEGER DiffTime;
  56. DiffTime.QuadPart = SecondTime.QuadPart - FirstTime.QuadPart;
  57. DiffTime.QuadPart = DiffTime.QuadPart / 10000000;
  58. return(DiffTime);
  59. } // end CalculateDiffTime
  60. int OutputUsage(wchar_t *psCommand) {
  61. WCHAR sUsageText[MAX_OUTPUT_STRING_LENGTH];
  62. LoadString(NULL, IDS_USAGETEXT, sUsageText, MAX_OUTPUT_STRING_LENGTH);
  63. wprintf(sUsageText, psCommand);
  64. return 0;
  65. }
  66. int ConnectToRoboServer(wchar_t *psRoboServerName) {
  67. struct addrinfo *servai;
  68. char psRSNameA[MAX_SERVER_NAME];
  69. WSADATA wsaData;
  70. WORD wVersionRequested;
  71. WCHAR sErrorText[MAX_OUTPUT_STRING_LENGTH];
  72. // Initialize Winsock
  73. wVersionRequested = MAKEWORD( 2, 2 );
  74. if (WSAStartup( wVersionRequested, &wsaData ) != 0) {
  75. LoadString(NULL, IDS_WINSOCKNOINIT, sErrorText,
  76. MAX_OUTPUT_STRING_LENGTH);
  77. wprintf(sErrorText);
  78. return -1;
  79. }
  80. g_WinSockActivated = TRUE;
  81. WideCharToMultiByte(CP_ACP, 0, psRoboServerName, -1, psRSNameA,
  82. MAX_SERVER_NAME, 0, 0);
  83. if (getaddrinfo(psRSNameA, DEFAULT_PORT, NULL, &servai) != 0) {
  84. LoadString(NULL, IDS_UNKNOWNHOST, sErrorText,
  85. MAX_OUTPUT_STRING_LENGTH);
  86. wprintf(sErrorText, psRoboServerName);
  87. return -1;
  88. }
  89. g_sockRoboServer = socket(servai->ai_family, SOCK_STREAM, 0);
  90. if (g_sockRoboServer == INVALID_SOCKET) {
  91. LoadString(NULL, IDS_SOCKETERROR, sErrorText,
  92. MAX_OUTPUT_STRING_LENGTH);
  93. wprintf(sErrorText);
  94. return -1;
  95. }
  96. if (connect(g_sockRoboServer, servai->ai_addr, (int) servai->ai_addrlen)
  97. != 0) {
  98. LoadString(NULL, IDS_CONNECTERROR, sErrorText,
  99. MAX_OUTPUT_STRING_LENGTH);
  100. wprintf(sErrorText);
  101. return -1;
  102. }
  103. // We've connected.
  104. return 0;
  105. }
  106. int HandleDeadGuy(WINSTATIONINFORMATION winfoDeadGuy) {
  107. WCHAR sOutputText[MAX_OUTPUT_STRING_LENGTH];
  108. switch (g_DoToBadSessions) {
  109. case LOGTHEMOFF:
  110. // this is where we log him off
  111. // figure out session number
  112. // (session number == winfoDeadGuy.LogonId)
  113. // log off session
  114. LoadString(NULL, IDS_LOGGINGOFFIDLE, sOutputText,
  115. MAX_OUTPUT_STRING_LENGTH);
  116. wprintf(sOutputText);
  117. if (WinStationReset(g_hServer, winfoDeadGuy.LogonId, TRUE)
  118. == FALSE) {
  119. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
  120. GetLastError(), 0, sOutputText,
  121. MAX_OUTPUT_STRING_LENGTH, 0);
  122. }
  123. // inform roboserver
  124. sprintf(g_SendString, "restart %03d", GetSMCNumber(
  125. winfoDeadGuy.UserName));
  126. SendToRS(g_SendString);
  127. break;
  128. case BEEPANDDONOTHING:
  129. sprintf(g_SendString, "idle %03d", GetSMCNumber(
  130. winfoDeadGuy.UserName));
  131. SendToRS(g_SendString);
  132. if ( !g_Silent ) {
  133. Beep(BEEP_FREQUENCY, BEEP_DURATION);
  134. }
  135. break;
  136. case DISCONNECTTHEM:
  137. break;
  138. }
  139. return 0;
  140. }
  141. // Function to handle CTRL+C so we can exit gracefully
  142. BOOL WINAPI CleanUpHandler(DWORD dwCtrlType) {
  143. WCHAR sOutputString[MAX_OUTPUT_STRING_LENGTH];
  144. // Load the correct string from the string table and output it.
  145. switch (dwCtrlType) {
  146. case CTRL_C_EVENT:
  147. LoadString(NULL, IDS_TERMCTRLC, sOutputString,
  148. MAX_OUTPUT_STRING_LENGTH);
  149. break;
  150. case CTRL_BREAK_EVENT:
  151. LoadString(NULL, IDS_TERMCTRLBREAK, sOutputString,
  152. MAX_OUTPUT_STRING_LENGTH);
  153. break;
  154. case CTRL_CLOSE_EVENT:
  155. LoadString(NULL, IDS_TERMCLOSE, sOutputString,
  156. MAX_OUTPUT_STRING_LENGTH);
  157. break;
  158. case CTRL_LOGOFF_EVENT:
  159. LoadString(NULL, IDS_TERMLOGOFF, sOutputString,
  160. MAX_OUTPUT_STRING_LENGTH);
  161. break;
  162. case CTRL_SHUTDOWN_EVENT:
  163. LoadString(NULL, IDS_TERMSHUTDOWN, sOutputString,
  164. MAX_OUTPUT_STRING_LENGTH);
  165. break;
  166. }
  167. wprintf(sOutputString);
  168. // Perform cleanup activity
  169. WinStationCloseServer(g_hServer);
  170. if (g_WinSockActivated == TRUE)
  171. WSACleanup();
  172. ExitProcess(0);
  173. return TRUE;
  174. }
  175. int __cdecl
  176. wmain( int argc, wchar_t *argv[ ] )
  177. {
  178. PLOGONID pLogonId;
  179. ULONG Entries;
  180. ULONG ReturnLength;
  181. WINSTATIONINFORMATION WSInformation;
  182. WINSTATIONCLIENT WSClient;
  183. SYSTEMTIME currloctime;
  184. int numUsers;
  185. int numOtherUsers;
  186. ULONG i;
  187. WCHAR sOutputString[MAX_OUTPUT_STRING_LENGTH];
  188. WCHAR sIdleOutputString1[MAX_OUTPUT_STRING_LENGTH];
  189. WCHAR sIdleOutputString2[MAX_OUTPUT_STRING_LENGTH];
  190. WCHAR sDisconnectedOutputString[MAX_OUTPUT_STRING_LENGTH];
  191. WCHAR sSummaryString[MAX_OUTPUT_STRING_LENGTH];
  192. if ((argc < 2) || (argc > 4)) {
  193. OutputUsage(argv[0]);
  194. return -1;
  195. }
  196. if (wcscmp(argv[1], L"/?") == 0) {
  197. OutputUsage(argv[0]);
  198. return -1;
  199. }
  200. if ( argc > 2 ) {
  201. if ( !wcscmp(argv[2], L"/s") || (argc > 3 && !wcscmp(argv[3], L"/s")) ) {
  202. g_Silent = TRUE;
  203. }
  204. else {
  205. OutputUsage(argv[0]);
  206. return -1;
  207. }
  208. }
  209. if (SetConsoleCtrlHandler(CleanUpHandler, TRUE) == 0) {
  210. LoadString(NULL, IDS_CANTDOCTRLC, sOutputString,
  211. MAX_OUTPUT_STRING_LENGTH);
  212. wprintf(sOutputString);
  213. return -1;
  214. }
  215. LoadString(NULL, IDS_TITLE_TEXT, sOutputString, MAX_OUTPUT_STRING_LENGTH);
  216. wprintf(sOutputString);
  217. g_hServer = WinStationOpenServer(argv[1]);
  218. if (g_hServer == NULL) {
  219. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
  220. GetLastError(), 0, sOutputString,
  221. MAX_OUTPUT_STRING_LENGTH, 0);
  222. LoadString(NULL, IDS_ERROROPENINGSERVER, sOutputString,
  223. MAX_OUTPUT_STRING_LENGTH);
  224. wprintf(sOutputString, argv[1]);
  225. return -1;
  226. }
  227. if (argc > 2) {
  228. if (wcsncmp(argv[2], L"/r:", 3) == 0) {
  229. if (ConnectToRoboServer(&(argv[2])[3]) == 0) {
  230. g_DoToBadSessions = BEEPANDDONOTHING;
  231. } else {
  232. LoadString(NULL, IDS_ROBOSRVCONNECTERROR, sOutputString,
  233. MAX_OUTPUT_STRING_LENGTH);
  234. wprintf(sOutputString, &(argv[2])[3]);
  235. }
  236. }
  237. }
  238. LoadString(NULL, IDS_IDLESESSIONLINE1, sIdleOutputString1,
  239. MAX_OUTPUT_STRING_LENGTH);
  240. LoadString(NULL, IDS_IDLESESSIONLINE2, sIdleOutputString2,
  241. MAX_OUTPUT_STRING_LENGTH);
  242. LoadString(NULL, IDS_DISCONNECTED, sDisconnectedOutputString,
  243. MAX_OUTPUT_STRING_LENGTH);
  244. LoadString(NULL, IDS_SUMMARY, sSummaryString,
  245. MAX_OUTPUT_STRING_LENGTH);
  246. for ( ; ; ) {
  247. #define MAX_DATE_STR_LEN 80
  248. #define MAX_TIME_STR_LEN 80
  249. WCHAR psDateStr[MAX_DATE_STR_LEN];
  250. WCHAR psTimeStr[MAX_TIME_STR_LEN];
  251. // Display the current time
  252. GetLocalTime(&currloctime);
  253. GetDateFormat(0, 0, &currloctime, NULL, psDateStr, MAX_DATE_STR_LEN);
  254. GetTimeFormat(0, 0, &currloctime, NULL, psTimeStr, MAX_TIME_STR_LEN);
  255. wprintf(L"%s %s\n", psDateStr, psTimeStr);
  256. numUsers = 0;
  257. numOtherUsers = 0;
  258. if (WinStationEnumerate(g_hServer, &pLogonId, &Entries) == FALSE) {
  259. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
  260. GetLastError(), 0, sOutputString,
  261. MAX_OUTPUT_STRING_LENGTH, 0);
  262. break;
  263. }
  264. for (i = 0; i < Entries; i++) {
  265. LARGE_INTEGER DiffTime;
  266. LONG d_time;
  267. ELAPSEDTIME IdleTime;
  268. BOOLEAN bRetVal;
  269. bRetVal = WinStationQueryInformation(g_hServer,
  270. pLogonId[i].LogonId, WinStationInformation,
  271. &WSInformation, sizeof(WSInformation), &ReturnLength);
  272. if (bRetVal == FALSE) {
  273. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
  274. GetLastError(), 0, sOutputString,
  275. MAX_OUTPUT_STRING_LENGTH, 0);
  276. continue;
  277. }
  278. DiffTime = CalculateDiffTime(WSInformation.LastInputTime,
  279. WSInformation.CurrentTime);
  280. d_time = DiffTime.LowPart;
  281. // Calculate the days, hours, minutes, seconds since specified
  282. // time.
  283. IdleTime.days = (USHORT)(d_time / 86400L); // days since
  284. d_time = d_time % 86400L; // seconds => partial
  285. // day
  286. IdleTime.hours = (USHORT)(d_time / 3600L); // hours since
  287. d_time = d_time % 3600L; // seconds => partial
  288. // hour
  289. IdleTime.minutes = (USHORT)(d_time / 60L); // minutes since
  290. IdleTime.seconds = (USHORT)(d_time % 60L);// seconds remaining
  291. if (WSInformation.ConnectState == State_Active) {
  292. if (WinStationQueryInformationW(g_hServer, pLogonId[i].LogonId,
  293. WinStationClient,
  294. &WSClient, sizeof(WSClient), &ReturnLength) != FALSE) {
  295. // 2 or more minutes == bad
  296. if ((IdleTime.minutes > 1) || (IdleTime.hours > 0) ||
  297. (IdleTime.days > 0)) {
  298. // sIdleOutputString1, loaded above, is the first part of
  299. // the format string. sIdleOutputString2, also loaded
  300. // above, is the second part.
  301. wprintf(sIdleOutputString1, WSInformation.
  302. UserName, WSInformation.LogonId, WSClient.
  303. ClientName);
  304. wprintf(sIdleOutputString2, IdleTime.days,
  305. IdleTime.hours, IdleTime.minutes);
  306. if (wcsstr(WSInformation.UserName, L"smc") != 0)
  307. HandleDeadGuy(WSInformation);
  308. }
  309. {
  310. WCHAR *pPrefix = wcsstr(WSInformation.UserName, L"smc");
  311. if ( pPrefix != NULL ) {
  312. int index = wcstoul(pPrefix + 3, NULL, 10);
  313. if ( index >= 1 &&
  314. index <= 500 ) {
  315. numUsers++;
  316. } else {
  317. numOtherUsers++;
  318. }
  319. }
  320. }
  321. } else {
  322. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0,
  323. GetLastError(), 0, sOutputString,
  324. MAX_OUTPUT_STRING_LENGTH, 0);
  325. wprintf(sOutputString);
  326. }
  327. } else if (WSInformation.ConnectState == State_Disconnected) {
  328. wprintf(sDisconnectedOutputString, WSInformation.
  329. UserName, WSInformation.LogonId);
  330. }
  331. }
  332. wprintf(sSummaryString, numUsers, numOtherUsers);
  333. // Sleep for a while
  334. Sleep(SLEEP_DURATION);
  335. wprintf(L"\n");
  336. }
  337. // In case an error broke out of the loop
  338. GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, GetCurrentProcessId());
  339. // required to shut the dumb ia64 compiler up--will not get here
  340. return 0;
  341. } /* main() */
  342. // from a username of the format "smcxxx," where xxx is a three-digit
  343. // 0-padded base 10 number, returns the number or -1 on error
  344. int GetSMCNumber(wchar_t *psSmcName) {
  345. return _wtoi(&psSmcName[3]);
  346. }
  347. // sends the data in senddata to the RoboServer connection. Returns
  348. // SOCKET_ERROR on error, or the total number of bytes sent on success
  349. int SendToRS(char *senddata) {
  350. if (senddata != 0)
  351. return send(g_sockRoboServer, senddata, (int) strlen(senddata) + 1, 0);
  352. else
  353. return SOCKET_ERROR;
  354. }
  355. #pragma warning (pop)