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.

2045 lines
66 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. transitn.c
  5. Abstract:
  6. This module implements the routines for transitioning from the connected mode
  7. and vice versa
  8. Author:
  9. Balan Sethu Raman [SethuR] 11 - November - 1997
  10. Revision History:
  11. Notes:
  12. The transition of a connection from a connected mode to a disconnected mode
  13. and vice versa is guided by the principles of transparency and fideltiy.
  14. The principle of transparency demands that the transition be made smoothly
  15. on the detection of the appropriate condition without any user intervention
  16. if at all possible and the principle of fidelity relies upon the notion of
  17. truth and the responsibility for its maintenance. If we wish to adhere to the
  18. opinion that the client has the truth at all times and the server is merely
  19. a convenient repositiory for snapshots of the truth one set of semantics falls
  20. out. On the other hand we could insist that the server has the truth at all
  21. times and the client caches snapshots of the truth for offline availability
  22. and performance gains from avoiding network traffic a different set of
  23. semantics falls out. Note that under certain scenarios the both schemes yield
  24. identical results, i.e., absence of file sharing.
  25. Transitioning from connected mode to disconnected mode
  26. ------------------------------------------------------
  27. When transitioning from connected mode it is important to consider existing
  28. connections and the existing file system objects. In the mini redirector
  29. terminology it is the SRV_CALL, NET_ROOT instances and the FCB instances that
  30. are important.
  31. The trigger for the transition is normally due to the occurence of one of the
  32. following two events.
  33. 1) all the existing transports are going away, because the user has unplugged
  34. the net.
  35. 2) an ongoing operation on the connection returns an error that indicates that
  36. the server is no longer accessible.
  37. These two cases are different -- the first one indicates the unavailability
  38. of net for a potentially long period of time and the second one indicates a
  39. transient loss of the net. Consequently we treat these two different events
  40. in different ways -- the first one triggers a top down transition to a
  41. disconnected mode while the second one triggers a bottom up transition to a
  42. disconnected mode. As an example consider the case when we have two files
  43. foo.doc, foo1.doc open on a particular share. When we get an indication that
  44. the net is no longer available, we mark the SRV_CALL and NET_ROOT instances
  45. as having transitioned to the disconnected mode. This automatically entails
  46. that as file system operations are performed on the various open files, foo.doc
  47. foo1.doc respectively the corresponding transition occurs.
  48. On the other hand if there was an error in a particular operation of foo.doc
  49. then the transition to disconected mode is done for the appropriate FCB alone.
  50. Thus if we open a new file immediately after that and the net becomes
  51. available we go on the net for opening the second file.
  52. However, owing to the multi step renames that apps use we forego this option.
  53. Thus the following distinction needs to be made. When no FCB instances are
  54. open and an error occurs we delay the transition till a open request comes
  55. through. This will allow us to mask some transient failures on the NET.
  56. --*/
  57. #include "precomp.h"
  58. #pragma hdrstop
  59. #include "acd.h"
  60. #include "acdapi.h"
  61. #include "ntddmup.h"
  62. #pragma code_seg("PAGE")
  63. #define Dbg (DEBUG_TRACE_MRXSMBCSC_TRANSITN)
  64. RXDT_DefineCategory(MRXSMBCSC_TRANSITN);
  65. #define CSC_AUTODIAL_POLL_COUNT 10
  66. #define INVALID_SESSION_ID 0xffffffff
  67. BOOLEAN
  68. CscIsSpecialShare(
  69. PUNICODE_STRING ShareName);
  70. #define UNICODE_STRING_STRUCT(s) \
  71. {sizeof(s) - sizeof(WCHAR), sizeof(s) - sizeof(WCHAR), (s)}
  72. static UNICODE_STRING CscSpecialShares[] = {
  73. UNICODE_STRING_STRUCT(L"PIPE"),
  74. UNICODE_STRING_STRUCT(L"IPC$"),
  75. UNICODE_STRING_STRUCT(L"ADMIN$"),
  76. UNICODE_STRING_STRUCT(L"MAILSLOT")
  77. };
  78. KEVENT CscServerEntryTransitioningEvent;
  79. FAST_MUTEX CscServerEntryTransitioningMutex;
  80. PSMBCEDB_SERVER_ENTRY CscServerEntryBeingTransitioned = NULL;
  81. ULONG CscSessionIdCausingTransition = 0;
  82. HSHARE CscShareHandlePassedToAgent;
  83. BOOLEAN vfRetryFromUI = FALSE;
  84. PSMBCEDB_SERVER_ENTRY CscDfsRootServerEntryBeingTransitioned = NULL;
  85. BOOLEAN CscDisableOfflineOperation = FALSE;
  86. ULONG hTransitionMutexOwner=0;
  87. BOOLEAN CSCCheckForAcd(VOID);
  88. BOOLEAN CscTransitnOKToGoOffline(
  89. NTSTATUS RemoteStatus
  90. );
  91. BOOLEAN
  92. CscIsServerOffline(
  93. PWCHAR ServerName)
  94. /*++
  95. Routine Description:
  96. This routine initiates the processing of a transition request by notifying
  97. the agent and waiting for the response.
  98. Arguments:
  99. ServerName - the server name
  100. Return Value:
  101. returns TRUE if the server entry is offline
  102. Notes:
  103. If ServerName is NULL we return the status of the Net
  104. --*/
  105. {
  106. BOOLEAN ServerOffline;
  107. DWORD cntSlashes;
  108. UNICODE_STRING uniTemp;
  109. ServerOffline = (CscNetPresent == 0);
  110. if (ServerName != NULL) {
  111. PSMBCEDB_SERVER_ENTRY pServerEntry;
  112. USHORT ServerNameLengthInBytes;
  113. PWCHAR pTempName;
  114. UNICODE_STRING ServerNameString;
  115. ServerOffline = FALSE;
  116. pTempName = ServerName;
  117. ServerNameLengthInBytes = 0;
  118. cntSlashes = 0;
  119. if (*pTempName == L'\\')
  120. {
  121. ++pTempName;
  122. ++cntSlashes;
  123. }
  124. if (*pTempName == L'\\')
  125. {
  126. ++pTempName;
  127. ++cntSlashes;
  128. }
  129. // we allow \\servername or servername (with no \\)
  130. if (cntSlashes == 1)
  131. {
  132. return FALSE;
  133. }
  134. while (*pTempName++ != L'\0') {
  135. ServerNameLengthInBytes += sizeof(WCHAR);
  136. }
  137. ServerNameString.MaximumLength = ServerNameString.Length = ServerNameLengthInBytes;
  138. ServerNameString.Buffer = ServerName+cntSlashes;
  139. SmbCeAcquireResource();
  140. try
  141. {
  142. pServerEntry = SmbCeGetFirstServerEntry();
  143. while (pServerEntry != NULL) {
  144. uniTemp = pServerEntry->Name;
  145. // skip the single backslash on the server entry name
  146. uniTemp.Length -= sizeof(WCHAR);
  147. uniTemp.Buffer += 1;
  148. if (uniTemp.Length == ServerNameLengthInBytes) {
  149. if (RtlCompareUnicodeString(
  150. &uniTemp,
  151. &ServerNameString,
  152. TRUE) == 0) {
  153. ServerOffline = SmbCeIsServerInDisconnectedMode(pServerEntry);
  154. break;
  155. }
  156. }
  157. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  158. }
  159. }
  160. except(EXCEPTION_EXECUTE_HANDLER)
  161. {
  162. SmbCeReleaseResource();
  163. return FALSE;
  164. }
  165. SmbCeReleaseResource();
  166. if (!pServerEntry && !CscNetPresent)
  167. {
  168. HSHARE CscShareHandle = 0;
  169. ULONG ulRootHintFlags=0;
  170. GetHShareFromUNCString(
  171. ServerNameString.Buffer,
  172. ServerNameString.Length,
  173. 2, // No double-leading backslashes in the name passed in
  174. FALSE, // server name
  175. &CscShareHandle,
  176. &ulRootHintFlags);
  177. ServerOffline = (CscShareHandle != 0);
  178. }
  179. }
  180. return ServerOffline;
  181. }
  182. NTSTATUS
  183. CscTakeServerOffline(
  184. PWCHAR ServerName)
  185. {
  186. PSMBCEDB_SERVER_ENTRY pServerEntry;
  187. UNICODE_STRING ServerNameString;
  188. UNICODE_STRING tmpSrvName;
  189. NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
  190. // DbgPrint("CscTakeServerOffline(%ws)\n", ServerName);
  191. if (ServerName == NULL) {
  192. Status = ERROR_INVALID_PARAMETER;
  193. goto AllDone;
  194. }
  195. // Clip leading backslashes
  196. while (*ServerName == L'\\') {
  197. ServerName++;
  198. }
  199. RtlInitUnicodeString(&ServerNameString, ServerName);
  200. // Scan list of server entries looking for this one
  201. SmbCeAcquireResource();
  202. try {
  203. pServerEntry = SmbCeGetFirstServerEntry();
  204. while (pServerEntry != NULL) {
  205. if (pServerEntry->Server.CscState == ServerCscShadowing) {
  206. if (pServerEntry->DfsRootName.Length > 0) {
  207. tmpSrvName = pServerEntry->DfsRootName;
  208. tmpSrvName.Length -= sizeof(WCHAR);
  209. tmpSrvName.Buffer += 1;
  210. if (RtlCompareUnicodeString(&tmpSrvName, &ServerNameString, TRUE) == 0)
  211. break;
  212. } else {
  213. tmpSrvName = pServerEntry->Name;
  214. tmpSrvName.Length -= sizeof(WCHAR);
  215. tmpSrvName.Buffer += 1;
  216. if (RtlCompareUnicodeString(&tmpSrvName, &ServerNameString, TRUE) == 0)
  217. break;
  218. }
  219. }
  220. pServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  221. }
  222. } except(EXCEPTION_EXECUTE_HANDLER) {
  223. SmbCeReleaseResource();
  224. Status = ERROR_INVALID_PARAMETER;
  225. }
  226. if (pServerEntry != NULL) {
  227. // DbgPrint("Found ServerEntry@0x%x\n", pServerEntry);
  228. SmbCeReferenceServerEntry(pServerEntry);
  229. SmbCeReleaseResource();
  230. Status = CscTransitionServerEntryForDisconnectedOperation(
  231. pServerEntry,
  232. NULL,
  233. STATUS_BAD_NETWORK_NAME,
  234. FALSE);
  235. // Mark it so it will not auto-reconnect
  236. if (Status == STATUS_SUCCESS)
  237. pServerEntry->Server.IsPinnedOffline = TRUE;
  238. SmbCeDereferenceServerEntry(pServerEntry);
  239. } else {
  240. SmbCeReleaseResource();
  241. }
  242. AllDone:
  243. return Status;
  244. }
  245. BOOLEAN
  246. CscCheckWithAgentForTransitioningServerEntry(
  247. PSMBCEDB_SERVER_ENTRY pServerEntry,
  248. ULONG SessionId,
  249. HSHARE AgentShareHandle,
  250. BOOLEAN fInvokeAutoDial,
  251. BOOLEAN *lpfRetryFromUI,
  252. PSMBCEDB_SERVER_ENTRY *pDfsRootServerEntry
  253. )
  254. /*++
  255. Routine Description:
  256. This routine initiates the processing of a transition request by notifying
  257. the agent and waiting for the response.
  258. Arguments:
  259. pServerEntry - the server entry
  260. pNetRootEntry - the net root entry instance
  261. Return Value:
  262. returns TRUE if the server entry was transitioned for offlien operation
  263. --*/
  264. {
  265. LONG cntTransportsForCSC=0;
  266. BOOLEAN TransitionedServerEntry, OkToTransition = FALSE;
  267. PSMBCEDB_SERVER_ENTRY pTempServerEntry = NULL;
  268. if(!MRxSmbIsCscEnabled) {
  269. return(FALSE);
  270. }
  271. // DbgPrint("CscCheckWithAgent %wZ \n", &pServerEntry->Name);
  272. ExAcquireFastMutex(&CscServerEntryTransitioningMutex);
  273. hTransitionMutexOwner = GetCurThreadHandle();
  274. if (pServerEntry->DfsRootName.Length != 0)
  275. {
  276. PSMBCEDB_SERVER_ENTRY pThisServerEntry;
  277. PSMBCEDB_SERVER_ENTRY pNextServerEntry;
  278. SmbCeAcquireResource();
  279. pThisServerEntry = SmbCeGetFirstServerEntry();
  280. while (pThisServerEntry != NULL) {
  281. pNextServerEntry = SmbCeGetNextServerEntry(pThisServerEntry);
  282. if (RtlEqualUnicodeString(&pServerEntry->DfsRootName,
  283. &pThisServerEntry->Name,
  284. TRUE)) {
  285. // DbgPrint("CscCheckWithAgent DfsRoot %wZ \n", &pThisServerEntry->Name);
  286. pTempServerEntry = pThisServerEntry;
  287. break;
  288. }
  289. pThisServerEntry = pNextServerEntry;
  290. }
  291. SmbCeReleaseResource();
  292. }
  293. CscServerEntryBeingTransitioned = pServerEntry;
  294. CscDfsRootServerEntryBeingTransitioned = pTempServerEntry;
  295. CscShareHandlePassedToAgent = AgentShareHandle;
  296. vfRetryFromUI = FALSE;
  297. KeResetEvent(&CscServerEntryTransitioningEvent);
  298. OkToTransition = (!SmbCeIsServerInDisconnectedMode(pServerEntry)||
  299. (pTempServerEntry && !SmbCeIsServerInDisconnectedMode(pTempServerEntry)));
  300. if (OkToTransition) {
  301. // This is dropped in MRxSmbCscSignalAgent
  302. EnterShadowCrit();
  303. SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_SHARE_DISCONNECTED);
  304. if (fInvokeAutoDial)
  305. {
  306. SetFlag(sGS.uFlagsEvents,FLAG_GLOBALSTATUS_INVOKE_AUTODIAL);
  307. }
  308. sGS.hShareDisconnected = AgentShareHandle;
  309. CscSessionIdCausingTransition = SessionId;
  310. MRxSmbCscSignalAgent(
  311. NULL,
  312. SIGNALAGENTFLAG_CONTINUE_FOR_NO_AGENT);
  313. KeWaitForSingleObject(
  314. &CscServerEntryTransitioningEvent,
  315. Executive,
  316. KernelMode,
  317. FALSE,
  318. NULL);
  319. }
  320. TransitionedServerEntry = (SmbCeIsServerInDisconnectedMode(pServerEntry) &&
  321. (!pTempServerEntry || SmbCeIsServerInDisconnectedMode(pTempServerEntry)));
  322. *pDfsRootServerEntry = pTempServerEntry;
  323. CscServerEntryBeingTransitioned = NULL;
  324. CscShareHandlePassedToAgent = 0;
  325. CscDfsRootServerEntryBeingTransitioned = NULL;
  326. CscSessionIdCausingTransition = 0;
  327. *lpfRetryFromUI = vfRetryFromUI;
  328. hTransitionMutexOwner = 0;
  329. ExReleaseFastMutex(&CscServerEntryTransitioningMutex);
  330. return TransitionedServerEntry;
  331. }
  332. NTSTATUS
  333. CscTransitionServerToOffline(
  334. ULONG SessionId,
  335. HSHARE hShare,
  336. ULONG TransitionStatus)
  337. /*++
  338. Routine Description:
  339. This routine updates the RDR data structures based upon the decision of the
  340. agent
  341. Arguments:
  342. hShare - the shadow handle to the server
  343. TransitionStatus -- it is tri state value.
  344. 0 implies retry the operation.
  345. 1 transition this server for offline operation
  346. anything else means fail
  347. Return Value:
  348. NTSTATUS - The return status for the operation
  349. --*/
  350. {
  351. LONG CscState = ServerCscShadowing;
  352. if(!MRxSmbIsCscEnabled) {
  353. return(STATUS_UNSUCCESSFUL);
  354. }
  355. // DbgPrint("CscTransitionServerToOffline: Share 0x%x SessionId 0x%x (vs 0x%x)\n",
  356. // hShare,
  357. // SessionId,
  358. // CscSessionIdCausingTransition);
  359. switch (TransitionStatus) {
  360. case 1 :
  361. if (fShadow && // only if CSC is turned ON by the agent do we go disconnected
  362. CscServerEntryBeingTransitioned && // there is a server entry (this must be true
  363. CscSessionIdCausingTransition == SessionId && // The right session
  364. CscShareHandlePassedToAgent // and we have a share in the database
  365. )
  366. {
  367. // then it is OK to go disconnected
  368. CscState = ServerCscDisconnected;
  369. }
  370. break;
  371. case 0 : // UI said retry
  372. vfRetryFromUI = TRUE;
  373. break;
  374. default:
  375. break;
  376. }
  377. if (CscServerEntryBeingTransitioned != NULL && SessionId == CscSessionIdCausingTransition) {
  378. // DbgPrint("CscTransitionServerToOffline %wZ \n", &CscServerEntryBeingTransitioned->Name);
  379. InterlockedExchange(
  380. &CscServerEntryBeingTransitioned->Server.CscState,
  381. CscState);
  382. // DbgPrint("CscTransitionServerToOffline %wZ Sess 0x%x\n",
  383. // &CscServerEntryBeingTransitioned->Name,
  384. // SessionId);
  385. if (CscDfsRootServerEntryBeingTransitioned)
  386. {
  387. // if this is an alternate, then also put the
  388. // dfs root in disconnected state if it isn't already
  389. if (!SmbCeIsServerInDisconnectedMode(CscDfsRootServerEntryBeingTransitioned))
  390. {
  391. SmbCeReferenceServerEntry(CscDfsRootServerEntryBeingTransitioned);
  392. }
  393. InterlockedExchange(
  394. &CscDfsRootServerEntryBeingTransitioned->Server.CscState,
  395. CscState);
  396. }
  397. // Signal the event on which the other requests in the RDR are waiting
  398. KeSetEvent(
  399. &CscServerEntryTransitioningEvent,
  400. 0,
  401. FALSE );
  402. } else {
  403. // ASSERT(!"No server entry is transitioning to offline");
  404. }
  405. return STATUS_SUCCESS;
  406. }
  407. VOID
  408. CscPrepareServerEntryForOnlineOperation(
  409. PSMBCEDB_SERVER_ENTRY pServerEntry,
  410. BOOL fGoAllTheWay
  411. )
  412. /*++
  413. Routine Description:
  414. This routine transitions a given server entry for online operation
  415. Arguments:
  416. pServerEntry - the server entry that needs to be transitioned
  417. NTSTATUS - The return status for the operation
  418. --*/
  419. {
  420. PSMBCEDB_SESSION_ENTRY pSessionEntry;
  421. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  422. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  423. LONG CscState;
  424. SmbCeLog(("Transition SE %lx fGoAllTheWay=%d\n",pServerEntry, fGoAllTheWay));
  425. SmbLog(LOG,
  426. CscPrepareServerEntryForOnlineOperation_1,
  427. LOGULONG(fGoAllTheWay)
  428. LOGPTR(pServerEntry)
  429. LOGUSTR(pServerEntry->Name));
  430. if (fGoAllTheWay)
  431. {
  432. CscState = InterlockedCompareExchange(
  433. &pServerEntry->Server.CscState,
  434. ServerCscTransitioningToShadowing,
  435. ServerCscDisconnected);
  436. if(pServerEntry->Server.IsFakeDfsServerForOfflineUse == TRUE)
  437. {
  438. HookKdPrint(TRANSITION, ("CscPrepareServerEntryForOnlineOperation: %x is a FAKE DFS entry, mark it for destruction \n", pServerEntry));
  439. pServerEntry->Header.State = SMBCEDB_DESTRUCTION_IN_PROGRESS;
  440. }
  441. SmbCeLog(("Transition SE %lx %wZ fGoAllTheWay CscState=%x\n",pServerEntry, &pServerEntry->Name, CscState));
  442. SmbLog(LOG,
  443. CscPrepareServerEntryForOnlineOperation_2,
  444. LOGULONG(CscState)
  445. LOGPTR(pServerEntry)
  446. LOGUSTR(pServerEntry->Name));
  447. }
  448. if (!fGoAllTheWay || (CscState == ServerCscDisconnected)) {
  449. SmbCeLog(("Transition SE CO %lx, fGoAllTheWay=%d\n",pServerEntry, fGoAllTheWay));
  450. SmbLog(LOG,
  451. CscPrepareServerEntryForOnlineOperation_3,
  452. LOGULONG(fGoAllTheWay)
  453. LOGPTR(pServerEntry)
  454. LOGUSTR(pServerEntry->Name));
  455. InterlockedCompareExchange(
  456. &pServerEntry->Header.State,
  457. SMBCEDB_DESTRUCTION_IN_PROGRESS,
  458. SMBCEDB_ACTIVE);
  459. SmbCeReferenceServerEntry(pServerEntry);
  460. SmbCeResumeAllOutstandingRequestsOnError(pServerEntry);
  461. pServerEntry->ServerStatus = STATUS_CONNECTION_DISCONNECTED;
  462. if (fGoAllTheWay)
  463. {
  464. MRxSmbCSCResumeAllOutstandingOperations(pServerEntry);
  465. pServerEntry->Server.CscState = ServerCscShadowing;
  466. pServerEntry->Server.IsPinnedOffline = FALSE;
  467. SmbCeDereferenceServerEntry(pServerEntry);
  468. }
  469. }
  470. }
  471. VOID
  472. CscPrepareServerEntryForOnlineOperationFull(
  473. PSMBCEDB_SERVER_ENTRY pServerEntry
  474. )
  475. /*++
  476. Routine Description:
  477. This routine transitions a given server entry for online operation
  478. Arguments:
  479. pServerEntry - the server entry that needs to be transitioned
  480. NTSTATUS - The return status for the operation
  481. --*/
  482. {
  483. CscPrepareServerEntryForOnlineOperation(pServerEntry, TRUE);
  484. }
  485. VOID
  486. CscPrepareServerEntryForOnlineOperationPartial(
  487. PSMBCEDB_SERVER_ENTRY pServerEntry
  488. )
  489. /*++
  490. Routine Description:
  491. This routine transitions a given server entry for online operation
  492. Arguments:
  493. pServerEntry - the server entry that needs to be transitioned
  494. NTSTATUS - The return status for the operation
  495. --*/
  496. {
  497. CscPrepareServerEntryForOnlineOperation(pServerEntry, FALSE);
  498. }
  499. NTSTATUS
  500. CscTransitionServerToOnline(
  501. HSHARE hShare)
  502. /*++
  503. Routine Description:
  504. This routine updates the RDR data structures based upon the decision of the
  505. agent
  506. Arguments:
  507. hShare - the shadow handle to the server
  508. Return Value:
  509. NTSTATUS - The return status for the operation
  510. --*/
  511. {
  512. PSMBCEDB_SERVER_ENTRY pServerEntry;
  513. SHAREINFOW sSR;
  514. NTSTATUS Status=STATUS_INVALID_PARAMETER;
  515. if (hShare == 0) {
  516. Status=STATUS_SUCCESS;
  517. SmbCeLog(("Transtioning all servers online \n"));
  518. SmbLog(LOG,
  519. CscTransitionServerToOnline_1,
  520. LOGULONG(hShare));
  521. SmbCeAcquireResource();
  522. pServerEntry = SmbCeGetFirstServerEntry();
  523. while (pServerEntry != NULL) {
  524. PSMBCEDB_SERVER_ENTRY pNextServerEntry;
  525. pNextServerEntry = SmbCeGetNextServerEntry(pServerEntry);
  526. CscPrepareServerEntryForOnlineOperationFull(pServerEntry);
  527. pServerEntry = pNextServerEntry;
  528. }
  529. SmbCeReleaseResource();
  530. } else {
  531. int iRet;
  532. EnterShadowCrit();
  533. iRet = GetShareInfo(hShare, &sSR, NULL);
  534. LeaveShadowCrit();
  535. SmbCeLog(("Transtioning %ls online \n", sSR.rgSharePath));
  536. SmbLog(LOG,
  537. CscTransitionServerToOnline_2,
  538. LOGWSTR(sSR.rgSharePath));
  539. if (iRet >= 0)
  540. {
  541. Status = STATUS_SUCCESS;
  542. if ((FindServerEntryFromCompleteUNCPath(sSR.rgSharePath, &pServerEntry)) == STATUS_SUCCESS)
  543. {
  544. PSMBCEDB_SERVER_ENTRY pThisServerEntry;
  545. PSMBCEDB_SERVER_ENTRY pNextServerEntry;
  546. // DbgPrint("Close all open files on %wZ\n", &pServerEntry->Name);
  547. CloseOpenFiles(hShare, &pServerEntry->Name, 1); // skip one slash
  548. SmbCeAcquireResource();
  549. pThisServerEntry = SmbCeGetFirstServerEntry();
  550. while (pThisServerEntry != NULL) {
  551. pNextServerEntry = SmbCeGetNextServerEntry(pThisServerEntry);
  552. if (pThisServerEntry != pServerEntry &&
  553. pThisServerEntry->DfsRootName.Length != 0) {
  554. if (RtlEqualUnicodeString(&pThisServerEntry->DfsRootName,
  555. &pServerEntry->Name,
  556. TRUE)) {
  557. SmbCeLog(("Go online ServerEntry With DFS name %x\n",pThisServerEntry));
  558. SmbLog(LOG,
  559. CscTransitionServerToOnline_3,
  560. LOGPTR(pThisServerEntry)
  561. LOGUSTR(pThisServerEntry->Name));
  562. CscPrepareServerEntryForOnlineOperationFull(pThisServerEntry);
  563. }
  564. }
  565. pThisServerEntry = pNextServerEntry;
  566. }
  567. CscPrepareServerEntryForOnlineOperationFull(pServerEntry);
  568. SmbCeDereferenceServerEntry(pServerEntry);
  569. SmbCeReleaseResource();
  570. }
  571. }
  572. }
  573. return Status;
  574. }
  575. NTSTATUS
  576. CscpTransitionServerEntryForDisconnectedOperation(
  577. RX_CONTEXT *RxContext,
  578. PSMBCEDB_SERVER_ENTRY pServerEntry,
  579. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry,
  580. NTSTATUS RemoteStatus,
  581. BOOLEAN fInvokeAutoDial,
  582. ULONG uFlags
  583. )
  584. /*++
  585. Routine Description:
  586. This routine transitions the server entry for disconnected mode of
  587. operation
  588. Arguments:
  589. pServerEntry -- the server entry instance to be transitioned
  590. pNetRootEntry -- the net root entry instance
  591. RemoteStatus -- the failed status of the remote operation
  592. Return Value:
  593. NTSTATUS - The return status for the operation
  594. Notes:
  595. If this routine returns STATUS_RETRY it implies that the associated server
  596. entry has been successfully trnaisitioned for disconnected operation.
  597. --*/
  598. {
  599. NTSTATUS Status;
  600. BOOLEAN TransitionServerEntryToDisconnectedMode, fRetryFromUI=FALSE;
  601. ULONG ulRootHintFlags=0;
  602. LONG CscState, cntTransports=0;
  603. ULONG SessionId = INVALID_SESSION_ID;
  604. SmbCeLog(("CscTrPSrv IN DFSFlgs %x\n",uFlags));
  605. SmbLog(LOG,
  606. CscpTransitionServerEntryForDisconnectedOperation_1,
  607. LOGULONG(uFlags));
  608. if(!MRxSmbIsCscEnabled ||
  609. !CscTransitnOKToGoOffline(RemoteStatus) ||
  610. !(uFlags & DFS_FLAG_LAST_ALTERNATE) ||
  611. pServerEntry->Server.IsLoopBack) {
  612. SmbCeLog(("CscTrPSrv Out RemoteStatus=%x\n",RemoteStatus));
  613. SmbLog(LOG,
  614. CscpTransitionServerEntryForDisconnectedOperation_2,
  615. LOGULONG(RemoteStatus));
  616. return(RemoteStatus);
  617. }
  618. // if we are supposed to invoke autodial, check if autodial service is running
  619. // this will ensure that we don't go up in usermode when we shouldn't.
  620. if (fInvokeAutoDial) {
  621. fInvokeAutoDial = CSCCheckForAcd();
  622. }
  623. SmbCeLog(("CscTrPSrv Autodial %x\n",fInvokeAutoDial));
  624. SmbLog(LOG,
  625. CscpTransitionServerEntryForDisconnectedOperation_3,
  626. LOGUCHAR(fInvokeAutoDial));
  627. if (!fInvokeAutoDial) {
  628. // Notify the CSC agent of any transport changes if required
  629. CscNotifyAgentOfNetStatusChangeIfRequired(FALSE);
  630. }
  631. // Ensure that we are never called to prepare for a transition if the remote
  632. // operation was successful.
  633. ASSERT(RemoteStatus != STATUS_SUCCESS);
  634. // The transition to disconnected operation is a three step process...
  635. // If the remote status is not one of the list of statuses that can signal
  636. // a transition to disconnected operation relect the remote status back.
  637. Status = RemoteStatus;
  638. if (CscDisableOfflineOperation) {
  639. return Status;
  640. }
  641. CscState = InterlockedCompareExchange(
  642. &pServerEntry->Server.CscState,
  643. ServerCscTransitioningToDisconnected,
  644. ServerCscShadowing);
  645. if (CscState == ServerCscShadowing) {
  646. HSHARE CscShareHandle = 0;
  647. if (pNetRootEntry != NULL) {
  648. CscShareHandle = pNetRootEntry->NetRoot.sCscRootInfo.hShare;
  649. }
  650. /***********************************************************************************************
  651. ACHTUNG !!! do not hold the shadow critical section here
  652. This may cause a deadlock, as a paging read could come down this way because
  653. a server has gone down. The guy doing the paging read may be holding the
  654. VCB and the FCB locks on FAT. Some other thread might own the shadowcritsect
  655. and may be trying to open a file. This would cause it to try to acquire the
  656. VCB and hence block. Thus we have classic deadlock situation.
  657. This happens only on FAT.
  658. The only consequence of not holding the critsect here is that we
  659. may get a false warning for a share that used to be in the database but has gotten
  660. deleted. It would be very difficult to hit that timing window so the
  661. chances of this happening are slim to none.
  662. There is another aspect to this solution, which is to make sure that handle for
  663. the shares inode is always kept open, so FAT will never have to hold the VCB
  664. ***********************************************************************************************/
  665. // do any CSC operations only if it is indeed enabled
  666. if (fShadow )
  667. {
  668. if (CscShareHandle == 0) {
  669. PDFS_NAME_CONTEXT pDfsNameContext = NULL;
  670. UNICODE_STRING uUncName = {0, 0, NULL};
  671. UNICODE_STRING uShareName = {0, 0, NULL};
  672. BOOL fIsShareName = FALSE;
  673. PIO_STACK_LOCATION IrpSp = NULL;
  674. PQUERY_PATH_REQUEST QpReq;
  675. ULONG cntSlashes = 0;
  676. ULONG i;
  677. if (RxContext != NULL && RxContext->CurrentIrpSp != NULL) {
  678. IrpSp = RxContext->CurrentIrpSp;
  679. //
  680. // If this is a create AND a dfs path, use the dfs path passed in
  681. //
  682. if (IrpSp->MajorFunction == IRP_MJ_CREATE) {
  683. pDfsNameContext = CscIsValidDfsNameContext(
  684. RxContext->Create.NtCreateParameters.DfsNameContext);
  685. if (pDfsNameContext != NULL) {
  686. // DbgPrint("DfsNameContext UNCFileName=[%wZ]\n",
  687. // &pDfsNameContext->UNCFileName);
  688. uUncName = pDfsNameContext->UNCFileName;
  689. fIsShareName = TRUE;
  690. }
  691. //
  692. // If this is a query ioctl, use the path we're querying
  693. //
  694. } else if (IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL
  695. &&
  696. IrpSp->MinorFunction == 0
  697. &&
  698. IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH
  699. ) {
  700. QpReq =
  701. (PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  702. uUncName.Buffer = QpReq->FilePathName;
  703. uUncName.Length = (USHORT) QpReq->PathNameLength;
  704. uUncName.MaximumLength = uUncName.Length;
  705. fIsShareName = TRUE;
  706. }
  707. }
  708. //
  709. // Not a dfs create nor a query path - use the redir's netrootentry,
  710. // if we have one
  711. //
  712. if (uUncName.Buffer == NULL && pNetRootEntry && pNetRootEntry->Name.Length) {
  713. uUncName = pNetRootEntry->Name;
  714. fIsShareName = TRUE;
  715. }
  716. //
  717. // Bottom out using the server entry, either the dfsrootname
  718. // or the serverentry name. This will take the server offline
  719. // w/o regard to which share the error was in reference to.
  720. //
  721. if (uUncName.Buffer == NULL) {
  722. if (pServerEntry->DfsRootName.Buffer) {
  723. uUncName = pServerEntry->DfsRootName;
  724. } else {
  725. uUncName = pServerEntry->Name;
  726. }
  727. }
  728. //
  729. // Be sure all we have is \server\share, or \server,
  730. //
  731. for (cntSlashes = i = 0; i < uUncName.Length/sizeof(WCHAR); i++) {
  732. if (uUncName.Buffer[i] == L'\\')
  733. cntSlashes++;
  734. if (cntSlashes >= 3) {
  735. uUncName.Length = (USHORT) (sizeof(WCHAR) * i);
  736. break;
  737. }
  738. }
  739. //
  740. // If this is a special share (like IPC$), treat it as a valid
  741. // share to go offline against. (IE, we go offline against
  742. // \server\IPC$)
  743. if (fIsShareName == TRUE) {
  744. uShareName = uUncName;
  745. for (cntSlashes = i = 0; i < uUncName.Length/sizeof(WCHAR); i++) {
  746. uShareName.Buffer++;
  747. uShareName.Length -= sizeof(WCHAR);
  748. if (uUncName.Buffer[i] == L'\\')
  749. cntSlashes++;
  750. if (cntSlashes == 2)
  751. break;
  752. }
  753. if (CscIsSpecialShare(&uShareName) == TRUE) {
  754. fIsShareName = FALSE;
  755. // revert to just \servername
  756. uUncName.Length -= uShareName.Length + sizeof(WCHAR);
  757. }
  758. }
  759. GetHShareFromUNCString(
  760. uUncName.Buffer,
  761. uUncName.Length,
  762. 1,
  763. fIsShareName,
  764. &CscShareHandle,
  765. &ulRootHintFlags);
  766. ulRootHintFlags &= ~FLAG_CSC_HINT_PIN_SYSTEM;
  767. // DbgPrint("CscpTransitionServerEntry: [%wZ] CSCHandle=%x\n",
  768. // &uUncName,
  769. // CscShareHandle);
  770. RxDbgTrace(0, Dbg, ("CscpTransitionServerEntry: [%wZ] CSCHandle=%x\n",
  771. &uUncName,
  772. CscShareHandle));
  773. } else {
  774. ulRootHintFlags = 0;
  775. }
  776. } // if (fShadow)
  777. else
  778. {
  779. CscShareHandle = 0; // if the agent hasn't turned on CSC
  780. // then don't tell him for CSC shares
  781. }
  782. if (fInvokeAutoDial || // either autodial
  783. (CscShareHandle != 0)) { // or CSC
  784. if (MRxSmbCscTransitionEnabledByDefault) {
  785. RxDbgTrace(0, Dbg, ("CscTransitionServerEntryForDisconnectedOperation: silently going offline on %wZ\r\n", CscShareHandle, ulRootHintFlags));
  786. InterlockedExchange(
  787. &pServerEntry->Server.CscState,
  788. ServerCscDisconnected);
  789. SmbCeReferenceServerEntry(pServerEntry);
  790. Status = STATUS_SUCCESS;
  791. RxDbgTrace(0, Dbg, ("Transitioning Server Entry for DC %lx Status %lx\n",pServerEntry,Status));
  792. SmbCeLog(("Transitioning Server Entry for DC %lx Status %lx\n",pServerEntry,Status));
  793. SmbLog(LOG,
  794. CscpTransitionServerEntryForDisconnectedOperation_4,
  795. LOGULONG(Status)
  796. LOGPTR(pServerEntry)
  797. LOGUSTR(pServerEntry->Name));
  798. } else {
  799. PSMBCEDB_SERVER_ENTRY pDfsRootServerEntry = NULL;
  800. PIO_STACK_LOCATION IrpSp = NULL;
  801. if (RxContext != NULL && RxContext->CurrentIrpSp != NULL)
  802. IrpSp = RxContext->CurrentIrpSp;
  803. // If the remote status was such that a transition to disconnected operation
  804. // should be triggerred we need to signal the agent to trigger the appropriate
  805. // mechanism for involving the client in this decision and decide based on the
  806. // result.
  807. cntTransports = vcntTransportsForCSC;
  808. SmbCeLog(("CscTrPSrv ChkAgnt %x\n",CscShareHandle));
  809. SmbLog(LOG,
  810. CscpTransitionServerEntryForDisconnectedOperation_5,
  811. LOGULONG(CscShareHandle));
  812. RxDbgTrace(0, Dbg, ("CscTransitionServerEntryForDisconnectedOperation: Checking with agent before going offline on CscShareHandle=%x HintFlags=%x\r\n", CscShareHandle, ulRootHintFlags));
  813. // if (RxContext != NULL && RxContext->CurrentIrpSp != NULL) {
  814. // DbgPrint("** Transition: MJ/MN = 0x%x/0x%x\n",
  815. // RxContext->CurrentIrpSp->MajorFunction,
  816. // RxContext->CurrentIrpSp->MinorFunction);
  817. // }
  818. if (
  819. RxContext
  820. &&
  821. RxContext->pRelevantSrvOpen
  822. &&
  823. RxContext->pRelevantSrvOpen->pVNetRoot
  824. ) {
  825. SessionId = RxContext->pRelevantSrvOpen->pVNetRoot->SessionId;
  826. } else {
  827. // DbgPrint("** pVnetRoot's sessionid not present\n");
  828. }
  829. if (
  830. SessionId == INVALID_SESSION_ID
  831. &&
  832. IrpSp != NULL
  833. &&
  834. IrpSp->MajorFunction == IRP_MJ_CREATE
  835. ) {
  836. PIO_SECURITY_CONTEXT pSecurityContext;
  837. PACCESS_TOKEN pAccessToken;
  838. // DbgPrint("**CREATE\n");
  839. pSecurityContext = RxContext->Create.NtCreateParameters.SecurityContext;
  840. pAccessToken = SeQuerySubjectContextToken(
  841. &pSecurityContext->AccessState->SubjectSecurityContext);
  842. if (!SeTokenIsRestricted(pAccessToken))
  843. SeQuerySessionIdToken(pAccessToken, &SessionId);
  844. }
  845. if (
  846. SessionId == INVALID_SESSION_ID
  847. &&
  848. IrpSp != NULL
  849. &&
  850. IrpSp->MajorFunction == IRP_MJ_DEVICE_CONTROL
  851. &&
  852. IrpSp->Parameters.DeviceIoControl.IoControlCode == IOCTL_REDIR_QUERY_PATH
  853. ) {
  854. PQUERY_PATH_REQUEST QpReq;
  855. PSECURITY_SUBJECT_CONTEXT pSecurityContext;
  856. // DbgPrint("**QUERY_PATH\n");
  857. QpReq = (PQUERY_PATH_REQUEST)IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  858. pSecurityContext = &QpReq->SecurityContext->AccessState->SubjectSecurityContext;
  859. if (pSecurityContext->ClientToken != NULL)
  860. SeQuerySessionIdToken(pSecurityContext->ClientToken, &SessionId);
  861. else
  862. SeQuerySessionIdToken(pSecurityContext->PrimaryToken, &SessionId);
  863. }
  864. if (SessionId == INVALID_SESSION_ID) {
  865. // DbgPrint("** Not CREATE or QUERY_PATH...\n");
  866. if (RxContext != NULL && RxContext->CurrentIrp != NULL)
  867. IoGetRequestorSessionId(RxContext->CurrentIrp, &SessionId);
  868. }
  869. if (SessionId == INVALID_SESSION_ID) {
  870. // DbgPrint("All sessionid attempts failed, setting to 0..\n");
  871. SessionId = 0;
  872. }
  873. // DbgPrint("** CscTrPSrv ChkAgnt SessionId: 0x%x\n", SessionId);
  874. if (CscCheckWithAgentForTransitioningServerEntry(
  875. pServerEntry,
  876. SessionId,
  877. CscShareHandle,
  878. fInvokeAutoDial,
  879. &fRetryFromUI,
  880. &pDfsRootServerEntry
  881. )) {
  882. SmbCeReferenceServerEntry(pServerEntry);
  883. Status = STATUS_SUCCESS;
  884. RxDbgTrace(0, Dbg, ("Transitioning Server Entry for DC %lx Status %lx\n",pServerEntry,Status));
  885. SmbCeLog(("Transitioning Server Entry for DC %lx Status %lx\n",pServerEntry,Status));
  886. SmbLog(LOG,
  887. CscpTransitionServerEntryForDisconnectedOperation_4,
  888. LOGULONG(Status)
  889. LOGPTR(pServerEntry)
  890. LOGUSTR(pServerEntry->Name));
  891. }
  892. else if (fRetryFromUI)
  893. {
  894. LARGE_INTEGER interval;
  895. int i;
  896. SmbCeLog(("CscTrPSrv UIretry\n"));
  897. SmbLog(LOG,
  898. CscpTransitionServerEntryForDisconnectedOperation_6,
  899. LOGUCHAR(fRetryFromUI));
  900. RxDbgTrace(0, Dbg, ("UI sent us rerty, polling for %d seconds\n", CSC_AUTODIAL_POLL_COUNT));
  901. for (i=0; i<CSC_AUTODIAL_POLL_COUNT; ++i)
  902. {
  903. if(cntTransports != vcntTransportsForCSC)
  904. {
  905. Status = STATUS_RETRY;
  906. RxDbgTrace(0, Dbg, ("A new transport arrived \r\n"));
  907. break;
  908. }
  909. interval.QuadPart = -1*10*1000*10*100; // 1 second
  910. KeDelayExecutionThread( KernelMode, FALSE, &interval );
  911. }
  912. InterlockedExchange(
  913. &pServerEntry->Server.CscState,
  914. ServerCscShadowing);
  915. }
  916. }
  917. }
  918. else
  919. {
  920. InterlockedExchange(
  921. &pServerEntry->Server.CscState,
  922. ServerCscShadowing);
  923. }
  924. } else if (CscState == ServerCscDisconnected) {
  925. Status = STATUS_SUCCESS;
  926. }
  927. SmbCeLog(("CscTrPSrv Out St %x\n",Status));
  928. SmbLog(LOG,
  929. CscpTransitionServerEntryForDisconnectedOperation_7,
  930. LOGULONG(Status));
  931. return Status;
  932. }
  933. BOOLEAN
  934. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation(
  935. PRX_CONTEXT RxContext)
  936. {
  937. BOOLEAN TransitionVNetRoot = FALSE;
  938. SmbCeLog(("CSCTrIsDfs IN %x\n", RxContext));
  939. SmbLog(LOG,
  940. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation_1,
  941. LOGPTR(RxContext));
  942. if ((RxContext != NULL) &&
  943. RxContext->CurrentIrpSp &&
  944. (RxContext->CurrentIrpSp->MajorFunction == IRP_MJ_CREATE)){
  945. NTSTATUS Status;
  946. PDFS_NAME_CONTEXT pDfsNameContext;
  947. UNICODE_STRING ShareName;
  948. pDfsNameContext = CscIsValidDfsNameContext(
  949. RxContext->Create.NtCreateParameters.DfsNameContext);
  950. if (pDfsNameContext != NULL) {
  951. // Ensure that the server handles in the NET_ROOT instance
  952. // are initialized. This is because the DFS server munges
  953. // the names and the original DFS name needs to be presented
  954. // to the user for transitioning.
  955. SmbCeLog(("CSCTrIsDfs IsDsf %x\n", pDfsNameContext));
  956. SmbLog(LOG,
  957. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation_2,
  958. LOGPTR(pDfsNameContext)
  959. LOGULONG(pDfsNameContext->NameContextType)
  960. LOGULONG(pDfsNameContext->Flags)
  961. LOGUSTR(pDfsNameContext->UNCFileName));
  962. Status = CscDfsParseDfsPath(
  963. &pDfsNameContext->UNCFileName,
  964. NULL,
  965. &ShareName,
  966. NULL);
  967. if (Status == STATUS_SUCCESS) {
  968. SHADOWINFO ShadowInfo;
  969. int Result;
  970. SmbCeLog(("CSCTrDfs Parsed %wZ\n",&ShareName));
  971. SmbLog(LOG,
  972. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation_3,
  973. LOGUSTR(ShareName));
  974. EnterShadowCrit();
  975. TransitionVNetRoot = (FindCreateShareForNt(
  976. &ShareName,
  977. FALSE, // do not create a new one
  978. &ShadowInfo,
  979. NULL) == SRET_OK);
  980. LeaveShadowCrit();
  981. if (!fShadow && TransitionVNetRoot)
  982. {
  983. // DbgPrint("FindCreateServerForNt incorrectly returned TRUE for %wZ\n", &ShareName);
  984. ASSERT(FALSE);
  985. }
  986. if (TransitionVNetRoot)
  987. {
  988. SmbCeLog(("CSCTrDfs TrOffl \n"));
  989. SmbLog(LOG,
  990. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation_4,
  991. LOGUCHAR(TransitionVNetRoot));
  992. // DbgPrint("CSC:transitioning DFS share %wZ to offline hShare=%x shadowinfo=%x\n",&ShareName, ShadowInfo.hShare, &ShadowInfo);
  993. ASSERT(ShadowInfo.hShare != 0);
  994. }
  995. }
  996. } else {
  997. TransitionVNetRoot = FALSE;
  998. }
  999. } else {
  1000. TransitionVNetRoot = FALSE;
  1001. }
  1002. SmbCeLog(("CSCTrIsDfs Out %x\n", TransitionVNetRoot));
  1003. SmbLog(LOG,
  1004. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation_5,
  1005. LOGUCHAR(TransitionVNetRoot));
  1006. return TransitionVNetRoot;
  1007. }
  1008. NTSTATUS
  1009. CscPrepareDfsServerEntryForDisconnectedOperation(
  1010. PSMBCEDB_SERVER_ENTRY pCurrentServerEntry,
  1011. PRX_CONTEXT RxContext)
  1012. {
  1013. NTSTATUS Status = STATUS_SUCCESS;
  1014. PDFS_NAME_CONTEXT pDfsNameContext;
  1015. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1016. BOOLEAN fNewServerEntry;
  1017. UNICODE_STRING ServerName;
  1018. if ((RxContext == NULL) ||
  1019. (RxContext->CurrentIrp == NULL) ||
  1020. (RxContext->CurrentIrpSp->MajorFunction != IRP_MJ_CREATE)) {
  1021. return Status;
  1022. }
  1023. pDfsNameContext = CscIsValidDfsNameContext(
  1024. RxContext->Create.NtCreateParameters.DfsNameContext);
  1025. if (pDfsNameContext == NULL) {
  1026. return Status;
  1027. }
  1028. Status = CscDfsParseDfsPath(
  1029. &pDfsNameContext->UNCFileName,
  1030. &ServerName,
  1031. NULL,
  1032. NULL);
  1033. if (Status != STATUS_SUCCESS) {
  1034. return Status;
  1035. }
  1036. if (!fShadow)
  1037. {
  1038. ASSERT(FALSE);
  1039. }
  1040. // Ensure that a server entry in the disconnected
  1041. // state is created
  1042. SmbCeAcquireResource();
  1043. pServerEntry = SmbCeFindServerEntry(
  1044. &ServerName,
  1045. SMBCEDB_FILE_SERVER,
  1046. NULL);
  1047. if (pServerEntry == NULL) {
  1048. Status = SmbCeFindOrConstructServerEntry(
  1049. &ServerName,
  1050. SMBCEDB_FILE_SERVER,
  1051. &pServerEntry,
  1052. &fNewServerEntry,
  1053. NULL);
  1054. if (pServerEntry && fNewServerEntry)
  1055. {
  1056. pServerEntry->Server.IsFakeDfsServerForOfflineUse = TRUE;
  1057. // DbgPrint(
  1058. // "CscPrepareDfsServerEntryForDisconnectedOperation: 0x%x [%wZ] is a FAKE DFS entry\n",
  1059. // pServerEntry,
  1060. // &ServerName);
  1061. }
  1062. } else {
  1063. if (pServerEntry == pCurrentServerEntry) {
  1064. // The find routine references the server entry.
  1065. // If this happens to be the same as the current server
  1066. // entry then the appropriate referencing for disconnected
  1067. // operaton has already been done,
  1068. SmbCeDereferenceServerEntry(pServerEntry);
  1069. }
  1070. }
  1071. if (pServerEntry != NULL) {
  1072. // DbgPrint("CscPrepareDfsServerEntry %wZ \n", &pServerEntry->Name);
  1073. InterlockedExchange(
  1074. &pServerEntry->Server.CscState,
  1075. ServerCscDisconnected);
  1076. } else {
  1077. Status = STATUS_INSUFFICIENT_RESOURCES;
  1078. }
  1079. SmbCeReleaseResource();
  1080. if (Status == STATUS_SUCCESS) {
  1081. Status = CscGrabPathFromDfs(
  1082. RxContext->CurrentIrpSp->FileObject,
  1083. pDfsNameContext);
  1084. }
  1085. return Status;
  1086. }
  1087. NTSTATUS
  1088. CscTransitionVNetRootForDisconnectedOperation(
  1089. PRX_CONTEXT RxContext,
  1090. PMRX_V_NET_ROOT pVNetRoot,
  1091. NTSTATUS RemoteStatus)
  1092. /*++
  1093. Routine Description:
  1094. This routine transitions the server entry for disconnected mode of
  1095. operation
  1096. Arguments:
  1097. pVNetRoot -- the net root instance
  1098. RemoteStatus -- the failed status of the remote operation
  1099. Return Value:
  1100. NTSTATUS - The return status for the operation
  1101. Notes:
  1102. If this routine returns STATUS_RETRY it implies that the associated server
  1103. entry has been successfully tranisitioned for disconnected operation.
  1104. --*/
  1105. {
  1106. NTSTATUS Status,ReturnStatus;
  1107. PMRX_FOBX capFobx = NULL;
  1108. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext = NULL;
  1109. PSMBCEDB_NET_ROOT_ENTRY pNetRootEntry;
  1110. if(!MRxSmbIsCscEnabled || !fShadow) {
  1111. return(RemoteStatus);
  1112. }
  1113. // Notify the CSC agent of any transport changes if required
  1114. CscNotifyAgentOfNetStatusChangeIfRequired(FALSE);
  1115. ReturnStatus = RemoteStatus;
  1116. if (!CscTransitnOKToGoOffline(RemoteStatus)) {
  1117. return RemoteStatus;
  1118. }
  1119. if (pVNetRoot != NULL) {
  1120. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(pVNetRoot);
  1121. }
  1122. SmbCeLog(("CSCTrVNR %x VNR\n", pVNetRootContext));
  1123. SmbLog(LOG,
  1124. CscTransitionVNetRootForDisconnectedOperation_1,
  1125. LOGPTR(pVNetRootContext));
  1126. if (pVNetRootContext == NULL ||
  1127. pVNetRootContext->pServerEntry->Server.IsLoopBack) {
  1128. return RemoteStatus;
  1129. }
  1130. if (RxContext != NULL) {
  1131. capFobx = RxContext->pFobx;
  1132. }
  1133. pNetRootEntry = pVNetRootContext->pNetRootEntry;
  1134. if (!FlagOn(
  1135. pVNetRootContext->Flags,
  1136. SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE) &&
  1137. (pNetRootEntry != NULL) &&
  1138. (pNetRootEntry->NetRoot.NetRootType == NET_ROOT_DISK ||
  1139. pNetRootEntry->NetRoot.NetRootType == NET_ROOT_WILD)) {
  1140. if (pNetRootEntry->NetRoot.CscFlags != SMB_CSC_NO_CACHING) {
  1141. BOOLEAN TransitionVNetRoot;
  1142. UNICODE_STRING ServerName;
  1143. PDFS_NAME_CONTEXT pDfsNameContext = NULL;
  1144. ULONG uFlags = DFS_FLAG_LAST_ALTERNATE;
  1145. TransitionVNetRoot = TRUE;
  1146. if ((capFobx != NULL) &&
  1147. (capFobx->pSrvOpen != NULL)) {
  1148. PMRX_SMB_SRV_OPEN smbSrvOpen = MRxSmbGetSrvOpenExtension(capFobx->pSrvOpen);
  1149. if ((pVNetRootContext->pServerEntry->Server.Version -
  1150. smbSrvOpen->Version) > 1) {
  1151. TransitionVNetRoot = FALSE;
  1152. }
  1153. }
  1154. if (TransitionVNetRoot) {
  1155. PDFS_NAME_CONTEXT pDfsNameContext = NULL;
  1156. ULONG uFlags = DFS_FLAG_LAST_ALTERNATE;
  1157. if (RxContext &&
  1158. RxContext->CurrentIrpSp &&
  1159. RxContext->CurrentIrpSp->MajorFunction == IRP_MJ_CREATE) {
  1160. pDfsNameContext = CscIsValidDfsNameContext(RxContext->Create.NtCreateParameters.DfsNameContext);
  1161. if (pDfsNameContext)
  1162. {
  1163. uFlags = pDfsNameContext->Flags;
  1164. }
  1165. }
  1166. SmbCeLog(("CSCTrVNR DfsFlgs %x\n", uFlags));
  1167. SmbLog(LOG,
  1168. CscTransitionVNetRootForDisconnectedOperation_2,
  1169. LOGULONG(uFlags));
  1170. Status = CscpTransitionServerEntryForDisconnectedOperation(
  1171. RxContext,
  1172. pVNetRootContext->pServerEntry,
  1173. pNetRootEntry,
  1174. RemoteStatus,
  1175. FALSE, // to autodial or not to autodial
  1176. uFlags
  1177. );
  1178. // If the DFS share is in the database and the agent says it is OK to go disconnected
  1179. // then we want to create a DFS server entry and put that one in
  1180. // disconnected state too
  1181. if ((Status == STATUS_SUCCESS) &&
  1182. ((pDfsNameContext != NULL)||(pNetRootEntry->NetRoot.DfsAware))) {
  1183. // DbgPrint("CSCTransitionVNETroot: Transitioning %wZ \n", &pVNetRootContext->pServerEntry->Name);
  1184. SmbCeLog(("CSCTrVNR try Tr %wZ \n", &pVNetRootContext->pServerEntry->Name));
  1185. SmbLog(LOG,
  1186. CscTransitionVNetRootForDisconnectedOperation_3,
  1187. LOGUSTR(pVNetRootContext->pServerEntry->Name));
  1188. Status = CscPrepareDfsServerEntryForDisconnectedOperation(
  1189. pVNetRootContext->pServerEntry,
  1190. RxContext);
  1191. }
  1192. if (Status != STATUS_SUCCESS) {
  1193. ReturnStatus = Status;
  1194. } else {
  1195. ReturnStatus = STATUS_RETRY;
  1196. }
  1197. }
  1198. }
  1199. }
  1200. return ReturnStatus;
  1201. }
  1202. NTSTATUS
  1203. CscTransitionServerEntryForDisconnectedOperation(
  1204. PSMBCEDB_SERVER_ENTRY pServerEntry,
  1205. PRX_CONTEXT RxContext,
  1206. NTSTATUS RemoteStatus,
  1207. BOOLEAN AutoDialRequired)
  1208. {
  1209. NTSTATUS TransitionStatus = STATUS_SUCCESS;
  1210. PMRX_V_NET_ROOT pVNetRoot = NULL;
  1211. ULONG uFlags = DFS_FLAG_LAST_ALTERNATE;
  1212. SmbCeLog(("CSCTrSvr IN %x %x %x %x\n", pServerEntry, RxContext, RemoteStatus, AutoDialRequired));
  1213. SmbLog(LOG,
  1214. CscTransitionServerEntryForDisconnectedOperation_1,
  1215. LOGPTR(pServerEntry)
  1216. LOGPTR(RxContext)
  1217. LOGULONG(RemoteStatus)
  1218. LOGUCHAR(AutoDialRequired)
  1219. LOGUSTR(pServerEntry->Name));
  1220. if ((RxContext != NULL) &&
  1221. (RxContext->CurrentIrp != NULL) &&
  1222. (RxContext->CurrentIrpSp->MajorFunction == IRP_MJ_CREATE)) {
  1223. PDFS_NAME_CONTEXT pDfsNameContext;
  1224. pDfsNameContext = CscIsValidDfsNameContext(
  1225. RxContext->Create.NtCreateParameters.DfsNameContext);
  1226. if (pDfsNameContext != NULL) {
  1227. uFlags = pDfsNameContext->Flags;
  1228. SmbCeLog(("CSCTrSvr DFSFlgs %x\n", uFlags));
  1229. SmbLog(LOG,
  1230. CscTransitionServerEntryForDisconnectedOperation_2,
  1231. LOGULONG(uFlags));
  1232. }
  1233. }
  1234. if ((RxContext != NULL) &&
  1235. (RxContext->pFobx != NULL) &&
  1236. (RxContext->pFobx->pSrvOpen != NULL)) {
  1237. pVNetRoot = RxContext->pFobx->pSrvOpen->pVNetRoot;
  1238. }
  1239. if (pVNetRoot != NULL) {
  1240. TransitionStatus =
  1241. CscTransitionVNetRootForDisconnectedOperation(
  1242. RxContext,
  1243. pVNetRoot,
  1244. pServerEntry->ServerStatus);
  1245. } else {
  1246. TransitionStatus =
  1247. CscpTransitionServerEntryForDisconnectedOperation(
  1248. RxContext,
  1249. pServerEntry,
  1250. NULL,
  1251. RemoteStatus,
  1252. AutoDialRequired,
  1253. uFlags
  1254. );
  1255. if ((TransitionStatus == STATUS_SUCCESS) &&
  1256. (RxContext != NULL)) {
  1257. BOOLEAN TransitionDfsVNetRoot = FALSE;
  1258. TransitionDfsVNetRoot =
  1259. CscIsThisDfsCreateOperationTransitionableForDisconnectedOperation(
  1260. RxContext);
  1261. if (TransitionDfsVNetRoot) {
  1262. // DbgPrint("CSCTransitionServerEntry: Transitioning DFS server for ServerEntry %x \n", pServerEntry);
  1263. TransitionStatus = CscPrepareDfsServerEntryForDisconnectedOperation(
  1264. pServerEntry,
  1265. RxContext);
  1266. }
  1267. }
  1268. }
  1269. // Pulse the fill thread so it will start 10-min tries to reconnect
  1270. // It will go back to sleep if it succeeds
  1271. // DbgPrint("###CSCTransitionServerEntry: pulsing fill event\n");
  1272. MRxSmbCscSignalFillAgent(NULL, 0);
  1273. SmbCeLog(("CSCTrSvr Out %x\n", TransitionStatus));
  1274. SmbLog(LOG,
  1275. CscTransitionServerEntryForDisconnectedOperation_3,
  1276. LOGULONG(TransitionStatus));
  1277. return TransitionStatus;
  1278. }
  1279. BOOLEAN
  1280. CscPerformOperationInDisconnectedMode(
  1281. PRX_CONTEXT RxContext)
  1282. /*++
  1283. Routine Description:
  1284. This routine detects if the operation should be performed in a disconnected
  1285. mode. Additionally if the operation needs to be performed in a disconnected
  1286. mode it prepares the open accordingly.
  1287. Arguments:
  1288. RxContext - the Wrapper context for the operation
  1289. Return Value:
  1290. TRUE -- if the operation needs to be performed in the disconnected mode
  1291. and FALSE otherwise
  1292. Notes:
  1293. There are certain opens that are deferred by the SMB mini redirector in
  1294. the connected mode. These modes need to be evaluated when the transition is
  1295. made to disconnected mode, since in disconnected mode there are no
  1296. deferred opens.
  1297. The appropriate buffering change requests need to be done as well (TBI)
  1298. --*/
  1299. {
  1300. NTSTATUS Status;
  1301. RxCaptureFcb;
  1302. RxCaptureFobx;
  1303. PMRX_SRV_OPEN SrvOpen;
  1304. PMRX_SMB_SRV_OPEN smbSrvOpen;
  1305. PSMBCEDB_SERVER_ENTRY pServerEntry;
  1306. PSMBCE_V_NET_ROOT_CONTEXT pVNetRootContext;
  1307. BOOLEAN PerformOperationInDisconnectedMode = FALSE;
  1308. if(!MRxSmbIsCscEnabled) {
  1309. return(FALSE);
  1310. }
  1311. SrvOpen = RxContext->pRelevantSrvOpen;
  1312. // check if SrvOpen is NULL. This could happen if a mailslot operation was passed in here
  1313. if (!SrvOpen)
  1314. {
  1315. return(FALSE);
  1316. }
  1317. smbSrvOpen = MRxSmbGetSrvOpenExtension(SrvOpen);
  1318. if (FlagOn(smbSrvOpen->Flags, SMB_SRVOPEN_FLAG_LOCAL_OPEN)) {
  1319. return FALSE;
  1320. }
  1321. pServerEntry = SmbCeGetAssociatedServerEntry(capFcb->pNetRoot->pSrvCall);
  1322. pVNetRootContext = SmbCeGetAssociatedVNetRootContext(capFobx->pSrvOpen->pVNetRoot);
  1323. if (SmbCeIsServerInDisconnectedMode(pServerEntry) &&
  1324. !FlagOn(
  1325. pVNetRootContext->Flags,
  1326. SMBCE_V_NET_ROOT_CONTEXT_CSCAGENT_INSTANCE)) {
  1327. PMRX_SMB_FCB smbFcb;
  1328. smbFcb = MRxSmbGetFcbExtension(capFcb);
  1329. if (smbFcb->hShadow == 0) {
  1330. BOOLEAN FcbAcquired;
  1331. BOOLEAN PreviouslyAcquiredShared = FALSE;
  1332. // If the FCB resource has not been acquired, acquire it before
  1333. // performing the create.
  1334. if (!RxIsFcbAcquiredExclusive(capFcb)) {
  1335. if (RxIsFcbAcquiredShared(capFcb)) {
  1336. RxDbgTrace(0, Dbg, ("Shared holding condition detected for disconnected operation\n"));
  1337. RxReleaseFcbResourceInMRx(capFcb);
  1338. PreviouslyAcquiredShared = TRUE;
  1339. }
  1340. RxAcquireExclusiveFcbResourceInMRx(capFcb );
  1341. FcbAcquired = TRUE;
  1342. } else {
  1343. FcbAcquired = FALSE;
  1344. }
  1345. // This is a case of a deferred open for which the transition has
  1346. // been made to disconnected operation.
  1347. Status = MRxSmbDeferredCreate(RxContext);
  1348. //RxIndicateChangeOfBufferingState(
  1349. // capFcb->pNetRoot->pSrvCall,
  1350. // MRxSmbMakeSrvOpenKey(smbFcb->Tid,smbSrvOpen->Fid),
  1351. // (PVOID)2);
  1352. if (FcbAcquired) {
  1353. RxReleaseFcbResourceInMRx(capFcb);
  1354. }
  1355. if (PreviouslyAcquiredShared) {
  1356. RxAcquireSharedFcbResourceInMRx(capFcb );
  1357. }
  1358. }
  1359. PerformOperationInDisconnectedMode = TRUE;
  1360. }
  1361. return PerformOperationInDisconnectedMode;
  1362. }
  1363. #if 0
  1364. int
  1365. AllPinnedFilesFilled(
  1366. HSHARE hShare,
  1367. BOOL *lpfComplete
  1368. )
  1369. /*++
  1370. Routine Description:
  1371. Arguments:
  1372. Return Value:
  1373. Notes:
  1374. --*/
  1375. {
  1376. CSC_ENUMCOOKIE hPQ;
  1377. PQPARAMS sPQP;
  1378. int iRet = SRET_ERROR;
  1379. ASSERT(hShare);
  1380. ASSERT(lpfComplete);
  1381. // Open the priority q
  1382. if (!(hPQ = HBeginPQEnum()))
  1383. {
  1384. RxDbgTrace(0, Dbg, ("AllPinnedFilesFilled: Error opening Priority Q database\r\n"));
  1385. return SRET_ERROR;
  1386. }
  1387. *lpfComplete = TRUE;
  1388. memset(&sPQP, 0, sizeof(PQPARAMS));
  1389. sPQP.uEnumCookie = hPQ;
  1390. // go down the Q once
  1391. do
  1392. {
  1393. if(NextPriSHADOW(&sPQP) < SRET_OK)
  1394. {
  1395. RxDbgTrace(0, Dbg, ("AllPinnedFilesFilled: PQ record read error\r\n"));
  1396. goto bailout;
  1397. }
  1398. if (!sPQP.hShadow)
  1399. {
  1400. break;
  1401. }
  1402. // see if any of the pinned files for the specific
  1403. // server is sparse
  1404. if ((hShare == sPQP.hShare)
  1405. && (sPQP.ulStatus & SHADOW_IS_FILE) // It is a file
  1406. && ((sPQP.ulHintPri || mPinFlags(sPQP.ulHintFlags)))// it is a pinned file
  1407. )
  1408. {
  1409. if (sPQP.ulStatus & SHADOW_SPARSE)
  1410. {
  1411. // we found a sparse file
  1412. *lpfComplete = FALSE;
  1413. break;
  1414. }
  1415. }
  1416. }
  1417. while (sPQP.uPos);
  1418. iRet = SRET_OK;
  1419. bailout:
  1420. if (hPQ)
  1421. {
  1422. EndPQEnum(hPQ);
  1423. }
  1424. if (iRet == SRET_ERROR)
  1425. {
  1426. *lpfComplete = FALSE;
  1427. }
  1428. return (iRet);
  1429. }
  1430. #endif
  1431. BOOLEAN
  1432. CscGetServerNameWaitingToGoOffline(
  1433. OUT PWCHAR ServerName,
  1434. IN OUT LPDWORD lpdwBufferSize,
  1435. OUT NTSTATUS *lpStatus
  1436. )
  1437. /*++
  1438. Routine Description:
  1439. This routine returns the name of the server which has asked the agent to
  1440. throw a popup to the user.
  1441. Arguments:
  1442. ServerName returns the name of the server
  1443. Return Value:
  1444. Fails if no server is waiting for the popup to comeback
  1445. Notes:
  1446. --*/
  1447. {
  1448. BOOLEAN fRet = FALSE;
  1449. DWORD dwSize = *lpdwBufferSize;
  1450. *lpStatus = STATUS_UNSUCCESSFUL;
  1451. if (CscServerEntryBeingTransitioned)
  1452. {
  1453. PWCHAR Name;
  1454. ULONG NameLength;
  1455. if (!CscDfsRootServerEntryBeingTransitioned) {
  1456. NameLength = CscServerEntryBeingTransitioned->Name.Length;
  1457. Name = CscServerEntryBeingTransitioned->Name.Buffer;
  1458. } else {
  1459. NameLength = CscDfsRootServerEntryBeingTransitioned->Name.Length;
  1460. Name = CscDfsRootServerEntryBeingTransitioned->Name.Buffer;
  1461. }
  1462. *lpdwBufferSize = (DWORD)(NameLength+2+2);
  1463. if(dwSize >= (DWORD)(NameLength+2+2))
  1464. {
  1465. *ServerName='\\';
  1466. memcpy(
  1467. ServerName+1,
  1468. Name,
  1469. NameLength);
  1470. memset(((LPBYTE)(ServerName+1))+NameLength, 0, 2);
  1471. *lpStatus = STATUS_SUCCESS;
  1472. fRet = TRUE;
  1473. }
  1474. else
  1475. {
  1476. *lpStatus = STATUS_BUFFER_TOO_SMALL;
  1477. }
  1478. }
  1479. return fRet;
  1480. }
  1481. BOOLEAN
  1482. CscShareIdToShareName(
  1483. IN ULONG hShare,
  1484. OUT PWCHAR ShareName,
  1485. IN OUT LPDWORD lpdwBufferSize,
  1486. OUT NTSTATUS *lpStatus
  1487. )
  1488. {
  1489. SHAREREC sSR;
  1490. DWORD dwSize = *lpdwBufferSize;
  1491. ULONG NameLength;
  1492. INT iRet;
  1493. // DbgPrint("CscShareIdToShareName(%d)\n", hShare);
  1494. *lpStatus = STATUS_OBJECT_NAME_NOT_FOUND;
  1495. if (hShare == 0)
  1496. goto AllDone;
  1497. EnterShadowCrit();
  1498. iRet = GetShareRecord(lpdbShadow, hShare, &sSR);
  1499. LeaveShadowCrit();
  1500. if (iRet >= 0 && sSR.uchType == (UCHAR)REC_DATA) {
  1501. NameLength = (wcslen(sSR.rgPath)+1) * sizeof(WCHAR);
  1502. *lpdwBufferSize = (DWORD)NameLength;
  1503. if(dwSize >= (DWORD)(NameLength)) {
  1504. memset(ShareName, 0, dwSize);
  1505. if (NameLength > 0)
  1506. memcpy(ShareName, sSR.rgPath, NameLength);
  1507. *lpStatus = STATUS_SUCCESS;
  1508. } else {
  1509. *lpStatus = STATUS_BUFFER_TOO_SMALL;
  1510. }
  1511. }
  1512. AllDone:
  1513. // DbgPrint("CscShareIdToShareName exit 0x%x\n", *lpStatus);
  1514. return TRUE;
  1515. }
  1516. BOOLEAN
  1517. CSCCheckForAcd(VOID)
  1518. /*++
  1519. Routine Description:
  1520. Arguments:
  1521. Return Value:
  1522. Notes:
  1523. --*/
  1524. {
  1525. NTSTATUS status;
  1526. UNICODE_STRING nameString;
  1527. IO_STATUS_BLOCK ioStatusBlock;
  1528. PFILE_OBJECT pAcdFileObject;
  1529. PDEVICE_OBJECT pAcdDeviceObject;
  1530. BOOLEAN fAutoDialON=FALSE;
  1531. PIRP pIrp;
  1532. //
  1533. // Initialize the name of the automatic
  1534. // connection device.
  1535. //
  1536. RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME);
  1537. //
  1538. // Get the file and device objects for the
  1539. // device.
  1540. //
  1541. status = IoGetDeviceObjectPointer(
  1542. &nameString,
  1543. SYNCHRONIZE|GENERIC_READ|GENERIC_WRITE,
  1544. &pAcdFileObject,
  1545. &pAcdDeviceObject);
  1546. if (status != STATUS_SUCCESS)
  1547. {
  1548. RxDbgTrace(0, Dbg, ("CSCCheckForAcd: failed with status=%x \r\n", status));
  1549. return FALSE;
  1550. }
  1551. //
  1552. // Reference the device object.
  1553. //
  1554. ObReferenceObject(pAcdDeviceObject);
  1555. //
  1556. // Remove the reference IoGetDeviceObjectPointer()
  1557. // put on the file object.
  1558. //
  1559. ObDereferenceObject(pAcdFileObject);
  1560. pIrp = IoBuildDeviceIoControlRequest(
  1561. IOCTL_INTERNAL_ACD_QUERY_STATE,
  1562. pAcdDeviceObject,
  1563. NULL,
  1564. 0,
  1565. &fAutoDialON,
  1566. sizeof(fAutoDialON),
  1567. TRUE,
  1568. NULL,
  1569. &ioStatusBlock);
  1570. if (pIrp == NULL) {
  1571. ObDereferenceObject(pAcdDeviceObject);
  1572. return FALSE;
  1573. }
  1574. //
  1575. // Submit the request to the
  1576. // automatic connection driver.
  1577. //
  1578. status = IoCallDriver(pAcdDeviceObject, pIrp);
  1579. ObDereferenceObject(pAcdDeviceObject);
  1580. return fAutoDialON;
  1581. }
  1582. BOOLEAN
  1583. CscTransitnOKToGoOffline(
  1584. NTSTATUS RemoteStatus
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. Arguments:
  1589. Return Value:
  1590. Notes:
  1591. --*/
  1592. {
  1593. switch (RemoteStatus) {
  1594. case STATUS_CONNECTION_DISCONNECTED:
  1595. case STATUS_IO_TIMEOUT:
  1596. case STATUS_NETWORK_UNREACHABLE:
  1597. case STATUS_BAD_NETWORK_NAME:
  1598. case STATUS_BAD_NETWORK_PATH:
  1599. case STATUS_NETWORK_NAME_DELETED:
  1600. return TRUE;
  1601. default :
  1602. return FALSE;
  1603. }
  1604. }
  1605. BOOLEAN
  1606. CscIsSpecialShare(
  1607. PUNICODE_STRING ShareName)
  1608. {
  1609. ULONG i;
  1610. BOOLEAN fSpecial = FALSE;
  1611. // DbgPrint("CscIsSpecialShare(%wZ)\n", ShareName);
  1612. for (i = 0;
  1613. (i < (sizeof(CscSpecialShares) / sizeof(CscSpecialShares[0]))) &&
  1614. !fSpecial;
  1615. i++) {
  1616. if (CscSpecialShares[i].Length == ShareName->Length) {
  1617. if (_wcsnicmp(
  1618. CscSpecialShares[i].Buffer,
  1619. ShareName->Buffer,
  1620. ShareName->Length/sizeof(WCHAR)) == 0) {
  1621. fSpecial = TRUE;
  1622. }
  1623. }
  1624. }
  1625. // DbgPrint("CscIsSpecialShare returning %d\n", fSpecial);
  1626. return fSpecial;
  1627. }