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.

964 lines
24 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. sda.c
  5. Abstract:
  6. This module contains the session data area manipulation routines.
  7. Author:
  8. Jameel Hyder (microsoft!jameelh)
  9. Revision History:
  10. 25 Apr 1992 Initial Version
  11. Notes: Tab stop: 4
  12. --*/
  13. #define _SDA_LOCALS
  14. #define FILENUM FILE_SDA
  15. #include <afp.h>
  16. #include <scavengr.h>
  17. #include <access.h>
  18. #include <client.h>
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text( INIT, AfpSdaInit)
  21. #pragma alloc_text( PAGE, afpCloseSessionAndFreeSda)
  22. #pragma alloc_text( PAGE, AfpSdaCheckSession)
  23. #endif
  24. /*** AfpSdaInit
  25. *
  26. * Initialize Sda Data structures. Called at init time.
  27. */
  28. NTSTATUS
  29. AfpSdaInit(
  30. VOID
  31. )
  32. {
  33. ASSERT(sizeof(SDA) <= 512);
  34. INITIALIZE_SPIN_LOCK(&AfpSdaLock);
  35. return STATUS_SUCCESS;
  36. }
  37. /*** AfpSdaReferenceSessionById
  38. *
  39. * Reference a session by its id. The SDA cannot be referenced if it is
  40. * marked closed. The SDA should be referenced before using it.
  41. *
  42. * LOCKS: AfpSdaLock (SPIN), sda_Lock (SPIN)
  43. * LOCK_ORDER: sda_Lock after AfpSdaLock
  44. */
  45. PSDA FASTCALL
  46. AfpSdaReferenceSessionById(
  47. IN DWORD SessId
  48. )
  49. {
  50. PSDA pSda=NULL;
  51. PSDA pRetSda=NULL;
  52. KIRQL OldIrql;
  53. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  54. for (pSda = AfpSessionList;
  55. (pSda != NULL) && (pSda->sda_SessionId >= SessId);
  56. pSda = pSda->sda_Next)
  57. {
  58. if (pSda->sda_SessionId == SessId)
  59. {
  60. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  61. if ((pSda->sda_Flags & SDA_CLOSING) == 0)
  62. {
  63. ASSERT((pSda->sda_RefCount > 0) &&
  64. (pSda->sda_SessionId != 0));
  65. pSda->sda_RefCount ++;
  66. pRetSda = pSda;
  67. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  68. ("AfpSdaReferenceSessionById: New Count %d\n", pSda->sda_RefCount));
  69. }
  70. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  71. break;
  72. }
  73. }
  74. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  75. return pRetSda;
  76. }
  77. /*** AfpSdaReferenceSessionByPointer
  78. *
  79. * Reference a session by pointer. The SDA cannot be referenced if it is
  80. * marked closed. The SDA should be referenced before using it.
  81. *
  82. */
  83. PSDA FASTCALL
  84. AfpSdaReferenceSessionByPointer(
  85. IN PSDA pSda
  86. )
  87. {
  88. PSDA pRetSda=NULL;
  89. KIRQL OldIrql;
  90. ASSERT(VALID_SDA(pSda));
  91. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  92. if ((pSda->sda_Flags & SDA_CLOSING) == 0)
  93. {
  94. pSda->sda_RefCount ++;
  95. pRetSda = pSda;
  96. }
  97. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  98. return pRetSda;
  99. }
  100. /*** afpSdaCloseSessionAndFreeSda
  101. *
  102. * Run by the scavenger in the worker context. This is initiated as part of
  103. * session cleanup.
  104. */
  105. LOCAL AFPSTATUS FASTCALL
  106. afpCloseSessionAndFreeSda(
  107. IN PSDA pSda
  108. )
  109. {
  110. POPENFORKSESS pOpenForkSess;
  111. PASP_XPORT_ENTRIES XportTable;
  112. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  113. ("afpCloseSessionAndFreeSda: Cleaning up session %lx\n",
  114. pSda->sda_SessionId));
  115. PAGED_CODE( );
  116. #ifdef OPTIMIZE_GUEST_LOGONS
  117. if (pSda->sda_ClientType != SDA_CLIENT_GUEST)
  118. {
  119. #endif
  120. #ifndef INHERIT_DIRECTORY_PERMS
  121. // First free up paged memory used by the sda
  122. if (pSda->sda_pSecDesc != NULL)
  123. {
  124. if (pSda->sda_pSecDesc->Dacl != NULL)
  125. AfpFreeMemory(pSda->sda_pSecDesc->Dacl);
  126. AfpFreeMemory(pSda->sda_pSecDesc);
  127. }
  128. #endif
  129. if ((pSda->sda_UserSid != NULL) && (pSda->sda_UserSid != &AfpSidWorld))
  130. AfpFreeMemory(pSda->sda_UserSid);
  131. if ((pSda->sda_GroupSid != NULL) && (pSda->sda_GroupSid != &AfpSidWorld))
  132. AfpFreeMemory(pSda->sda_GroupSid);
  133. if (pSda->sda_pGroups != NULL)
  134. AfpFreeMemory(pSda->sda_pGroups);
  135. #ifdef OPTIMIZE_GUEST_LOGONS
  136. }
  137. #endif
  138. // Free any chains of fork entries that we created
  139. pOpenForkSess = pSda->sda_OpenForkSess.ofs_Link;
  140. while (pOpenForkSess != NULL)
  141. {
  142. POPENFORKSESS pFree;
  143. pFree = pOpenForkSess;
  144. pOpenForkSess = pOpenForkSess->ofs_Link;
  145. AfpFreeMemory(pFree);
  146. }
  147. // Next log-out the user
  148. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  149. ("afpCloseSessionAndFreeSda: Closing User Token\n"));
  150. #ifdef OPTIMIZE_GUEST_LOGON
  151. if ((pSda->sda_UserToken != NULL) && (pSda->sda_ClientType != SDA_CLIENT_GUEST))
  152. #else
  153. if (pSda->sda_UserToken != NULL)
  154. #endif
  155. NtClose(pSda->sda_UserToken);
  156. // Make sure there are no resource leaks
  157. ASSERT (pSda->sda_cOpenVolumes == 0);
  158. ASSERT (pSda->sda_pConnDesc == 0);
  159. ASSERT (pSda->sda_cOpenForks == 0);
  160. XportTable = pSda->sda_XportTable;
  161. (*(XportTable->asp_FreeConn))(pSda->sda_SessHandle);
  162. if (pSda->sda_ReplyBuf)
  163. {
  164. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_ERR,
  165. ("afpCloseSessionAndFreeSda: %d bytes would have leaked!\n",pSda->sda_ReplySize));
  166. // TRUE => lie that the lock is held: we don't need lock no more
  167. AfpFreeReplyBuf(pSda, TRUE);
  168. }
  169. // Free the sda memory, finally
  170. AfpFreeMemory(pSda);
  171. // If the server is stopping and the count of sessions has gone to zero
  172. // clear the termination confirmation event to unblock the admin thread
  173. if (((AfpServerState == AFP_STATE_STOP_PENDING) ||
  174. (AfpServerState == AFP_STATE_SHUTTINGDOWN)) &&
  175. (AfpNumSessions == 0))
  176. {
  177. DBGPRINT(DBG_COMP_ADMINAPI, DBG_LEVEL_WARN,
  178. ("afpSdaCloseSessionAndFreeSda: Unblocking server stop\n"));
  179. KeSetEvent(&AfpStopConfirmEvent, IO_NETWORK_INCREMENT, False);
  180. }
  181. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO, ("afpCloseSessionAndFreeSda: Done\n"));
  182. return AFP_ERR_NONE;
  183. }
  184. /*** AfpSdaDereferenceSession
  185. *
  186. * Dereference this SDA. This is called in response to either a AfpLogout
  187. * request, a forced shutdown of this session by either SessionClose() api,
  188. * the server shutdown or the session shutdown from the client end.
  189. * The Sda should not be dereferenced until the entire request is processed
  190. * i.e. the reply has ALSO COMPLETED.
  191. *
  192. * NOTE: We unlink the session from the list but do not update the count till
  193. * the entire cleanup is complete.
  194. *
  195. * LOCKS: AfpSdaLock (SPIN), sda_Lock (SPIN), AfpStatisticsLock (SPIN)
  196. */
  197. VOID FASTCALL
  198. AfpSdaDereferenceSession(
  199. IN PSDA pSda
  200. )
  201. {
  202. PSDA * ppSda;
  203. KIRQL OldIrql;
  204. LONG RefCount;
  205. BOOLEAN fTcpSession=TRUE;
  206. ASSERT(VALID_SDA(pSda));
  207. ASSERT((pSda->sda_RefCount > 0) &&
  208. (pSda->sda_SessionId != 0));
  209. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  210. RefCount = -- (pSda->sda_RefCount);
  211. if (RefCount == 0)
  212. {
  213. pSda->sda_Flags |= SDA_CLOSING;
  214. fTcpSession = (pSda->sda_Flags & SDA_SESSION_OVER_TCP)? TRUE : FALSE;
  215. }
  216. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  217. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  218. ("AfpSdaDereferenceSession: Session %ld, New Count %ld\n",
  219. pSda->sda_SessionId, RefCount));
  220. // If there are more references, then we are done.
  221. if (RefCount > 0)
  222. return;
  223. ASSERT(RefCount == 0); // catch refcount going below 0!
  224. ASSERT (!(pSda->sda_Flags & SDA_REQUEST_IN_PROCESS));
  225. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  226. ("AfpSdaDereferenceSession: Closing down session %ld\n",
  227. pSda->sda_SessionId));
  228. // Cancel the scavenger event for checking this user's kickoff time
  229. AfpScavengerKillEvent(AfpSdaCheckSession,
  230. (PVOID)((ULONG_PTR)(pSda->sda_SessionId)));
  231. // First unlink the Sda from the sessions list
  232. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  233. for (ppSda = &AfpSessionList;
  234. *ppSda != NULL;
  235. ppSda = &(*ppSda)->sda_Next)
  236. if (pSda == *ppSda)
  237. break;
  238. ASSERT(*ppSda == pSda);
  239. *ppSda = pSda->sda_Next;
  240. // Update the count of active sessions
  241. ASSERT (AfpNumSessions > 0);
  242. --AfpNumSessions;
  243. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  244. // Free all buffers associated with the Sda
  245. // Now free the SDA memory
  246. if (pSda->sda_WSName.Buffer != NULL)
  247. AfpFreeMemory(pSda->sda_WSName.Buffer);
  248. if ((pSda->sda_ClientType != SDA_CLIENT_GUEST) &&
  249. (pSda->sda_UserName.Buffer != NULL))
  250. AfpFreeMemory(pSda->sda_UserName.Buffer);
  251. if (pSda->sda_Challenge != NULL)
  252. AfpFreeMemory(pSda->sda_Challenge);
  253. if (pSda->sda_DomainName.Buffer != NULL)
  254. AfpFreeMemory(pSda->sda_DomainName.Buffer);
  255. if (pSda->sda_Message != NULL)
  256. AfpFreeMemory(pSda->sda_Message);
  257. // Finally update statistics
  258. INTERLOCKED_ADD_ULONG((PLONG)&AfpServerStatistics.stat_CurrentSessions,
  259. (ULONG)-1,
  260. &AfpStatisticsLock);
  261. // it was a TCP session? update that counter as well
  262. if (fTcpSession)
  263. {
  264. INTERLOCKED_ADD_ULONG((PLONG)&AfpServerStatistics.stat_TcpSessions,
  265. (ULONG)-1,
  266. &AfpStatisticsLock);
  267. }
  268. // The balance of the clean-up has to happen at LOW_LEVEL in the context
  269. // of the worker thread. So queue it up
  270. if ((OldIrql == DISPATCH_LEVEL) ||
  271. (PsGetCurrentProcess() != AfpProcessObject))
  272. {
  273. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  274. ("AfpSdaDereferenceSession: Queuing Close&Free to Scavenger\n"));
  275. AfpScavengerScheduleEvent(afpCloseSessionAndFreeSda,
  276. (PVOID)pSda,
  277. 0,
  278. True);
  279. }
  280. else
  281. {
  282. afpCloseSessionAndFreeSda(pSda);
  283. }
  284. }
  285. /*** AfpSdaCreateNewSession
  286. *
  287. * A new session has been initiated. Allocate and initialize a Sda and return a
  288. * pointer to it. The new sda is linked into the list of active sessions.
  289. *
  290. * LOCKS: AfpSdaLock (SPIN), AfpServerGlobalLock (SPIN)
  291. * LOCK_ORDER: AfpServerGlobalLock after AfpSdaLock
  292. */
  293. PSDA FASTCALL
  294. AfpSdaCreateNewSession(
  295. IN PVOID SessionHandle,
  296. IN BOOLEAN fOverTcp
  297. )
  298. {
  299. KIRQL OldIrql;
  300. PSDA *ppSda, pSda = NULL;
  301. if ((DWORD)AfpNumSessions < AfpServerMaxSessions)
  302. {
  303. if ((pSda = (PSDA)AfpAllocNonPagedMemory(SDA_SIZE)) == NULL)
  304. return NULL;
  305. // Initialize SDA fields
  306. RtlZeroMemory(pSda, sizeof(SDA));
  307. #if DBG
  308. pSda->Signature = SDA_SIGNATURE;
  309. #endif
  310. INITIALIZE_SPIN_LOCK(&pSda->sda_Lock);
  311. // Reference this Session
  312. pSda->sda_RefCount = 1;
  313. pSda->sda_Flags = SDA_USER_NOT_LOGGEDIN;
  314. if (fOverTcp)
  315. {
  316. pSda->sda_Flags |= SDA_SESSION_OVER_TCP;
  317. pSda->sda_XportTable = &AfpDsiEntries;
  318. pSda->sda_MaxWriteSize = DSI_SERVER_REQUEST_QUANTUM;
  319. }
  320. else
  321. {
  322. pSda->sda_XportTable = &AfpAspEntries;
  323. pSda->sda_MaxWriteSize = ASP_QUANTUM;
  324. }
  325. pSda->sda_SessHandle = SessionHandle;
  326. InitializeListHead(&pSda->sda_DeferredQueue);
  327. AfpInitializeWorkItem(&pSda->sda_WorkItem,
  328. AfpStartApiProcessing,
  329. pSda);
  330. AfpGetCurrentTimeInMacFormat(&pSda->sda_TimeLoggedOn);
  331. pSda->sda_tTillKickOff = MAXLONG;
  332. // Initialize space for request/response
  333. pSda->sda_SizeNameXSpace = (USHORT)(SDA_SIZE - sizeof(SDA));
  334. pSda->sda_NameXSpace = (PBYTE)pSda + sizeof(SDA);
  335. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  336. // Assign a new session id to this session
  337. pSda->sda_SessionId = afpNextSessionId ++;
  338. ASSERT(pSda->sda_SessionId != 0);
  339. // Link the Sda into the active session list
  340. for (ppSda = &AfpSessionList;
  341. *ppSda != NULL;
  342. ppSda = &((*ppSda)->sda_Next))
  343. {
  344. if ((*ppSda)->sda_SessionId < pSda->sda_SessionId)
  345. break;
  346. }
  347. pSda->sda_Next = *ppSda;
  348. *ppSda = pSda;
  349. // Update the count of active sessions
  350. AfpNumSessions++;
  351. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  352. // Finally update statistics
  353. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  354. AfpServerStatistics.stat_CurrentSessions ++;
  355. AfpServerStatistics.stat_TotalSessions ++;
  356. if (AfpServerStatistics.stat_CurrentSessions >
  357. AfpServerStatistics.stat_MaxSessions)
  358. AfpServerStatistics.stat_MaxSessions =
  359. AfpServerStatistics.stat_CurrentSessions;
  360. if (fOverTcp)
  361. {
  362. AfpServerStatistics.stat_TcpSessions++;
  363. if (AfpServerStatistics.stat_TcpSessions >
  364. AfpServerStatistics.stat_MaxTcpSessions)
  365. {
  366. AfpServerStatistics.stat_MaxTcpSessions =
  367. AfpServerStatistics.stat_TcpSessions;
  368. }
  369. }
  370. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  371. }
  372. return pSda;
  373. }
  374. /*** AfpSdaCloseSession
  375. *
  376. * Setup to close the session
  377. */
  378. AFPSTATUS FASTCALL
  379. AfpSdaCloseSession(
  380. IN PSDA pSda
  381. )
  382. {
  383. LONG ConnRef;
  384. DWORD ForkRef, MaxOForkRefNum;
  385. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  386. ("AfpSdaCloseSession: Entered for session %lx\n",
  387. pSda->sda_SessionId));
  388. // We should be coming in from the scavenger worker in its context i.e. at LOW_LEVEL.
  389. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  390. // Close down the open forks from this session
  391. MaxOForkRefNum = pSda->sda_MaxOForkRefNum;
  392. for (ForkRef = 1; ForkRef <= MaxOForkRefNum; ForkRef++)
  393. {
  394. POPENFORKENTRY pOpenForkEntry;
  395. KIRQL OldIrql;
  396. KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
  397. pOpenForkEntry = AfpForkReferenceByRefNum(pSda, ForkRef);
  398. KeLowerIrql(OldIrql);
  399. if (pOpenForkEntry != NULL)
  400. {
  401. DBGPRINT(DBG_COMP_VOLUME, DBG_LEVEL_INFO,
  402. ("AfpSdaCloseSession: Forcing close of fork %lx, id %lx\n",
  403. ForkRef, pOpenForkEntry->ofe_ForkId));
  404. AfpForkClose(pOpenForkEntry);
  405. AfpForkDereference(pOpenForkEntry);
  406. }
  407. }
  408. // Now close down all open volumes.
  409. // Note that AfpConnectionClose will unlink the ConnDesc from the Sda
  410. for (ConnRef = 1; ConnRef <= afpLargestVolIdInUse; ConnRef++)
  411. {
  412. PCONNDESC pConnDesc;
  413. if ((pConnDesc = AfpConnectionReference(pSda, ConnRef)) != NULL)
  414. {
  415. AfpConnectionClose(pConnDesc);
  416. AfpConnectionDereference(pConnDesc);
  417. }
  418. }
  419. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO, ("AfpCloseSession: Done\n"));
  420. ASSERT (pSda->sda_Flags & SDA_SESSION_CLOSED);
  421. AfpSdaDereferenceSession(pSda);
  422. return AFP_ERR_NONE;
  423. }
  424. /*** AfpAdmWSessionClose
  425. *
  426. * Close a session forcibly. This is an admin operation and must be queued
  427. * up since this can potentially cause filesystem operations that are valid
  428. * only in the system process context.
  429. *
  430. * LOCKS: AfpSdaLock (SPIN), sda_Lock (SPIN)
  431. * LOCK_ORDER: sda_Lock after AfpSdaLock
  432. */
  433. NTSTATUS
  434. AfpAdmWSessionClose(
  435. IN OUT PVOID InBuf OPTIONAL,
  436. IN LONG OutBufLen OPTIONAL,
  437. OUT PVOID OutBuf OPTIONAL
  438. )
  439. {
  440. AFPSTATUS Status = AFPERR_InvalidId;
  441. DWORD SessId;
  442. PSDA pSda;
  443. KIRQL OldIrql;
  444. PAFP_SESSION_INFO pSessInfo = (PAFP_SESSION_INFO)InBuf;
  445. USHORT AttnWord;
  446. BOOLEAN Shoot = False;
  447. AttnWord = ATTN_USER_DISCONNECT;
  448. if ((AfpServerState == AFP_STATE_SHUTTINGDOWN) ||
  449. (AfpServerState == AFP_STATE_STOP_PENDING))
  450. AttnWord = ATTN_SERVER_SHUTDOWN;
  451. if ((SessId = pSessInfo->afpsess_id) != 0)
  452. {
  453. if ((pSda = AfpSdaReferenceSessionById(SessId)) != NULL)
  454. {
  455. Status = AFP_ERR_NONE;
  456. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  457. if ((pSda->sda_Flags & (SDA_CLOSING | SDA_SESSION_CLOSED | SDA_CLIENT_CLOSE)) == 0)
  458. {
  459. Shoot = True;
  460. pSda->sda_Flags |= SDA_CLOSING | SDA_SESSION_CLOSED;
  461. }
  462. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  463. if (Shoot)
  464. {
  465. // Tell the client (s)he's being shot
  466. AfpSpSendAttention(pSda, AttnWord, True);
  467. AfpSpCloseSession(pSda);
  468. }
  469. AfpSdaDereferenceSession(pSda);
  470. }
  471. else
  472. {
  473. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_ERR,
  474. ("AfpAdmWSessionClose: no pSda found for SessId %d\n",pSessInfo->afpsess_id));
  475. }
  476. }
  477. else
  478. {
  479. PSDA pSdaNext;
  480. // Here we want to block incoming sessions while we kill the existing ones
  481. AfpSpDisableListens();
  482. Status = AFP_ERR_NONE;
  483. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  484. for (pSda = AfpSessionList; pSda != NULL; pSda = pSdaNext)
  485. {
  486. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  487. Shoot = False;
  488. pSdaNext = pSda->sda_Next;
  489. if ((pSda->sda_Flags & (SDA_CLOSING | SDA_SESSION_CLOSED | SDA_CLIENT_CLOSE)) == 0)
  490. {
  491. pSda->sda_Flags |= SDA_CLOSING | SDA_SESSION_CLOSED;
  492. pSda->sda_RefCount ++;
  493. Shoot = True;
  494. }
  495. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  496. if (Shoot)
  497. {
  498. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  499. // Tell the client (s)he's being shot
  500. AfpSpSendAttention(pSda, AttnWord, True);
  501. AfpSpCloseSession(pSda);
  502. AfpSdaDereferenceSession(pSda);
  503. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  504. pSdaNext = AfpSessionList;
  505. }
  506. }
  507. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  508. // Enable new incoming sessions - but only if we are not paused
  509. if ((AfpServerState & (AFP_STATE_PAUSED | AFP_STATE_PAUSE_PENDING)) == 0)
  510. {
  511. AfpSpEnableListens();
  512. }
  513. }
  514. return Status;
  515. }
  516. /*** AfpSdaCheckSession
  517. *
  518. * Check if a session needs to be forcibly closed. If we are called by the
  519. * scavenger for the first time and our scavenger interval is not
  520. * SESSION_CHECK_TIME, we need to reschedule ourselves to run at this
  521. * interval.
  522. *
  523. * Since the sda_tTillKickOff is only used here, it needs
  524. * no protection.
  525. */
  526. AFPSTATUS FASTCALL
  527. AfpSdaCheckSession(
  528. IN PVOID pContext
  529. )
  530. {
  531. PSDA pSda;
  532. DWORD SessionId = (DWORD)((ULONG_PTR)pContext);
  533. AFPSTATUS Status = AFP_ERR_REQUEUE;
  534. BOOLEAN RequeueOurself = False;
  535. PAGED_CODE( );
  536. if ((pSda = AfpSdaReferenceSessionById(SessionId)) != NULL)
  537. {
  538. if (pSda->sda_tTillKickOff > SESSION_WARN_TIME)
  539. {
  540. // This is the first time this routine has run, and it was
  541. // originally scheduled to run at a time greater than
  542. // SESSION_WARN_TIME. Therefore, we need to reschedule this
  543. // scavenger event ourselves with a new SESSION_CHECK_TIME
  544. // interval. This is the only time we need to do this.
  545. pSda->sda_tTillKickOff = SESSION_WARN_TIME;
  546. Status = AFP_ERR_NONE;
  547. RequeueOurself = True;
  548. }
  549. else if (pSda->sda_tTillKickOff > 0)
  550. pSda->sda_tTillKickOff -= SESSION_CHECK_TIME;
  551. ASSERT(pSda->sda_tTillKickOff <= SESSION_WARN_TIME);
  552. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_WARN,
  553. ("AfpSdaCheckSession: Below warn level %ld\n",
  554. pSda->sda_tTillKickOff));
  555. // If we are at 0, kick this user out. Else just
  556. // send him a friendly warning.
  557. if (pSda->sda_tTillKickOff == 0)
  558. {
  559. AFP_SESSION_INFO SessionInfo;
  560. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_WARN,
  561. ("AfpSdaCheckSession: Booting session %ld\n", SessionId));
  562. SessionInfo.afpsess_id = SessionId;
  563. AfpAdmWSessionClose(&SessionInfo, 0, NULL);
  564. Status = AFP_ERR_NONE; // Do not reschedule
  565. }
  566. else
  567. {
  568. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_WARN,
  569. ("AfpSdaCheckSession: Warning session %ld\n", SessionId));
  570. AfpSpSendAttention(pSda,
  571. (USHORT)(ATTN_USER_DISCONNECT |
  572. ((pSda->sda_tTillKickOff/60) & ATTN_TIME_MASK)),
  573. True);
  574. }
  575. if (RequeueOurself)
  576. {
  577. AfpScavengerScheduleEvent(
  578. AfpSdaCheckSession,
  579. (PVOID)((ULONG_PTR)pSda->sda_SessionId),
  580. SESSION_CHECK_TIME,
  581. True);
  582. }
  583. AfpSdaDereferenceSession(pSda);
  584. }
  585. return Status;
  586. }
  587. /*** AfpKillSessionsOverProtocol
  588. *
  589. * Kill all the sessions over a specific protocol (TCP/IP or Appletalk)
  590. */
  591. VOID FASTCALL
  592. AfpKillSessionsOverProtocol(
  593. IN BOOLEAN fAppletalkSessions
  594. )
  595. {
  596. PSDA pSda;
  597. PSDA pSdaNext;
  598. KIRQL OldIrql;
  599. USHORT AttnWord;
  600. AttnWord = ATTN_USER_DISCONNECT;
  601. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  602. for (pSda = AfpSessionList; pSda != NULL; pSda = pSdaNext)
  603. {
  604. ACQUIRE_SPIN_LOCK_AT_DPC(&pSda->sda_Lock);
  605. pSdaNext = pSda->sda_Next;
  606. //
  607. // if this session is already being closing, skip it
  608. //
  609. if (pSda->sda_Flags & (SDA_CLOSING | SDA_SESSION_CLOSED | SDA_CLIENT_CLOSE))
  610. {
  611. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  612. continue;
  613. }
  614. //
  615. // if we are asked to kill all Appletalk sessions and this session
  616. // over Appletalk, skip it
  617. //
  618. if (fAppletalkSessions)
  619. {
  620. if (pSda->sda_Flags & SDA_SESSION_OVER_TCP)
  621. {
  622. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  623. ("AfpKillSessionsOverProtocol: skipping TCP session %lx\n",pSda));
  624. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  625. continue;
  626. }
  627. }
  628. //
  629. // we are asked to kill all TCP/IP sessions, and this session is
  630. // over Appletalk: skip it
  631. //
  632. else
  633. {
  634. if (!(pSda->sda_Flags & SDA_SESSION_OVER_TCP))
  635. {
  636. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  637. ("AfpKillSessionsOverProtocol: skipping Appletalk session %lx\n",pSda));
  638. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  639. continue;
  640. }
  641. }
  642. pSda->sda_Flags |= SDA_CLOSING | SDA_SESSION_CLOSED;
  643. // put a DISCONNECT refcount
  644. pSda->sda_RefCount ++;
  645. RELEASE_SPIN_LOCK_FROM_DPC(&pSda->sda_Lock);
  646. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  647. // give client the bad news
  648. AfpSpSendAttention(pSda, AttnWord, True);
  649. AfpSpCloseSession(pSda);
  650. // and remove that DISCONNECT refcount
  651. AfpSdaDereferenceSession(pSda);
  652. ACQUIRE_SPIN_LOCK(&AfpSdaLock, &OldIrql);
  653. // start from the head of the list
  654. pSdaNext = AfpSessionList;
  655. }
  656. RELEASE_SPIN_LOCK(&AfpSdaLock, OldIrql);
  657. }
  658. /*** AfpFreeReplyBuf
  659. *
  660. * Free up the reply buffer
  661. *
  662. */
  663. VOID
  664. AfpFreeReplyBuf(
  665. IN PSDA pSda,
  666. IN BOOLEAN fLockHeld
  667. )
  668. {
  669. KIRQL OldIrql;
  670. BOOLEAN fRelease=FALSE;
  671. PBYTE pReplyBuffer;
  672. if (!fLockHeld)
  673. {
  674. ACQUIRE_SPIN_LOCK(&pSda->sda_Lock, &OldIrql);
  675. fRelease = TRUE;
  676. }
  677. ASSERT(pSda->sda_ReplyBuf != NULL);
  678. pReplyBuffer = pSda->sda_ReplyBuf - DSI_BACKFILL_OFFSET(pSda);
  679. if (pReplyBuffer == pSda->sda_NameXSpace)
  680. {
  681. ASSERT(pSda->sda_Flags & SDA_NAMEXSPACE_IN_USE);
  682. pSda->sda_Flags &= ~SDA_NAMEXSPACE_IN_USE;
  683. }
  684. else
  685. {
  686. AfpFreeMemory(pReplyBuffer);
  687. }
  688. pSda->sda_ReplyBuf = NULL;
  689. pSda->sda_ReplySize = 0;
  690. if (fRelease)
  691. {
  692. RELEASE_SPIN_LOCK(&pSda->sda_Lock, OldIrql);
  693. }
  694. }
  695. /*** afpUpdateDiskQuotaInfo
  696. *
  697. * Get Available disk quota for this user
  698. *
  699. */
  700. VOID FASTCALL
  701. afpUpdateDiskQuotaInfo(
  702. IN PCONNDESC pConnDesc
  703. )
  704. {
  705. FILE_FS_SIZE_INFORMATION fssizeinfo;
  706. IO_STATUS_BLOCK IoStsBlk;
  707. NTSTATUS rc;
  708. LONG BytesPerAllocationUnit;
  709. LARGE_INTEGER FreeBytes, VolumeSize;
  710. KIRQL OldIrql;
  711. ASSERT(VALID_CONNDESC(pConnDesc));
  712. ASSERT(VALID_VOLDESC(pConnDesc->cds_pVolDesc));
  713. ASSERT(VALID_VOLDESC(pConnDesc->cds_pVolDesc) &&
  714. VALID_FSH(&pConnDesc->cds_pVolDesc->vds_hRootDir) &&
  715. (KeGetCurrentIrql() < DISPATCH_LEVEL));
  716. AfpImpersonateClient(pConnDesc->cds_pSda);
  717. rc = NtQueryVolumeInformationFile(
  718. pConnDesc->cds_pVolDesc->vds_hRootDir.fsh_FileHandle,
  719. &IoStsBlk,
  720. (PVOID)&fssizeinfo,
  721. sizeof(fssizeinfo),
  722. FileFsSizeInformation);
  723. AfpRevertBack();
  724. if (!NT_SUCCESS(rc))
  725. {
  726. DBGPRINT(DBG_COMP_FILEIO, DBG_LEVEL_ERR,
  727. ("afpUpdateDiskQuotaInfo: NtQueryVolInfoFile failed 0x%lx\n",rc));
  728. // take away the refcount we put before calling this routine
  729. AfpConnectionDereference(pConnDesc);
  730. return;
  731. }
  732. //
  733. // note Macintosh can only handle 2Gb volume size. So kludge appropriately.
  734. // System 7.5 and beyond has upped this to 4GB. Optionally handle this if
  735. // the volume has that bit turned on.
  736. //
  737. BytesPerAllocationUnit =
  738. (LONG)(fssizeinfo.BytesPerSector * fssizeinfo.SectorsPerAllocationUnit);
  739. FreeBytes = RtlExtendedIntegerMultiply(fssizeinfo.AvailableAllocationUnits,
  740. BytesPerAllocationUnit);
  741. VolumeSize = RtlExtendedIntegerMultiply(fssizeinfo.TotalAllocationUnits,
  742. BytesPerAllocationUnit);
  743. ACQUIRE_SPIN_LOCK(&pConnDesc->cds_ConnLock, &OldIrql);
  744. pConnDesc->cds_QuotaLimit = VolumeSize;
  745. pConnDesc->cds_QuotaAvl = FreeBytes;
  746. RELEASE_SPIN_LOCK(&pConnDesc->cds_ConnLock, OldIrql);
  747. DBGPRINT(DBG_COMP_SDA, DBG_LEVEL_INFO,
  748. ("afpUpdateDiskQuotaInfo: Conn %lx Limit=%ld, Available=%ld\n",
  749. pConnDesc,pConnDesc->cds_QuotaLimit.LowPart,pConnDesc->cds_QuotaAvl.LowPart));
  750. // take away the refcount we put before calling this routine
  751. AfpConnectionDereference(pConnDesc);
  752. return;
  753. }