Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1283 lines
35 KiB

  1. /*
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. server.c
  5. Abstract:
  6. This module contains server global data and server init code.
  7. This is used by the admin interface to start-off the server.
  8. Author:
  9. Jameel Hyder (microsoft!jameelh)
  10. Revision History:
  11. 25 Apr 1992 Initial Version
  12. Notes: Tab stop: 4
  13. --*/
  14. #define _GLOBALS_
  15. #define SERVER_LOCALS
  16. #define FILENUM FILE_SERVER
  17. #include <seposix.h>
  18. #include <afp.h>
  19. #include <afpadmin.h>
  20. #include <access.h>
  21. #include <client.h>
  22. #include <tcp.h>
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text( INIT, AfpInitializeDataAndSubsystems)
  25. #pragma alloc_text( PAGE, AfpDeinitializeSubsystems)
  26. #pragma alloc_text( PAGE, AfpAdmSystemShutdown)
  27. #pragma alloc_text( PAGE, AfpCreateNewThread)
  28. #pragma alloc_text( PAGE_AFP, AfpAdmWServerSetInfo)
  29. //#pragma alloc_text( PAGE_AFP, AfpSetServerStatus)
  30. #endif
  31. // This is the device handle to the stack.
  32. BOOLEAN afpSpNameRegistered = False;
  33. HANDLE afpSpAddressHandle = NULL;
  34. PDEVICE_OBJECT afpSpAppleTalkDeviceObject = NULL;
  35. PFILE_OBJECT afpSpAddressObject = NULL;
  36. LONG afpSpNumOutstandingReplies = 0;
  37. /*** AfpInitializeDataAndSubsystems
  38. *
  39. * Initialize Server Data and all subsystems.
  40. */
  41. NTSTATUS
  42. AfpInitializeDataAndSubsystems(
  43. VOID
  44. )
  45. {
  46. NTSTATUS Status;
  47. PBYTE pBuffer;
  48. PBYTE pDest;
  49. LONG i, j;
  50. // Initialize various global locks
  51. INITIALIZE_SPIN_LOCK(&AfpServerGlobalLock);
  52. INITIALIZE_SPIN_LOCK(&AfpSwmrLock);
  53. INITIALIZE_SPIN_LOCK(&AfpStatisticsLock);
  54. #if DBG
  55. INITIALIZE_SPIN_LOCK(&AfpDebugSpinLock);
  56. InitializeListHead(&AfpDebugDelAllocHead);
  57. #endif
  58. KeInitializeEvent(&AfpStopConfirmEvent, NotificationEvent, False);
  59. KeInitializeMutex(&AfpPgLkMutex, 0xFFFF);
  60. AfpInitializeWorkItem(&AfpTerminateThreadWI, NULL, NULL);
  61. // The default security quality of service
  62. AfpSecurityQOS.Length = sizeof(AfpSecurityQOS);
  63. AfpSecurityQOS.ImpersonationLevel = SecurityImpersonation;
  64. AfpSecurityQOS.ContextTrackingMode = SECURITY_STATIC_TRACKING;
  65. AfpSecurityQOS.EffectiveOnly = False;
  66. // Timeout(s) value used by AfpIoWait
  67. FiveSecTimeOut.QuadPart = (-5*NUM_100ns_PER_SECOND);
  68. ThreeSecTimeOut.QuadPart = (-3*NUM_100ns_PER_SECOND);
  69. TwoSecTimeOut.QuadPart = (-2*NUM_100ns_PER_SECOND);
  70. OneSecTimeOut.QuadPart = (-1*NUM_100ns_PER_SECOND);
  71. // Default Type Creator. Careful with the initialization here.This has
  72. // to be processor independent
  73. AfpSwmrInitSwmr(&AfpEtcMapLock);
  74. PUTBYTE42BYTE4(&AfpDefaultEtcMap.etc_type, AFP_DEFAULT_ETC_TYPE);
  75. PUTBYTE42BYTE4(&AfpDefaultEtcMap.etc_creator, AFP_DEFAULT_ETC_CREATOR);
  76. PUTBYTE42BYTE4(&AfpDefaultEtcMap.etc_extension, AFP_DEFAULT_ETC_EXT);
  77. // Determine if the machine is little or big endian. This is not currently used
  78. // at all. The idea is to maintain all on-disk databases in little-endian
  79. // format and on big-endian machines, convert on the way-in and out.
  80. i = 0x01020304;
  81. AfpIsMachineLittleEndian = (*(BYTE *)(&i) == 0x04);
  82. AfpServerState = AFP_STATE_IDLE;
  83. AfpServerOptions = AFP_SRVROPT_NONE;
  84. AfpServerMaxSessions = AFP_MAXSESSIONS;
  85. AfpGetCurrentTimeInMacFormat((PAFPTIME)&AfpServerStatistics.stat_TimeStamp);
  86. //AfpGetCurrentTimeInMacFormat(&AfpSrvrNotifSentTime);
  87. // generate a "unique" signature for our server
  88. pDest = &AfpServerSignature[0];
  89. for (i=0; i<2; i++)
  90. {
  91. pBuffer = AfpGetChallenge();
  92. if (pBuffer)
  93. {
  94. RtlCopyMemory(pDest, pBuffer, MSV1_0_CHALLENGE_LENGTH);
  95. pDest += MSV1_0_CHALLENGE_LENGTH;
  96. AfpFreeMemory(pBuffer);
  97. }
  98. }
  99. #ifdef PROFILING
  100. // Allocate this directly since AfpAllocMemory() uses AfpServerProfile !!!
  101. if ((AfpServerProfile = (PAFP_PROFILE_INFO)ExAllocatePoolWithTag(NonPagedPool,
  102. sizeof(AFP_PROFILE_INFO),
  103. AFP_TAG)) == NULL)
  104. return STATUS_INSUFFICIENT_RESOURCES;
  105. RtlZeroMemory(AfpServerProfile, sizeof(AFP_PROFILE_INFO));
  106. KeQueryPerformanceCounter(&AfpServerProfile->perf_PerfFreq);
  107. #endif
  108. AfpInitStrings();
  109. // Initialize the sub-systems
  110. for (i = 0; i < NUM_INIT_SYSTEMS; i++)
  111. {
  112. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  113. ("AfpInitializeDataAndSubsystems: Initializing s\n",
  114. AfpInitSubSystems[i].InitRoutineName));
  115. if (AfpInitSubSystems[i].InitRoutine != NULL)
  116. {
  117. Status = (*AfpInitSubSystems[i].InitRoutine)();
  118. if (!NT_SUCCESS(Status))
  119. {
  120. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  121. ("AfpInitializeDataAndSubsystems: %s failed %lx\n",
  122. AfpInitSubSystems[i].InitRoutineName, Status));
  123. // One of the subsystems failed to initialize. Deinitialize all
  124. // of them which succeeded.
  125. for (j = 0; j < i; j++)
  126. {
  127. if (AfpInitSubSystems[j].DeInitRoutine != NULL)
  128. {
  129. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  130. ("AfpInitializeDataAndSubsystems: Deinitializing %s\n",
  131. AfpInitSubSystems[j].DeInitRoutineName));
  132. (*AfpInitSubSystems[j].DeInitRoutine)();
  133. }
  134. #if DBG
  135. AfpInitSubSystems[j].Deinitialized = True;
  136. #endif
  137. }
  138. return Status;
  139. }
  140. #if DBG
  141. AfpInitSubSystems[i].Initialized = True;
  142. #endif
  143. }
  144. }
  145. return STATUS_SUCCESS;
  146. }
  147. /*** AfpDeinitializeSubsystems
  148. *
  149. * De-initialize all subsystems.
  150. */
  151. VOID
  152. AfpDeinitializeSubsystems(
  153. VOID
  154. )
  155. {
  156. LONG i;
  157. PAGED_CODE( );
  158. // De-initialize the sub-systems
  159. for (i = 0; i < NUM_INIT_SYSTEMS; i++)
  160. {
  161. if (AfpInitSubSystems[i].DeInitRoutine != NULL)
  162. {
  163. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  164. ("AfpDeinitializeDataAndSubsystems: Deinitializing %s\n",
  165. AfpInitSubSystems[i].DeInitRoutineName));
  166. (*AfpInitSubSystems[i].DeInitRoutine)();
  167. }
  168. #if DBG
  169. AfpInitSubSystems[i].Deinitialized = True;
  170. #endif
  171. }
  172. }
  173. /*** AfpSetServerStatus
  174. *
  175. * Set the Server status block via afpSpSetStatus. This is called in once at
  176. * server startup and anytime a change in server status makes this necessary.
  177. * By now, ServerSetInfo() has happened and it has been validated that all
  178. * paramters are kosher.
  179. *
  180. * LOCKS: AfpServerGlobalLock (SPIN)
  181. */
  182. AFPSTATUS
  183. AfpSetServerStatus(
  184. IN VOID
  185. )
  186. {
  187. KIRQL OldIrql;
  188. AFPSTATUS Status=STATUS_SUCCESS;
  189. AFPSTATUS Status2;
  190. struct _StatusHeader
  191. {
  192. BYTE _MachineString[2]; // These are offsets relative to the struct
  193. BYTE _AfpVersions[2]; // ---------- do ------------
  194. BYTE _UAMs[2]; // ---------- do ------------
  195. BYTE _VolumeIcon[2]; // ---------- do ------------
  196. BYTE _Flags[2]; // Server Flags
  197. // The actual strings start here
  198. } *pStatusHeader;
  199. PASCALSTR pStr;
  200. PBYTE pNumUamPtr;
  201. LONG Size;
  202. USHORT Flags;
  203. BOOLEAN GuestAllowed = False,
  204. ClearTextAllowed = False,
  205. NativeAppleUamSupported = False,
  206. MicrosoftUamSupported = False,
  207. AllowSavePass = False;
  208. BYTE CountOfUams;
  209. PBYTE pSignOffset;
  210. PBYTE pNetAddrOffset;
  211. DWORD IpAddrCount=0;
  212. PBYTE IpAddrBlob=NULL;
  213. NTSTATUS ntStatus;
  214. // Assert that all the info that we can possibly stuff in can indeed fit
  215. // in the buffer that we'll allocate
  216. // Allocate a buffer to fill the status information in. This will be
  217. // freed by AfpSpSetStatus(), this can be freed. We do not know up front
  218. // how much we'll need. Err on the safe side
  219. if ((pStatusHeader = (struct _StatusHeader *)
  220. AfpAllocZeroedNonPagedMemory(ASP_MAX_STATUS_BUF)) == NULL)
  221. {
  222. return STATUS_INSUFFICIENT_RESOURCES;
  223. }
  224. //
  225. // first, find out if we have any TCPIP addresses
  226. //
  227. ntStatus = DsiGetIpAddrBlob(&IpAddrCount, &IpAddrBlob);
  228. if (!NT_SUCCESS(ntStatus))
  229. {
  230. AfpFreeMemory(pStatusHeader);
  231. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  232. ("AfpSetServerStatus: DsiGetIpAddrBlob failed %lx\n",ntStatus));
  233. return STATUS_INSUFFICIENT_RESOURCES;
  234. }
  235. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  236. GuestAllowed = (AfpServerOptions & AFP_SRVROPT_GUESTLOGONALLOWED) ?
  237. True : False;
  238. ClearTextAllowed = (AfpServerOptions & AFP_SRVROPT_CLEARTEXTLOGONALLOWED) ?
  239. True : False;
  240. MicrosoftUamSupported = (AfpServerOptions & AFP_SRVROPT_MICROSOFT_UAM)?
  241. True : False;
  242. NativeAppleUamSupported = (AfpServerOptions & AFP_SRVROPT_NATIVEAPPLEUAM) ?
  243. True : False;
  244. if (!ClearTextAllowed && !MicrosoftUamSupported && !NativeAppleUamSupported)
  245. {
  246. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
  247. ("AfpSetServerStatus: got to enable at least one UAM! Failing request\n"));
  248. RELEASE_SPIN_LOCK(&AfpServerGlobalLock, OldIrql);
  249. AfpFreeMemory(pStatusHeader);
  250. if (IpAddrBlob)
  251. {
  252. AfpFreeMemory(IpAddrBlob);
  253. }
  254. return(STATUS_INVALID_PARAMETER);
  255. }
  256. Size = sizeof(struct _StatusHeader) + // Status header
  257. AfpServerName.Length + 1 + // Server Name
  258. AFP_MACHINE_TYPE_LEN + 1 + // Machine String
  259. AfpVersion20.Length + 1 + // Afp Versions
  260. AfpVersion21.Length + 1 +
  261. ICONSIZE_ICN; // Volume Icon & Mask
  262. ASSERT(Size <= ASP_MAX_STATUS_BUF);
  263. // Specify our capabilities
  264. Flags = SRVRINFO_SUPPORTS_COPYFILE |
  265. SRVRINFO_SUPPORTS_CHGPASSWD |
  266. SRVRINFO_SUPPORTS_SERVERMSG |
  267. SRVRINFO_SUPPORTS_SRVSIGN |
  268. SRVRINFO_SUPPORTS_SRVNOTIFY |
  269. #ifdef CLIENT36
  270. SRVRINFO_SUPPORTS_MGETREQS |
  271. #endif
  272. ((AfpServerOptions & AFP_SRVROPT_ALLOWSAVEDPASSWORD) ?
  273. 0: SRVRINFO_DISALLOW_SAVEPASS);
  274. // do we have any ipaddresses?
  275. if (IpAddrCount > 0)
  276. {
  277. Flags |= SRVRINFO_SUPPORTS_TCPIP;
  278. }
  279. PUTSHORT2SHORT(&pStatusHeader->_Flags, Flags);
  280. // Copy the Server Name
  281. pStr = (PASCALSTR)((PBYTE)pStatusHeader + sizeof(struct _StatusHeader));
  282. pStr->ps_Length = (BYTE)(AfpServerName.Length);
  283. RtlCopyMemory(pStr->ps_String, AfpServerName.Buffer, AfpServerName.Length);
  284. (PBYTE)pStr += AfpServerName.Length + 1;
  285. // do we need a pad byte?
  286. if (((PBYTE)pStr - (PBYTE)pStatusHeader) % 2 == 1)
  287. {
  288. *(PBYTE)pStr = 0;
  289. ((PBYTE)pStr)++;
  290. }
  291. // skip past the Signature Offset field: we'll store the value later
  292. pSignOffset = (PBYTE)pStr;
  293. ((PBYTE)pStr) += 2;
  294. if (AfpServerBoundToAsp || AfpServerBoundToTcp)
  295. {
  296. // skip past the Network Address Count Offset: we'll store the value later
  297. pNetAddrOffset = (PBYTE)pStr;
  298. ((PBYTE)pStr) += 2;
  299. }
  300. else
  301. {
  302. DBGPRINT(DBG_COMP_STACKIF, DBG_LEVEL_ERR,
  303. ("AfpSetServerStatus: Neither TCP nor Appletalk is active!!\n"));
  304. }
  305. PUTSHORT2SHORT(pStatusHeader->_MachineString,
  306. (USHORT)((PBYTE)pStr - (PBYTE)pStatusHeader));
  307. // Copy the machine name string
  308. pStr->ps_Length = (BYTE) AFP_MACHINE_TYPE_LEN;
  309. RtlCopyMemory(pStr->ps_String, AFP_MACHINE_TYPE_STR, AFP_MACHINE_TYPE_LEN);
  310. (PBYTE)pStr += AFP_MACHINE_TYPE_LEN + 1;
  311. // Copy the Afp Version Strings
  312. PUTSHORT2SHORT(pStatusHeader->_AfpVersions,
  313. (USHORT)((PBYTE)pStr - (PBYTE)pStatusHeader));
  314. *((PBYTE)pStr)++ = AFP_NUM_VERSIONS;
  315. pStr->ps_Length = (BYTE)AfpVersion20.Length;
  316. RtlCopyMemory(pStr->ps_String, AfpVersion20.Buffer, AfpVersion20.Length);
  317. (PBYTE)pStr += AfpVersion20.Length + 1;
  318. pStr->ps_Length = (BYTE)AfpVersion21.Length;
  319. RtlCopyMemory(pStr->ps_String, AfpVersion21.Buffer, AfpVersion21.Length);
  320. (PBYTE)pStr += AfpVersion21.Length + 1;
  321. pStr->ps_Length = (BYTE)AfpVersion22.Length;
  322. RtlCopyMemory(pStr->ps_String, AfpVersion22.Buffer, AfpVersion22.Length);
  323. (PBYTE)pStr += AfpVersion22.Length + 1;
  324. // We always support at least one UAM!
  325. PUTSHORT2SHORT(pStatusHeader->_UAMs, (USHORT)((PBYTE)pStr - (PBYTE)pStatusHeader));
  326. pNumUamPtr = (PBYTE)pStr;
  327. ((PBYTE)pStr)++;
  328. CountOfUams = 0;
  329. if (GuestAllowed)
  330. {
  331. pStr->ps_Length = (BYTE)AfpUamGuest.Length;
  332. RtlCopyMemory(pStr->ps_String, AfpUamGuest.Buffer,
  333. AfpUamGuest.Length);
  334. (PBYTE)pStr += AfpUamGuest.Length + 1;
  335. CountOfUams++;
  336. Size += (AfpUamGuest.Length + 1);
  337. }
  338. else
  339. {
  340. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  341. ("AfpSetServerStatus: Guest is disabled\n"));
  342. }
  343. if (ClearTextAllowed)
  344. {
  345. pStr->ps_Length = (BYTE)AfpUamClearText.Length;
  346. RtlCopyMemory(pStr->ps_String, AfpUamClearText.Buffer,
  347. AfpUamClearText.Length);
  348. (PBYTE)pStr += AfpUamClearText.Length + 1;
  349. CountOfUams++;
  350. Size += (AfpUamClearText.Length + 1);
  351. }
  352. else
  353. {
  354. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  355. ("AfpSetServerStatus: ClearText UAM is NOT configured\n"));
  356. }
  357. if (MicrosoftUamSupported)
  358. {
  359. // copy in "Microsoft V1.0" string
  360. pStr->ps_Length = (BYTE)AfpUamCustomV1.Length;
  361. RtlCopyMemory(pStr->ps_String, AfpUamCustomV1.Buffer, AfpUamCustomV1.Length);
  362. (PBYTE)pStr += AfpUamCustomV1.Length + 1;
  363. CountOfUams++;
  364. Size += (AfpUamCustomV1.Length + 1 + 1);
  365. // copy in "Microsoft V2.0" string
  366. pStr->ps_Length = (BYTE)AfpUamCustomV2.Length;
  367. RtlCopyMemory(pStr->ps_String, AfpUamCustomV2.Buffer, AfpUamCustomV2.Length);
  368. (PBYTE)pStr += AfpUamCustomV2.Length + 1;
  369. CountOfUams++;
  370. Size += (AfpUamCustomV2.Length + 1 + 1);
  371. }
  372. else
  373. {
  374. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  375. ("AfpSetServerStatus: Microsoft UAM is NOT configured\n"));
  376. }
  377. if (NativeAppleUamSupported)
  378. {
  379. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_ERR,
  380. ("AfpSetServerStatus: Apple's native UAM is configured\n"));
  381. pStr->ps_Length = (BYTE)AfpUamApple.Length;
  382. RtlCopyMemory(pStr->ps_String, AfpUamApple.Buffer, AfpUamApple.Length);
  383. (PBYTE)pStr += AfpUamApple.Length + 1;
  384. CountOfUams++;
  385. Size += (AfpUamApple.Length + 1 + 1);
  386. // 2-way not included for now
  387. #if ALLOW_2WAY_ASWELL
  388. pStr->ps_Length = (BYTE)AfpUamApple2Way.Length;
  389. RtlCopyMemory(pStr->ps_String, AfpUamApple2Way.Buffer, AfpUamApple2Way.Length);
  390. (PBYTE)pStr += AfpUamApple2Way.Length + 1;
  391. CountOfUams++;
  392. Size += (AfpUamApple2Way.Length + 1 + 1);
  393. #endif
  394. }
  395. // how many UAM's are we telling the client we support
  396. *pNumUamPtr = CountOfUams;
  397. // now we know where Server signature goes: write the offset
  398. PUTSHORT2SHORT(pSignOffset,(USHORT)((PBYTE)pStr - (PBYTE)pStatusHeader));
  399. // copy the Server signature
  400. RtlCopyMemory((PBYTE)pStr, AfpServerSignature, 16);
  401. ((PBYTE)pStr) += 16;
  402. //
  403. // if we have network address(es), send that info over!
  404. //
  405. if ((IpAddrCount > 0) || (AfpServerBoundToAsp))
  406. {
  407. // now we know where Network Address Count Offset goes: write the offset
  408. PUTSHORT2SHORT(pNetAddrOffset,(USHORT)((PBYTE)pStr - (PBYTE)pStatusHeader));
  409. // how many addresses are we returning?
  410. *(PBYTE)pStr = ((BYTE)IpAddrCount) + ((AfpServerBoundToAsp) ? 1 : 0);
  411. ((PBYTE)pStr)++;
  412. // copy the ipaddresses, if bound
  413. if (IpAddrCount > 0)
  414. {
  415. // copy the blob containing the Length, Tag and Ipaddress info
  416. RtlCopyMemory((PBYTE)pStr, IpAddrBlob, IpAddrCount*DSI_NETWORK_ADDR_LEN);
  417. ((PBYTE)pStr) += (IpAddrCount*DSI_NETWORK_ADDR_LEN);
  418. }
  419. // now copy the appletalk addres, if bound
  420. if (AfpServerBoundToAsp)
  421. {
  422. *(PBYTE)pStr = DSI_NETWORK_ADDR_LEN;
  423. ((PBYTE)pStr)++;
  424. *(PBYTE)pStr = ATALK_NETWORK_ADDR_ATKTAG;
  425. ((PBYTE)pStr)++;
  426. PUTDWORD2DWORD((PBYTE)pStr, AfpAspEntries.asp_AtalkAddr.Address);
  427. ((PBYTE)pStr) += sizeof(DWORD);
  428. }
  429. }
  430. // Now get the volume icon, if any
  431. if (AfpServerIcon != NULL)
  432. {
  433. RtlCopyMemory((PBYTE)pStr, AfpServerIcon, ICONSIZE_ICN);
  434. PUTSHORT2SHORT(pStatusHeader->_VolumeIcon,
  435. (USHORT)((PBYTE)pStr - (PBYTE)pStatusHeader));
  436. }
  437. else PUTSHORT2SHORT(pStatusHeader->_VolumeIcon, 0);
  438. RELEASE_SPIN_LOCK(&AfpServerGlobalLock, OldIrql);
  439. if (AfpServerBoundToAsp)
  440. {
  441. Status = AfpSpSetAspStatus((PBYTE)pStatusHeader, Size);
  442. }
  443. if (AfpServerBoundToTcp)
  444. {
  445. Status2 = AfpSpSetDsiStatus((PBYTE)pStatusHeader, Size);
  446. // as long as one succeeds, we want the call to succeed
  447. if (!NT_SUCCESS(Status))
  448. {
  449. Status = Status2;
  450. }
  451. }
  452. AfpFreeMemory(pStatusHeader);
  453. if (IpAddrBlob)
  454. {
  455. AfpFreeMemory(IpAddrBlob);
  456. }
  457. return Status;
  458. }
  459. /*** AfpAdmWServerSetInfo
  460. *
  461. * This routine sets various server globals with data supplied by the admin. The
  462. * following server globals are set by this routine:
  463. *
  464. * - Server Name
  465. * - Maximum Sessions (valid values are 1 through AFP_MAXSESSIONS)
  466. * - Server Options (i.e. guest logon allowed, etc.)
  467. * - Server Login Message
  468. * - Maximum paged and non-paged memory limits
  469. * - Macintosh Code Page File
  470. *
  471. * The server name and memory limits can only be changed while the server
  472. * is stopped. The Macintosh Code Page File may only be set ONE time after
  473. * the AFP server driver is loaded. i.e. if you want to reset the codepage,
  474. * the service must unload the AFP server, then reload it.
  475. *
  476. * This routine must execute in the context of the worker thread, since we
  477. * need to map the Macintosh CodePage into the server's virtual memory
  478. * space, not the client's.
  479. *
  480. * LOCKS: AfpServerGlobalLock (SPIN)
  481. */
  482. AFPSTATUS
  483. AfpAdmWServerSetInfo(
  484. IN OUT PVOID InBuf OPTIONAL,
  485. IN LONG OutBufLen OPTIONAL,
  486. OUT PVOID OutBuf OPTIONAL
  487. )
  488. {
  489. KIRQL OldIrql;
  490. AFPSTATUS rc;
  491. ANSI_STRING amsg, aname;
  492. UNICODE_STRING uname, umsg, oldloginmsgU;
  493. DWORD parmflags = ((PSETINFOREQPKT)InBuf)->sirqp_parmnum;
  494. PAFP_SERVER_INFO pSvrInfo = (PAFP_SERVER_INFO)((PCHAR)InBuf+sizeof(SETINFOREQPKT));
  495. BOOLEAN setstatus = False;
  496. BOOLEAN locktaken = False;
  497. BOOLEAN servernameexists = False;
  498. amsg.Length = 0;
  499. amsg.MaximumLength = 0;
  500. amsg.Buffer = NULL;
  501. aname.Length = 0;
  502. aname.MaximumLength = 0;
  503. aname.Buffer = NULL;
  504. AfpSetEmptyUnicodeString(&umsg, 0, NULL);
  505. AfpSetEmptyUnicodeString(&oldloginmsgU, 0, NULL);
  506. /* Validate all limits */
  507. if ((parmflags & ~AFP_SERVER_PARMNUM_ALL) ||
  508. ((parmflags & AFP_SERVER_PARMNUM_OPTIONS) &&
  509. (pSvrInfo->afpsrv_options & ~AFP_SRVROPT_ALL)) ||
  510. ((parmflags & AFP_SERVER_PARMNUM_MAX_SESSIONS) &&
  511. ((pSvrInfo->afpsrv_max_sessions > AFP_MAXSESSIONS) ||
  512. (pSvrInfo->afpsrv_max_sessions == 0))))
  513. {
  514. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  515. ("AfpAdmWServerSetInfo: invalid parm!\n"));
  516. return AFPERR_InvalidParms_MaxSessions;
  517. }
  518. if (parmflags == AFP_SERVER_GUEST_ACCT_NOTIFY)
  519. {
  520. AfpServerOptions ^= AFP_SRVROPT_GUESTLOGONALLOWED;
  521. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  522. ("AfpAdmWServerSetInfo: Guest account is now %s\n",
  523. (AfpServerOptions & AFP_SRVROPT_GUESTLOGONALLOWED)? "enabled":"disabled"));
  524. AfpSetServerStatus();
  525. return(STATUS_SUCCESS);
  526. }
  527. if (parmflags & AFP_SERVER_PARMNUM_CODEPAGE)
  528. {
  529. // You may only set the Macintosh CodePage once
  530. if (AfpMacCPBaseAddress != NULL)
  531. return AFPERR_InvalidServerState;
  532. else
  533. {
  534. rc = AfpGetMacCodePage(pSvrInfo->afpsrv_codepage);
  535. if (!NT_SUCCESS(rc))
  536. {
  537. return AFPERR_CodePage;
  538. }
  539. }
  540. }
  541. if (parmflags & AFP_SERVER_PARMNUM_LOGINMSG)
  542. {
  543. RtlInitUnicodeString(&umsg, pSvrInfo->afpsrv_login_msg);
  544. if (umsg.Length == 0)
  545. {
  546. umsg.Buffer = NULL;
  547. }
  548. amsg.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&umsg);
  549. amsg.Length = amsg.MaximumLength - 1;
  550. if (amsg.Length > AFP_MESSAGE_LEN)
  551. {
  552. return AFPERR_InvalidParms_LoginMsg;
  553. }
  554. if (amsg.Length != 0)
  555. {
  556. if ((umsg.Buffer =
  557. (LPWSTR)AfpAllocPagedMemory(umsg.Length+1)) == NULL)
  558. {
  559. return STATUS_INSUFFICIENT_RESOURCES;
  560. }
  561. if ((amsg.Buffer =
  562. (PCHAR)AfpAllocNonPagedMemory(amsg.MaximumLength)) == NULL)
  563. {
  564. AfpFreeMemory(umsg.Buffer);
  565. return STATUS_INSUFFICIENT_RESOURCES;
  566. }
  567. RtlCopyMemory(umsg.Buffer, pSvrInfo->afpsrv_login_msg, umsg.Length);
  568. rc = RtlUnicodeStringToAnsiString(&amsg, &umsg, False);
  569. if (!NT_SUCCESS(rc))
  570. {
  571. AfpFreeMemory(amsg.Buffer);
  572. AfpFreeMemory(umsg.Buffer);
  573. return AFPERR_InvalidParms;
  574. }
  575. else AfpConvertHostAnsiToMacAnsi(&amsg);
  576. }
  577. }
  578. do
  579. {
  580. if (parmflags & AFP_SERVER_PARMNUM_NAME)
  581. {
  582. RtlInitUnicodeString(&uname,pSvrInfo->afpsrv_name);
  583. aname.MaximumLength = (USHORT)RtlUnicodeStringToAnsiSize(&uname);
  584. aname.Length = aname.MaximumLength - 1;
  585. if ((aname.Length == 0) || (aname.Length > AFP_SERVERNAME_LEN))
  586. {
  587. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  588. ("AfpAdmWServerSetInfo: bad name length %d, rejecting\n,aname.Length"));
  589. rc = AFPERR_InvalidServerName_Length;
  590. break;
  591. }
  592. if ((aname.Buffer = AfpAllocNonPagedMemory(aname.MaximumLength)) == NULL)
  593. {
  594. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  595. ("AfpAdmWServerSetInfo: malloc failed on name change\n"));
  596. rc = STATUS_INSUFFICIENT_RESOURCES;
  597. break;
  598. }
  599. rc = AfpConvertStringToAnsi(&uname, &aname);
  600. if (!NT_SUCCESS(rc))
  601. {
  602. rc = AFPERR_InvalidServerName;
  603. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  604. ("AfpAdmWServerSetInfo: AfpConvertStringToAnsi failed %lx\n",rc));
  605. break;
  606. }
  607. }
  608. rc = STATUS_SUCCESS;
  609. //
  610. // take the global data lock and set the new information
  611. //
  612. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  613. locktaken = True;
  614. // Validate if we are in the right state to receive some of the
  615. // parameters
  616. if ((AfpServerState != AFP_STATE_IDLE) &&
  617. (parmflags & (AFP_SERVER_PARMNUM_PAGEMEMLIM |
  618. AFP_SERVER_PARMNUM_NONPAGEMEMLIM)))
  619. {
  620. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  621. ("AfpAdmWServerSetInfo: failure at 1\n"));
  622. rc = AFPERR_InvalidServerState;
  623. break;
  624. }
  625. else if ((AfpServerState == AFP_STATE_IDLE) &&
  626. (parmflags & (AFP_SERVER_PARMNUM_NAME |
  627. AFP_SERVER_PARMNUM_PAGEMEMLIM |
  628. AFP_SERVER_PARMNUM_NONPAGEMEMLIM)) !=
  629. (DWORD)(AFP_SERVER_PARMNUM_NAME |
  630. AFP_SERVER_PARMNUM_PAGEMEMLIM |
  631. AFP_SERVER_PARMNUM_NONPAGEMEMLIM))
  632. {
  633. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  634. ("AfpAdmWServerSetInfo: failure at 2\n"));
  635. rc = AFPERR_InvalidParms;
  636. break;
  637. }
  638. if (parmflags & (AFP_SERVER_PARMNUM_PAGEMEMLIM |
  639. AFP_SERVER_PARMNUM_NONPAGEMEMLIM))
  640. {
  641. AfpPagedPoolLimit = pSvrInfo->afpsrv_max_paged_mem * 1024;
  642. AfpNonPagedPoolLimit = pSvrInfo->afpsrv_max_nonpaged_mem * 1024;
  643. }
  644. if (parmflags & AFP_SERVER_PARMNUM_NAME)
  645. {
  646. setstatus = ((AfpServerState == AFP_STATE_RUNNING) ||
  647. (AfpServerState == AFP_STATE_START_PENDING));
  648. rc = STATUS_SUCCESS;
  649. if (AfpServerName.Buffer == NULL)
  650. {
  651. AfpServerName = aname;
  652. }
  653. else
  654. {
  655. servernameexists = True;
  656. }
  657. // Re-register the name only if the service up and running
  658. // No point registering the name on a service not functioning.
  659. // This causes problems as we falsely advertise
  660. // the AFP server in the browser when it is not really available.
  661. if (setstatus)
  662. {
  663. // deregister the old name, if one exists
  664. if ((AfpServerBoundToAsp) && (servernameexists))
  665. {
  666. RELEASE_SPIN_LOCK(&AfpServerGlobalLock,OldIrql);
  667. rc = AfpSpRegisterName(&AfpServerName, False);
  668. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  669. AfpFreeMemory(AfpServerName.Buffer);
  670. }
  671. AfpServerName = aname;
  672. // if deregister succeeded, register the new name
  673. if ((NT_SUCCESS(rc)) && (AfpServerBoundToAsp))
  674. {
  675. RELEASE_SPIN_LOCK(&AfpServerGlobalLock,OldIrql);
  676. rc = AfpSpRegisterName(&AfpServerName, True);
  677. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  678. }
  679. }
  680. }
  681. if (parmflags & AFP_SERVER_PARMNUM_OPTIONS)
  682. {
  683. if (pSvrInfo->afpsrv_options & AFP_SRVROPT_STANDALONE)
  684. {
  685. // Server is NtProductServer or NtProductWinNt
  686. AfpServerIsStandalone = True;
  687. if (AfpSidNone == NULL)
  688. {
  689. // If we didn't initialize the AfpSidNone during
  690. // AfpInitSidOffsets then the service either sent
  691. // us bogus offsets, or this bit is bogus
  692. rc = AFPERR_InvalidParms;
  693. break;
  694. }
  695. pSvrInfo->afpsrv_options &= ~AFP_SRVROPT_STANDALONE;
  696. }
  697. if (!setstatus)
  698. {
  699. setstatus =
  700. (AfpServerOptions ^ pSvrInfo->afpsrv_options) ? True : False;
  701. setstatus = setstatus &&
  702. ((AfpServerState == AFP_STATE_RUNNING) ||
  703. (AfpServerState == AFP_STATE_START_PENDING));
  704. }
  705. AfpServerOptions = pSvrInfo->afpsrv_options;
  706. }
  707. if (parmflags & AFP_SERVER_PARMNUM_LOGINMSG)
  708. {
  709. if (AfpLoginMsg.Buffer != NULL)
  710. {
  711. AfpFreeMemory(AfpLoginMsg.Buffer);
  712. }
  713. AfpLoginMsg = amsg;
  714. oldloginmsgU = AfpLoginMsgU;
  715. AfpLoginMsgU = umsg;
  716. }
  717. if (parmflags & AFP_SERVER_PARMNUM_MAX_SESSIONS)
  718. {
  719. if (AfpServerMaxSessions != pSvrInfo->afpsrv_max_sessions)
  720. {
  721. BOOLEAN KillSome;
  722. KillSome = (AfpServerMaxSessions > pSvrInfo->afpsrv_max_sessions);
  723. AfpServerMaxSessions = pSvrInfo->afpsrv_max_sessions;
  724. RELEASE_SPIN_LOCK(&AfpServerGlobalLock,OldIrql);
  725. locktaken = False;
  726. }
  727. }
  728. } while (False);
  729. if (locktaken)
  730. {
  731. RELEASE_SPIN_LOCK(&AfpServerGlobalLock,OldIrql);
  732. }
  733. if (!NT_SUCCESS(rc))
  734. {
  735. DBGPRINT(DBG_COMP_ADMINAPI_SRV, DBG_LEVEL_ERR,
  736. ("AfpAdmWServerSetInfo: returning %lx\n",rc));
  737. if (amsg.Buffer != NULL)
  738. {
  739. AfpFreeMemory(amsg.Buffer);
  740. }
  741. if (aname.Buffer != NULL)
  742. {
  743. if (AfpServerName.Buffer == aname.Buffer)
  744. {
  745. AfpServerName.Buffer = NULL;
  746. AfpServerName.MaximumLength = 0;
  747. AfpServerName.Length = 0;
  748. }
  749. AfpFreeMemory(aname.Buffer);
  750. }
  751. }
  752. else if (setstatus)
  753. {
  754. return (AfpSetServerStatus());
  755. }
  756. if (oldloginmsgU.Buffer != NULL)
  757. AfpFreeMemory(oldloginmsgU.Buffer);
  758. return rc;
  759. }
  760. /*** AfpCreateNewThread
  761. *
  762. * Create either an admin or a worker thread.
  763. */
  764. NTSTATUS FASTCALL
  765. AfpCreateNewThread(
  766. IN VOID (*ThreadFunc)(IN PVOID pContext),
  767. IN LONG ThreadNum
  768. )
  769. {
  770. NTSTATUS Status;
  771. HANDLE FspThread;
  772. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  773. ("AfpCreateNewThread: Creating thread %lx\n", ThreadFunc));
  774. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  775. ASSERT ((AfpServerState == AFP_STATE_IDLE) ||
  776. (ThreadNum < AFP_MAX_THREADS) && (AfpNumThreads >= AFP_MIN_THREADS));
  777. Status = PsCreateSystemThread(&FspThread,
  778. THREAD_ALL_ACCESS,
  779. NULL,
  780. NtCurrentProcess(),
  781. NULL,
  782. ThreadFunc,
  783. (PVOID)((ULONG_PTR)ThreadNum));
  784. if (!NT_SUCCESS(Status))
  785. {
  786. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
  787. ("AfpCreateNewThread: Cannot create threads %lx\n", Status));
  788. AFPLOG_DDERROR(AFPSRVMSG_CREATE_THREAD, Status, NULL, 0, NULL);
  789. }
  790. else
  791. {
  792. // Close the handle to the thread so that it goes away when the
  793. // thread terminates
  794. NtClose(FspThread);
  795. }
  796. return Status;
  797. }
  798. /*** AfpQueueWorkItem
  799. *
  800. * Queue a work item to the worker thread.
  801. *
  802. * LOCKS: AfpStatisticsLock
  803. */
  804. VOID FASTCALL
  805. AfpQueueWorkItem(
  806. IN PWORK_ITEM pWI
  807. )
  808. {
  809. KIRQL OldIrql;
  810. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  811. AfpServerStatistics.stat_CurrQueueLength ++;
  812. #ifdef PROFILING
  813. AfpServerProfile->perf_QueueCount ++;
  814. #endif
  815. if (AfpServerStatistics.stat_CurrQueueLength > AfpServerStatistics.stat_MaxQueueLength)
  816. AfpServerStatistics.stat_MaxQueueLength++;
  817. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  818. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  819. ("AfpQueueWorkItem: Queueing %lx (%lx)\n",
  820. pWI->wi_Worker, pWI->wi_Context));
  821. INTERLOCKED_ADD_ULONG(&AfpWorkerRequests, 1, &AfpServerGlobalLock);
  822. // Insert work item in worker queue
  823. KeInsertQueue(&AfpWorkerQueue, &pWI->wi_List);
  824. }
  825. /*** AfpWorkerThread
  826. *
  827. * This thread is used to do all the work that is queued to the FSP.
  828. *
  829. * We want to dynamically create and destroy threads so that we can
  830. * optimize the number of threads used. The number of threads range
  831. * from AFP_MIN_THREADS - AFP_MAX_THREADS.
  832. * A new thread is created if the number of entries in the queue
  833. * exceeds AFP_THREAD_THRESHOLD_REQ. A thread is terminated if the request count
  834. * drops below AFP_THREAD_THRESHOLD_IDLE.
  835. */
  836. VOID
  837. AfpWorkerThread(
  838. IN PVOID pContext
  839. )
  840. {
  841. NTSTATUS Status;
  842. PLIST_ENTRY pList;
  843. PWORK_ITEM pWI;
  844. LONG IdleCount = 0;
  845. LONG ThreadNum, CreateId;
  846. ULONG BasePriority = THREAD_BASE_PRIORITY_MAX;
  847. KIRQL OldIrql;
  848. BOOLEAN Release = False;
  849. BOOLEAN ReasonToLive = True;
  850. ThreadNum = (LONG)(LONG_PTR)pContext;
  851. ASSERT (AfpThreadState[ThreadNum] == AFP_THREAD_STARTED);
  852. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
  853. ("AfpWorkerThread: Thread %ld Starting. NumThreads %ld\n",
  854. ThreadNum, AfpNumThreads));
  855. // Update the thread statistics.
  856. ACQUIRE_SPIN_LOCK(&AfpStatisticsLock, &OldIrql);
  857. AfpServerStatistics.stat_CurrThreadCount ++;
  858. if (AfpServerStatistics.stat_CurrThreadCount > AfpServerStatistics.stat_MaxThreadCount)
  859. AfpServerStatistics.stat_MaxThreadCount = AfpServerStatistics.stat_CurrThreadCount;
  860. RELEASE_SPIN_LOCK(&AfpStatisticsLock, OldIrql);
  861. // Set the thread base priority to 'foreground'
  862. NtSetInformationThread( NtCurrentThread(),
  863. ThreadBasePriority,
  864. &BasePriority,
  865. sizeof(BasePriority));
  866. // Disable hard-error pop-ups for this thread
  867. IoSetThreadHardErrorMode( FALSE );
  868. AfpThreadPtrsW[ThreadNum] = PsGetCurrentThread();
  869. do
  870. {
  871. AfpThreadState[ThreadNum] = AFP_THREAD_WAITING;
  872. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  873. ("AfpWorkerThread: About to block\n"));
  874. // DELALLOCQUEUE: unrem the #if 0 part
  875. #if 0
  876. //
  877. // first check if there is someone waiting to get buffer allocation:
  878. // let's deal with them first, so some connection doesn't get "blocked"
  879. // because transport underneath doesn't have buffer
  880. //
  881. pList = KeRemoveQueue(&AfpDelAllocQueue, KernelMode, NULL);
  882. if (pList != NULL)
  883. {
  884. AfpThreadState[ThreadNum] = AFP_THREAD_BUSY;
  885. pWI = CONTAINING_RECORD(pList, WORK_ITEM, wi_List);
  886. // Call the worker
  887. (pWI->wi_Worker)(pWI->wi_Context);
  888. IdleCount = 0;
  889. continue;
  890. }
  891. #endif
  892. pList = KeRemoveQueue(&AfpWorkerQueue, KernelMode, &ThreeSecTimeOut);
  893. Status = STATUS_SUCCESS;
  894. if ((NTSTATUS)((ULONG_PTR)pList) == STATUS_TIMEOUT)
  895. Status = STATUS_TIMEOUT;
  896. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  897. ("AfpWorkerThread: %s\n",
  898. (Status == STATUS_SUCCESS) ? "Another Work item" : "Timer - check"));
  899. if (Status == STATUS_SUCCESS)
  900. {
  901. pWI = CONTAINING_RECORD(pList, WORK_ITEM, wi_List);
  902. if (pWI == &AfpTerminateThreadWI)
  903. {
  904. BOOLEAN Requeue;
  905. ReasonToLive = False;
  906. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  907. AfpNumThreads --;
  908. Requeue = (AfpNumThreads != 0);
  909. RELEASE_SPIN_LOCK(&AfpServerGlobalLock, OldIrql);
  910. AfpThreadState[ThreadNum] = AFP_THREAD_DEAD;
  911. if (!Requeue)
  912. {
  913. ASSERT((AfpServerState == AFP_STATE_STOPPED) ||
  914. (AfpServerState == AFP_STATE_IDLE));
  915. Release = True;
  916. }
  917. else
  918. {
  919. // Re-queue this work-item so that other threads can die too !!!
  920. KeInsertQueue(&AfpWorkerQueue, &AfpTerminateThreadWI.wi_List);
  921. }
  922. break;
  923. }
  924. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  925. ("AfpWorkerThread: Dispatching %lx (%lx)\n",
  926. pWI->wi_Worker, pWI->wi_Context));
  927. AfpThreadState[ThreadNum] = AFP_THREAD_BUSY;
  928. #if DBG
  929. AfpThreadDispCount[ThreadNum] ++;
  930. #endif
  931. // Call the worker
  932. (pWI->wi_Worker)(pWI->wi_Context);
  933. ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL);
  934. INTERLOCKED_ADD_ULONG((PLONG)(&AfpServerStatistics.stat_CurrQueueLength),
  935. (ULONG)-1,
  936. &AfpStatisticsLock);
  937. INTERLOCKED_ADD_ULONG(&AfpWorkerRequests, (ULONG)-1, &AfpServerGlobalLock);
  938. IdleCount = 0;
  939. }
  940. else
  941. {
  942. IdleCount ++;
  943. }
  944. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  945. if (((AfpWorkerRequests - AfpNumThreads) > AFP_THREAD_THRESHOLD_REQS) &&
  946. (AfpNumThreads < AFP_MAX_THREADS))
  947. {
  948. for (CreateId = 0; CreateId < AFP_MAX_THREADS; CreateId++)
  949. {
  950. if (AfpThreadState[CreateId] == AFP_THREAD_DEAD)
  951. {
  952. AfpThreadState[CreateId] = AFP_THREAD_STARTED;
  953. break;
  954. }
  955. }
  956. if (CreateId < AFP_MAX_THREADS)
  957. {
  958. AfpNumThreads++;
  959. ASSERT (CreateId < AFP_MAX_THREADS);
  960. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
  961. ("AfpWorkerThread: Creating New Thread %ld\n", CreateId));
  962. RELEASE_SPIN_LOCK(&AfpServerGlobalLock, OldIrql);
  963. Status = AfpCreateNewThread(AfpWorkerThread, CreateId);
  964. ACQUIRE_SPIN_LOCK(&AfpServerGlobalLock, &OldIrql);
  965. if (!NT_SUCCESS(Status))
  966. {
  967. ASSERT(AfpThreadState[CreateId] == AFP_THREAD_STARTED);
  968. AfpThreadState[CreateId] = AFP_THREAD_DEAD;
  969. AfpNumThreads --;
  970. }
  971. }
  972. }
  973. else if ((AfpNumThreads > AFP_MIN_THREADS) &&
  974. (IdleCount >= AFP_THREAD_THRESHOLD_IDLE))
  975. {
  976. ReasonToLive = False;
  977. AfpThreadState[ThreadNum] = AFP_THREAD_DEAD;
  978. AfpNumThreads --;
  979. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
  980. ("AfpWorkerThread: Thread %ld About to commit suicide, NumThreads %ld\n",
  981. ThreadNum, AfpNumThreads));
  982. }
  983. RELEASE_SPIN_LOCK(&AfpServerGlobalLock, OldIrql);
  984. } while (ReasonToLive);
  985. AfpThreadPtrsW[ThreadNum] = NULL;
  986. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_WARN,
  987. ("AfpWorkerThread: Thread %ld Quitting\n", ThreadNum));
  988. INTERLOCKED_ADD_ULONG((PLONG)&AfpServerStatistics.stat_CurrThreadCount,
  989. (ULONG)-1,
  990. &AfpStatisticsLock);
  991. // if this is the last thread in the system, set things up so that unload code
  992. // can wait on the pointer and know when this thread has really died and not just
  993. // when KeSetEvent is called
  994. if (Release)
  995. {
  996. AfpThreadPtrsW[ThreadNum] = PsGetCurrentThread();
  997. ObReferenceObject(AfpThreadPtrsW[ThreadNum]);
  998. KeSetEvent(&AfpStopConfirmEvent, IO_NETWORK_INCREMENT, False);
  999. }
  1000. }
  1001. /*** AfpInitStrings
  1002. *
  1003. * Initializes all the strings
  1004. */
  1005. VOID FASTCALL
  1006. AfpInitStrings(
  1007. IN VOID
  1008. )
  1009. {
  1010. // Initialize UAM Strings
  1011. RtlInitString(&AfpUamGuest, NO_USER_AUTHENT_NAME);
  1012. RtlInitString(&AfpUamClearText, CLEAR_TEXT_AUTHENT_NAME);
  1013. RtlInitString(&AfpUamCustomV1, CUSTOM_UAM_NAME_V1);
  1014. RtlInitString(&AfpUamCustomV2, CUSTOM_UAM_NAME_V2);
  1015. RtlInitString(&AfpUamApple, RANDNUM_EXCHANGE_NAME);
  1016. RtlInitString(&AfpUamApple2Way, TWOWAY_EXCHANGE_NAME);
  1017. // Initialize AFP Versions
  1018. RtlInitString(&AfpVersion20, AFP_VER_20_NAME);
  1019. RtlInitString(&AfpVersion21, AFP_VER_21_NAME);
  1020. RtlInitString(&AfpVersion22, AFP_VER_22_NAME);
  1021. // Default Workstation name
  1022. RtlInitUnicodeString(&AfpDefaultWksta, AFP_DEFAULT_WORKSTATION);
  1023. RtlInitUnicodeString(&AfpNetworkTrashNameU, AFP_NWTRASH_NAME_U);
  1024. }
  1025. /*** AfpAdmSystemShutdown
  1026. *
  1027. * Called during system shutdown. Simply close all active sessions and stop the volumes.
  1028. */
  1029. AFPSTATUS
  1030. AfpAdmSystemShutdown(
  1031. IN OUT PVOID Inbuf OPTIONAL,
  1032. IN LONG OutBufLen OPTIONAL,
  1033. OUT PVOID Outbuf OPTIONAL
  1034. )
  1035. {
  1036. AFP_SESSION_INFO SessInfo;
  1037. NTSTATUS Status;
  1038. if ((AfpServerState & ( AFP_STATE_STOPPED |
  1039. AFP_STATE_STOP_PENDING |
  1040. AFP_STATE_SHUTTINGDOWN)) == 0)
  1041. {
  1042. AfpServerState = AFP_STATE_SHUTTINGDOWN;
  1043. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  1044. ("AfpAdmSystemShutdown: Shutting down server\n"));
  1045. // Disable listens now that we are about to stop
  1046. AfpSpDisableListens();
  1047. SessInfo.afpsess_id = 0; // Shutdown all sessions
  1048. AfpAdmWSessionClose(&SessInfo, 0, NULL);
  1049. // Wait for the sessions to complete, if there were active sessions
  1050. if (AfpNumSessions > 0) do
  1051. {
  1052. Status = AfpIoWait(&AfpStopConfirmEvent, &FiveSecTimeOut);
  1053. if (Status == STATUS_TIMEOUT)
  1054. {
  1055. DBGPRINT(DBG_COMP_ADMINAPI_SC, DBG_LEVEL_ERR,
  1056. ("AfpAdmSystemShutdown: Timeout Waiting for %ld sessions to die, re-waiting\n",
  1057. AfpNumSessions));
  1058. }
  1059. } while (Status == STATUS_TIMEOUT);
  1060. // bring down the DSI-TCP interface
  1061. DsiDestroyAdapter();
  1062. // wait until DSI cleans up its interface with TCP
  1063. AfpIoWait(&DsiShutdownEvent, NULL);
  1064. // Set the flag to indicate that server is shutting down
  1065. fAfpServerShutdownEvent = TRUE;
  1066. // Now tell each of the volume scavengers to shut-down
  1067. AfpVolumeStopAllVolumes();
  1068. }
  1069. return AFP_ERR_NONE;
  1070. }