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.

1238 lines
33 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // Copyright (C) 1996, Microsoft Corporation
  4. //
  5. // File: creds.c
  6. //
  7. // Contents: Code to handle user-defined credentials
  8. //
  9. // Classes: None
  10. //
  11. // Functions: DfsCreateCredentials --
  12. // DfsFreeCredentials --
  13. // DfsInsertCredentials --
  14. // DfsDeleteCredentials --
  15. // DfsLookupCredentials --
  16. //
  17. // History: March 18, 1996 Milans Created
  18. //
  19. //-----------------------------------------------------------------------------
  20. #include "dfsprocs.h"
  21. #include <align.h>
  22. #include <ntddnfs.h>
  23. #include "dnr.h"
  24. #include "rpselect.h"
  25. #include "creds.h"
  26. VOID
  27. DfspFillEa(
  28. OUT PFILE_FULL_EA_INFORMATION EA,
  29. IN LPSTR EaName,
  30. IN PUNICODE_STRING EaValue);
  31. NTSTATUS
  32. DfspTreeConnectToService(
  33. IN PDFS_SERVICE Service,
  34. IN PDFS_CREDENTIALS Creds);
  35. VOID
  36. DfspDeleteAllAuthenticatedConnections(
  37. IN PDFS_CREDENTIALS Creds);
  38. NTSTATUS
  39. DfsCompleteDeleteTreeConnection(
  40. IN PDEVICE_OBJECT DeviceObject,
  41. IN PIRP Irp,
  42. IN PVOID Ctx);
  43. #ifdef ALLOC_PRAGMA
  44. #pragma alloc_text(PAGE,DfsCreateCredentials)
  45. #pragma alloc_text(PAGE,DfsVerifyCredentials)
  46. #pragma alloc_text(PAGE,DfspFillEa)
  47. #pragma alloc_text(PAGE,DfsFreeCredentials)
  48. #pragma alloc_text(PAGE,DfsInsertCredentials)
  49. #pragma alloc_text(PAGE,DfsDeleteCredentials)
  50. #pragma alloc_text(PAGE,DfsLookupCredentials)
  51. #pragma alloc_text(PAGE,DfsLookupCredentialsByServerShare)
  52. #pragma alloc_text(PAGE,DfspTreeConnectToService)
  53. #pragma alloc_text(PAGE,DfspDeleteAllAuthenticatedConnections)
  54. #pragma alloc_text(PAGE,DfsDeleteTreeConnection)
  55. #endif // ALLOC_PRAGMA
  56. //+----------------------------------------------------------------------------
  57. //
  58. // Function: DfsCreateCredentials
  59. //
  60. // Synopsis: Creates a DFS_CREDENTIALS structure from a
  61. // FILE_DFS_DEF_ROOT_CREDENTIALS structure.
  62. //
  63. // Arguments: [CredDef] -- The input PFILE_DFS_DEF_ROOT_CREDENTIALS.
  64. // [CredDefSize] -- Size in bytes of *CredDef.
  65. // [Creds] -- On successful return, contains a pointer to the
  66. // allocated PDFS_CREDENTIALS structure.
  67. //
  68. // Returns: [STATUS_SUCCESS] -- Allocated credentials
  69. //
  70. // [STATUS_INVALID_PARAMETER] -- CredDef didn't pass mustard.
  71. //
  72. // [STATUS_INSUFFICIENT_RESOURCES] -- Unable to allocate pool.
  73. //
  74. //-----------------------------------------------------------------------------
  75. #define DEF_NAME_TO_UNICODE_STRING(srcLength, dest, srcBuf, destBuf) \
  76. if ((srcLength)) { \
  77. (dest)->Length = (dest)->MaximumLength = srcLength; \
  78. (dest)->Buffer = (destBuf); \
  79. RtlMoveMemory((dest)->Buffer, (srcBuf), (dest)->Length); \
  80. srcBuf += ((dest)->Length / sizeof(WCHAR)); \
  81. destBuf += ((dest)->Length / sizeof(WCHAR)); \
  82. }
  83. #ifdef TERMSRV
  84. NTSTATUS
  85. DfsCreateCredentials(
  86. IN PFILE_DFS_DEF_ROOT_CREDENTIALS CredDef,
  87. IN ULONG CredDefSize,
  88. IN ULONG SessionID,
  89. IN PLUID LogonID,
  90. OUT PDFS_CREDENTIALS *Creds
  91. )
  92. #else // TERMSRV
  93. NTSTATUS
  94. DfsCreateCredentials(
  95. IN PFILE_DFS_DEF_ROOT_CREDENTIALS CredDef,
  96. IN ULONG CredDefSize,
  97. IN PLUID LogonID,
  98. OUT PDFS_CREDENTIALS *Creds)
  99. #endif // TERMSRV
  100. {
  101. NTSTATUS status = STATUS_SUCCESS;
  102. ULONG totalSize;
  103. PDFS_CREDENTIALS creds;
  104. PWCHAR nameSrc, nameBuf;
  105. PFILE_FULL_EA_INFORMATION ea;
  106. ULONG eaLength;
  107. totalSize = CredDef->DomainNameLen +
  108. CredDef->UserNameLen +
  109. CredDef->PasswordLen +
  110. CredDef->ServerNameLen +
  111. CredDef->ShareNameLen;
  112. //
  113. // Validate the CredDef buffer
  114. //
  115. if ((totalSize + sizeof(FILE_DFS_DEF_ROOT_CREDENTIALS) - sizeof(WCHAR)) >
  116. CredDefSize)
  117. status = STATUS_INVALID_PARAMETER;
  118. else if (CredDef->ServerNameLen == 0)
  119. status = STATUS_INVALID_PARAMETER;
  120. else if (CredDef->ShareNameLen == 0)
  121. status = STATUS_INVALID_PARAMETER;
  122. //
  123. // Allocate the new DFS_CREDENTIALS structure
  124. //
  125. if (NT_SUCCESS(status)) {
  126. //
  127. // Add in the size of the DFS_CREDENTIALS_STRUCTURE itself.
  128. //
  129. totalSize += sizeof(DFS_CREDENTIALS);
  130. //
  131. // Add in the size of the EA_BUFFER that we will create. The
  132. // eaLength has room for 4 FILE_FULL_EA_INFORMATION structures,
  133. // the names and values of the four EAs we will use, and, since each
  134. // EA structure has to be long-word aligned, 4 ULONGs.
  135. //
  136. eaLength = 4 * sizeof(FILE_FULL_EA_INFORMATION) +
  137. sizeof(EA_NAME_DOMAIN) +
  138. sizeof(EA_NAME_USERNAME) +
  139. sizeof(EA_NAME_PASSWORD) +
  140. sizeof(EA_NAME_CSCAGENT) +
  141. CredDef->DomainNameLen +
  142. CredDef->UserNameLen +
  143. CredDef->PasswordLen +
  144. 4 * sizeof(ULONG);
  145. if (CredDef->Flags & DFS_USE_NULL_PASSWORD) {
  146. eaLength += sizeof(UNICODE_NULL);
  147. totalSize += sizeof(UNICODE_NULL);
  148. }
  149. //
  150. // The buffers for DomainName, UserName etc. will start right after
  151. // the EaBuffer of DFS_CREDENTIALS. So, EaLength has to be WCHAR
  152. // aligned.
  153. //
  154. eaLength = ROUND_UP_COUNT(eaLength, ALIGN_WCHAR);
  155. //
  156. // Now, allocate the pool
  157. //
  158. creds = (PDFS_CREDENTIALS) ExAllocatePoolWithTag(
  159. NonPagedPool,
  160. totalSize + eaLength,
  161. ' puM');
  162. if (creds == NULL)
  163. status = STATUS_INSUFFICIENT_RESOURCES;
  164. }
  165. //
  166. // Fill up the DFS_CREDENTIALS structure.
  167. //
  168. if (NT_SUCCESS(status)) {
  169. nameSrc = CredDef->Buffer;
  170. nameBuf =
  171. (PWCHAR) ((PUCHAR) creds + sizeof(DFS_CREDENTIALS) + eaLength);
  172. RtlZeroMemory( creds, sizeof(DFS_CREDENTIALS) );
  173. DEF_NAME_TO_UNICODE_STRING(
  174. CredDef->DomainNameLen,
  175. &creds->DomainName,
  176. nameSrc,
  177. nameBuf);
  178. DEF_NAME_TO_UNICODE_STRING(
  179. CredDef->UserNameLen,
  180. &creds->UserName,
  181. nameSrc,
  182. nameBuf);
  183. if (CredDef->Flags & DFS_USE_NULL_PASSWORD) {
  184. LPWSTR nullPassword = L"";
  185. DEF_NAME_TO_UNICODE_STRING(
  186. sizeof(UNICODE_NULL),
  187. &creds->Password,
  188. nullPassword,
  189. nameBuf);
  190. } else {
  191. DEF_NAME_TO_UNICODE_STRING(
  192. CredDef->PasswordLen,
  193. &creds->Password,
  194. nameSrc,
  195. nameBuf);
  196. }
  197. DEF_NAME_TO_UNICODE_STRING(
  198. CredDef->ServerNameLen,
  199. &creds->ServerName,
  200. nameSrc,
  201. nameBuf);
  202. DEF_NAME_TO_UNICODE_STRING(
  203. CredDef->ShareNameLen,
  204. &creds->ShareName,
  205. nameSrc,
  206. nameBuf);
  207. creds->RefCount = 0;
  208. creds->NetUseCount = 0;
  209. eaLength = 0;
  210. ea = (PFILE_FULL_EA_INFORMATION) &creds->EaBuffer[0];
  211. if (creds->DomainName.Length != 0) {
  212. DfspFillEa(ea, EA_NAME_DOMAIN, &creds->DomainName);
  213. eaLength += ea->NextEntryOffset;
  214. }
  215. if (creds->UserName.Length != 0) {
  216. ea = (PFILE_FULL_EA_INFORMATION)
  217. ((PUCHAR) ea + ea->NextEntryOffset);
  218. DfspFillEa(ea, EA_NAME_USERNAME, &creds->UserName);
  219. eaLength += ea->NextEntryOffset;
  220. }
  221. if (CredDef->Flags & DFS_USE_NULL_PASSWORD) {
  222. UNICODE_STRING nullPassword;
  223. RtlInitUnicodeString(&nullPassword, L"");
  224. ea = (PFILE_FULL_EA_INFORMATION)
  225. ((PUCHAR) ea + ea->NextEntryOffset);
  226. DfspFillEa(ea, EA_NAME_PASSWORD, &nullPassword);
  227. eaLength += ea->NextEntryOffset;
  228. } else if (creds->Password.Length != 0) {
  229. ea = (PFILE_FULL_EA_INFORMATION)
  230. ((PUCHAR) ea + ea->NextEntryOffset);
  231. DfspFillEa(ea, EA_NAME_PASSWORD, &creds->Password);
  232. eaLength += ea->NextEntryOffset;
  233. }
  234. if (CredDef->CSCAgentCreate == TRUE) {
  235. UNICODE_STRING EmptyUniString;
  236. RtlInitUnicodeString(&EmptyUniString, NULL);
  237. ea = (PFILE_FULL_EA_INFORMATION)
  238. ((PUCHAR) ea + ea->NextEntryOffset);
  239. DfspFillEa(ea, EA_NAME_CSCAGENT, &EmptyUniString);
  240. eaLength += ea->NextEntryOffset;
  241. }
  242. ea->NextEntryOffset = 0;
  243. creds->EaLength = eaLength;
  244. #ifdef TERMSRV
  245. creds->SessionID = SessionID;
  246. #endif // TERMSRV
  247. RtlCopyLuid(&creds->LogonID, LogonID);
  248. *Creds = creds;
  249. }
  250. //
  251. // Done...
  252. //
  253. return( status );
  254. }
  255. //+----------------------------------------------------------------------------
  256. //
  257. // Function: DfspFillEa
  258. //
  259. // Synopsis: Helper routine to fill up an EA Buffer
  260. //
  261. // Arguments: [EA] -- Pointer to FILE_FULL_EA_INFORMATION to fill
  262. //
  263. // [EaName] -- Name of Ea
  264. //
  265. // [EaValue] -- Value (UNICODE_STRING) of Ea
  266. //
  267. // Returns:
  268. //
  269. //-----------------------------------------------------------------------------
  270. VOID
  271. DfspFillEa(
  272. OUT PFILE_FULL_EA_INFORMATION EA,
  273. IN LPSTR EaName,
  274. IN PUNICODE_STRING EaValue)
  275. {
  276. ULONG nameLen;
  277. nameLen = strlen(EaName) + sizeof(CHAR);
  278. EA->Flags = 0;
  279. EA->EaNameLength =
  280. (UCHAR) ROUND_UP_COUNT(nameLen, ALIGN_WCHAR) - sizeof(CHAR);
  281. EA->EaValueLength = EaValue->Length;
  282. //
  283. // Set the last character of EaName to 0 - the IO subsystem checks for
  284. // this
  285. //
  286. EA->EaName[ EA->EaNameLength ] = 0;
  287. RtlMoveMemory(&EA->EaName[0], EaName, nameLen);
  288. if (EaValue->Length > 0) {
  289. RtlMoveMemory(
  290. &EA->EaName[ EA->EaNameLength + 1 ],
  291. EaValue->Buffer,
  292. EA->EaValueLength);
  293. }
  294. EA->NextEntryOffset = ROUND_UP_COUNT(
  295. FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaName[0]) +
  296. EA->EaNameLength +
  297. EA->EaValueLength,
  298. ALIGN_DWORD);
  299. }
  300. //+----------------------------------------------------------------------------
  301. //
  302. // Function: DfsFreeCredentials
  303. //
  304. // Synopsis: Frees up the resources used by the DFS_CREDENTIALS structure.
  305. // Dual of DfsCreateCredentials
  306. //
  307. // Arguments: [Creds] -- The credentials structure to free
  308. //
  309. // Returns: Nothing
  310. //
  311. //-----------------------------------------------------------------------------
  312. VOID
  313. DfsFreeCredentials(
  314. PDFS_CREDENTIALS Creds)
  315. {
  316. ExFreePool( Creds );
  317. }
  318. //+----------------------------------------------------------------------------
  319. //
  320. // Function: DfsInsertCredentials
  321. //
  322. // Synopsis: Inserts a new user credential into DfsData.Credentials queue.
  323. // Note that if this routine finds an existing credential
  324. // record, it will free up the passed in one, bump up the ref
  325. // count on the existing one, return a pointer to the
  326. // existing one, and return STATUS_OBJECT_NAME_COLLISION.
  327. //
  328. // Arguments: [Creds] -- Pointer to DFS_CREDENTIALS structure to insert.
  329. // [ForDevicelessConnection] -- If TRUE, the creds are being
  330. // inserted because the caller wants to create a
  331. // deviceless connection.
  332. //
  333. // Returns: [STATUS_SUCCESS] -- Successfully inserted structure
  334. //
  335. // [STATUS_NETWORK_CREDENTIAL_CONFLICT] -- There is already
  336. // another set of credentials for the given server\share.
  337. //
  338. // [STATUS_OBJECT_NAME_COLLISION] -- There is already another
  339. // net use to the same server\share with the same
  340. // credentials.
  341. //
  342. //-----------------------------------------------------------------------------
  343. NTSTATUS
  344. DfsInsertCredentials(
  345. IN OUT PDFS_CREDENTIALS *Creds,
  346. IN BOOLEAN ForDevicelessConnection)
  347. {
  348. NTSTATUS status = STATUS_SUCCESS;
  349. PDFS_CREDENTIALS creds, existingCreds;
  350. creds = *Creds;
  351. ASSERT(creds->ServerName.Length != 0);
  352. ASSERT(creds->ShareName.Length != 0);
  353. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  354. #ifdef TERMSRV
  355. existingCreds =
  356. DfsLookupCredentialsByServerShare(
  357. &creds->ServerName,
  358. &creds->ShareName,
  359. creds->SessionID,
  360. &creds->LogonID );
  361. #else // TERMSRV
  362. existingCreds = DfsLookupCredentialsByServerShare(
  363. &creds->ServerName,
  364. &creds->ShareName,
  365. &creds->LogonID );
  366. #endif // TERMSRV
  367. if (existingCreds != NULL) {
  368. if (
  369. (creds->DomainName.Length > 0 && !RtlEqualUnicodeString(
  370. &existingCreds->DomainName,
  371. &creds->DomainName,
  372. TRUE))
  373. ||
  374. (creds->UserName.Length > 0 && !RtlEqualUnicodeString(
  375. &existingCreds->UserName,
  376. &creds->UserName,
  377. TRUE))
  378. ||
  379. //
  380. // For compatibility reasons, check for password inconsistency ONLY
  381. // if we have a previously setup credentials and the previous
  382. // credentials had explicit password and the current request
  383. // has explicitly specified password.
  384. // rdr2\rdbss\rxconnct.c also has a similar check for the rdr.
  385. //
  386. (existingCreds->Password.Length > 0 && creds->Password.Length > 0 && !RtlEqualUnicodeString(
  387. &existingCreds->Password,
  388. &creds->Password,
  389. TRUE))
  390. ) {
  391. status = STATUS_NETWORK_CREDENTIAL_CONFLICT;
  392. } else {
  393. //
  394. // Do this for both deviceless and has device cases.
  395. // With deep net uses of deviceless, multiple DevlessRoots
  396. // may point to the same credentials.
  397. //
  398. existingCreds->NetUseCount++;
  399. existingCreds->RefCount++;
  400. DfsFreeCredentials( *Creds );
  401. *Creds = existingCreds;
  402. status = STATUS_OBJECT_NAME_COLLISION;
  403. }
  404. } else {
  405. ASSERT(creds->RefCount == 0);
  406. ASSERT(creds->NetUseCount == 0);
  407. creds->RefCount = 1;
  408. creds->NetUseCount = 1;
  409. InsertTailList( &DfsData.Credentials, &creds->Link );
  410. status = STATUS_SUCCESS;
  411. }
  412. if (status != STATUS_NETWORK_CREDENTIAL_CONFLICT) {
  413. if (ForDevicelessConnection)
  414. (*Creds)->Flags |= CRED_IS_DEVICELESS;
  415. else
  416. (*Creds)->Flags |= CRED_HAS_DEVICE;
  417. }
  418. ExReleaseResourceLite( &DfsData.Resource );
  419. return( status );
  420. }
  421. //+----------------------------------------------------------------------------
  422. //
  423. // Function: DfsDeleteCredentials
  424. //
  425. // Synopsis: Deletes a user credential record. This is the dual of
  426. // DfsInsertCredentials, NOT DfsCreateCredentials.
  427. //
  428. // Arguments: [Creds] -- Pointer to DFS_CREDENTIALS record to delete.
  429. //
  430. // Returns: Nothing
  431. //
  432. //-----------------------------------------------------------------------------
  433. VOID
  434. DfsDeleteCredentials(
  435. IN PDFS_CREDENTIALS Creds)
  436. {
  437. ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
  438. Creds->NetUseCount--;
  439. Creds->RefCount--;
  440. if (Creds->NetUseCount == 0) {
  441. DfspDeleteAllAuthenticatedConnections( Creds );
  442. RemoveEntryList( &Creds->Link );
  443. InsertTailList( &DfsData.DeletedCredentials, &Creds->Link );
  444. }
  445. ExReleaseResourceLite( &DfsData.Resource );
  446. }
  447. //+----------------------------------------------------------------------------
  448. //
  449. // Function: DfsLookupCredentials
  450. //
  451. // Synopsis: Looks up a credential, if any, associated with a file name.
  452. //
  453. // Arguments: [FileName] -- Name of file. Assumed to have atleast a
  454. // \server\share part.
  455. //
  456. // Returns: Pointer to DFS_CREDENTIALS to use, NULL if not found.
  457. //
  458. //-----------------------------------------------------------------------------
  459. #ifdef TERMSRV
  460. PDFS_CREDENTIALS
  461. DfsLookupCredentials(
  462. IN PUNICODE_STRING FileName,
  463. IN ULONG SessionID,
  464. IN PLUID LogonID
  465. )
  466. #else // TERMSRV
  467. PDFS_CREDENTIALS
  468. DfsLookupCredentials(
  469. IN PUNICODE_STRING FileName,
  470. IN PLUID LogonID
  471. )
  472. #endif // TERMSRV
  473. {
  474. UNICODE_STRING server, share;
  475. USHORT i;
  476. //
  477. // FileName has to be atleast \a\b
  478. //
  479. if (FileName->Length < 4 * sizeof(WCHAR))
  480. return( NULL );
  481. if (FileName->Buffer[0] != UNICODE_PATH_SEP)
  482. return( NULL );
  483. server.Buffer = &FileName->Buffer[1];
  484. for (i = 1, server.Length = 0;
  485. i < FileName->Length/sizeof(WCHAR) &&
  486. FileName->Buffer[i] != UNICODE_PATH_SEP;
  487. i++, server.Length += sizeof(WCHAR)) {
  488. NOTHING;
  489. }
  490. server.MaximumLength = server.Length;
  491. i++; // Go past the backslash
  492. share.Buffer = &FileName->Buffer[i];
  493. for (share.Length = 0;
  494. i < FileName->Length/sizeof(WCHAR) &&
  495. FileName->Buffer[i] != UNICODE_PATH_SEP;
  496. i++, share.Length += sizeof(WCHAR)) {
  497. NOTHING;
  498. }
  499. share.MaximumLength = share.Length;
  500. if ((server.Length == 0) || (share.Length == 0))
  501. return( NULL );
  502. #ifdef TERMSRV
  503. return DfsLookupCredentialsByServerShare( &server, &share, SessionID, LogonID );
  504. #else // TERMSRV
  505. return DfsLookupCredentialsByServerShare( &server, &share, LogonID );
  506. #endif // TERMSRV
  507. }
  508. //+----------------------------------------------------------------------------
  509. //
  510. // Function: DfsLookupCredentialsByServerShare
  511. //
  512. // Synopsis: Searches DfsData.Credentials for credentials given a server
  513. // and share name.
  514. //
  515. // Arguments: [ServerName] -- Name of server to match.
  516. // [ShareName] -- Name of share to match.
  517. //
  518. // Returns: Pointer to DFS_CREDENTIALS, NULL if not found.
  519. //
  520. //-----------------------------------------------------------------------------
  521. #ifdef TERMSRV
  522. PDFS_CREDENTIALS
  523. DfsLookupCredentialsByServerShare(
  524. IN PUNICODE_STRING ServerName,
  525. IN PUNICODE_STRING ShareName,
  526. IN ULONG SessionID,
  527. IN PLUID LogonID
  528. )
  529. #else // TERMSRV
  530. PDFS_CREDENTIALS
  531. DfsLookupCredentialsByServerShare(
  532. IN PUNICODE_STRING ServerName,
  533. IN PUNICODE_STRING ShareName,
  534. IN PLUID LogonID
  535. )
  536. #endif // TERMSRV
  537. {
  538. PLIST_ENTRY link;
  539. PDFS_CREDENTIALS matchedCreds = NULL;
  540. for (link = DfsData.Credentials.Flink;
  541. link != &DfsData.Credentials && matchedCreds == NULL;
  542. link = link->Flink) {
  543. PDFS_CREDENTIALS creds;
  544. creds = CONTAINING_RECORD(link, DFS_CREDENTIALS, Link);
  545. if (RtlEqualUnicodeString(ServerName, &creds->ServerName, TRUE) &&
  546. RtlEqualUnicodeString(ShareName, &creds->ShareName, TRUE)) {
  547. #ifdef TERMSRV
  548. if( (creds->SessionID == SessionID) &&
  549. RtlEqualLuid(&creds->LogonID, LogonID) ) {
  550. matchedCreds = creds;
  551. }
  552. #else // TERMSRV
  553. if( RtlEqualLuid(&creds->LogonID, LogonID) ) {
  554. matchedCreds = creds;
  555. }
  556. #endif // TERMSRV
  557. }
  558. }
  559. return( matchedCreds );
  560. }
  561. //+----------------------------------------------------------------------------
  562. //
  563. // Function: DfsVerifyCredentials
  564. //
  565. // Synopsis: Returns the result of trying to connect to a Dfs share using
  566. // the supplied credentials
  567. //
  568. // Arguments: [Prefix] -- The Dfs Prefix to connect to.
  569. // [Creds] -- The DFS_CREDENTIALS record to use for connecting.
  570. //
  571. // Returns: [STATUS_SUCCESS] -- Successfully connected.
  572. //
  573. // [STATUS_BAD_NETWORK_PATH] -- Unable to find Prefix
  574. // in Pkt or a server for prefix could not be found.
  575. //
  576. // NT Status of Tree Connect attempt
  577. //
  578. //-----------------------------------------------------------------------------
  579. NTSTATUS
  580. DfsVerifyCredentials(
  581. IN PUNICODE_STRING Prefix,
  582. IN PDFS_CREDENTIALS Creds)
  583. {
  584. NTSTATUS status;
  585. UNICODE_STRING remPath, shareName;
  586. PDFS_PKT pkt;
  587. PDFS_PKT_ENTRY pktEntry;
  588. PDFS_SERVICE service;
  589. ULONG i, USN;
  590. BOOLEAN pktLocked, fRetry;
  591. UNICODE_STRING UsePrefix;
  592. DfsGetServerShare( &UsePrefix,
  593. Prefix );
  594. pkt = _GetPkt();
  595. //
  596. // We acquire Pkt exclusive because we might tear down the IPC$ connection
  597. // to a server while trying to establish a connection with supplied
  598. // credentials.
  599. //
  600. PktAcquireExclusive( TRUE, &pktLocked );
  601. do {
  602. fRetry = FALSE;
  603. pktEntry = PktLookupEntryByPrefix( pkt, &UsePrefix, &remPath );
  604. if (pktEntry != NULL) {
  605. InterlockedIncrement(&pktEntry->UseCount);
  606. USN = pktEntry->USN;
  607. status = STATUS_BAD_NETWORK_PATH;
  608. for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
  609. service = &pktEntry->Info.ServiceList[i];
  610. status = DfspTreeConnectToService(service, Creds);
  611. //
  612. // If tree connect succeeded, we are done.
  613. //
  614. if (NT_SUCCESS(status))
  615. break;
  616. //
  617. // If tree connect failed with an "interesting error" like
  618. // STATUS_ACCESS_DENIED, we are done.
  619. //
  620. if (!ReplIsRecoverableError(status))
  621. break;
  622. //
  623. // Tree connect failed because of an error like host not
  624. // reachable. In that case, we want to go on to the next
  625. // server in the list. But before we do that, we have to see
  626. // if the pkt changed on us while we were off doing the tree
  627. // connect.
  628. //
  629. if (USN != pktEntry->USN) {
  630. fRetry = TRUE;
  631. break;
  632. }
  633. }
  634. InterlockedDecrement(&pktEntry->UseCount);
  635. } else {
  636. status = STATUS_BAD_NETWORK_PATH;
  637. }
  638. } while ( fRetry );
  639. PktRelease();
  640. return( status );
  641. }
  642. //+----------------------------------------------------------------------------
  643. //
  644. // Function: DfspTreeConnectToService
  645. //
  646. // Synopsis: Helper routine to tree connect to a DFS_SERVICE with supplied
  647. // credentials.
  648. //
  649. // Arguments: [Service] -- The service to connect to
  650. // [Creds] -- The credentials to use to tree connect
  651. //
  652. // Returns: NT Status of tree connect
  653. //
  654. // Notes: This routine assumes that the Pkt has been acquired before
  655. // being called. This routine will release and reacquire the Pkt
  656. // so the caller should be prepared for the event that the Pkt
  657. // has changed after a call to this routine.
  658. //
  659. //-----------------------------------------------------------------------------
  660. NTSTATUS
  661. DfspTreeConnectToService(
  662. IN PDFS_SERVICE Service,
  663. IN PDFS_CREDENTIALS Creds)
  664. {
  665. NTSTATUS status;
  666. UNICODE_STRING shareName;
  667. HANDLE treeHandle;
  668. OBJECT_ATTRIBUTES objectAttributes;
  669. IO_STATUS_BLOCK ioStatusBlock;
  670. BOOLEAN pktLocked;
  671. USHORT i, k;
  672. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() );
  673. //
  674. // Compute the share name...
  675. //
  676. if (Service->pProvider != NULL &&
  677. Service->pProvider->DeviceName.Buffer != NULL &&
  678. Service->pProvider->DeviceName.Length > 0) {
  679. //
  680. // We have a provider already - use it
  681. //
  682. shareName.MaximumLength =
  683. Service->pProvider->DeviceName.Length +
  684. Service->Address.Length;
  685. } else {
  686. //
  687. // We don't have a provider yet - give it to the mup to find one
  688. //
  689. shareName.MaximumLength =
  690. sizeof(DD_NFS_DEVICE_NAME_U) +
  691. Service->Address.Length;
  692. }
  693. shareName.Buffer = ExAllocatePoolWithTag(PagedPool, shareName.MaximumLength, ' puM');
  694. if (shareName.Buffer != NULL) {
  695. //
  696. // If we have a cached connection to the IPC$ share of this server,
  697. // close it or it might conflict with the credentials supplied here.
  698. //
  699. if (Service->ConnFile != NULL) {
  700. ExAcquireResourceExclusiveLite(&DfsData.Resource, TRUE);
  701. if (Service->ConnFile != NULL)
  702. DfsCloseConnection(Service);
  703. ExReleaseResourceLite(&DfsData.Resource);
  704. }
  705. //
  706. // Now, build the share name to tree connect to.
  707. //
  708. shareName.Length = 0;
  709. if (Service->pProvider != NULL &&
  710. Service->pProvider->DeviceName.Buffer != NULL &&
  711. Service->pProvider->DeviceName.Length > 0) {
  712. //
  713. // We have a provider already - use it
  714. //
  715. RtlAppendUnicodeToString(
  716. &shareName,
  717. Service->pProvider->DeviceName.Buffer);
  718. } else {
  719. //
  720. // We don't have a provider yet - give it to the mup to find one
  721. //
  722. RtlAppendUnicodeToString(
  723. &shareName,
  724. DD_NFS_DEVICE_NAME_U);
  725. }
  726. RtlAppendUnicodeStringToString(&shareName, &Service->Address);
  727. //
  728. // One can only do tree connects to server\share. So, in case
  729. // pService->Address refers to something deeper than the share,
  730. // make sure we setup a tree-conn only to server\share. Note that
  731. // by now, shareName is of the form
  732. // \Device\LanmanRedirector\server\share<\path>. So, count up to
  733. // 4 slashes and terminate the share name there.
  734. //
  735. for (i = 0, k = 0;
  736. i < shareName.Length/sizeof(WCHAR) && k < 5;
  737. i++) {
  738. if (shareName.Buffer[i] == UNICODE_PATH_SEP)
  739. k++;
  740. }
  741. shareName.Length = i * sizeof(WCHAR);
  742. if (k == 5)
  743. shareName.Length -= sizeof(WCHAR);
  744. InitializeObjectAttributes(
  745. &objectAttributes,
  746. &shareName,
  747. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  748. NULL,
  749. NULL);
  750. //
  751. // Release the Pkt before going over the net...
  752. //
  753. PktRelease();
  754. status = ZwCreateFile(
  755. &treeHandle,
  756. SYNCHRONIZE,
  757. &objectAttributes,
  758. &ioStatusBlock,
  759. NULL,
  760. FILE_ATTRIBUTE_NORMAL,
  761. FILE_SHARE_READ |
  762. FILE_SHARE_WRITE |
  763. FILE_SHARE_DELETE,
  764. FILE_OPEN_IF,
  765. FILE_CREATE_TREE_CONNECTION |
  766. FILE_SYNCHRONOUS_IO_NONALERT,
  767. (PVOID) Creds->EaBuffer,
  768. Creds->EaLength);
  769. if (NT_SUCCESS(status)) {
  770. PFILE_OBJECT fileObject;
  771. //
  772. // 426184, need to check return code for errors.
  773. //
  774. status = ObReferenceObjectByHandle(
  775. treeHandle,
  776. 0,
  777. NULL,
  778. KernelMode,
  779. &fileObject,
  780. NULL);
  781. ZwClose( treeHandle );
  782. if (NT_SUCCESS(status)) {
  783. DfsDeleteTreeConnection( fileObject, USE_FORCE );
  784. }
  785. }
  786. ExFreePool( shareName.Buffer );
  787. PktAcquireShared( TRUE, &pktLocked );
  788. } else {
  789. status = STATUS_INSUFFICIENT_RESOURCES;
  790. }
  791. return( status );
  792. }
  793. //+----------------------------------------------------------------------------
  794. //
  795. // Function: DfspDeleteAllAuthenticatedConnections
  796. //
  797. // Synopsis: Deletes all authenticated connections made using a particular
  798. // set of credentials that we might have cached. Useful to
  799. // implement net use /d
  800. //
  801. // Arguments: [Creds] -- The Credentials to match against authenticated
  802. // connection
  803. //
  804. // Returns: Nothing
  805. //
  806. // Notes: Pkt and DfsData must have been acquired before calling!
  807. //
  808. //-----------------------------------------------------------------------------
  809. VOID
  810. DfspDeleteAllAuthenticatedConnections(
  811. IN PDFS_CREDENTIALS Creds)
  812. {
  813. PDFS_PKT_ENTRY pktEntry;
  814. ULONG i;
  815. PDFS_MACHINE_ENTRY machine;
  816. ASSERT( PKT_LOCKED_FOR_SHARED_ACCESS() ||
  817. PKT_LOCKED_FOR_EXCLUSIVE_ACCESS() );
  818. ASSERT( ExIsResourceAcquiredExclusiveLite( &DfsData.Resource ) );
  819. for (pktEntry = PktFirstEntry(&DfsData.Pkt);
  820. pktEntry != NULL;
  821. pktEntry = PktNextEntry(&DfsData.Pkt, pktEntry)) {
  822. for (i = 0; i < pktEntry->Info.ServiceCount; i++) {
  823. //
  824. // Tear down connection to IPC$ if we have one...
  825. //
  826. if (pktEntry->Info.ServiceList[i].ConnFile != NULL)
  827. DfsCloseConnection( &pktEntry->Info.ServiceList[i] );
  828. machine = pktEntry->Info.ServiceList[i].pMachEntry;
  829. if (machine->Credentials == Creds) {
  830. DfsDeleteTreeConnection(machine->AuthConn, USE_LOTS_OF_FORCE);
  831. machine->AuthConn = NULL;
  832. machine->Credentials->RefCount--;
  833. machine->Credentials = NULL;
  834. }
  835. }
  836. }
  837. }
  838. //+----------------------------------------------------------------------------
  839. //
  840. // Function: DfsDeleteTreeConnection, public
  841. //
  842. // Synopsis: Tears down tree connections given the file object representing
  843. // the tree connection.
  844. //
  845. // Arguments: [TreeConnFileObj] -- The tree connection to tear down.
  846. // [ForceFilesClosed] -- If TRUE, the tree connection will be
  847. // torn down even if files are open on the server
  848. //
  849. // Returns: Nothing
  850. //
  851. //-----------------------------------------------------------------------------
  852. VOID
  853. DfsDeleteTreeConnection(
  854. IN PFILE_OBJECT TreeConnFileObj,
  855. IN ULONG Level)
  856. {
  857. PIRP irp;
  858. KEVENT event;
  859. static LMR_REQUEST_PACKET req;
  860. KeInitializeEvent( &event, SynchronizationEvent, FALSE );
  861. req.Version = REQUEST_PACKET_VERSION;
  862. req.Level = Level;
  863. irp = DnrBuildFsControlRequest(
  864. TreeConnFileObj,
  865. &event,
  866. FSCTL_LMR_DELETE_CONNECTION,
  867. &req,
  868. sizeof(req),
  869. NULL,
  870. 0,
  871. DfsCompleteDeleteTreeConnection);
  872. if (irp != NULL) {
  873. IoCallDriver(
  874. IoGetRelatedDeviceObject( TreeConnFileObj ),
  875. irp);
  876. KeWaitForSingleObject(
  877. &event,
  878. UserRequest,
  879. KernelMode,
  880. FALSE, // Alertable
  881. NULL); // Timeout
  882. IoFreeIrp( irp );
  883. ObDereferenceObject(TreeConnFileObj);
  884. }
  885. }
  886. NTSTATUS
  887. DfsCompleteDeleteTreeConnection(
  888. IN PDEVICE_OBJECT DeviceObject,
  889. IN PIRP Irp,
  890. IN PVOID Ctx)
  891. {
  892. KeSetEvent( (PKEVENT) Ctx, EVENT_INCREMENT, FALSE );
  893. return( STATUS_MORE_PROCESSING_REQUIRED );
  894. }
  895. VOID
  896. DfsGetServerShare(
  897. PUNICODE_STRING pDest,
  898. PUNICODE_STRING pSrc)
  899. {
  900. ULONG i;
  901. *pDest = *pSrc;
  902. for (i = 0; ((i < pDest->Length/sizeof(WCHAR)) && (pDest->Buffer[i] == UNICODE_PATH_SEP)); i++)
  903. {
  904. NOTHING;
  905. }
  906. for (; ((i < pDest->Length/sizeof(WCHAR)) && (pDest->Buffer[i] != UNICODE_PATH_SEP)); i++)
  907. {
  908. NOTHING;
  909. }
  910. for (i = i + 1; ((i < pDest->Length/sizeof(WCHAR)) && (pDest->Buffer[i] != UNICODE_PATH_SEP)); i++)
  911. {
  912. NOTHING;
  913. }
  914. if (i <= pDest->Length/sizeof(WCHAR))
  915. {
  916. pDest->Length = (USHORT)i * sizeof(WCHAR);
  917. }
  918. }