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.

1005 lines
33 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: CredentialTransfer.cpp
  3. //
  4. // Copyright (c) 2001, Microsoft Corporation
  5. //
  6. // Classes to handle credential transfer from one winlogon to another.
  7. //
  8. // History: 2001-01-11 vtan created
  9. // --------------------------------------------------------------------------
  10. #include "StandardHeader.h"
  11. #include "CredentialTransfer.h"
  12. #include <winsta.h>
  13. #include "Access.h"
  14. #include "Compatibility.h"
  15. #include "RegistryResources.h"
  16. #include "StatusCode.h"
  17. // --------------------------------------------------------------------------
  18. // CCredentials::s_hKeyCredentials
  19. // CCredentials::s_szCredentialKeyName
  20. // CCredentials::s_szCredentialValueName
  21. //
  22. // Purpose: Static member variables.
  23. //
  24. // History: 2001-01-12 vtan created
  25. // --------------------------------------------------------------------------
  26. HKEY CCredentials::s_hKeyCredentials = NULL;
  27. const TCHAR CCredentials::s_szCredentialKeyName[] = TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Credentials");
  28. const TCHAR CCredentials::s_szCredentialValueName[] = TEXT("Name");
  29. // --------------------------------------------------------------------------
  30. // CCredentials::CCredentials
  31. //
  32. // Arguments: <none>
  33. //
  34. // Returns: <none>
  35. //
  36. // Purpose: Constructor for CCredentials.
  37. //
  38. // History: 2001-01-12 vtan created
  39. // --------------------------------------------------------------------------
  40. CCredentials::CCredentials (void)
  41. {
  42. }
  43. // --------------------------------------------------------------------------
  44. // CCredentials::~CCredentials
  45. //
  46. // Arguments: <none>
  47. //
  48. // Returns: <none>
  49. //
  50. // Purpose: Destructor for CCredentials.
  51. //
  52. // History: 2001-01-12 vtan created
  53. // --------------------------------------------------------------------------
  54. CCredentials::~CCredentials (void)
  55. {
  56. }
  57. // --------------------------------------------------------------------------
  58. // CCredentials::OpenConduit
  59. //
  60. // Arguments: phPipe = Handle to the named pipe returned.
  61. //
  62. // Returns: NTSTATUS
  63. //
  64. // Purpose: Reads the name of the named pipe from the volatile section of
  65. // the registry and opens the named pipe for read access. Returns
  66. // this handle back to the caller.
  67. //
  68. // History: 2001-01-12 vtan created
  69. // --------------------------------------------------------------------------
  70. NTSTATUS CCredentials::OpenConduit (HANDLE *phPipe)
  71. {
  72. NTSTATUS status;
  73. HANDLE hPipe;
  74. TCHAR szName[MAX_PATH];
  75. hPipe = NULL;
  76. if (s_hKeyCredentials != NULL)
  77. {
  78. status = GetConduitName(szName, ARRAYSIZE(szName));
  79. if (NT_SUCCESS(status))
  80. {
  81. hPipe = CreateFile(szName,
  82. GENERIC_READ,
  83. 0,
  84. NULL,
  85. OPEN_EXISTING,
  86. 0,
  87. NULL);
  88. if (hPipe == INVALID_HANDLE_VALUE)
  89. {
  90. status = CStatusCode::StatusCodeOfLastError();
  91. }
  92. }
  93. }
  94. else
  95. {
  96. hPipe = INVALID_HANDLE_VALUE;
  97. status = STATUS_ACCESS_DENIED;
  98. }
  99. *phPipe = hPipe;
  100. return(status);
  101. }
  102. // --------------------------------------------------------------------------
  103. // CCredentials::CreateConduit
  104. //
  105. // Arguments: pSecurityAttributes = Security to apply to named pipe.
  106. // phPipe = Handle to named pipe returned.
  107. //
  108. // Returns: NTSTATUS
  109. //
  110. // Purpose: Creates a uniquely named pipe and places this name in the
  111. // volatile section of the registry for the open method.
  112. //
  113. // History: 2001-01-12 vtan created
  114. // --------------------------------------------------------------------------
  115. NTSTATUS CCredentials::CreateConduit (LPSECURITY_ATTRIBUTES pSecurityAttributes, HANDLE *phPipe)
  116. {
  117. NTSTATUS status;
  118. HANDLE hPipe;
  119. hPipe = NULL;
  120. if (s_hKeyCredentials != NULL)
  121. {
  122. DWORD dwNumber;
  123. int iCount;
  124. TCHAR szName[MAX_PATH];
  125. dwNumber = GetTickCount();
  126. iCount = 0;
  127. do
  128. {
  129. // Create a name for the pipe based on the tickcount. If this collides
  130. // with one already there (unlikely but possible) then add tickcount and
  131. // try again. The named pipe is actually short lived.
  132. (NTSTATUS)CreateConduitName(dwNumber, szName);
  133. hPipe = CreateNamedPipe(szName,
  134. PIPE_ACCESS_OUTBOUND | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
  135. PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
  136. 1,
  137. 0,
  138. 0,
  139. NMPWAIT_USE_DEFAULT_WAIT,
  140. pSecurityAttributes);
  141. if (hPipe == NULL)
  142. {
  143. dwNumber += GetTickCount();
  144. status = CStatusCode::StatusCodeOfLastError();
  145. }
  146. else
  147. {
  148. status = STATUS_SUCCESS;
  149. }
  150. } while (!NT_SUCCESS(status) && (++iCount <= 5));
  151. if (NT_SUCCESS(status))
  152. {
  153. status = SetConduitName(szName);
  154. }
  155. }
  156. else
  157. {
  158. hPipe = NULL;
  159. status = STATUS_ACCESS_DENIED;
  160. }
  161. *phPipe = hPipe;
  162. return(status);
  163. }
  164. // --------------------------------------------------------------------------
  165. // CCredentials::ClearConduit
  166. //
  167. // Arguments: <none>
  168. //
  169. // Returns: NTSTATUS
  170. //
  171. // Purpose: Clears the named stored in the volatile section of the
  172. // registry.
  173. //
  174. // History: 2001-01-12 vtan created
  175. // --------------------------------------------------------------------------
  176. NTSTATUS CCredentials::ClearConduit (void)
  177. {
  178. return(ClearConduitName());
  179. }
  180. // --------------------------------------------------------------------------
  181. // CCredentials::Pack
  182. //
  183. // Arguments: pLogonIPCCredentials = Credentials to pack.
  184. // ppvData = Block of memory allocated.
  185. // pdwDataSize = Size of block of memory allocated.
  186. //
  187. // Returns: NTSTATUS
  188. //
  189. // Purpose: Packs the credentials into a stream-lined structure for
  190. // transmission across a named pipe. This packs the user name,
  191. // domain and password into a known structure for the client
  192. // to pick up. The password is run encoded. The structure has
  193. // pointer references removed.
  194. //
  195. // History: 2001-01-12 vtan created
  196. // --------------------------------------------------------------------------
  197. NTSTATUS CCredentials::Pack (LOGONIPC_CREDENTIALS *pLogonIPCCredentials, void* *ppvData, DWORD *pdwDataSize)
  198. {
  199. NTSTATUS status;
  200. DWORD dwSize, dwSizeUsername, dwSizeDomain, dwSizePassword;
  201. unsigned char *pUC;
  202. // Marshall the credentials into the struct that is transferred across
  203. // a named pipe. Calculate the size of the buffer required.
  204. dwSizeUsername = lstrlenW(pLogonIPCCredentials->userID.wszUsername) + sizeof('\0');
  205. dwSizeDomain = lstrlenW(pLogonIPCCredentials->userID.wszDomain) + sizeof('\0');
  206. dwSizePassword = lstrlenW(pLogonIPCCredentials->wszPassword) + sizeof('\0');
  207. *pdwDataSize = dwSize = sizeof(CREDENTIALS) + ((dwSizeUsername + dwSizeDomain + dwSizePassword) * sizeof(WCHAR));
  208. // Allocate the buffer.
  209. *ppvData = pUC = static_cast<unsigned char*>(LocalAlloc(LMEM_FIXED, dwSize));
  210. if (pUC != NULL)
  211. {
  212. WCHAR *pszUsername, *pszDomain, *pszPassword;
  213. CREDENTIALS *pCredentials;
  214. // Establish pointers into the buffer to fill it.
  215. pCredentials = reinterpret_cast<CREDENTIALS*>(pUC);
  216. pszUsername = reinterpret_cast<WCHAR*>(pUC + sizeof(CREDENTIALS));
  217. pszDomain = pszUsername + dwSizeUsername;
  218. pszPassword = pszDomain + dwSizeDomain;
  219. // Copy the strings into the buffer.
  220. (WCHAR*)lstrcpyW(pszUsername, pLogonIPCCredentials->userID.wszUsername);
  221. (WCHAR*)lstrcpyW(pszDomain, pLogonIPCCredentials->userID.wszDomain);
  222. (WCHAR*)lstrcpyW(pszPassword, pLogonIPCCredentials->wszPassword);
  223. // Erase the password string given.
  224. ZeroMemory(pLogonIPCCredentials->wszPassword, dwSizePassword * sizeof(WCHAR));
  225. // Prepare a seed for the run encode.
  226. pCredentials->dwSize = dwSize;
  227. pCredentials->ucPasswordSeed = static_cast<unsigned char>(GetTickCount());
  228. // Create UNICODE_STRING structures into the buffer.
  229. RtlInitUnicodeString(&pCredentials->username, pszUsername);
  230. RtlInitUnicodeString(&pCredentials->domain, pszDomain);
  231. RtlInitUnicodeString(&pCredentials->password, pszPassword);
  232. // Run encode the password.
  233. RtlRunEncodeUnicodeString(&pCredentials->ucPasswordSeed, &pCredentials->password);
  234. // Make the pointers relative.
  235. pCredentials->username.Buffer = reinterpret_cast<WCHAR*>(reinterpret_cast<unsigned char*>(pCredentials->username.Buffer) - pUC);
  236. pCredentials->domain.Buffer = reinterpret_cast<WCHAR*>(reinterpret_cast<unsigned char*>(pCredentials->domain.Buffer) - pUC);
  237. pCredentials->password.Buffer = reinterpret_cast<WCHAR*>(reinterpret_cast<unsigned char*>(pCredentials->password.Buffer) - pUC);
  238. status = STATUS_SUCCESS;
  239. }
  240. else
  241. {
  242. status = STATUS_NO_MEMORY;
  243. }
  244. return(status);
  245. }
  246. // --------------------------------------------------------------------------
  247. // CCredentials::Unpack
  248. //
  249. // Arguments: pvData = Packed credentials from server.
  250. // pLogonIPCCredentials = Credentials received.
  251. //
  252. // Returns: NTSTATUS
  253. //
  254. // Purpose: Client side usage that unpacks the structure.
  255. //
  256. // History: 2001-01-12 vtan created
  257. // --------------------------------------------------------------------------
  258. NTSTATUS CCredentials::Unpack (void *pvData, LOGONIPC_CREDENTIALS *pLogonIPCCredentials)
  259. {
  260. NTSTATUS status;
  261. unsigned char *pUC;
  262. // Marshall the credentials from the struct that is transferred across
  263. // a named pipe.
  264. pUC = static_cast<unsigned char*>(pvData);
  265. if (pUC != NULL)
  266. {
  267. CREDENTIALS *pCredentials;
  268. pCredentials = reinterpret_cast<CREDENTIALS*>(pUC);
  269. // Make the relative pointers absolute again.
  270. pCredentials->username.Buffer = reinterpret_cast<WCHAR*>(pUC + PtrToUlong(pCredentials->username.Buffer));
  271. pCredentials->domain.Buffer = reinterpret_cast<WCHAR*>(pUC + PtrToUlong(pCredentials->domain.Buffer));
  272. pCredentials->password.Buffer = reinterpret_cast<WCHAR*>(pUC + PtrToUlong(pCredentials->password.Buffer));
  273. // Decode the run encoded password.
  274. RtlRunDecodeUnicodeString(pCredentials->ucPasswordSeed, &pCredentials->password);
  275. // Copy it to the caller's struct.
  276. (WCHAR*)lstrcpyW(pLogonIPCCredentials->userID.wszUsername, pCredentials->username.Buffer);
  277. (WCHAR*)lstrcpyW(pLogonIPCCredentials->userID.wszDomain, pCredentials->domain.Buffer);
  278. (WCHAR*)lstrcpyW(pLogonIPCCredentials->wszPassword, pCredentials->password.Buffer);
  279. // Zero the named pipe buffer.
  280. ZeroMemory(pCredentials->password.Buffer, (lstrlen(pCredentials->password.Buffer) + sizeof('\0')) * sizeof(WCHAR));
  281. status = STATUS_SUCCESS;
  282. }
  283. else
  284. {
  285. status = STATUS_INVALID_PARAMETER;
  286. }
  287. return(status);
  288. }
  289. // --------------------------------------------------------------------------
  290. // CCredentials::StaticInitialize
  291. //
  292. // Arguments: fCreate = Create or open the registry key.
  293. //
  294. // Returns: NTSTATUS
  295. //
  296. // Purpose: Creates the volatile key in the registry where the named pipe
  297. // name is placed for the client winlogon to pick. This section
  298. // is volatile and ACL'd to prevent access by anything other than
  299. // S-1-5-18 (NT AUTHORITY\SYSTEM).
  300. //
  301. // History: 2001-01-12 vtan created
  302. // 2001-04-03 vtan add opening capability
  303. // --------------------------------------------------------------------------
  304. NTSTATUS CCredentials::StaticInitialize (bool fCreate)
  305. {
  306. NTSTATUS status;
  307. if (s_hKeyCredentials == NULL)
  308. {
  309. LONG lErrorCode;
  310. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  311. // Build a security descriptor for the registry key that allows:
  312. // S-1-5-18 NT AUTHORITY\SYSTEM KEY_ALL_ACCESS
  313. static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
  314. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  315. {
  316. {
  317. &s_SecurityNTAuthority,
  318. 1,
  319. SECURITY_LOCAL_SYSTEM_RID,
  320. 0, 0, 0, 0, 0, 0, 0,
  321. KEY_ALL_ACCESS
  322. }
  323. };
  324. if (fCreate)
  325. {
  326. // Build a security descriptor that allows the described access above.
  327. pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  328. if (pSecurityDescriptor != NULL)
  329. {
  330. SECURITY_ATTRIBUTES securityAttributes;
  331. securityAttributes.nLength = sizeof(securityAttributes);
  332. securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  333. securityAttributes.bInheritHandle = FALSE;
  334. lErrorCode = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  335. s_szCredentialKeyName,
  336. 0,
  337. NULL,
  338. REG_OPTION_VOLATILE,
  339. KEY_QUERY_VALUE,
  340. &securityAttributes,
  341. &s_hKeyCredentials,
  342. NULL);
  343. (HLOCAL)LocalFree(pSecurityDescriptor);
  344. }
  345. else
  346. {
  347. lErrorCode = ERROR_OUTOFMEMORY;
  348. }
  349. }
  350. else
  351. {
  352. lErrorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  353. s_szCredentialKeyName,
  354. 0,
  355. KEY_QUERY_VALUE,
  356. &s_hKeyCredentials);
  357. }
  358. status = CStatusCode::StatusCodeOfErrorCode(lErrorCode);
  359. }
  360. else
  361. {
  362. status = STATUS_SUCCESS;
  363. }
  364. return(status);
  365. }
  366. // --------------------------------------------------------------------------
  367. // CCredentials::StaticTerminate
  368. //
  369. // Arguments: <none>
  370. //
  371. // Returns: NTSTATUS
  372. //
  373. // Purpose: If a key is present the release the resource.
  374. //
  375. // History: 2001-01-12 vtan created
  376. // --------------------------------------------------------------------------
  377. NTSTATUS CCredentials::StaticTerminate (void)
  378. {
  379. if (s_hKeyCredentials != NULL)
  380. {
  381. TW32(RegCloseKey(s_hKeyCredentials));
  382. s_hKeyCredentials = NULL;
  383. }
  384. return(STATUS_SUCCESS);
  385. }
  386. // --------------------------------------------------------------------------
  387. // CCredentials::GetConduitName
  388. //
  389. // Arguments: pszName = Buffer for name of named pipe returned.
  390. // dwNameSize = Count of characters of buffer.
  391. //
  392. // Returns: NTSTATUS
  393. //
  394. // Purpose: Gets the name of the named pipe from the volatile section of
  395. // the registry.
  396. //
  397. // History: 2001-01-12 vtan created
  398. // --------------------------------------------------------------------------
  399. NTSTATUS CCredentials::GetConduitName (TCHAR *pszName, DWORD dwNameSize)
  400. {
  401. LONG lErrorCode;
  402. CRegKey regKey;
  403. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  404. s_szCredentialKeyName,
  405. KEY_QUERY_VALUE);
  406. if (ERROR_SUCCESS == lErrorCode)
  407. {
  408. lErrorCode = regKey.GetString(s_szCredentialValueName, pszName, dwNameSize);
  409. }
  410. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  411. }
  412. // --------------------------------------------------------------------------
  413. // CCredentials::SetConduitName
  414. //
  415. // Arguments: pszName = Name of the named pipe to write.
  416. //
  417. // Returns: NTSTATUS
  418. //
  419. // Purpose: Writes the name of the named pipe to the secure volatile
  420. // section of the registry.
  421. //
  422. // History: 2001-01-12 vtan created
  423. // --------------------------------------------------------------------------
  424. NTSTATUS CCredentials::SetConduitName (const TCHAR *pszName)
  425. {
  426. LONG lErrorCode;
  427. CRegKey regKey;
  428. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  429. s_szCredentialKeyName,
  430. KEY_SET_VALUE);
  431. if (ERROR_SUCCESS == lErrorCode)
  432. {
  433. lErrorCode = regKey.SetString(s_szCredentialValueName, pszName);
  434. }
  435. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  436. }
  437. // --------------------------------------------------------------------------
  438. // CCredentials::ClearConduitName
  439. //
  440. // Arguments: <none>
  441. //
  442. // Returns: NTSTATUS
  443. //
  444. // Purpose: Clears the name of the named pipe in the volatile section of
  445. // the registry.
  446. //
  447. // History: 2001-01-12 vtan created
  448. // --------------------------------------------------------------------------
  449. NTSTATUS CCredentials::ClearConduitName (void)
  450. {
  451. LONG lErrorCode;
  452. CRegKey regKey;
  453. lErrorCode = regKey.Open(HKEY_LOCAL_MACHINE,
  454. s_szCredentialKeyName,
  455. KEY_SET_VALUE);
  456. if (ERROR_SUCCESS == lErrorCode)
  457. {
  458. lErrorCode = regKey.DeleteValue(s_szCredentialValueName);
  459. }
  460. return(CStatusCode::StatusCodeOfErrorCode(lErrorCode));
  461. }
  462. // --------------------------------------------------------------------------
  463. // CCredentials::CreateConduitName
  464. //
  465. // Arguments: dwNumber = Number to use.
  466. // pszName = Name generated return buffer.
  467. //
  468. // Returns: NTSTATUS
  469. //
  470. // Purpose: Generate a name based on the number for the named pipe. This
  471. // algorithm can be changed and all the callers will get the
  472. // result.
  473. //
  474. // History: 2001-01-12 vtan created
  475. // --------------------------------------------------------------------------
  476. NTSTATUS CCredentials::CreateConduitName (DWORD dwNumber, TCHAR *pszName)
  477. {
  478. (int)wsprintf(pszName, TEXT("\\\\.\\pipe\\LogonCredentials_0x%08x"), dwNumber);
  479. return(STATUS_SUCCESS);
  480. }
  481. // --------------------------------------------------------------------------
  482. // CCredentialServer::CCredentialServer
  483. //
  484. // Arguments: dwTimeout = Time out to wait.
  485. // pLogonIPCCredentials = Credentials to serve up.
  486. //
  487. // Returns: <none>
  488. //
  489. // Purpose: Constructor for the credential server. Allocate resources
  490. // required for the server end of the named pipe.
  491. //
  492. // History: 2001-01-11 vtan created
  493. // 2001-06-13 vtan added timeout
  494. // --------------------------------------------------------------------------
  495. CCredentialServer::CCredentialServer (DWORD dwTimeout, LOGONIPC_CREDENTIALS *pLogonIPCCredentials) :
  496. CThread(),
  497. _dwTimeout((dwTimeout != 0) ? dwTimeout : INFINITE),
  498. _fTerminate(false),
  499. _hPipe(NULL),
  500. _pvData(NULL),
  501. _dwSize(0)
  502. {
  503. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  504. ASSERTMSG(_dwTimeout != 0, "_dwTimeout cannot be 0 in CCredentialServer::CCredentialServer");
  505. ZeroMemory(&_overlapped, sizeof(_overlapped));
  506. // Build a security descriptor for the named pipe that allows:
  507. // S-1-5-18 NT AUTHORITY\SYSTEM GENERIC_ALL | STANDARD_RIGHTS_ALL
  508. // S-1-5-32-544 <local administrators> READ_CONTROL
  509. static SID_IDENTIFIER_AUTHORITY s_SecurityNTAuthority = SECURITY_NT_AUTHORITY;
  510. static const CSecurityDescriptor::ACCESS_CONTROL s_AccessControl[] =
  511. {
  512. {
  513. &s_SecurityNTAuthority,
  514. 1,
  515. SECURITY_LOCAL_SYSTEM_RID,
  516. 0, 0, 0, 0, 0, 0, 0,
  517. GENERIC_ALL | STANDARD_RIGHTS_ALL
  518. },
  519. {
  520. &s_SecurityNTAuthority,
  521. 2,
  522. SECURITY_BUILTIN_DOMAIN_RID,
  523. DOMAIN_ALIAS_RID_ADMINS,
  524. 0, 0, 0, 0, 0, 0,
  525. READ_CONTROL
  526. }
  527. };
  528. // Build a security descriptor that allows the described access above.
  529. pSecurityDescriptor = CSecurityDescriptor::Create(ARRAYSIZE(s_AccessControl), s_AccessControl);
  530. if (pSecurityDescriptor != NULL)
  531. {
  532. SECURITY_ATTRIBUTES securityAttributes;
  533. securityAttributes.nLength = sizeof(securityAttributes);
  534. securityAttributes.lpSecurityDescriptor = pSecurityDescriptor;
  535. securityAttributes.bInheritHandle = FALSE;
  536. // Create the named pipe with the security descriptor.
  537. if (NT_SUCCESS(CCredentials::CreateConduit(&securityAttributes, &_hPipe)))
  538. {
  539. ASSERTMSG(_hPipe != NULL, "NULL hPipe but success NTSTATUS code in CCredentialServer::CCredentialServer");
  540. // Create an event for overlapped I/O.
  541. _overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  542. }
  543. (HLOCAL)LocalFree(pSecurityDescriptor);
  544. // Package credentials.
  545. TSTATUS(CCredentials::Pack(pLogonIPCCredentials, &_pvData, &_dwSize));
  546. }
  547. }
  548. // --------------------------------------------------------------------------
  549. // CCredentialServer::~CCredentialServer
  550. //
  551. // Arguments: <none>
  552. //
  553. // Returns: <none>
  554. //
  555. // Purpose: Destructor for CCredentialServer. Release memory and
  556. // resources.
  557. //
  558. // History: 2001-01-11 vtan created
  559. // --------------------------------------------------------------------------
  560. CCredentialServer::~CCredentialServer (void)
  561. {
  562. ReleaseMemory(_pvData);
  563. ReleaseHandle(_overlapped.hEvent);
  564. ReleaseHandle(_hPipe);
  565. }
  566. // --------------------------------------------------------------------------
  567. // CCredentialServer::IsReady
  568. //
  569. // Arguments: <none>
  570. //
  571. // Returns: bool
  572. //
  573. // Purpose: Is the credential server ready to run?
  574. //
  575. // History: 2001-01-11 vtan created
  576. // --------------------------------------------------------------------------
  577. bool CCredentialServer::IsReady (void) const
  578. {
  579. return((_hPipe != NULL) && (_overlapped.hEvent != NULL));
  580. }
  581. // --------------------------------------------------------------------------
  582. // CCredentialServer::Start
  583. //
  584. // Arguments: pLogonIPCCredentials = Logon credentials.
  585. // dwWaitTime = Timeout value.
  586. //
  587. // Returns: NTSTATUS
  588. //
  589. // Purpose: Starts a new thread as the server of the credentials for the
  590. // new logon session.
  591. //
  592. // History: 2001-04-06 vtan created
  593. // --------------------------------------------------------------------------
  594. NTSTATUS CCredentialServer::Start (LOGONIPC_CREDENTIALS *pLogonIPCCredentials, DWORD dwWaitTime)
  595. {
  596. NTSTATUS status;
  597. CCredentialServer *pCredentialServer;
  598. // Otherwise credentials need to be transferred across sessions to
  599. // a newly created session. Start the credential transfer server.
  600. status = STATUS_NO_MEMORY;
  601. pCredentialServer = new CCredentialServer(dwWaitTime, pLogonIPCCredentials);
  602. if (pCredentialServer != NULL)
  603. {
  604. if (pCredentialServer->IsCreated() && pCredentialServer->IsReady())
  605. {
  606. pCredentialServer->Resume();
  607. // If the server is set up then disconnect the console.
  608. // If this fails then we'll let the server thread timeout
  609. // and terminate itself eventually.
  610. if (WinStationDisconnect(SERVERNAME_CURRENT, USER_SHARED_DATA->ActiveConsoleId, TRUE) != FALSE)
  611. {
  612. status = STATUS_SUCCESS;
  613. if ((dwWaitTime != 0) && (WAIT_OBJECT_0 != pCredentialServer->WaitForCompletion(dwWaitTime)))
  614. {
  615. status = STATUS_UNSUCCESSFUL;
  616. }
  617. }
  618. else
  619. {
  620. status = CStatusCode::StatusCodeOfLastError();
  621. }
  622. if (!NT_SUCCESS(status))
  623. {
  624. pCredentialServer->ExecutePrematureTermination();
  625. }
  626. }
  627. else
  628. {
  629. TSTATUS(pCredentialServer->Terminate());
  630. }
  631. pCredentialServer->Release();
  632. }
  633. return(status);
  634. }
  635. // --------------------------------------------------------------------------
  636. // CCredentialServer::Start
  637. //
  638. // Arguments: pszUsername = User name.
  639. // pszDomain = Domain.
  640. // pszPassword = Password.
  641. // dwWaitTime = Timeout value.
  642. //
  643. // Returns: NTSTATUS
  644. //
  645. // Purpose: Package up the parameters into the required struct and pass
  646. // it to the real function.
  647. //
  648. // History: 2001-04-06 vtan created
  649. // --------------------------------------------------------------------------
  650. NTSTATUS CCredentialServer::Start (const WCHAR *pszUsername, const WCHAR *pszDomain, WCHAR *pszPassword, DWORD dwWaitTime)
  651. {
  652. LOGONIPC_CREDENTIALS logonIPCCredentials;
  653. (WCHAR*)lstrcpynW(logonIPCCredentials.userID.wszUsername, pszUsername, ARRAYSIZE(logonIPCCredentials.userID.wszUsername));
  654. (WCHAR*)lstrcpynW(logonIPCCredentials.userID.wszDomain, pszDomain, ARRAYSIZE(logonIPCCredentials.userID.wszDomain));
  655. (WCHAR*)lstrcpynW(logonIPCCredentials.wszPassword, pszPassword, ARRAYSIZE(logonIPCCredentials.wszPassword));
  656. return(Start(&logonIPCCredentials, dwWaitTime));
  657. }
  658. // --------------------------------------------------------------------------
  659. // CCredentialServer::Entry
  660. //
  661. // Arguments: <none>
  662. //
  663. // Returns: DWORD
  664. //
  665. // Purpose: Handles the server side of the named pipe credential transfer.
  666. //
  667. // History: 2001-01-11 vtan created
  668. // --------------------------------------------------------------------------
  669. DWORD CCredentialServer::Entry (void)
  670. {
  671. DWORD dwWaitResult;
  672. // Wait for a client to connect to the named pipe. Wait no more than 30 seconds.
  673. (BOOL)ConnectNamedPipe(_hPipe, &_overlapped);
  674. dwWaitResult = WaitForSingleObjectEx(_overlapped.hEvent, _dwTimeout, TRUE);
  675. if (!_fTerminate && (dwWaitResult == WAIT_OBJECT_0))
  676. {
  677. // Write the size of the buffer to the named pipe for the client to retrieve.
  678. TBOOL(ResetEvent(_overlapped.hEvent));
  679. if (WriteFileEx(_hPipe,
  680. &_dwSize,
  681. sizeof(_dwSize),
  682. &_overlapped,
  683. CB_FileIOCompletionRoutine) != FALSE)
  684. {
  685. do
  686. {
  687. dwWaitResult = WaitForSingleObjectEx(_overlapped.hEvent, _dwTimeout, TRUE);
  688. } while (!_fTerminate && (dwWaitResult == WAIT_IO_COMPLETION));
  689. if (!_fTerminate)
  690. {
  691. // Write the actual contents of the credentials to the named pipe.
  692. TBOOL(ResetEvent(_overlapped.hEvent));
  693. if (WriteFileEx(_hPipe,
  694. _pvData,
  695. _dwSize,
  696. &_overlapped,
  697. CB_FileIOCompletionRoutine) != FALSE)
  698. {
  699. do
  700. {
  701. dwWaitResult = WaitForSingleObjectEx(_overlapped.hEvent, _dwTimeout, TRUE);
  702. } while (!_fTerminate && (dwWaitResult == WAIT_IO_COMPLETION));
  703. }
  704. }
  705. }
  706. }
  707. #ifdef DEBUG
  708. else
  709. {
  710. INFORMATIONMSG("Wait on named pipe LogonCredentials abandoned in CCredentialsServer::Entry");
  711. }
  712. #endif
  713. // Disconnect the server side invalidating the client handle.
  714. TBOOL(DisconnectNamedPipe(_hPipe));
  715. // Clear the name of the named pipe used in the volatile section of the registry.
  716. TSTATUS(CCredentials::ClearConduit());
  717. return(0);
  718. }
  719. // --------------------------------------------------------------------------
  720. // CCredentialServer::ExecutePrematureTermination
  721. //
  722. // Arguments: <none>
  723. //
  724. // Returns: <none>
  725. //
  726. // Purpose: Queues an APC to the server thread to force it to terminate.
  727. // Don't check for an error. Don't wait for termination.
  728. // Reference counting should ensure that abnormal termination
  729. // will still clean up references correctly.
  730. //
  731. // History: 2001-06-13 vtan created
  732. // --------------------------------------------------------------------------
  733. void CCredentialServer::ExecutePrematureTermination (void)
  734. {
  735. _fTerminate = true;
  736. (BOOL)QueueUserAPC(CB_APCProc, _hThread, NULL);
  737. }
  738. // --------------------------------------------------------------------------
  739. // CCredentialServer::CB_APCProc
  740. //
  741. // Arguments: dwParam = User defined data.
  742. //
  743. // Returns: <none>
  744. //
  745. // Purpose: APCProc executed on thread in alertable wait state.
  746. //
  747. // History: 2001-06-13 vtan created
  748. // --------------------------------------------------------------------------
  749. void CALLBACK CCredentialServer::CB_APCProc (ULONG_PTR dwParam)
  750. {
  751. UNREFERENCED_PARAMETER(dwParam);
  752. }
  753. // --------------------------------------------------------------------------
  754. // CCredentialServer::CB_FileIOCompletionRoutine
  755. //
  756. // Arguments: dwErrorCode = Error code of operation.
  757. // dwNumberOfBytesTransferred = Number of bytes transferred.
  758. // lpOverlapped = OVERLAPPED structure.
  759. //
  760. // Returns: <none>
  761. //
  762. // Purpose: Does nothing but is required for overlapped I/O.
  763. //
  764. // History: 2001-01-11 vtan created
  765. // --------------------------------------------------------------------------
  766. void CALLBACK CCredentialServer::CB_FileIOCompletionRoutine (DWORD dwErrorCode, DWORD dwNumberOfBytesTransferred, LPOVERLAPPED lpOverlapped)
  767. {
  768. UNREFERENCED_PARAMETER(dwErrorCode);
  769. UNREFERENCED_PARAMETER(dwNumberOfBytesTransferred);
  770. TBOOL(SetEvent(lpOverlapped->hEvent));
  771. }
  772. // --------------------------------------------------------------------------
  773. // CCredentialClient::Get
  774. //
  775. // Arguments: pLogonIPCCredentials = Credentials returned from server.
  776. //
  777. // Returns: NTSTATUS
  778. //
  779. // Purpose: Opens and reads the named pipe for the credential transfer
  780. // from server (previous winlogon) to client (this winlogon).
  781. //
  782. // History: 2001-01-12 vtan created
  783. // --------------------------------------------------------------------------
  784. NTSTATUS CCredentialClient::Get (LOGONIPC_CREDENTIALS *pLogonIPCCredentials)
  785. {
  786. NTSTATUS status;
  787. HANDLE hPipe;
  788. // Open the named pipe.
  789. status = CCredentials::OpenConduit(&hPipe);
  790. if (NT_SUCCESS(status))
  791. {
  792. DWORD dwSize, dwNumberOfBytesRead;
  793. ASSERTMSG(hPipe != INVALID_HANDLE_VALUE, "INVALID_HANDLE_VALUE in CCredentialClient::Get");
  794. // Read the size of the buffer from the named pipe.
  795. if (ReadFile(hPipe,
  796. &dwSize,
  797. sizeof(dwSize),
  798. &dwNumberOfBytesRead,
  799. NULL) != FALSE)
  800. {
  801. void *pvData;
  802. // Allocate a block of memory for the buffer to be received
  803. // from the named pipe.
  804. pvData = LocalAlloc(LMEM_FIXED, dwSize);
  805. if (pvData != NULL)
  806. {
  807. // Read the buffer from the named pipe.
  808. if (ReadFile(hPipe,
  809. pvData,
  810. dwSize,
  811. &dwNumberOfBytesRead,
  812. NULL) != FALSE)
  813. {
  814. // Make an additional read to release the server side of the
  815. // named pipe.
  816. (BOOL)ReadFile(hPipe,
  817. &dwSize,
  818. sizeof(dwSize),
  819. &dwNumberOfBytesRead,
  820. NULL);
  821. // Unpack the data into the LOGONIPC_CREDENTIALS parameter buffer.
  822. status = CCredentials::Unpack(pvData, pLogonIPCCredentials);
  823. }
  824. else
  825. {
  826. status = CStatusCode::StatusCodeOfLastError();
  827. }
  828. (HLOCAL)LocalFree(pvData);
  829. }
  830. else
  831. {
  832. status = STATUS_NO_MEMORY;
  833. }
  834. }
  835. else
  836. {
  837. status = CStatusCode::StatusCodeOfLastError();
  838. }
  839. TBOOL(CloseHandle(hPipe));
  840. }
  841. return(status);
  842. }