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.

515 lines
18 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: LogonIPC.cpp
  3. //
  4. // Copyright (c) 1999, Microsoft Corporation
  5. //
  6. // Class that implements communication between an external process and the
  7. // GINA logon dialog.
  8. //
  9. // History: 1999-08-20 vtan created
  10. // 2000-01-31 vtan moved from Neptune to Whistler
  11. // --------------------------------------------------------------------------
  12. #include "priv.h"
  13. #include "limits.h"
  14. #include "LogonIPC.h"
  15. #include "GinaIPC.h"
  16. // --------------------------------------------------------------------------
  17. // CLogonIPC::CLogonIPC
  18. //
  19. // Arguments: <none>
  20. //
  21. // Returns: <none>
  22. //
  23. // Purpose: Initializes the CLogonIPC class.
  24. //
  25. // History: 1999-08-20 vtan created
  26. // --------------------------------------------------------------------------
  27. CLogonIPC::CLogonIPC (void) :
  28. _iLogonAttemptCount(0),
  29. _hwndLogonService(NULL)
  30. {
  31. }
  32. // --------------------------------------------------------------------------
  33. // CLogonIPC::~CLogonIPC
  34. //
  35. // Arguments: <none>
  36. //
  37. // Returns: <none>
  38. //
  39. // Purpose: Releases any resources used by the CLogonIPC class.
  40. //
  41. // History: 1999-08-20 vtan created
  42. // --------------------------------------------------------------------------
  43. CLogonIPC::~CLogonIPC (void)
  44. {
  45. }
  46. // --------------------------------------------------------------------------
  47. // CLogonIPC::IsLogonServiceAvailable
  48. //
  49. // Arguments: <none>
  50. //
  51. // Returns: bool = Presence or abscence.
  52. //
  53. // Purpose: Finds out if the window providing logon service in GINA is
  54. // available. The determination is not performed statically but
  55. // rather dynamically which allows this class to be hosted by
  56. // the actual window providing the service as well.
  57. //
  58. // History: 1999-08-20 vtan created
  59. // --------------------------------------------------------------------------
  60. bool CLogonIPC::IsLogonServiceAvailable (void)
  61. {
  62. _hwndLogonService = FindWindow(NULL, TEXT("GINA Logon"));
  63. return(_hwndLogonService != NULL);
  64. }
  65. // --------------------------------------------------------------------------
  66. // CLogonIPC::IsUserLoggedOn
  67. //
  68. // Arguments: pwszUsername = User name.
  69. // pwszDomain = User domain.
  70. //
  71. // Returns: bool = Presence or abscence.
  72. //
  73. // Purpose: Finds out if the given user is logged onto the system. You
  74. // may pass a NULL pwszDomain for the local machine.
  75. //
  76. // History: 1999-08-20 vtan created
  77. // --------------------------------------------------------------------------
  78. bool CLogonIPC::IsUserLoggedOn (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
  79. {
  80. LOGONIPC_USERID logonIPCUserID;
  81. PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
  82. return(SendToLogonService(LOGON_QUERY_LOGGED_ON, &logonIPCUserID, sizeof(logonIPCUserID), true));
  83. }
  84. // --------------------------------------------------------------------------
  85. // CLogonIPC::LogUserOn
  86. //
  87. // Arguments: pwszUsername = User name.
  88. // pwszDomain = User domain.
  89. // pwszPassword = User password. This is passed clear text.
  90. // Once encoded the password buffer is
  91. // zeroed. This function owns the memory that
  92. // you pass in.
  93. //
  94. // Returns: bool = Success or failure.
  95. //
  96. // Purpose: Attempts to log the user with the given credentials onto the
  97. // system. The password buffer is owned by this function for the
  98. // purpose of clearing it once encoded. Failed logon attempts
  99. // cause a counter to be incremented and a subsequent delay using
  100. // that counter is done to slow dictionary attacks.
  101. //
  102. // History: 1999-08-20 vtan created
  103. // --------------------------------------------------------------------------
  104. bool CLogonIPC::LogUserOn (const WCHAR *pwszUsername, const WCHAR *pwszDomain, WCHAR *pwszPassword)
  105. {
  106. bool fResult;
  107. int iPasswordLength, iTruePasswordLength;
  108. UNICODE_STRING passwordString;
  109. LOGONIPC_CREDENTIALS logonIPCCredentials;
  110. PackageIdentification(pwszUsername, pwszDomain, &logonIPCCredentials.userID);
  111. // Limit the password to 127 characters. RtlRunEncodeUnicodeString
  112. // does not support strings greater than 127 characters.
  113. iTruePasswordLength = iPasswordLength = lstrlenW(pwszPassword);
  114. if (iPasswordLength > 127)
  115. {
  116. iPasswordLength = 127;
  117. }
  118. pwszPassword[iPasswordLength] = L'\0';
  119. lstrcpyW(logonIPCCredentials.wszPassword, pwszPassword);
  120. logonIPCCredentials.iPasswordLength = iPasswordLength;
  121. ZeroMemory(pwszPassword, (iTruePasswordLength + sizeof('\0')) * sizeof(WCHAR));
  122. logonIPCCredentials.ucPasswordSeed = static_cast<unsigned char>(GetTickCount());
  123. RtlInitUnicodeString(&passwordString, logonIPCCredentials.wszPassword);
  124. RtlRunEncodeUnicodeString(&logonIPCCredentials.ucPasswordSeed, &passwordString);
  125. fResult = SendToLogonService(LOGON_LOGON_USER, &logonIPCCredentials, sizeof(logonIPCCredentials), false);
  126. if (!fResult)
  127. {
  128. Sleep(_iLogonAttemptCount * 1000);
  129. if (_iLogonAttemptCount < 5)
  130. {
  131. ++_iLogonAttemptCount;
  132. }
  133. }
  134. return(fResult);
  135. }
  136. // --------------------------------------------------------------------------
  137. // CLogonIPC::LogUserOff
  138. //
  139. // Arguments: pwszUsername = User name.
  140. // pwszDomain = User domain.
  141. //
  142. // Returns: bool = Success or failure.
  143. //
  144. // Purpose: Attempts to log the given user off the system. This will fail
  145. // if they aren't logged on.
  146. //
  147. // History: 1999-08-20 vtan created
  148. // --------------------------------------------------------------------------
  149. bool CLogonIPC::LogUserOff (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
  150. {
  151. LOGONIPC_USERID logonIPCUserID;
  152. PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
  153. return(SendToLogonService(LOGON_LOGOFF_USER, &logonIPCUserID, sizeof(logonIPCUserID), true));
  154. }
  155. // --------------------------------------------------------------------------
  156. // CLogonIPC::TestBlankPassword
  157. //
  158. // Arguments: pwszUsername = User name.
  159. // pwszDomain = User domain.
  160. //
  161. // Returns: bool = Success or failure.
  162. //
  163. // Purpose: Attempts to log the given user on the system with a blank
  164. // password. The token is then dump and failure/success returned.
  165. //
  166. // History: 2000-03-09 vtan created
  167. // --------------------------------------------------------------------------
  168. bool CLogonIPC::TestBlankPassword (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
  169. {
  170. LOGONIPC_USERID logonIPCUserID;
  171. PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
  172. return(SendToLogonService(LOGON_TEST_BLANK_PASSWORD, &logonIPCUserID, sizeof(logonIPCUserID), true));
  173. }
  174. // --------------------------------------------------------------------------
  175. // CLogonIPC::TestInteractiveLogonAllowed
  176. //
  177. // Arguments: pwszUsername = User name.
  178. // pwszDomain = User domain.
  179. //
  180. // Returns: bool
  181. //
  182. // Purpose: Test whether the user has interactive logon rights to this
  183. // machine. The presence of SeDenyInteractiveLogonRight
  184. // determines this - NOT the presence of SeInteractiveLogonRight.
  185. //
  186. // History: 2000-08-15 vtan created
  187. // --------------------------------------------------------------------------
  188. bool CLogonIPC::TestInteractiveLogonAllowed (const WCHAR *pwszUsername, const WCHAR *pwszDomain)
  189. {
  190. LOGONIPC_USERID logonIPCUserID;
  191. PackageIdentification(pwszUsername, pwszDomain, &logonIPCUserID);
  192. return(SendToLogonService(LOGON_TEST_INTERACTIVE_LOGON_ALLOWED, &logonIPCUserID, sizeof(logonIPCUserID), true));
  193. }
  194. // --------------------------------------------------------------------------
  195. // CLogonIPC::TestEjectAllowed
  196. //
  197. // Arguments: <none>
  198. //
  199. // Returns: bool = Success or failure.
  200. //
  201. // Purpose: Tests whether the computer is ejectable (docked laptop).
  202. //
  203. // History: 2001-01-10 vtan created
  204. // --------------------------------------------------------------------------
  205. bool CLogonIPC::TestEjectAllowed (void)
  206. {
  207. LOGONIPC logonIPC;
  208. return(SendToLogonService(LOGON_TEST_EJECT_ALLOWED, &logonIPC, sizeof(logonIPC), true));
  209. }
  210. // --------------------------------------------------------------------------
  211. // CLogonIPC::TestShutdownAllowed
  212. //
  213. // Arguments: <none>
  214. //
  215. // Returns: bool = Success or failure.
  216. //
  217. // Purpose: Tests whether the computer can be shut down.
  218. //
  219. // History: 2001-02-22 vtan created
  220. // --------------------------------------------------------------------------
  221. bool CLogonIPC::TestShutdownAllowed (void)
  222. {
  223. LOGONIPC logonIPC;
  224. return(SendToLogonService(LOGON_TEST_SHUTDOWN_ALLOWED, &logonIPC, sizeof(logonIPC), true));
  225. }
  226. // --------------------------------------------------------------------------
  227. // CLogonIPC::TurnOffComputer
  228. //
  229. // Arguments: <none>
  230. //
  231. // Returns: bool = Success or failure.
  232. //
  233. // Purpose: Brings up the "Turn Off Computer" dialog and allows the user
  234. // to choose what to do.
  235. //
  236. // History: 2000-04-20 vtan created
  237. // --------------------------------------------------------------------------
  238. bool CLogonIPC::TurnOffComputer (void)
  239. {
  240. LOGONIPC logonIPC;
  241. return(SendToLogonService(LOGON_TURN_OFF_COMPUTER, &logonIPC, sizeof(logonIPC), false));
  242. }
  243. // --------------------------------------------------------------------------
  244. // CLogonIPC::EjectComputer
  245. //
  246. // Arguments: <none>
  247. //
  248. // Returns: bool = Success or failure.
  249. //
  250. // Purpose: Ejects the computer (docked laptop).
  251. //
  252. // History: 2001-01-10 vtan created
  253. // --------------------------------------------------------------------------
  254. bool CLogonIPC::EjectComputer (void)
  255. {
  256. LOGONIPC logonIPC;
  257. return(SendToLogonService(LOGON_EJECT_COMPUTER, &logonIPC, sizeof(logonIPC), true));
  258. }
  259. // --------------------------------------------------------------------------
  260. // CLogonIPC::SignalUIHostFailure
  261. //
  262. // Arguments: <none>
  263. //
  264. // Returns: bool
  265. //
  266. // Purpose: Called when the UI host has an error that it cannot recover
  267. // from. This signals msgina to fall back to classic mode.
  268. //
  269. // History: 2000-03-09 vtan created
  270. // --------------------------------------------------------------------------
  271. bool CLogonIPC::SignalUIHostFailure (void)
  272. {
  273. LOGONIPC logonIPC;
  274. return(SendToLogonService(LOGON_SIGNAL_UIHOST_FAILURE, &logonIPC, sizeof(logonIPC), true));
  275. }
  276. // --------------------------------------------------------------------------
  277. // CLogonIPC::AllowExternalCredentials
  278. //
  279. // Arguments: <none>
  280. //
  281. // Returns: bool = Success or failure.
  282. //
  283. // Purpose:
  284. //
  285. // History: 2000-06-26 vtan created
  286. // --------------------------------------------------------------------------
  287. bool CLogonIPC::AllowExternalCredentials (void)
  288. {
  289. LOGONIPC logonIPC;
  290. return(SendToLogonService(LOGON_ALLOW_EXTERNAL_CREDENTIALS, &logonIPC, sizeof(logonIPC), true));
  291. }
  292. // --------------------------------------------------------------------------
  293. // CLogonIPC::RequestExternalCredentials
  294. //
  295. // Arguments: <none>
  296. //
  297. // Returns: bool
  298. //
  299. // Purpose:
  300. //
  301. // History: 2000-06-26 vtan created
  302. // --------------------------------------------------------------------------
  303. bool CLogonIPC::RequestExternalCredentials (void)
  304. {
  305. LOGONIPC logonIPC;
  306. return(SendToLogonService(LOGON_REQUEST_EXTERNAL_CREDENTIALS, &logonIPC, sizeof(logonIPC), true));
  307. }
  308. // --------------------------------------------------------------------------
  309. // CLogonIPC::PackageIdentification
  310. //
  311. // Arguments: pwszUsername = User name.
  312. // pwszDomain = User domain.
  313. // pIdentification = Pointer to a LOGONIPC_USERID struct
  314. // which is masked as void* to allow
  315. // LogonIPC.h to not expose this detail.
  316. //
  317. // Returns: <none>
  318. //
  319. // Purpose: Takes the user name and domain and packages them into the
  320. // given struct. If no domain is given the a zero length string
  321. // is used which indicates to the logon service provider that
  322. // the local machine is desired.
  323. //
  324. // Now parses the user name given. If the user has "\" then it
  325. // is assumed to be of the form "DOMAIN\USER". If the user has
  326. // "@" then it is assumed to be a UPN name.
  327. //
  328. // History: 1999-08-20 vtan created
  329. // 2000-06-27 vtan added UPN and DOMAIN parsing support
  330. // --------------------------------------------------------------------------
  331. void CLogonIPC::PackageIdentification (const WCHAR *pwszUsername, const WCHAR *pwszDomain, void *pIdentification)
  332. {
  333. bool fDone;
  334. int i, iStringLength;
  335. LOGONIPC_USERID *pLogonIPCUserID;
  336. pLogonIPCUserID = reinterpret_cast<LOGONIPC_USERID*>(pIdentification);
  337. iStringLength = lstrlen(pwszUsername);
  338. for (fDone = false, i = 0; !fDone && (i < iStringLength); ++i)
  339. {
  340. if (pwszUsername[i] == L'\\')
  341. {
  342. lstrcpynW(pLogonIPCUserID->wszDomain, pwszUsername, ARRAYSIZE(pLogonIPCUserID->wszDomain));
  343. pLogonIPCUserID->wszDomain[i] = L'\0';
  344. ++i;
  345. lstrcpynW(pLogonIPCUserID->wszUsername, pwszUsername + i, ARRAYSIZE(pLogonIPCUserID->wszUsername));
  346. fDone = true;
  347. }
  348. else if (pwszUsername[i] == L'@')
  349. {
  350. lstrcpynW(pLogonIPCUserID->wszUsername, pwszUsername, ARRAYSIZE(pLogonIPCUserID->wszUsername));
  351. pLogonIPCUserID->wszDomain[0] = L'\0';
  352. fDone = true;
  353. }
  354. }
  355. if (!fDone)
  356. {
  357. lstrcpyW(pLogonIPCUserID->wszUsername, pwszUsername);
  358. if (pwszDomain != NULL)
  359. {
  360. lstrcpyW(pLogonIPCUserID->wszDomain, pwszDomain);
  361. }
  362. else
  363. {
  364. pLogonIPCUserID->wszDomain[0] = L'\0';
  365. }
  366. }
  367. }
  368. // --------------------------------------------------------------------------
  369. // CLogonIPC::SendToLogonService
  370. //
  371. // Arguments: wQueryType = What type of service we are interested in.
  372. // pData = Pointer to the data.
  373. // wDataSize = Size of the data.
  374. // fBlock = Block message pump or not.
  375. //
  376. // Returns: bool = Success or failure.
  377. //
  378. // Purpose: Takes the package data and sends the message to the logon
  379. // service provider and receives the result. The logon service
  380. // provider started this process and reads this process' memory
  381. // directly (like a debugger would).
  382. //
  383. // This function should block the message pump because if it
  384. // processes another state change message while waiting for a
  385. // response it could destroy data.
  386. //
  387. // History: 1999-08-20 vtan created
  388. // 2001-06-22 vtan changed to SendMessageTimeout
  389. // 2001-06-28 vtan added block parameter
  390. // --------------------------------------------------------------------------
  391. bool CLogonIPC::SendToLogonService (WORD wQueryType, void *pData, WORD wDataSize, bool fBlock)
  392. {
  393. bool fResult;
  394. fResult = IsLogonServiceAvailable();
  395. if (fResult)
  396. {
  397. DWORD_PTR dwResult;
  398. reinterpret_cast<LOGONIPC*>(pData)->fResult = false;
  399. // WARNING: Danger Will Robinson.
  400. // Do NOT change INT_MAX to INFINITE. INT_MAX is a SIGNED number.
  401. // INFINITE is an UNSIGNED number. Despite the SDK and prototype
  402. // of SendMessageTimeout this timeout value is a SIGNED number.
  403. // Passing in an unsigned number causes the timeout to be
  404. // ignored and the function returns with a timeout.
  405. (LRESULT)SendMessageTimeout(_hwndLogonService,
  406. WM_LOGONSERVICEREQUEST,
  407. MAKEWPARAM(wDataSize, wQueryType),
  408. reinterpret_cast<LPARAM>(pData),
  409. fBlock ? SMTO_BLOCK : SMTO_NORMAL,
  410. INT_MAX, // See above warning.
  411. &dwResult);
  412. fResult = (reinterpret_cast<LOGONIPC*>(pData)->fResult != FALSE);
  413. }
  414. return(fResult);
  415. }
  416. // --------------------------------------------------------------------------
  417. // CLogonIPC::PostToLogonService
  418. //
  419. // Arguments: wQueryType = What type of service we are interested in.
  420. // pData = Pointer to the data.
  421. // wDataSize = Size of the data.
  422. //
  423. // Returns: <none>
  424. //
  425. // Purpose: Takes the package data and posts the message to the logon
  426. // service provider and receives the result. The logon service
  427. // provider started this process and reads this process' memory
  428. // directly (like a debugger would).
  429. //
  430. // History: 1999-11-26 vtan created
  431. // --------------------------------------------------------------------------
  432. void CLogonIPC::PostToLogonService (WORD wQueryType, void *pData, WORD wDataSize)
  433. {
  434. if (IsLogonServiceAvailable())
  435. {
  436. TBOOL(PostMessage(_hwndLogonService, WM_LOGONSERVICEREQUEST, MAKEWPARAM(wDataSize, wQueryType), reinterpret_cast<LPARAM>(pData)));
  437. }
  438. }