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.

1568 lines
41 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. secutil.c
  5. Abstract:
  6. This module contains code to accomplish the following tasks:
  7. 1) Translate a SID to a name.
  8. 2) Translate a name to a SID.
  9. 3) Change the password for a given user.
  10. 4) Translate a SID to a Mac Id.
  11. 5) Translate a Mac Id to a SID.
  12. 6) Server event logging
  13. This module communicates with the AFP Server Service to accomplish these
  14. functions. The real work is done in the Server Service. This utility
  15. exists because these functions cannot be made by calling APIs in kernel
  16. mode.
  17. The basic flow of control begins with an FSCTL from the server service.
  18. This FSCTL is marked as pending till one of the four functions is to be
  19. carried out. Then the IRP output buffer contains the function ID and
  20. function input data and the IRP is maeked as complete. The actual
  21. function is executed by the server service and the results are obtained
  22. by the server FSD via the next FSCTL. Most if this information is cached
  23. in paged-memory.
  24. Author:
  25. Narendra Gidwani (microsoft!nareng)
  26. Revision History:
  27. 8 Sept 1992 Initial Version
  28. 28 Jan 1993 SueA - added support for server event logging
  29. --*/
  30. #define _SECUTIL_LOCALS
  31. #define FILENUM FILE_SECUTIL
  32. #include <afp.h>
  33. #include <scavengr.h>
  34. #include <secutil.h>
  35. #include <access.h>
  36. #include <seposix.h>
  37. #ifdef ALLOC_PRAGMA
  38. #pragma alloc_text(INIT, AfpSecUtilInit)
  39. #pragma alloc_text(PAGE, AfpSecUtilDeInit)
  40. #pragma alloc_text(PAGE, afpDeInitializeSecurityUtility)
  41. #pragma alloc_text(PAGE, AfpInitSidOffsets)
  42. #pragma alloc_text(PAGE, AfpNameToSid)
  43. #pragma alloc_text(PAGE, afpCompleteNameToSid)
  44. #pragma alloc_text(PAGE, AfpSidToName)
  45. #pragma alloc_text(PAGE, afpCompleteSidToName)
  46. #pragma alloc_text(PAGE, AfpSidToMacId)
  47. #pragma alloc_text(PAGE, AfpMacIdToSid)
  48. #pragma alloc_text(PAGE, AfpChangePassword)
  49. #pragma alloc_text(PAGE, afpCompleteChangePassword)
  50. #pragma alloc_text(PAGE, afpLookupSid)
  51. #pragma alloc_text(PAGE, afpUpdateNameSidCache)
  52. #pragma alloc_text(PAGE, afpHashSid)
  53. #pragma alloc_text(PAGE, AfpLogEvent)
  54. #pragma alloc_text(PAGE, afpCompleteLogEvent)
  55. #pragma alloc_text(PAGE, afpQueueSecWorkItem)
  56. #pragma alloc_text(PAGE, afpAgeSidNameCache)
  57. #endif
  58. /*** AfpSecUtilInit
  59. *
  60. * This routine will allocate intialize all the cache tables and
  61. * data structures used by this module. afpDeInitializeSecurityUtility
  62. * should be call to Deallocate this memory.
  63. */
  64. NTSTATUS
  65. AfpSecUtilInit(
  66. VOID
  67. )
  68. {
  69. ULONG Index;
  70. NTSTATUS Status = STATUS_SUCCESS;
  71. // Initialize
  72. do
  73. {
  74. INITIALIZE_SPIN_LOCK(&afpSecUtilLock);
  75. // Set to Signalled state initially since there is no work in progress
  76. KeInitializeEvent(&afpUtilWorkInProgressEvent, NotificationEvent, True);
  77. // Initialize Single Write Multi-reader access for the SID/NAME cache
  78. AfpSwmrInitSwmr(&afpSWMRForSidNameCache);
  79. InitializeListHead(&afpSecWorkItemQ);
  80. // Allocate space for the SID Lookup table
  81. afpSidLookupTable = (PAFP_SID_NAME*)ALLOC_ACCESS_MEM(sizeof(PAFP_SID_NAME) * SIZE_SID_LOOKUP_TABLE);
  82. if (afpSidLookupTable == NULL)
  83. {
  84. Status = STATUS_INSUFFICIENT_RESOURCES;
  85. break;
  86. }
  87. // Initialize Sid lookup table
  88. RtlZeroMemory(afpSidLookupTable,
  89. sizeof(PAFP_SID_NAME) * SIZE_SID_LOOKUP_TABLE);
  90. afpSidToMacIdTable = (PAFP_SID_MACID *)
  91. ALLOC_ACCESS_MEM(sizeof(PAFP_SID_MACID) * SIZE_SID_LOOKUP_TABLE);
  92. if (afpSidToMacIdTable == NULL)
  93. {
  94. AfpFreeMemory(afpSidLookupTable);
  95. Status = STATUS_INSUFFICIENT_RESOURCES;
  96. break;
  97. }
  98. RtlZeroMemory(afpSidToMacIdTable, sizeof(PAFP_SID_NAME) * SIZE_SID_LOOKUP_TABLE);
  99. // Initialize array of thread structures.
  100. for (Index = 0; Index < NUM_SECURITY_UTILITY_THREADS; Index++)
  101. {
  102. afpSecurityThread[Index].State = NOT_AVAILABLE;
  103. afpSecurityThread[Index].pSecWorkItem = (PSEC_WORK_ITEM)NULL;
  104. afpSecurityThread[Index].pIrp = (PIRP)NULL;
  105. }
  106. // Start the aging process
  107. AfpScavengerScheduleEvent(afpAgeSidNameCache,
  108. NULL,
  109. SID_NAME_AGE,
  110. True);
  111. } while(False);
  112. return Status;
  113. }
  114. /*** AfpSecUtilDeInit
  115. *
  116. * This routine will free the allocated resources from this module.
  117. * This is called during server unload.
  118. */
  119. VOID
  120. AfpSecUtilDeInit(
  121. VOID
  122. )
  123. {
  124. PAFP_SID_NAME pSidName, pFree;
  125. PAFP_SID_MACID pSidMacId, pFreeM;
  126. DWORD Count;
  127. PAGED_CODE();
  128. // De-Allocate space for the Sid Lookup table
  129. for(Count = 0; Count < SIZE_SID_LOOKUP_TABLE; Count++)
  130. {
  131. for (pSidName = afpSidLookupTable[Count]; pSidName != NULL; NOTHING)
  132. {
  133. pFree = pSidName;
  134. pSidName = pSidName->SidLink;
  135. AfpFreeMemory(pFree);
  136. }
  137. }
  138. AfpFreeMemory(afpSidLookupTable);
  139. afpLastCachedSid = NULL;
  140. // De-Allocate space for the Sid-to-MacId Lookup table
  141. for(Count = 0; Count < SIZE_SID_LOOKUP_TABLE; Count++)
  142. {
  143. for (pSidMacId = afpSidToMacIdTable[Count]; pSidMacId != NULL; NOTHING)
  144. {
  145. pFreeM = pSidMacId;
  146. pSidMacId = pSidMacId->Next;
  147. AfpFreeMemory(pFreeM);
  148. }
  149. }
  150. AfpFreeMemory(afpSidToMacIdTable);
  151. ASSERT(IsListEmpty(&afpSecWorkItemQ));
  152. }
  153. /*** AfpTerminateSecurityUtility
  154. *
  155. * This is called during server stop. All the service threads are told
  156. * to terminate.
  157. */
  158. VOID
  159. AfpTerminateSecurityUtility(
  160. VOID
  161. )
  162. {
  163. KIRQL OldIrql;
  164. ULONG Index;
  165. PAFP_SECURITY_THREAD pSecThrd;
  166. PVOID pBufOut;
  167. PIO_STACK_LOCATION pIrpSp;
  168. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  169. ("AfpTerminateSecurityUtility: waiting for workers to finish work..."));
  170. // Allow any remaining event logs to be processed
  171. AfpIoWait(&afpUtilWorkInProgressEvent, NULL);
  172. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  173. ("AfpTerminateSecurityUtility: done waiting."));
  174. do {
  175. ACQUIRE_SPIN_LOCK(&afpSecUtilLock, &OldIrql);
  176. for (pSecThrd = afpSecurityThread,Index = 0;
  177. Index < NUM_SECURITY_UTILITY_THREADS;
  178. Index++, pSecThrd++)
  179. {
  180. if (pSecThrd->State != NOT_AVAILABLE)
  181. {
  182. ASSERT(pSecThrd->State != BUSY);
  183. pSecThrd->State = NOT_AVAILABLE ;
  184. break;
  185. }
  186. }
  187. RELEASE_SPIN_LOCK(&afpSecUtilLock, OldIrql);
  188. // We are done, all threads are terminated
  189. if (Index == NUM_SECURITY_UTILITY_THREADS)
  190. return;
  191. DBGPRINT(DBG_COMP_INIT, DBG_LEVEL_INFO,
  192. ("AfpTerminateSecurityUtility: Terminating thread %ld\n", Index));
  193. pIrpSp = IoGetCurrentIrpStackLocation(pSecThrd->pIrp);
  194. pBufOut = pSecThrd->pIrp->AssociatedIrp.SystemBuffer;
  195. ASSERT(pIrpSp->Parameters.FileSystemControl.OutputBufferLength >= sizeof(AFP_FSD_CMD_HEADER));
  196. ((PAFP_FSD_CMD_HEADER)pBufOut)->dwId = Index;
  197. ((PAFP_FSD_CMD_HEADER)pBufOut)->FsdCommand = AFP_FSD_CMD_TERMINATE_THREAD;
  198. pSecThrd->pIrp->IoStatus.Information = sizeof(AFP_FSD_CMD_HEADER);
  199. pSecThrd->pIrp->IoStatus.Status = STATUS_SUCCESS;
  200. IoCompleteRequest(pSecThrd->pIrp, IO_NETWORK_INCREMENT);
  201. pSecThrd->pIrp = NULL;
  202. } while (True);
  203. }
  204. /*** AfpInitSidOffsets
  205. *
  206. * This routine will be called by AfpAdmServerSetParms to initialize the
  207. * the array of Sid-Offset pairs.
  208. */
  209. AFPSTATUS FASTCALL
  210. AfpInitSidOffsets(
  211. IN ULONG SidOffstPairs,
  212. IN PAFP_SID_OFFSET pSidOff
  213. )
  214. {
  215. ULONG SizeOfBufReqd = 0, SizeAdminSid = 0, SizeNoneSid = 0, SubAuthCount;
  216. LONG i;
  217. BOOLEAN IsDC = True; // Assume Domain Controller
  218. PAGED_CODE();
  219. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  220. ("AfpInitSidOffsets: Entered, Count = %ld\n", SidOffstPairs));
  221. //
  222. // Determine if this is a Domain Controller or not by looking for
  223. // the 'account' domain. If the machine is a PDC/BDC, the service will
  224. // NOT send down the Account domain offset.
  225. //
  226. for (i = 0; i < (LONG)SidOffstPairs; i++)
  227. {
  228. if ((pSidOff[i].SidType == AFP_SID_TYPE_DOMAIN) &&
  229. (pSidOff[i].Offset == SE_ACCOUNT_DOMAIN_POSIX_OFFSET))
  230. {
  231. // We are either a server or a workstation (i.e. NtProductServer
  232. // or NtProductWinNt)
  233. IsDC = False;
  234. }
  235. }
  236. //
  237. // Determine the amount of memory needed
  238. //
  239. for (i = 0; i < (LONG)SidOffstPairs; i++)
  240. {
  241. SizeOfBufReqd += sizeof(AFP_SID_OFFSET) + RtlLengthSid(pSidOff[i].pSid);
  242. // Initialize DomainAdmins sid and size if this is a domain controller
  243. // AND this is the primary domain offset
  244. if (IsDC && (pSidOff[i].SidType == AFP_SID_TYPE_PRIMARY_DOMAIN))
  245. {
  246. ASSERT (SizeAdminSid == 0);
  247. ASSERT (AfpSidAdmins == NULL);
  248. SubAuthCount = *RtlSubAuthorityCountSid(pSidOff[i].pSid);
  249. SizeAdminSid = RtlLengthRequiredSid(SubAuthCount + 1);
  250. if ((AfpSidAdmins = (PSID)ALLOC_ACCESS_MEM(SizeAdminSid)) == NULL)
  251. {
  252. return STATUS_INSUFFICIENT_RESOURCES;
  253. }
  254. RtlCopySid(SizeAdminSid, AfpSidAdmins, pSidOff[i].pSid);
  255. // Add the relative ID
  256. *RtlSubAuthorityCountSid(AfpSidAdmins) = (UCHAR)(SubAuthCount+1);
  257. *RtlSubAuthoritySid(AfpSidAdmins, SubAuthCount) = DOMAIN_GROUP_RID_ADMINS;
  258. AfpSizeSidAdmins = RtlLengthSid(AfpSidAdmins);
  259. }
  260. }
  261. ASSERT (SizeOfBufReqd != 0);
  262. // HACK: To fake out the loop below we set SizeNoneSid to nonzero
  263. // on PDC/BDC. Since the AfpServerIsStandalone variable will not
  264. // get set until service calls AfpAdmWServerSetInfo we can
  265. // infer it here since we don't want to try to manufacture the None
  266. // sid on a PDC/BDC.
  267. if (IsDC)
  268. SizeNoneSid = 1;
  269. // If we did not get the Domain admins sid, we must be running on a
  270. // stand-alone machine. So manufacture MACHINE\Administrators
  271. // SID instead. Also manufacture MACHINE\None if this is not a DC.
  272. for (i = SidOffstPairs - 1;
  273. ((SizeAdminSid == 0) || (SizeNoneSid == 0)) && (i >= 0);
  274. i--)
  275. {
  276. // Initialize "Administrators" sid and size
  277. if (pSidOff[i].SidType == AFP_SID_TYPE_DOMAIN)
  278. {
  279. if (RtlEqualSid(&AfpSidBuiltIn, pSidOff[i].pSid))
  280. {
  281. ASSERT (SizeAdminSid == 0);
  282. ASSERT (AfpSidAdmins == NULL);
  283. SubAuthCount = *RtlSubAuthorityCountSid(pSidOff[i].pSid);
  284. SizeAdminSid = RtlLengthRequiredSid(SubAuthCount + 1);
  285. if ((AfpSidAdmins = (PSID)ALLOC_ACCESS_MEM(SizeAdminSid)) == NULL)
  286. {
  287. return STATUS_INSUFFICIENT_RESOURCES;
  288. }
  289. RtlCopySid(SizeAdminSid, AfpSidAdmins, pSidOff[i].pSid);
  290. // Add the relative ID
  291. *RtlSubAuthorityCountSid(AfpSidAdmins) = (UCHAR)(SubAuthCount+1);
  292. *RtlSubAuthoritySid(AfpSidAdmins, SubAuthCount) = DOMAIN_ALIAS_RID_ADMINS;
  293. AfpSizeSidAdmins = RtlLengthSid(AfpSidAdmins);
  294. }
  295. else if (pSidOff[i].Offset == SE_ACCOUNT_DOMAIN_POSIX_OFFSET)
  296. {
  297. ASSERT (SizeNoneSid == 0);
  298. ASSERT (AfpSidNone == NULL);
  299. SubAuthCount = *RtlSubAuthorityCountSid(pSidOff[i].pSid);
  300. SizeNoneSid = RtlLengthRequiredSid(SubAuthCount + 1);
  301. if ((AfpSidNone = (PSID)ALLOC_ACCESS_MEM(SizeNoneSid)) == NULL)
  302. {
  303. return STATUS_INSUFFICIENT_RESOURCES;
  304. }
  305. RtlCopySid(SizeNoneSid, AfpSidNone, pSidOff[i].pSid);
  306. // Add the relative ID
  307. *RtlSubAuthorityCountSid(AfpSidNone) = (UCHAR)(SubAuthCount+1);
  308. // Note that the "None" sid on standalone is the same as the
  309. // "Domain Users" Sid on PDC/BDC. (On PDC/BDC the primary
  310. // domain is the same as the account domain).
  311. *RtlSubAuthoritySid(AfpSidNone, SubAuthCount) = DOMAIN_GROUP_RID_USERS;
  312. AfpSizeSidNone = RtlLengthSid(AfpSidNone);
  313. }
  314. }
  315. }
  316. ASSERT (SizeAdminSid != 0);
  317. ASSERT (AfpSidAdmins != NULL);
  318. #if DBG
  319. if (IsDC)
  320. {
  321. ASSERT(AfpSidNone == NULL);
  322. }
  323. else
  324. {
  325. ASSERT(AfpSidNone != NULL);
  326. }
  327. #endif
  328. return AFP_ERR_NONE;
  329. }
  330. /*** AfpSecurityUtilityWorker
  331. *
  332. * This is the main entry point for the security utility thread that
  333. * comes from the AFP server service. This is called if the FSD receives
  334. * a IRP_MJ_FILE_SYSTEM_CONTROL major function code.
  335. *
  336. * This routine will:
  337. * 1) Assign a thread structure if this is a newly created thread.
  338. * 2) Complete the previous work item if this is not a newly created
  339. * thread.
  340. * 3) Check to see if there are any work items to be processed from the
  341. * Security utility work item queue. If there is a work item, it will
  342. * de-queue the work item and complete the IRP. Otherwise it will
  343. * mark the IRP as pending and return STATUS_PENDING.
  344. *
  345. */
  346. NTSTATUS
  347. AfpSecurityUtilityWorker(
  348. IN PIRP pIrp,
  349. IN PIO_STACK_LOCATION pIrpSp // Pointer to the IRP stack location
  350. )
  351. {
  352. USHORT FuncCode;
  353. USHORT Method;
  354. KIRQL OldIrql;
  355. PVOID pBufIn;
  356. PVOID pBufOut;
  357. LONG iBufLen;
  358. ULONG Index;
  359. NTSTATUS Status;
  360. BOOLEAN FoundMoreWork = False;
  361. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  362. ("afpSecurityUtilityWorker: Entered \n"));
  363. FuncCode = (USHORT)
  364. AFP_CC_BASE(pIrpSp->Parameters.FileSystemControl.FsControlCode);
  365. Method = (USHORT)
  366. AFP_CC_METHOD(pIrpSp->Parameters.FileSystemControl.FsControlCode);
  367. if ((FuncCode != CC_BASE_GET_FSD_COMMAND) || (Method != METHOD_BUFFERED))
  368. return STATUS_INVALID_PARAMETER;
  369. // Get the output buffer and its length. Input and Output buffers are
  370. // both pointed to by the SystemBuffer
  371. iBufLen = pIrpSp->Parameters.FileSystemControl.InputBufferLength;
  372. pBufIn = pIrp->AssociatedIrp.SystemBuffer;
  373. if ((iBufLen != 0) && (iBufLen < sizeof(AFP_FSD_CMD_HEADER)))
  374. {
  375. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  376. ("afpSecurityUtilityWorker: iBufLen too small %d\n",iBufLen));
  377. ASSERT(0);
  378. return STATUS_INVALID_PARAMETER;
  379. }
  380. pBufOut = pBufIn;
  381. if (pBufOut == NULL)
  382. return STATUS_INVALID_PARAMETER;
  383. // If this is a newly created thread, we need to find a slot for it
  384. if (iBufLen == 0)
  385. {
  386. ACQUIRE_SPIN_LOCK(&afpSecUtilLock,&OldIrql);
  387. for (Index = 0; Index < NUM_SECURITY_UTILITY_THREADS; Index++)
  388. {
  389. if (afpSecurityThread[Index].State == NOT_AVAILABLE)
  390. {
  391. afpSecurityThread[Index].State = BUSY;
  392. break;
  393. }
  394. }
  395. RELEASE_SPIN_LOCK(&afpSecUtilLock,OldIrql);
  396. // no more threads? fail the request
  397. if (Index == NUM_SECURITY_UTILITY_THREADS)
  398. {
  399. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  400. ("afpSecurityUtilityWorker: no thread available, failing request\n"));
  401. ASSERT(0);
  402. return STATUS_INSUFFICIENT_RESOURCES;
  403. }
  404. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  405. ("afpSecurityUtilityWorker: New Thread given slot=%d\n",Index));
  406. }
  407. else
  408. {
  409. PAFP_SECURITY_THREAD pSecThrd;
  410. // The id is actually the slot index into the array of security threads
  411. Index = ((PAFP_FSD_CMD_HEADER)pBufIn)->dwId;
  412. if (Index >= NUM_SECURITY_UTILITY_THREADS)
  413. return STATUS_INVALID_PARAMETER;
  414. pSecThrd = &afpSecurityThread[Index];
  415. if (pSecThrd->State != BUSY)
  416. {
  417. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_ERR,
  418. ("afpSecurityUtilityWorker: thread is not busy!\n"));
  419. ASSERT(0);
  420. return STATUS_INVALID_PARAMETER;
  421. }
  422. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  423. ("afpSecurityUtilityThread: Thread slot=%d completed request\n",Index));
  424. // Complete the current job
  425. (*((pSecThrd->pSecWorkItem)->pCompletionRoutine))(Index, pBufIn);
  426. // The job is completed so set the work item pointer to NULL.
  427. pSecThrd->pSecWorkItem = (PSEC_WORK_ITEM)NULL;
  428. }
  429. // OK, we are done with the previous job. Now we check to see if there
  430. // are any jobs in the queue
  431. ACQUIRE_SPIN_LOCK(&afpSecUtilLock,&OldIrql);
  432. if (iBufLen != 0)
  433. {
  434. ASSERT(afpUtilWorkInProgress > 0);
  435. // This is not a newly created thread, so decrement the count of
  436. // work items in progress. If it goes to zero and the work queue
  437. // is empty, signal the event signifying there is no work in progress
  438. if ((--afpUtilWorkInProgress == 0) && IsListEmpty(&afpSecWorkItemQ))
  439. {
  440. KeSetEvent(&afpUtilWorkInProgressEvent, IO_NETWORK_INCREMENT, False);
  441. }
  442. }
  443. if (IsListEmpty(&afpSecWorkItemQ))
  444. {
  445. // There is no work to be done so mark this irp as pending and
  446. // wait for a job
  447. afpSecurityThread[Index].State = IDLE;
  448. IoMarkIrpPending(pIrp);
  449. afpSecurityThread[Index].pIrp = pIrp;
  450. Status = STATUS_PENDING;
  451. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  452. ("afpSecurityUtilityWorker: Thread slot=%d marked as IDLE\n",Index));
  453. }
  454. else
  455. {
  456. // Otherwise, there is a job to be processed, so take it off the queue.
  457. // Increment the count of work items in progress and set the event
  458. // to not signalled
  459. afpUtilWorkInProgress ++;
  460. KeClearEvent(&afpUtilWorkInProgressEvent);
  461. FoundMoreWork = True;
  462. afpSecurityThread[Index].State = BUSY;
  463. afpSecurityThread[Index].pSecWorkItem =
  464. (PSEC_WORK_ITEM)RemoveHeadList(&afpSecWorkItemQ);
  465. ASSERT(afpSecWorkItemQLength > 0);
  466. afpSecWorkItemQLength--;
  467. ASSERT((LONG)(pIrpSp->Parameters.FileSystemControl.OutputBufferLength) >=
  468. (afpSecurityThread[Index].pSecWorkItem)->OutputBufSize);
  469. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  470. ("afpSecurityUtilityWorker: Thread slot=%d marked as BUSY\n",Index));
  471. }
  472. RELEASE_SPIN_LOCK(&afpSecUtilLock,OldIrql);
  473. // If there is a work item to process
  474. if (FoundMoreWork)
  475. {
  476. Status = STATUS_SUCCESS;
  477. // Simply copy the command packet into the IRP and return.
  478. RtlCopyMemory(pBufOut,
  479. (afpSecurityThread[Index].pSecWorkItem)->pOutput,
  480. (afpSecurityThread[Index].pSecWorkItem)->OutputBufSize);
  481. ((PAFP_FSD_CMD_HEADER)pBufOut)->dwId = Index;
  482. pIrp->IoStatus.Information =
  483. (afpSecurityThread[Index].pSecWorkItem)->OutputBufSize;
  484. }
  485. return Status;
  486. }
  487. /*** afpGetIndexOfIdle
  488. *
  489. * This routine will first check to see if there are any threads that
  490. * are idle and are waiting for work to do. If there are, then it will
  491. * mark it as busy and up the count of in progress items and release the
  492. * InProgress event. Else it will queue up the work-item.
  493. */
  494. LONG FASTCALL
  495. afpGetIndexOfIdle(
  496. IN PSEC_WORK_ITEM pSecWorkItem
  497. )
  498. {
  499. KIRQL OldIrql;
  500. LONG Index;
  501. ACQUIRE_SPIN_LOCK(&afpSecUtilLock, &OldIrql);
  502. // See if there are any threads that are ready to process this request
  503. for (Index = 0; Index < NUM_SECURITY_UTILITY_THREADS; Index++)
  504. {
  505. if (afpSecurityThread[Index].State == IDLE)
  506. {
  507. // If we found a thread that is ready, mark it as busy
  508. // Increment the count of work items in progress and set the event
  509. // to not signalled
  510. afpUtilWorkInProgress ++;
  511. KeClearEvent(&afpUtilWorkInProgressEvent);
  512. afpSecurityThread[Index].State = BUSY;
  513. break;
  514. }
  515. }
  516. if (Index == NUM_SECURITY_UTILITY_THREADS)
  517. {
  518. // All threads are busy so queue up this request.
  519. // Alternatively, it could be the case that someone has tried
  520. // to log an event before the usermode utility thread(s) have
  521. // started, in which case we should just queue up the item.
  522. InsertTailList(&afpSecWorkItemQ, &pSecWorkItem->Links);
  523. afpSecWorkItemQLength++;
  524. }
  525. RELEASE_SPIN_LOCK(&afpSecUtilLock, OldIrql);
  526. return Index;
  527. }
  528. /*** afpQueueSecWorkItem
  529. *
  530. * This routine will first check to see if there are any threads that
  531. * are idle and are waiting for work to do. If there are, then it will
  532. * copy the command packet into the IRP's output buffer and mark that
  533. * IRP as complete. Otherwise, it will insert this work item at the
  534. * tail of the work item queue.
  535. */
  536. LOCAL NTSTATUS
  537. afpQueueSecWorkItem(
  538. IN AFP_FSD_CMD_ID FsdCommand,
  539. IN PSDA pSda,
  540. IN PKEVENT pEvent,
  541. IN PAFP_FSD_CMD_PKT pAfpFsdCmdPkt,
  542. IN LONG BufSize,
  543. IN SEC_COMPLETION_ROUTINE pCompletionRoutine
  544. )
  545. {
  546. LONG Index;
  547. PSEC_WORK_ITEM pSecWorkItem;
  548. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  549. ("afpQueueSecWorkItem: Entered \n"));
  550. if ((pSecWorkItem = ALLOC_SWI()) == NULL)
  551. return STATUS_NO_MEMORY;
  552. pSecWorkItem->pSda = pSda;
  553. pSecWorkItem->pCompletionEvent = pEvent;
  554. pSecWorkItem->pCompletionRoutine = pCompletionRoutine;
  555. pSecWorkItem->OutputBufSize = BufSize;
  556. pSecWorkItem->pOutput = pAfpFsdCmdPkt;
  557. pAfpFsdCmdPkt->Header.FsdCommand = FsdCommand;
  558. Index = afpGetIndexOfIdle(pSecWorkItem);
  559. if (Index < NUM_SECURITY_UTILITY_THREADS)
  560. {
  561. PAFP_SECURITY_THREAD pSecThrd;
  562. PIO_STACK_LOCATION pIrpSp;
  563. // Wake this thread up by marking this IRP as complete
  564. pSecThrd = &afpSecurityThread[Index];
  565. pIrpSp = IoGetCurrentIrpStackLocation(pSecThrd->pIrp);
  566. ASSERT((LONG)(pIrpSp->Parameters.FileSystemControl.OutputBufferLength) >=
  567. pSecWorkItem->OutputBufSize);
  568. pAfpFsdCmdPkt->Header.dwId = Index;
  569. RtlCopyMemory(pSecThrd->pIrp->AssociatedIrp.SystemBuffer,
  570. pAfpFsdCmdPkt,
  571. BufSize);
  572. pSecThrd->pSecWorkItem = pSecWorkItem;
  573. pSecThrd->pIrp->IoStatus.Information = (ULONG)(pSecWorkItem->OutputBufSize);
  574. pSecThrd->pIrp->IoStatus.Status = STATUS_SUCCESS;
  575. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  576. ("afpQueueSecWorkItem: Abount to release IRP\n"));
  577. IoCompleteRequest(afpSecurityThread[Index].pIrp, IO_NETWORK_INCREMENT);
  578. }
  579. return AFP_ERR_EXTENDED;
  580. }
  581. /*** AfpNameToSid
  582. *
  583. * The FSD will call this routine to do a Name to SID translation.
  584. * This routine will simply create a work item to do the translation.
  585. * This work item will eventually be executed by the user-mode service.
  586. * When the work item is completed, afpCompleteNameToSid will be called
  587. * which will put the result in the SDA.
  588. *
  589. * Returns: STATUS_SUCCESS
  590. * STATUS_NO_MEMORY
  591. *
  592. * MODE: Non-blocking
  593. */
  594. NTSTATUS FASTCALL
  595. AfpNameToSid(
  596. IN PSDA pSda,
  597. IN PUNICODE_STRING Name
  598. )
  599. {
  600. PAFP_FSD_CMD_PKT pAfpFsdCmdPkt;
  601. LONG BufSize;
  602. PAGED_CODE();
  603. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  604. ("AfpNameToSid: mapping %ws\n", Name->Buffer));
  605. // Set up the work item that will translate the name to the SID
  606. BufSize = sizeof(AFP_FSD_CMD_PKT) + Name->Length + sizeof(WCHAR);
  607. if ((pAfpFsdCmdPkt = (PAFP_FSD_CMD_PKT)AfpAllocPagedMemory(BufSize)) == NULL)
  608. {
  609. return STATUS_NO_MEMORY;
  610. }
  611. RtlCopyMemory(pAfpFsdCmdPkt->Data.Name,
  612. Name->Buffer,
  613. Name->Length);
  614. *(PWCHAR)(&pAfpFsdCmdPkt->Data.Name[Name->Length]) = UNICODE_NULL;
  615. return afpQueueSecWorkItem(AFP_FSD_CMD_NAME_TO_SID,
  616. pSda,
  617. NULL,
  618. pAfpFsdCmdPkt,
  619. BufSize,
  620. afpCompleteNameToSid);
  621. }
  622. /*** afpCompleteNameToSid
  623. *
  624. * This routine will be called by AfpSecurityUtilityWorker when the
  625. * thread that processed the work item queued up by afpNameToSid returns.
  626. * This routine will free memory allocated by the afpNameToSid routine.
  627. * It will insert the result in the SDA, and then queue up the worker
  628. * routine that originally requested the lookup.
  629. */
  630. LOCAL VOID
  631. afpCompleteNameToSid(
  632. IN ULONG Index,
  633. IN PVOID pInBuf
  634. )
  635. {
  636. PAFP_FSD_CMD_PKT pAfpFsdCmdPkt;
  637. PSDA pSda;
  638. PSID pSid;
  639. PAGED_CODE();
  640. pSda = (afpSecurityThread[Index].pSecWorkItem)->pSda;
  641. pAfpFsdCmdPkt = (PAFP_FSD_CMD_PKT)
  642. (afpSecurityThread[Index].pSecWorkItem)->pOutput;
  643. // If there was no error then set the result in the SDA
  644. if (NT_SUCCESS(((PAFP_FSD_CMD_PKT)pInBuf)->Header.ntStatus))
  645. {
  646. pSid = (PSID)(((PAFP_FSD_CMD_PKT)pInBuf)->Data.Sid);
  647. afpUpdateNameSidCache((PWCHAR)pAfpFsdCmdPkt->Data.Name, pSid);
  648. pSda->sda_SecUtilSid = (PSID)AfpAllocPagedMemory(RtlLengthSid(pSid));
  649. if (pSda->sda_SecUtilSid == (PSID)NULL)
  650. pSda->sda_SecUtilResult = STATUS_NO_MEMORY;
  651. else RtlCopySid(RtlLengthSid(pSid), pSda->sda_SecUtilSid, pSid);
  652. }
  653. else pSda->sda_SecUtilSid = (PSID)NULL;
  654. pSda->sda_SecUtilResult = ((PAFP_FSD_CMD_PKT)pInBuf)->Header.ntStatus;
  655. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem->pOutput);
  656. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem);
  657. AfpQueueWorkItem(&(pSda->sda_WorkItem));
  658. }
  659. /*** AfpSidToName
  660. *
  661. * The FSD will call this routine to do a SID to Name translation. It
  662. * will first check to see if the SID is in the cache. If it is, it
  663. * will return a pointer to the AFP_SID_NAME structure from which the
  664. * translated Name value may be extracted and it will return
  665. * STATUS_SUCCESS.
  666. * Otherwise, it will queue up a SID to Name lookup request to the
  667. * AFP server service and return AFP_ERR_EXTENDED.
  668. *
  669. * MODE: Non-blocking
  670. */
  671. NTSTATUS
  672. AfpSidToName(
  673. IN PSDA pSda,
  674. IN PSID Sid,
  675. OUT PAFP_SID_NAME *ppTranslatedSid
  676. )
  677. {
  678. PAFP_FSD_CMD_PKT pAfpFsdCmdPkt;
  679. LONG BufSize;
  680. PAGED_CODE();
  681. // First, check to see if the SID is cached
  682. AfpDumpSid("AfpSidToName: mapping Sid", Sid);
  683. if ((*ppTranslatedSid = afpLookupSid(Sid)) != NULL)
  684. {
  685. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  686. ("AfpSidToName: mapped to %ws\n", (*ppTranslatedSid)->Name.Buffer));
  687. return STATUS_SUCCESS;
  688. }
  689. // Not cached so we need to call the user-mode service to do this
  690. // translation
  691. BufSize = sizeof(AFP_FSD_CMD_PKT) + RtlLengthSid(Sid);
  692. if ((pAfpFsdCmdPkt = (PAFP_FSD_CMD_PKT)AfpAllocPagedMemory(BufSize)) == NULL)
  693. {
  694. return STATUS_NO_MEMORY;
  695. }
  696. RtlCopyMemory(pAfpFsdCmdPkt->Data.Sid, Sid, BufSize - sizeof(AFP_FSD_CMD_PKT));
  697. return afpQueueSecWorkItem(AFP_FSD_CMD_SID_TO_NAME,
  698. pSda,
  699. NULL,
  700. pAfpFsdCmdPkt,
  701. BufSize,
  702. afpCompleteSidToName);
  703. }
  704. /*** afpCompleteSidToName
  705. *
  706. * This routine will be called by AfpSecurityUtilityWorker when the
  707. * thread that processed the work item queued up by AfpSidToName returns.
  708. * This routine will update the Name/SID cache, free memory allocated
  709. * by the AfpSidtoName routine, and then queue up the worker routine that
  710. * originally requested the lookup.
  711. */
  712. LOCAL VOID
  713. afpCompleteSidToName(
  714. IN ULONG Index,
  715. IN PVOID pInBuf
  716. )
  717. {
  718. PAFP_FSD_CMD_PKT pAfpFsdCmdPkt;
  719. PSDA pSda;
  720. PAGED_CODE();
  721. pAfpFsdCmdPkt = (PAFP_FSD_CMD_PKT)
  722. (afpSecurityThread[Index].pSecWorkItem)->pOutput;
  723. // If there was no error then update the cache
  724. if (NT_SUCCESS(((PAFP_FSD_CMD_PKT)pInBuf)->Header.ntStatus))
  725. afpUpdateNameSidCache((WCHAR*)(((PAFP_FSD_CMD_PKT)pInBuf)->Data.Name),
  726. (PSID)(pAfpFsdCmdPkt->Data.Sid));
  727. pSda = (afpSecurityThread[Index].pSecWorkItem)->pSda;
  728. pSda->sda_SecUtilResult = ((PAFP_FSD_CMD_PKT)pInBuf)->Header.ntStatus;
  729. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem->pOutput);
  730. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem);
  731. AfpQueueWorkItem(&(pSda->sda_WorkItem));
  732. }
  733. /*** AfpSidToMacId
  734. *
  735. * This routine is called by the FSD to map a SID to an AFP ID. This call
  736. * will first extract the domain SID from this SID. IT will then check
  737. * to see if this domain SID exists in the afpSidOffsetTable cache.
  738. * If it does not exist STATUS_NONE_MAPPED will be returned.
  739. *
  740. * MODE: Blocking
  741. */
  742. NTSTATUS FASTCALL
  743. AfpSidToMacId(
  744. IN PSID pSid,
  745. OUT PULONG pMacId
  746. )
  747. {
  748. PAFP_SID_MACID pSidMacId, pPrevSidMacId=NULL;
  749. USHORT SidLen;
  750. NTSTATUS Status;
  751. ULONG Location;
  752. PAGED_CODE();
  753. AfpDumpSid("AfpSidToMacId: Mapping Sid", pSid);
  754. if (RtlEqualSid(pSid, &AfpSidNull) ||
  755. (AfpServerIsStandalone && RtlEqualSid(pSid, AfpSidNone)))
  756. {
  757. *pMacId = 0;
  758. return STATUS_SUCCESS;
  759. }
  760. ASSERT(afpSWMRForSidNameCache.swmr_ExclusiveOwner != PsGetCurrentThread());
  761. AfpSwmrAcquireExclusive(&afpSWMRForSidNameCache);
  762. Location = afpHashSid(pSid);
  763. for (pSidMacId = afpSidToMacIdTable[Location];
  764. pSidMacId != NULL;
  765. pSidMacId = pSidMacId->Next)
  766. {
  767. // Found the MacId for this Sid? we already have it: return it
  768. if (RtlEqualSid(pSid, &(pSidMacId->Sid)))
  769. {
  770. *pMacId = pSidMacId->MacId;
  771. AfpSwmrRelease(&afpSWMRForSidNameCache);
  772. return STATUS_SUCCESS;
  773. }
  774. pPrevSidMacId = pSidMacId;
  775. }
  776. //
  777. // we don't have a MacId for this sid in our cache. Create a new one
  778. //
  779. SidLen = (USHORT)RtlLengthSid(pSid);
  780. pSidMacId = (PAFP_SID_MACID)ALLOC_ACCESS_MEM(sizeof(AFP_SID_MACID) + SidLen);
  781. if (pSidMacId == NULL)
  782. {
  783. AfpSwmrRelease(&afpSWMRForSidNameCache);
  784. return STATUS_NO_MEMORY;
  785. }
  786. RtlCopyMemory(pSidMacId->Sid, pSid, SidLen);
  787. pSidMacId->Next = NULL;
  788. // assign a MacId for this Sid
  789. pSidMacId->MacId = afpNextMacIdToUse++;
  790. // and insert this into the list
  791. if (pPrevSidMacId)
  792. {
  793. ASSERT(pPrevSidMacId->Next == NULL);
  794. pPrevSidMacId->Next = pSidMacId;
  795. }
  796. else
  797. {
  798. ASSERT(afpSidToMacIdTable[Location] == NULL);
  799. afpSidToMacIdTable[Location] = pSidMacId;
  800. }
  801. *pMacId = pSidMacId->MacId;
  802. afpLastCachedSid = pSidMacId;
  803. AfpSwmrRelease(&afpSWMRForSidNameCache);
  804. return STATUS_SUCCESS;
  805. }
  806. /*** AfpMacIdToSid
  807. *
  808. * This routine is called by the FSD to map a Afp Id to SID.
  809. * *ppSid should be freed the caller using AfpFreeMemory.
  810. *
  811. * MODE: Blocking
  812. */
  813. NTSTATUS FASTCALL
  814. AfpMacIdToSid(
  815. IN ULONG MacId,
  816. OUT PSID * ppSid
  817. )
  818. {
  819. PAFP_SID_MACID pSidMacId;
  820. ULONG Count;
  821. DWORD cbSid;
  822. DWORD SubAuthCount;
  823. DWORD GreatestOffset;
  824. NTSTATUS Status;
  825. PAGED_CODE();
  826. if (MacId == 0)
  827. {
  828. *ppSid = &AfpSidNull;
  829. return STATUS_SUCCESS;
  830. }
  831. AfpSwmrAcquireShared(&afpSWMRForSidNameCache);
  832. // see if we just cached this Sid (quite likely)
  833. if ((afpLastCachedSid != NULL) &&
  834. (afpLastCachedSid->MacId == MacId))
  835. {
  836. *ppSid = &(afpLastCachedSid->Sid);
  837. AfpSwmrRelease(&afpSWMRForSidNameCache);
  838. return STATUS_SUCCESS;
  839. }
  840. for (Count = 0; Count < SIZE_SID_LOOKUP_TABLE; Count++)
  841. {
  842. for (pSidMacId = afpSidToMacIdTable[Count];
  843. pSidMacId != NULL;
  844. pSidMacId = pSidMacId->Next )
  845. {
  846. if (pSidMacId->MacId == MacId)
  847. {
  848. *ppSid = &(pSidMacId->Sid);
  849. AfpSwmrRelease(&afpSWMRForSidNameCache);
  850. return STATUS_SUCCESS;
  851. }
  852. }
  853. }
  854. AfpSwmrRelease(&afpSWMRForSidNameCache);
  855. *ppSid = NULL;
  856. return STATUS_NONE_MAPPED;
  857. }
  858. /*** AfpChangePassword
  859. *
  860. * This routine is called by the FSD to change a password for a user.
  861. * Most of the work for this is done by the AFP service. The work item
  862. * is simply queued up. This routine waits for the completion and returns
  863. * with thre result of the call.
  864. *
  865. * MODE: Blocking
  866. */
  867. NTSTATUS FASTCALL
  868. AfpChangePassword(
  869. IN PSDA pSda,
  870. IN PAFP_PASSWORD_DESC pPassword
  871. )
  872. {
  873. KEVENT CompletionEvent;
  874. PAFP_FSD_CMD_PKT pAfpFsdCmdPkt = NULL;
  875. NTSTATUS Status;
  876. PAGED_CODE();
  877. do
  878. {
  879. // Initialize the event that we will wait for
  880. //
  881. KeInitializeEvent(&CompletionEvent, NotificationEvent, False);
  882. if ((pAfpFsdCmdPkt =
  883. (PAFP_FSD_CMD_PKT)AfpAllocPagedMemory(sizeof(AFP_FSD_CMD_PKT))) == NULL)
  884. {
  885. Status = STATUS_NO_MEMORY;
  886. break;
  887. }
  888. // Copy all the change password data
  889. RtlCopyMemory(&(pAfpFsdCmdPkt->Data.Password),
  890. pPassword,
  891. sizeof(AFP_PASSWORD_DESC));
  892. DBGPRINT(DBG_COMP_SECURITY, DBG_LEVEL_INFO,
  893. ("afpChangePassword: Queing work item\n"));
  894. // Block till request completes
  895. if ((Status = afpQueueSecWorkItem(AFP_FSD_CMD_CHANGE_PASSWORD,
  896. pSda,
  897. &CompletionEvent,
  898. pAfpFsdCmdPkt,
  899. sizeof(AFP_FSD_CMD_PKT),
  900. afpCompleteChangePassword)) == AFP_ERR_EXTENDED)
  901. {
  902. AfpIoWait(&CompletionEvent, NULL);
  903. // Request complete. Set return code.
  904. Status = pSda->sda_SecUtilResult;
  905. }
  906. else AfpFreeMemory(pAfpFsdCmdPkt);
  907. } while(False);
  908. return Status;
  909. }
  910. /*** afpCompleteChangePassword
  911. *
  912. * MODE: Blocking
  913. */
  914. LOCAL VOID
  915. afpCompleteChangePassword(
  916. IN ULONG Index,
  917. IN PVOID pInBuf
  918. )
  919. {
  920. PSEC_WORK_ITEM pSecWorkItem = afpSecurityThread[Index].pSecWorkItem;
  921. PAGED_CODE();
  922. // Set the completion result
  923. pSecWorkItem->pSda->sda_SecUtilResult =
  924. ((PAFP_FSD_CMD_PKT)pInBuf)->Header.ntStatus;
  925. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem->pOutput);
  926. // Signal that this call is completed
  927. KeSetEvent(pSecWorkItem->pCompletionEvent,
  928. IO_NETWORK_INCREMENT,
  929. False);
  930. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem);
  931. }
  932. /*** afpLookupSid
  933. *
  934. * Given a pointer to a SID value, this routine will search the cache
  935. * for it. If it is found it returns a pointer to the AFP_SID_NAME
  936. * structure so that the translated name may be extracted from it.
  937. */
  938. LOCAL PAFP_SID_NAME FASTCALL
  939. afpLookupSid(
  940. IN PSID Sid
  941. )
  942. {
  943. PAFP_SID_NAME pAfpSidName;
  944. PAGED_CODE();
  945. AfpSwmrAcquireShared(&afpSWMRForSidNameCache);
  946. for (pAfpSidName = afpSidLookupTable[afpHashSid(Sid)];
  947. pAfpSidName != NULL;
  948. pAfpSidName = pAfpSidName->SidLink)
  949. {
  950. if (RtlEqualSid(Sid, &(pAfpSidName->Sid)))
  951. {
  952. break;
  953. }
  954. }
  955. AfpSwmrRelease(&afpSWMRForSidNameCache);
  956. return pAfpSidName;
  957. }
  958. /*** afpUpdateNameSidCache
  959. *
  960. * This routine will update the SID/Name cache given a SID/translated
  961. * name pair.
  962. */
  963. LOCAL NTSTATUS FASTCALL
  964. afpUpdateNameSidCache(
  965. IN WCHAR * Name,
  966. IN PSID Sid
  967. )
  968. {
  969. PAFP_SID_NAME pAfpSidName;
  970. ULONG Location;
  971. USHORT NameLen, SidLen;
  972. PAGED_CODE();
  973. NameLen = wcslen(Name) * sizeof(WCHAR);
  974. SidLen = (USHORT)RtlLengthSid(Sid);
  975. pAfpSidName = (PAFP_SID_NAME)ALLOC_ACCESS_MEM(sizeof(AFP_SID_NAME) +
  976. NameLen + SidLen + sizeof(WCHAR));
  977. if (pAfpSidName == NULL)
  978. return STATUS_NO_MEMORY;
  979. // Copy the data into the cache node
  980. RtlCopyMemory(pAfpSidName->Sid, Sid, SidLen);
  981. pAfpSidName->Name.Length = NameLen;
  982. pAfpSidName->Name.MaximumLength = NameLen + sizeof(WCHAR);
  983. pAfpSidName->Name.Buffer = (LPWSTR)((PBYTE)pAfpSidName +
  984. sizeof(AFP_SID_NAME) + SidLen);
  985. RtlCopyMemory(pAfpSidName->Name.Buffer, Name, NameLen);
  986. AfpGetCurrentTimeInMacFormat(&pAfpSidName->LastAccessedTime);
  987. // Insert into Sid lookup table
  988. AfpSwmrAcquireExclusive(&afpSWMRForSidNameCache);
  989. Location = afpHashSid(Sid);
  990. pAfpSidName->SidLink = afpSidLookupTable[Location];
  991. afpSidLookupTable[Location] = pAfpSidName;
  992. AfpSwmrRelease(&afpSWMRForSidNameCache);
  993. return STATUS_SUCCESS;
  994. }
  995. /*** afpHashSid
  996. *
  997. * Given a SID value, this routine will return the bucket index of
  998. * where this value is or should be stored.
  999. */
  1000. LOCAL ULONG FASTCALL
  1001. afpHashSid(
  1002. IN PSID Sid
  1003. )
  1004. {
  1005. ULONG Count;
  1006. ULONG Index;
  1007. ULONG Location;
  1008. PBYTE pByte;
  1009. PAGED_CODE();
  1010. for(Count = RtlLengthSid(Sid),
  1011. pByte = (PBYTE)Sid,
  1012. Index = 0,
  1013. Location = 0;
  1014. Index < Count;
  1015. Index++,
  1016. pByte++)
  1017. Location = (Location * SID_HASH_RADIX) + *pByte;
  1018. return (Location % SIZE_SID_LOOKUP_TABLE);
  1019. }
  1020. /*** afpAgeSidNameCache
  1021. *
  1022. * This is called by the scavenger periodically to age out the cache. The
  1023. * entries that are aged are the ones not accessed for atleast SID_NAME_AGE
  1024. * seconds.
  1025. */
  1026. AFPSTATUS FASTCALL
  1027. afpAgeSidNameCache(
  1028. IN PVOID pContext
  1029. )
  1030. {
  1031. PAFP_SID_NAME pSidName, *ppSidName;
  1032. AFPTIME Now;
  1033. int i;
  1034. PAGED_CODE();
  1035. AfpGetCurrentTimeInMacFormat(&Now);
  1036. AfpSwmrAcquireExclusive(&afpSWMRForSidNameCache);
  1037. for (i = 0; i < SIZE_SID_LOOKUP_TABLE; i++)
  1038. {
  1039. for (ppSidName = &afpSidLookupTable[i];
  1040. (pSidName = *ppSidName) != NULL;)
  1041. {
  1042. if ((Now - pSidName->LastAccessedTime) > SID_NAME_AGE)
  1043. {
  1044. *ppSidName = pSidName->SidLink;
  1045. AfpFreeMemory(pSidName);
  1046. }
  1047. else ppSidName = &pSidName->SidLink;
  1048. }
  1049. }
  1050. AfpSwmrRelease(&afpSWMRForSidNameCache);
  1051. // Requeue ourselves
  1052. return AFP_ERR_REQUEUE;
  1053. }
  1054. /*** AfpLogEvent
  1055. *
  1056. * Create a work item containing the event information for the user-mode
  1057. * service to write to the event log on behalf of the server. When the
  1058. * work item is completed, afpCompleteLogEvent will be called to cleanup
  1059. * the work item buffers. This routine is called to log both errors and
  1060. * events. If FileHandle is specified, the name of the file/dir associated
  1061. * with the handle will be queried, and that will be used as the *first*
  1062. * insertion string. Only one insertion string is allowed.
  1063. * Errorlog data will always be preceded by the file+line number from which
  1064. * the error was logged, and the NTSTATUS code.
  1065. */
  1066. VOID
  1067. AfpLogEvent(
  1068. IN USHORT EventType, // Error, Information etc.
  1069. IN ULONG MsgId,
  1070. IN DWORD File_Line OPTIONAL,// For errorlog only
  1071. IN NTSTATUS Status OPTIONAL,// For errorlog only
  1072. IN PBYTE RawDataBuf OPTIONAL,
  1073. IN LONG RawDataLen,
  1074. IN HANDLE FileHandle OPTIONAL,// For fileio errorlogs only
  1075. IN LONG String1Len,
  1076. IN PWSTR String1 OPTIONAL
  1077. )
  1078. {
  1079. PAFP_FSD_CMD_PKT pAfpFsdCmdPkt;
  1080. LONG outbuflen, extradatalen = 0;
  1081. UNICODE_STRING path;
  1082. PBYTE tmpptr = NULL;
  1083. PWSTR UNALIGNED * ppstr = NULL;
  1084. int stringcount = 0;
  1085. PAGED_CODE();
  1086. ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
  1087. #ifdef STOP_ON_ERRORS
  1088. DBGBRK(DBG_LEVEL_ERR);
  1089. #endif
  1090. AfpSetEmptyUnicodeString(&path, 0, NULL);
  1091. //
  1092. // if due to some weird condition, we have too many items pending on the queue, don't
  1093. // accept this (note that we aren't taking a spinlock here: it's ok to be off by 1!)
  1094. //
  1095. if (afpSecWorkItemQLength > MAX_SECWORKITEM_QLEN)
  1096. {
  1097. ASSERT(0);
  1098. return;
  1099. }
  1100. outbuflen = sizeof(AFP_FSD_CMD_HEADER) + sizeof(AFP_EVENTLOG_DESC) +
  1101. RawDataLen + String1Len + sizeof(WCHAR) +
  1102. sizeof(DWORD); // extra space for aligning string ptrs if needed
  1103. if (ARGUMENT_PRESENT(String1))
  1104. {
  1105. outbuflen += sizeof(PWSTR);
  1106. stringcount ++;
  1107. }
  1108. if (EventType == EVENTLOG_ERROR_TYPE)
  1109. {
  1110. extradatalen = sizeof(File_Line) + sizeof(Status);
  1111. outbuflen += extradatalen;
  1112. // Update error statistics count
  1113. INTERLOCKED_INCREMENT_LONG(&AfpServerStatistics.stat_Errors);
  1114. }
  1115. if (ARGUMENT_PRESENT(FileHandle))
  1116. {
  1117. outbuflen += sizeof(PWSTR);
  1118. stringcount ++;
  1119. // Figure out the filename associated with the handle
  1120. if (!NT_SUCCESS(AfpQueryPath(FileHandle, &path,
  1121. MAX_FSD_CMD_SIZE - outbuflen - sizeof(WCHAR))))
  1122. {
  1123. return;
  1124. }
  1125. outbuflen += path.Length + sizeof(WCHAR);
  1126. }
  1127. ASSERT(outbuflen <= MAX_FSD_CMD_SIZE);
  1128. pAfpFsdCmdPkt = (PAFP_FSD_CMD_PKT)AfpAllocZeroedNonPagedMemory(outbuflen);
  1129. if (pAfpFsdCmdPkt == NULL)
  1130. {
  1131. if (path.Buffer != NULL)
  1132. {
  1133. AfpFreeMemory(path.Buffer);
  1134. }
  1135. return;
  1136. }
  1137. // Fill in the command data
  1138. pAfpFsdCmdPkt->Data.Eventlog.MsgID = MsgId;
  1139. pAfpFsdCmdPkt->Data.Eventlog.EventType = EventType;
  1140. pAfpFsdCmdPkt->Data.Eventlog.StringCount = (USHORT)stringcount;
  1141. pAfpFsdCmdPkt->Data.Eventlog.DumpDataLen = RawDataLen + extradatalen;
  1142. // Fill in the offset to the dump data
  1143. pAfpFsdCmdPkt->Data.Eventlog.pDumpData = tmpptr = (PBYTE)0 +
  1144. sizeof(AFP_FSD_CMD_HEADER) +
  1145. sizeof(AFP_EVENTLOG_DESC);
  1146. OFFSET_TO_POINTER(tmpptr, pAfpFsdCmdPkt);
  1147. if (tmpptr == NULL)
  1148. {
  1149. if (path.Buffer != NULL)
  1150. {
  1151. AfpFreeMemory(path.Buffer);
  1152. path.Buffer = NULL;
  1153. }
  1154. if (pAfpFsdCmdPkt != NULL)
  1155. {
  1156. AfpFreeMemory(pAfpFsdCmdPkt);
  1157. pAfpFsdCmdPkt = NULL;
  1158. }
  1159. return;
  1160. }
  1161. if (EventType == EVENTLOG_ERROR_TYPE)
  1162. {
  1163. RtlCopyMemory(tmpptr, &File_Line, sizeof(File_Line));
  1164. tmpptr += sizeof(File_Line);
  1165. RtlCopyMemory(tmpptr, &Status, sizeof(Status));
  1166. tmpptr += sizeof(Status);
  1167. }
  1168. RtlCopyMemory(tmpptr, RawDataBuf, RawDataLen);
  1169. tmpptr += RawDataLen;
  1170. // Align tmpptr on DWORD boundary for filling in string pointers
  1171. tmpptr = (PBYTE)DWLEN((ULONG_PTR)tmpptr);
  1172. if (tmpptr == NULL)
  1173. {
  1174. if (path.Buffer != NULL)
  1175. {
  1176. AfpFreeMemory(path.Buffer);
  1177. path.Buffer = NULL;
  1178. }
  1179. if (pAfpFsdCmdPkt != NULL)
  1180. {
  1181. AfpFreeMemory(pAfpFsdCmdPkt);
  1182. pAfpFsdCmdPkt = NULL;
  1183. }
  1184. return;
  1185. }
  1186. // Fill in the offset to the insertion string pointers
  1187. pAfpFsdCmdPkt->Data.Eventlog.ppStrings = (PWSTR *)(tmpptr - (PBYTE)pAfpFsdCmdPkt);
  1188. ppstr = (PWSTR *)tmpptr;
  1189. ASSERT(((ULONG_PTR)ppstr & 3) == 0);
  1190. *ppstr = NULL;
  1191. // Advance over the string pointers to the place we will copy the strings
  1192. tmpptr += stringcount * sizeof(PWSTR);
  1193. ASSERT((LONG)(tmpptr - (PBYTE)pAfpFsdCmdPkt) < outbuflen);
  1194. // If a handle was supplied, its path will always be the first string
  1195. if (path.Length > 0)
  1196. {
  1197. ASSERT((LONG)(tmpptr + path.Length - (PBYTE)pAfpFsdCmdPkt) < outbuflen);
  1198. RtlCopyMemory(tmpptr, path.Buffer, path.Length);
  1199. *ppstr = (PWSTR)(tmpptr - (PBYTE)pAfpFsdCmdPkt);
  1200. ppstr ++;
  1201. tmpptr += path.Length;
  1202. ASSERT((LONG)(tmpptr + sizeof(WCHAR) - (PBYTE)pAfpFsdCmdPkt) <=
  1203. outbuflen);
  1204. *(PWCHAR)tmpptr = UNICODE_NULL;
  1205. tmpptr += sizeof(WCHAR);
  1206. AfpFreeMemory(path.Buffer);
  1207. }
  1208. ASSERT((LONG)(tmpptr + String1Len - (PBYTE)pAfpFsdCmdPkt) <
  1209. outbuflen);
  1210. if (String1Len > 0)
  1211. {
  1212. RtlCopyMemory(tmpptr, String1, String1Len);
  1213. *ppstr = (LPWSTR)(tmpptr - (ULONG_PTR)pAfpFsdCmdPkt);
  1214. tmpptr += String1Len;
  1215. ASSERT((LONG)(tmpptr + sizeof(WCHAR) - (PBYTE)pAfpFsdCmdPkt) <=
  1216. outbuflen);
  1217. *(PWCHAR)tmpptr = UNICODE_NULL;
  1218. }
  1219. afpQueueSecWorkItem(AFP_FSD_CMD_LOG_EVENT,
  1220. NULL,
  1221. NULL,
  1222. pAfpFsdCmdPkt,
  1223. outbuflen,
  1224. afpCompleteLogEvent);
  1225. }
  1226. /*** afpCompleteLogEvent
  1227. *
  1228. * This routine will be called by AfpSecurityUtilityWorker when the
  1229. * thread that processed the AfpLogEvent returns. All this does is frees
  1230. * up the work item memory.
  1231. */
  1232. LOCAL VOID
  1233. afpCompleteLogEvent(
  1234. IN ULONG Index,
  1235. IN PVOID pInBuf
  1236. )
  1237. {
  1238. PAGED_CODE();
  1239. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem->pOutput);
  1240. AfpFreeMemory(afpSecurityThread[Index].pSecWorkItem);
  1241. }