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.

939 lines
27 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. userkey.c
  5. Abstract:
  6. Implentation of the functions that get and generate user session keys
  7. RtlCalculateUserSessionKeyLm
  8. RtlCalculateUserSessionKeyNt
  9. RtlGetUserSessionKeyClient
  10. RtlGetUserSessionKeyServer
  11. Author:
  12. David Chalmers (Davidc) 10-21-91
  13. Revision History:
  14. --*/
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <ntddnfs.h>
  19. #include <rpc.h>
  20. #include <rpcndr.h>
  21. #include <crypt.h>
  22. #include <srvfsctl.h> // Server definitions
  23. #include <status.h> // Server return codes
  24. //
  25. // Define this if you want to know all about user session keys
  26. //
  27. // #define DEBUG_USER_SESSION_KEYS
  28. #define REDIRECTOR_DEVICENAME L"\\Device\\LanmanRedirector\\"
  29. #define REDIRECTOR_IPC_FILENAME L"\\IPC$"
  30. //
  31. // Define the user session key to be used for local connections
  32. // Make sure the initial data fills the structure completely !
  33. //
  34. USER_SESSION_KEY LocalSessionKey = { 'S', 'y', 's', 't', 'e', 'm', 'L', 'i',
  35. 'b', 'r', 'a', 'r', 'y', 'D', 'T', 'C'
  36. };
  37. //
  38. // Define the user session key that represents an error.
  39. // This value will be generated by other parts of the system on failure.
  40. // We will check for it in our query code and return an error if it's found.
  41. //
  42. USER_SESSION_KEY ErrorSessionKey = { 0, 0, 0, 0, 0, 0, 0, 0,
  43. 0, 0, 0, 0, 0, 0, 0, 0
  44. };
  45. NTSTATUS
  46. RtlCalculateUserSessionKeyLm(
  47. IN PLM_RESPONSE LmResponse,
  48. IN PLM_OWF_PASSWORD LmOwfPassword,
  49. OUT PUSER_SESSION_KEY UserSessionKey)
  50. /*++
  51. Routine Description:
  52. Takes the passed Response and OwfPassword and generates a UserSessionKey.
  53. The current implementation takes the one-way-function of the OwfPassword
  54. and returns this as the key.
  55. Arguments:
  56. LmResponse - The response sent during session setup.
  57. LmOwfPassword - The hashed version of the user's password.
  58. Return Values:
  59. STATUS_SUCCESS - The function was completed successfully.
  60. The UserSessionKey is in UserSessionKey.
  61. STATUS_UNSUCCESSFUL - Something failed. The UserSessionKey is undefined.
  62. --*/
  63. {
  64. NTSTATUS Status;
  65. NT_PASSWORD NtPassword;
  66. //
  67. // Make the Owf password look like an NT password
  68. //
  69. NtPassword.Buffer = (PWSTR)LmOwfPassword; // We can do this cast because we
  70. // know the OWF routine treats this
  71. // pointer as a byte pointer.
  72. NtPassword.Length = sizeof(*LmOwfPassword);
  73. NtPassword.MaximumLength = sizeof(*LmOwfPassword);
  74. //
  75. // Calculate the OWF of the OwfPassword
  76. //
  77. ASSERT(sizeof(NT_OWF_PASSWORD) == sizeof(*UserSessionKey));
  78. Status = RtlCalculateNtOwfPassword( &NtPassword,
  79. (PNT_OWF_PASSWORD)UserSessionKey
  80. );
  81. if (!NT_SUCCESS(Status)) {
  82. KdPrint(("RtlCalculateUserSessionKeyLm : OWF calculation failed, status = 0x%lx\n", Status));
  83. return(Status);
  84. }
  85. //
  86. // Check if we've generated the error session key
  87. //
  88. if (RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
  89. sizeof(*UserSessionKey)) == sizeof(*UserSessionKey)) {
  90. #ifdef DEBUG_USER_SESSION_KEYS
  91. KdPrint(("RtlCalculateSessionKeyLm - generated error session key, modifying it\n"));
  92. #endif
  93. //
  94. // Move away from the error session key
  95. //
  96. UserSessionKey->data[0].data[0] ++;
  97. ASSERT(RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
  98. sizeof(*UserSessionKey)) != sizeof(*UserSessionKey));
  99. }
  100. #ifdef DEBUG_USER_SESSION_KEYS
  101. KdPrint(("RtlCalculateUserSessionKeyLm : Key = 0x%lx : %lx : %lx : %lx\n",
  102. ((PULONG)UserSessionKey)[0], ((PULONG)UserSessionKey)[1],
  103. ((PULONG)UserSessionKey)[2], ((PULONG)UserSessionKey)[3]));
  104. #endif
  105. return(STATUS_SUCCESS);
  106. UNREFERENCED_PARAMETER(LmResponse);
  107. }
  108. NTSTATUS
  109. RtlCalculateUserSessionKeyNt(
  110. IN PNT_RESPONSE NtResponse,
  111. IN PNT_OWF_PASSWORD NtOwfPassword,
  112. OUT PUSER_SESSION_KEY UserSessionKey)
  113. /*++
  114. Routine Description:
  115. Takes the passed Response and OwfPassword and generates a UserSessionKey.
  116. Arguments:
  117. NtResponse - The response sent during session setup.
  118. NtOwfPassword - The hashed version of the user's password.
  119. Return Values:
  120. STATUS_SUCCESS - The function was completed successfully.
  121. The UserSessionKey is in UserSessionKey.
  122. STATUS_UNSUCCESSFUL - Something failed. The UserSessionKey is undefined.
  123. --*/
  124. {
  125. // Just call the LM version
  126. ASSERT(sizeof(NT_RESPONSE) == sizeof(LM_RESPONSE));
  127. ASSERT(sizeof(NT_OWF_PASSWORD) == sizeof(LM_OWF_PASSWORD));
  128. return(RtlCalculateUserSessionKeyLm((PLM_RESPONSE)NtResponse,
  129. (PLM_OWF_PASSWORD)NtOwfPassword,
  130. UserSessionKey));
  131. }
  132. NTSTATUS
  133. RtlGetUserSessionKeyClientBinding(
  134. IN PVOID RpcBindingHandle,
  135. OUT HANDLE *RedirHandle,
  136. OUT PUSER_SESSION_KEY UserSessionKey)
  137. /*++
  138. Routine Description:
  139. Returns the user session key associated with an rpc connection.
  140. This function should be called by the client side of the connection only.
  141. Arguments:
  142. RpcBindingHandle - The rpc connection we're interested in
  143. RedirHandle - Returns a handle to the redir. Since RpcBindingHandles don't represent
  144. and open connection to the server, we have to ensure the connection stays open
  145. until the server side has a chance to get this same UserSessionKey. The only
  146. way to do that is to keep the connect open.
  147. Returns NULL if no handle is needed.
  148. This handle should be closed by calling NtClose.
  149. UserSessionKey - The user session key is returned here
  150. Return Values:
  151. STATUS_SUCCESS - The function was completed successfully.
  152. The UserSessionKey is in UserSessionKey.
  153. STATUS_LOCAL_USER_SESSION_KEY - An informational status value.
  154. - The rpc connection is local, the usersessionkey returned
  155. - is constant and not unique to this connection.
  156. - There is little to be gained by encrypting data over
  157. - this connection
  158. STATUS_NO_USER_SESSION_KEY - No session key exists for this session.
  159. ------ these come from parsebinding -------
  160. RPC_NT_OUT_OF_MEMORY - Insufficent memory is available to allocate
  161. space for the fields of the string binding.
  162. RPC_NT_INVALID_STRING_BINDING - The string binding is syntactically
  163. invalid.
  164. RPC_NT_INVALID_ARG - The string binding is not specified
  165. (ie. ARGUMENT_PRESENT(StringBinding) is false).
  166. --*/
  167. {
  168. NTSTATUS Status, IgnoreStatus;
  169. WCHAR *StringBinding;
  170. WCHAR *ServerNameZ;
  171. WCHAR *BareServerNameZ; // Points to server name minus leading '\'s
  172. OBJECT_ATTRIBUTES Attributes;
  173. UNICODE_STRING ServerName;
  174. UNICODE_STRING RedirDevice;
  175. UNICODE_STRING IpcFileName;
  176. UNICODE_STRING ServerIpcFileName;
  177. USHORT LengthRequired;
  178. IO_STATUS_BLOCK IoStatusBlock;
  179. LMR_REQUEST_PACKET RdrRequestPacket;
  180. LMR_CONNECTION_INFO_2 ConnectionInfo;
  181. //
  182. // Get the string description of the binding from the rpc handle
  183. //
  184. *RedirHandle = NULL;
  185. Status = (NTSTATUS)I_RpcMapWin32Status(
  186. RpcBindingToStringBindingW(RpcBindingHandle, &StringBinding));
  187. if (!NT_SUCCESS(Status)) {
  188. KdPrint(("RtlGetUserSessionKeyClient - failed to get stringbinding, Status = 0x%lx\n\r", Status));
  189. return(Status);
  190. }
  191. //
  192. // Parse the stringbinding to get the server name
  193. //
  194. Status = (NTSTATUS)I_RpcMapWin32Status(RpcStringBindingParseW(
  195. StringBinding,
  196. NULL, // object uid
  197. NULL, // protseq !
  198. &ServerNameZ, // network address
  199. NULL, // endpoint
  200. NULL // network options
  201. ));
  202. //
  203. // We're finished with the string binding
  204. //
  205. IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&StringBinding));
  206. ASSERT(NT_SUCCESS(IgnoreStatus));
  207. //
  208. // Check the result of binding parse
  209. //
  210. if (!NT_SUCCESS(Status)) {
  211. KdPrint(("RtlGetUserSessionKeyClient - failed to parse stringbinding, status = 0x%lx\n\r", Status));
  212. return(Status);
  213. }
  214. //
  215. // Check for a local connection
  216. //
  217. if ( (ServerNameZ == NULL) || (ServerNameZ[0] == UNICODE_NULL) ) {
  218. #ifdef DEBUG_USER_SESSION_KEYS
  219. KdPrint(("RtlGetUserSessionKeyClient - server name is NULL, returning local key\n"));
  220. #endif
  221. //
  222. // Use a constant, default session key
  223. //
  224. *UserSessionKey = LocalSessionKey;
  225. IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
  226. ASSERT(NT_SUCCESS(IgnoreStatus));
  227. return(STATUS_LOCAL_USER_SESSION_KEY);
  228. }
  229. //
  230. // Strip the leading '\'s from the server name
  231. //
  232. BareServerNameZ = ServerNameZ;
  233. while (*BareServerNameZ == L'\\') {
  234. BareServerNameZ ++;
  235. }
  236. //
  237. // Set up a counted string for out server name
  238. //
  239. RtlInitUnicodeString(&ServerName, BareServerNameZ);
  240. //
  241. // Check for the local server name '.'
  242. //
  243. if ( (ServerName.Length == sizeof(*ServerName.Buffer)) &&
  244. (ServerName.Buffer[0] == L'.') ) {
  245. #ifdef DEBUG_USER_SESSION_KEYS
  246. KdPrint(("RtlGetUserSessionKeyClient - server name is '.', returning local key\n"));
  247. #endif
  248. //
  249. // Use a constant, default session key
  250. //
  251. *UserSessionKey = LocalSessionKey;
  252. IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
  253. ASSERT(NT_SUCCESS(IgnoreStatus));
  254. return(STATUS_LOCAL_USER_SESSION_KEY);
  255. }
  256. //
  257. // Create a redirector ipc file name for the referenced server
  258. //
  259. RtlInitUnicodeString(&RedirDevice, REDIRECTOR_DEVICENAME);
  260. RtlInitUnicodeString(&IpcFileName, REDIRECTOR_IPC_FILENAME);
  261. LengthRequired = RedirDevice.Length + ServerName.Length + IpcFileName.Length;
  262. //
  263. // Allocate space for the ipc file name we will create
  264. //
  265. ServerIpcFileName.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, LengthRequired);
  266. if (ServerIpcFileName.Buffer == NULL) {
  267. KdPrint(("RtlGetUserSessionKeyClient - failed to allocate space for server name (%d bytes)\n", LengthRequired));
  268. IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
  269. ASSERT(NT_SUCCESS(IgnoreStatus));
  270. return(STATUS_INSUFFICIENT_RESOURCES);
  271. }
  272. ServerIpcFileName.Length = 0;
  273. ServerIpcFileName.MaximumLength = LengthRequired;
  274. //
  275. // ServerIpcFileName = \Device\LanmanRedirector\ + servername + \ipc$
  276. //
  277. RtlCopyUnicodeString(&ServerIpcFileName, &RedirDevice);
  278. IgnoreStatus = RtlAppendUnicodeStringToString(&ServerIpcFileName, &ServerName);
  279. ASSERT(NT_SUCCESS(IgnoreStatus));
  280. IgnoreStatus = RtlAppendUnicodeStringToString(&ServerIpcFileName, &IpcFileName);
  281. ASSERT(NT_SUCCESS(IgnoreStatus));
  282. //
  283. // Don't need the server name any more
  284. //
  285. IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
  286. ASSERT(NT_SUCCESS(IgnoreStatus));
  287. //
  288. // Open up the redirector ipc file
  289. //
  290. InitializeObjectAttributes( &Attributes,
  291. &ServerIpcFileName,
  292. OBJ_CASE_INSENSITIVE,
  293. NULL,
  294. NULL );
  295. Status = NtOpenFile( RedirHandle,
  296. FILE_READ_DATA | // access required to get connection info
  297. SYNCHRONIZE, // access required to wait on object
  298. &Attributes,
  299. &IoStatusBlock,
  300. FILE_SHARE_READ,
  301. FILE_CREATE_TREE_CONNECTION );
  302. //
  303. // We're finished with the ipc filename
  304. //
  305. RtlFreeHeap( RtlProcessHeap(), 0, ServerIpcFileName.Buffer );
  306. ServerIpcFileName.Buffer = NULL;
  307. //
  308. // Check the result of the open
  309. //
  310. if (!NT_SUCCESS(Status)) {
  311. KdPrint(("RtlGetUserSessionKeyClient - failed to open redirector, status = 0x%lx\n\r", Status));
  312. *RedirHandle = NULL;
  313. return(Status);
  314. }
  315. //
  316. // Get the connection info for this link
  317. //
  318. RdrRequestPacket.Version = REQUEST_PACKET_VERSION;
  319. RdrRequestPacket.Level = 2; // We want the session key.
  320. Status = NtFsControlFile( *RedirHandle,
  321. NULL, // Event
  322. NULL, // APC routine
  323. NULL, // APC context
  324. &IoStatusBlock,
  325. FSCTL_LMR_GET_CONNECTION_INFO,
  326. &RdrRequestPacket, // Input buffer
  327. sizeof(RdrRequestPacket), // Input buffer length
  328. &ConnectionInfo, // Output buffer
  329. sizeof(ConnectionInfo) // Output buffer length
  330. );
  331. //
  332. // remove the reference created on the existing connection.
  333. // this logic assumes the caller of RtlGetUserSessionKeyClientXXX()
  334. // has already established a connection.
  335. //
  336. {
  337. LMR_REQUEST_PACKET Rrp; // Redirector request packet
  338. NTSTATUS TempStatus;
  339. RtlZeroMemory(&Rrp,sizeof(LMR_REQUEST_PACKET));
  340. Rrp.Level = USE_FORCE; // this tells rdr2 to take away the extra reference
  341. // to connection strucutre even when files are open.
  342. Rrp.Version = REQUEST_PACKET_VERSION;
  343. TempStatus = NtFsControlFile(
  344. *RedirHandle, // handle
  345. NULL, // no event
  346. NULL, // no APC routine
  347. NULL, // no APC context
  348. &IoStatusBlock, // I/O stat blk (set)
  349. FSCTL_LMR_DELETE_CONNECTION, // func code
  350. &Rrp,
  351. sizeof(LMR_REQUEST_PACKET),
  352. NULL,
  353. 0
  354. );
  355. //
  356. // block on the delete if necessary.
  357. //
  358. if( TempStatus == STATUS_PENDING )
  359. {
  360. NtWaitForSingleObject( *RedirHandle, TRUE, NULL );
  361. }
  362. }
  363. //
  364. // Check the result of the control file call
  365. //
  366. if (!NT_SUCCESS(Status)) {
  367. IgnoreStatus = NtClose(*RedirHandle);
  368. ASSERT(NT_SUCCESS(IgnoreStatus));
  369. *RedirHandle = NULL;
  370. KdPrint(("RtlGetUserSessionKeyClient - failed to get connection info, status = 0x%lx\n\r", Status));
  371. ASSERT(FALSE);
  372. return(Status);
  373. }
  374. //
  375. // Copy the session key into the passed buffer
  376. //
  377. *UserSessionKey = *(PUSER_SESSION_KEY)(ConnectionInfo.UserSessionKey);
  378. //
  379. // Check for the error session key
  380. //
  381. if (RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
  382. sizeof(*UserSessionKey)) == sizeof(*UserSessionKey)) {
  383. #ifdef DEBUG_USER_SESSION_KEYS
  384. KdPrint(("RtlGetUserSessionKeyClient - got error session key, returning error\n"));
  385. #endif
  386. Status = STATUS_NO_USER_SESSION_KEY;
  387. IgnoreStatus = NtClose(*RedirHandle);
  388. ASSERT(NT_SUCCESS(IgnoreStatus));
  389. *RedirHandle = NULL;
  390. }
  391. #ifdef DEBUG_USER_SESSION_KEYS
  392. KdPrint(("RtlGetUserSessionKeyClient : Key = 0x%lx : %lx : %lx : %lx\n",
  393. ((PULONG)UserSessionKey)[0], ((PULONG)UserSessionKey)[1],
  394. ((PULONG)UserSessionKey)[2], ((PULONG)UserSessionKey)[3]));
  395. #endif
  396. return(Status);
  397. }
  398. NTSTATUS
  399. RtlGetUserSessionKeyClient(
  400. IN PVOID RpcContextHandle,
  401. OUT PUSER_SESSION_KEY UserSessionKey)
  402. /*++
  403. Routine Description:
  404. Returns the user session key associated with an rpc connection.
  405. This function should be called by the client side of the connection only.
  406. Arguments:
  407. RpcContextHandle - The rpc connection we're interested in
  408. This can also be an RPC binding handle.
  409. UserSessionKey - The user session key is returned here
  410. Return Values:
  411. STATUS_SUCCESS - The function was completed successfully.
  412. The UserSessionKey is in UserSessionKey.
  413. STATUS_LOCAL_USER_SESSION_KEY - An informational status value.
  414. - The rpc connection is local, the usersessionkey returned
  415. - is constant and not unique to this connection.
  416. - There is little to be gained by encrypting data over
  417. - this connection
  418. STATUS_NO_USER_SESSION_KEY - No session key exists for this session.
  419. ------ these come from parsebinding -------
  420. RPC_NT_OUT_OF_MEMORY - Insufficent memory is available to allocate
  421. space for the fields of the string binding.
  422. RPC_NT_INVALID_STRING_BINDING - The string binding is syntactically
  423. invalid.
  424. RPC_NT_INVALID_ARG - The string binding is not specified
  425. (ie. ARGUMENT_PRESENT(StringBinding) is false).
  426. --*/
  427. {
  428. NTSTATUS Status;
  429. HANDLE RedirHandle = NULL;
  430. //
  431. // Call the worker routine.
  432. //
  433. Status = RtlGetUserSessionKeyClientBinding(
  434. NDRCContextBinding((NDR_CCONTEXT)RpcContextHandle),
  435. &RedirHandle,
  436. UserSessionKey );
  437. if ( RedirHandle != NULL ) {
  438. NtClose( RedirHandle );
  439. }
  440. return Status;
  441. }
  442. NTSTATUS
  443. RtlGetUserSessionKeyServer(
  444. IN PVOID RpcContextHandle OPTIONAL,
  445. OUT PUSER_SESSION_KEY UserSessionKey)
  446. /*++
  447. Routine Description:
  448. Returns the user session key associated with an rpc connection.
  449. This function should be called by the server side of the connection only.
  450. Arguments:
  451. RpcBindingHandle - The rpc connection we're interested in
  452. - Note this parameter is ignored for now
  453. UserSessionKey - The user session key is returned here
  454. Return Values:
  455. STATUS_SUCCESS - The function was completed successfully.
  456. The UserSessionKey is in UserSessionKey.
  457. STATUS_LOCAL_USER_SESSION_KEY - An informational status value.
  458. - The rpc connection is local, the usersessionkey returned
  459. - is constant and not unique to this connection.
  460. - There is little to be gained by encrypting data over
  461. - this connection
  462. STATUS_NO_USER_SESSION_KEY - No session key exists for this session.
  463. --*/
  464. {
  465. NTSTATUS Status, IgnoreStatus;
  466. HANDLE TokenHandle;
  467. TOKEN_STATISTICS TokenInfo;
  468. ULONG ReturnedLength;
  469. UNICODE_STRING ServerDevice;
  470. ANSI_STRING AnsiString;
  471. OBJECT_ATTRIBUTES Attributes;
  472. IO_STATUS_BLOCK IoStatusBlock;
  473. HANDLE ServerHandle;
  474. RPC_BINDING_HANDLE RpcBindingHandle;
  475. unsigned int RpcClientLocalFlag;
  476. //
  477. // Get the binding handle for this connection
  478. //
  479. // LATER RpcBindingHandle = (RPC_BINDING_HANDLE) RpcContextHandle;
  480. RpcBindingHandle = NULL;
  481. //
  482. // If this is a local connection then we can immediately
  483. // return the local session key.
  484. //
  485. Status = I_RpcBindingIsClientLocal(RpcBindingHandle, &RpcClientLocalFlag);
  486. if (!NT_SUCCESS(Status)) {
  487. KdPrint(("RtlGetUserSessionKeyServer: RpcBindingIsClientLocal failed, status = 0x%lx\n", Status));
  488. return(Status);
  489. }
  490. if (RpcClientLocalFlag != 0) {
  491. *UserSessionKey = LocalSessionKey;
  492. #ifdef DEBUG_USER_SESSION_KEYS
  493. KdPrint(("RtlGetUserSessionKeyServer: client is local, returning local key\n"));
  494. #endif
  495. return (STATUS_LOCAL_USER_SESSION_KEY);
  496. }
  497. //
  498. // Get a handle to the client's token
  499. //
  500. Status = NtOpenThreadToken(NtCurrentThread(),
  501. TOKEN_QUERY,
  502. TRUE,
  503. &TokenHandle);
  504. //
  505. // If we couldn't open the thread token because we weren't impersonating
  506. // then impersonate and try again.
  507. //
  508. if (!NT_SUCCESS(Status)) {
  509. //
  510. // Check we failed only because we weren't impersonating
  511. //
  512. if (Status != STATUS_NO_TOKEN) {
  513. KdPrint(("RtlGetUserSessionKeyServer - failed to open thread token, status = 0x%lx\n", Status));
  514. ASSERT(FALSE);
  515. return(Status);
  516. }
  517. //
  518. // Impersonate the client ourselves
  519. //
  520. Status = I_RpcMapWin32Status(RpcImpersonateClient(RpcBindingHandle));
  521. if (!NT_SUCCESS(Status)) {
  522. KdPrint(("RtlGetUserSessionKeyServer - RpcImpersonateClient failed, status = 0x%lx\n", Status));
  523. ASSERT(FALSE);
  524. return(Status);
  525. }
  526. //
  527. // Try to get a token handle now we're impersonating
  528. //
  529. Status = NtOpenThreadToken(NtCurrentThread(),
  530. TOKEN_QUERY,
  531. TRUE,
  532. &TokenHandle);
  533. if (!NT_SUCCESS(Status)) {
  534. KdPrint(("RtlGetUserSessionKeyServer - failed to open thread token after impersonating, status = 0x%lx\n", Status));
  535. ASSERT(FALSE);
  536. IgnoreStatus = I_RpcMapWin32Status(RpcRevertToSelf());
  537. ASSERT(NT_SUCCESS(IgnoreStatus));
  538. return(Status);
  539. }
  540. //
  541. // We've got a token handle, stop impersonating
  542. //
  543. Status = I_RpcMapWin32Status(RpcRevertToSelf());
  544. if (!NT_SUCCESS(Status)) {
  545. KdPrint(("RtlGetUserSessionKeyServer - RpcRevertToSelf failed, status = 0x%lx\n", Status));
  546. ASSERT(FALSE);
  547. IgnoreStatus = NtClose(TokenHandle);
  548. ASSERT(NT_SUCCESS(IgnoreStatus));
  549. return(Status);
  550. }
  551. }
  552. //
  553. // We've now got a token handle, get the authentication id from it.
  554. //
  555. Status = NtQueryInformationToken(
  556. TokenHandle,
  557. TokenStatistics,
  558. &TokenInfo,
  559. sizeof(TokenInfo),
  560. &ReturnedLength
  561. );
  562. //
  563. // We're done with the token
  564. //
  565. IgnoreStatus = NtClose(TokenHandle);
  566. ASSERT(NT_SUCCESS(IgnoreStatus));
  567. //
  568. // Check result of token query
  569. //
  570. if (!NT_SUCCESS(Status)) {
  571. KdPrint(("RtlGetUserSessionKeyServer - Failed to query token statistics from token, status = 0x%lx\n", Status));
  572. ASSERT(FALSE);
  573. return(Status);
  574. }
  575. //
  576. // Open the server device
  577. //
  578. RtlInitAnsiString(&AnsiString, SERVER_DEVICE_NAME);
  579. Status = RtlAnsiStringToUnicodeString(&ServerDevice, &AnsiString, TRUE);
  580. if (!NT_SUCCESS(Status)) {
  581. KdPrint(("RtlGetUserSessionKeyServer - RtlAnsiToUnicodeString failed, status = 0x%lx\n", Status));
  582. ASSERT(FALSE);
  583. return(Status);
  584. }
  585. InitializeObjectAttributes( &Attributes,
  586. &ServerDevice,
  587. OBJ_CASE_INSENSITIVE,
  588. NULL,
  589. NULL );
  590. Status = NtOpenFile( &ServerHandle,
  591. GENERIC_READ | GENERIC_WRITE, // LATER use correct access
  592. &Attributes,
  593. &IoStatusBlock,
  594. FILE_SHARE_READ,
  595. 0 );
  596. RtlFreeUnicodeString(&ServerDevice);
  597. if (!NT_SUCCESS(Status)) {
  598. //
  599. // Check for the case when the server driver is not present
  600. //
  601. if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
  602. #ifdef DEBUG_USER_SESSION_KEYS
  603. KdPrint(("RtlGetUserSessionKeyServer - server driver not present, returning local key\n"));
  604. #endif
  605. *UserSessionKey = LocalSessionKey;
  606. Status = STATUS_LOCAL_USER_SESSION_KEY;
  607. } else {
  608. KdPrint(("RtlGetUserSessionKeyServer - Failed to open the server, status = 0x%lx\n", Status));
  609. ASSERT(FALSE);
  610. }
  611. return(Status);
  612. }
  613. //
  614. // Get the session key for this client from the server
  615. //
  616. Status = NtFsControlFile( ServerHandle,
  617. NULL, // Event
  618. NULL, // APC
  619. NULL, // APC Context
  620. &IoStatusBlock,
  621. FSCTL_SRV_GET_CHALLENGE,
  622. &TokenInfo.AuthenticationId,
  623. sizeof(TokenInfo.AuthenticationId),
  624. (PVOID)UserSessionKey,
  625. sizeof(*UserSessionKey));
  626. //
  627. // We're done with the file handle
  628. //
  629. IgnoreStatus = NtClose(ServerHandle);
  630. ASSERT(NT_SUCCESS(IgnoreStatus));
  631. if (NT_SUCCESS(Status)) {
  632. //
  633. // Check for the error session key
  634. //
  635. if (RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
  636. sizeof(*UserSessionKey)) == sizeof(*UserSessionKey)) {
  637. #ifdef DEBUG_USER_SESSION_KEYS
  638. KdPrint(("RtlGetUserSessionKeyServer - got error session key, returning error\n"));
  639. #endif
  640. Status = STATUS_NO_USER_SESSION_KEY;
  641. }
  642. } else {
  643. //
  644. // If the server is not started or the token couldn't be found in the
  645. // list of server connections, then assume it's a local connection
  646. //
  647. if ( (Status == STATUS_SERVER_NOT_STARTED) ||
  648. (Status == STATUS_NO_TOKEN) ) {
  649. #ifdef DEBUG_USER_SESSION_KEYS
  650. KdPrint(("RtlGetUserSessionKeyServer - server not started or logon id not found (Status = 0x%lx), returning local key\n", Status));
  651. #endif
  652. *UserSessionKey = LocalSessionKey;
  653. Status = STATUS_LOCAL_USER_SESSION_KEY;
  654. } else {
  655. KdPrint(("RtlGetUserSessionKeyServer - Failed to query the user session key from the server, status = 0x%lx\n", Status));
  656. ASSERT(FALSE);
  657. }
  658. }
  659. #ifdef DEBUG_USER_SESSION_KEYS
  660. KdPrint(("RtlGetUserSessionKeyServer : Key = 0x%lx : %lx : %lx : %lx, status = 0x%lx\n",
  661. ((PULONG)UserSessionKey)[0], ((PULONG)UserSessionKey)[1],
  662. ((PULONG)UserSessionKey)[2], ((PULONG)UserSessionKey)[3], Status));
  663. #endif
  664. return(Status);
  665. }