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.

2896 lines
70 KiB

  1. /*++
  2. Copyright (c) 2002 Microsoft Corporation
  3. Module Name:
  4. ulnamesp.c
  5. Abstract:
  6. This module implements the namespace reservation and registration
  7. functions.
  8. Author:
  9. Anish Desai (anishd) 13-May-2002
  10. Revision History:
  11. --*/
  12. #include "precomp.h"
  13. #include "cgroupp.h"
  14. #ifdef ALLOC_PRAGMA
  15. #pragma alloc_text(PAGE, UlpFindPortNumberIndex)
  16. #pragma alloc_text(PAGE, UlpQuerySchemeForPort)
  17. #pragma alloc_text(PAGE, UlpBindSchemeToPort)
  18. #pragma alloc_text(PAGE, UlpUnbindSchemeFromPort)
  19. #pragma alloc_text(PAGE, UlpUpdateReservationInRegistry)
  20. #pragma alloc_text(INIT, UlpLogGeneralInitFailure)
  21. #pragma alloc_text(INIT, UlpLogSpecificInitFailure)
  22. #pragma alloc_text(INIT, UlpValidateUrlSdPair)
  23. #pragma alloc_text(INIT, UlpReadReservations)
  24. #pragma alloc_text(INIT, UlInitializeNamespace)
  25. #pragma alloc_text(PAGE, UlTerminateNamespace)
  26. #pragma alloc_text(PAGE, UlpNamespaceAccessCheck)
  27. #pragma alloc_text(PAGE, UlpTreeAllocateNamespace)
  28. #pragma alloc_text(PAGE, UlpTreeReserveNamespace)
  29. #pragma alloc_text(PAGE, UlpReserveUrlNamespace)
  30. #pragma alloc_text(PAGE, UlpAllocateDeferredRemoveItem)
  31. #pragma alloc_text(PAGE, UlpTreeRegisterNamespace)
  32. #pragma alloc_text(PAGE, UlpRegisterUrlNamespace)
  33. #pragma alloc_text(PAGE, UlpPrepareSecurityDescriptor)
  34. #pragma alloc_text(PAGE, UlpAddReservationEntry)
  35. #pragma alloc_text(PAGE, UlpDeleteReservationEntry)
  36. #endif
  37. //
  38. // File Global variables.
  39. //
  40. PUL_PORT_SCHEME_TABLE g_pPortSchemeTable = NULL;
  41. UL_PUSH_LOCK g_PortSchemeTableLock;
  42. BOOLEAN g_InitNamespace = FALSE;
  43. HANDLE g_pUrlAclKeyHandle = NULL;
  44. /**************************************************************************++
  45. Routine Description:
  46. This routine searches the global port scheme assignment table for a
  47. given port number. g_PortSchemeTableLock must be acquired either
  48. exclusive or shared.
  49. Arguments:
  50. PortNumber - Supplies the port number to be searched.
  51. pIndex - Returns the index where the port number is present.
  52. If no match is found, it contains the index where this PortNumber
  53. must be inserted.
  54. Return Value:
  55. TRUE - If a match is found.
  56. FALSE - Otherwise.
  57. --**************************************************************************/
  58. BOOLEAN
  59. UlpFindPortNumberIndex(
  60. IN USHORT PortNumber,
  61. OUT PLONG pIndex
  62. )
  63. {
  64. LONG StartIndex, EndIndex, Index;
  65. //
  66. // Sanity check.
  67. //
  68. PAGED_CODE();
  69. ASSERT(pIndex != NULL);
  70. ASSERT(g_pPortSchemeTable != NULL);
  71. ASSERT(g_pPortSchemeTable->UsedCount <= MAXUSHORT + 1);
  72. ASSERT(g_pPortSchemeTable->AllocatedCount <= MAXUSHORT + 1);
  73. StartIndex = 0;
  74. EndIndex = g_pPortSchemeTable->UsedCount - 1;
  75. //
  76. // Binary search the table of port numbers and schemes.
  77. //
  78. while (StartIndex <= EndIndex)
  79. {
  80. ASSERT(0 <= StartIndex && StartIndex < g_pPortSchemeTable->UsedCount);
  81. ASSERT(0 <= EndIndex && EndIndex < g_pPortSchemeTable->UsedCount);
  82. Index = (StartIndex + EndIndex) / 2;
  83. if (PortNumber == g_pPortSchemeTable->Table[Index].PortNumber)
  84. {
  85. //
  86. // Found the port number.
  87. //
  88. *pIndex = Index;
  89. return TRUE;
  90. }
  91. else if (PortNumber < g_pPortSchemeTable->Table[Index].PortNumber)
  92. {
  93. EndIndex = Index - 1;
  94. }
  95. else
  96. {
  97. StartIndex = Index + 1;
  98. }
  99. }
  100. //
  101. // Did not find a match. Return the position where it should be inserted.
  102. //
  103. *pIndex = StartIndex;
  104. return FALSE;
  105. }
  106. /**************************************************************************++
  107. Routine Description:
  108. This routine returns scheme bound to a port number.
  109. Arguments:
  110. PortNumber - Supplies the port number.
  111. Secure - Returns whether a http or https scheme is bound to the
  112. supplied port number.
  113. Return Value:
  114. STATUS_SUCCESS - if a scheme is bound to the port number.
  115. STATUS_INVALID_PARAMETER - if no scheme is bound to the port number.
  116. --**************************************************************************/
  117. NTSTATUS
  118. UlpQuerySchemeForPort(
  119. IN USHORT PortNumber,
  120. OUT PBOOLEAN Secure
  121. )
  122. {
  123. NTSTATUS Status;
  124. LONG Index;
  125. //
  126. // Sanity check.
  127. //
  128. PAGED_CODE();
  129. //
  130. // Find if there is a scheme bound to the port number.
  131. //
  132. Status = STATUS_INVALID_PARAMETER;
  133. UlAcquirePushLockShared(&g_PortSchemeTableLock);
  134. if (UlpFindPortNumberIndex(PortNumber, &Index))
  135. {
  136. *Secure = g_pPortSchemeTable->Table[Index].Secure;
  137. Status = STATUS_SUCCESS;
  138. }
  139. UlReleasePushLockShared(&g_PortSchemeTableLock);
  140. return Status;
  141. }
  142. /**************************************************************************++
  143. Routine Description:
  144. This routine adds a port, scheme pair to the global table.
  145. Arguments:
  146. PortNumber - Supplies the port number.
  147. Scheme - Supplies the scheme.
  148. Return Value:
  149. NTSTATUS.
  150. --**************************************************************************/
  151. NTSTATUS
  152. UlpBindSchemeToPort(
  153. IN BOOLEAN Secure,
  154. IN USHORT PortNumber
  155. )
  156. {
  157. LONG StartIndex;
  158. BOOLEAN bFound;
  159. NTSTATUS Status;
  160. //
  161. // Sanity check.
  162. //
  163. PAGED_CODE();
  164. //
  165. // Acquire lock exclusively.
  166. //
  167. UlAcquirePushLockExclusive(&g_PortSchemeTableLock);
  168. //
  169. // Find an existing scheme that is bound to the port.
  170. //
  171. bFound = UlpFindPortNumberIndex(PortNumber, &StartIndex);
  172. if (bFound)
  173. {
  174. ASSERT(0 <= StartIndex && StartIndex < g_pPortSchemeTable->UsedCount);
  175. ASSERT(g_pPortSchemeTable->Table[StartIndex].PortNumber == PortNumber);
  176. if (g_pPortSchemeTable->Table[StartIndex].Secure != Secure)
  177. {
  178. //
  179. // Trying to bind a scheme that is different from an
  180. // existing bound scheme.
  181. //
  182. Status = STATUS_OBJECT_NAME_COLLISION;
  183. goto end;
  184. }
  185. //
  186. // The reference count is a LONG. Don't let it overflow.
  187. //
  188. if (g_pPortSchemeTable->Table[StartIndex].RefCount == MAXLONG)
  189. {
  190. Status = STATUS_INTEGER_OVERFLOW;
  191. goto end;
  192. }
  193. //
  194. // Found an existing entry, increment the reference count.
  195. //
  196. ASSERT(g_pPortSchemeTable->Table[StartIndex].RefCount > 0);
  197. g_pPortSchemeTable->Table[StartIndex].RefCount++;
  198. Status = STATUS_SUCCESS;
  199. goto end;
  200. }
  201. //
  202. // StartIndex is the place where this new entry must be added!
  203. //
  204. ASSERT(0 <= StartIndex && StartIndex <= g_pPortSchemeTable->UsedCount);
  205. //
  206. // Is the table full?
  207. //
  208. if (g_pPortSchemeTable->UsedCount == g_pPortSchemeTable->AllocatedCount)
  209. {
  210. //
  211. // Allocate a bigger table.
  212. //
  213. PUL_PORT_SCHEME_TABLE pNewTable;
  214. ULONG NewTableSize;
  215. //
  216. // Table does not need more than 65536 entries.
  217. //
  218. ASSERT(g_pPortSchemeTable->AllocatedCount < MAXUSHORT + 1);
  219. NewTableSize = MIN(g_pPortSchemeTable->AllocatedCount*2, MAXUSHORT+1);
  220. pNewTable = UL_ALLOCATE_STRUCT_WITH_SPACE(
  221. PagedPool,
  222. UL_PORT_SCHEME_TABLE,
  223. sizeof(UL_PORT_SCHEME_PAIR) * NewTableSize,
  224. UL_PORT_SCHEME_TABLE_POOL_TAG
  225. );
  226. if (pNewTable == NULL)
  227. {
  228. Status = STATUS_NO_MEMORY;
  229. goto end;
  230. }
  231. //
  232. // Initialize the new table.
  233. //
  234. pNewTable->UsedCount = g_pPortSchemeTable->UsedCount;
  235. pNewTable->AllocatedCount = NewTableSize;
  236. //
  237. // Copy 0 to (StartIndex-1) entries from the current table to the
  238. // new table.
  239. //
  240. if (StartIndex > 0)
  241. {
  242. RtlCopyMemory(
  243. &pNewTable->Table[0],
  244. &g_pPortSchemeTable->Table[0],
  245. sizeof(UL_PORT_SCHEME_PAIR) * StartIndex
  246. );
  247. }
  248. //
  249. // Copy StartIndex to (UsedCount-1) entries from the current table
  250. // to the new table. They are copied from position (StartIndex+1)
  251. // in the new table, effectively creating a free entry at StartIndex.
  252. //
  253. if (g_pPortSchemeTable->UsedCount - StartIndex > 0)
  254. {
  255. RtlCopyMemory(
  256. &pNewTable->Table[StartIndex + 1],
  257. &g_pPortSchemeTable->Table[StartIndex],
  258. sizeof(UL_PORT_SCHEME_PAIR)
  259. * (g_pPortSchemeTable->UsedCount - StartIndex)
  260. );
  261. }
  262. //
  263. // Free the current table. Make new table current.
  264. //
  265. UL_FREE_POOL(g_pPortSchemeTable, UL_PORT_SCHEME_TABLE_POOL_TAG);
  266. g_pPortSchemeTable = pNewTable;
  267. }
  268. else
  269. {
  270. //
  271. // Table must have free entries at the bottom (higher indices.)
  272. //
  273. ASSERT(g_pPortSchemeTable->UsedCount
  274. < g_pPortSchemeTable->AllocatedCount);
  275. //
  276. // No table expansion. But move entries from StartIndex to
  277. // (UsedCount-1) to new location at (StartIndex+1) to UsedCount.
  278. //
  279. if (g_pPortSchemeTable->UsedCount - StartIndex > 0)
  280. {
  281. RtlMoveMemory(
  282. &g_pPortSchemeTable->Table[StartIndex + 1],
  283. &g_pPortSchemeTable->Table[StartIndex],
  284. sizeof(UL_PORT_SCHEME_PAIR)
  285. * (g_pPortSchemeTable->UsedCount - StartIndex)
  286. );
  287. }
  288. }
  289. //
  290. // Add the new entry to the table.
  291. //
  292. ASSERT(g_pPortSchemeTable->UsedCount < g_pPortSchemeTable->AllocatedCount);
  293. ASSERT(0 <= StartIndex && StartIndex <= g_pPortSchemeTable->UsedCount);
  294. g_pPortSchemeTable->UsedCount++;
  295. g_pPortSchemeTable->Table[StartIndex].PortNumber = PortNumber;
  296. g_pPortSchemeTable->Table[StartIndex].Secure = Secure;
  297. g_pPortSchemeTable->Table[StartIndex].RefCount = 1;
  298. Status = STATUS_SUCCESS;
  299. end:
  300. UlReleasePushLockExclusive(&g_PortSchemeTableLock);
  301. return Status;
  302. }
  303. /**************************************************************************++
  304. Routine Description:
  305. This routine unbinds a previously bound scheme from a port.
  306. Arguments:
  307. PortNumber - Supplies the port number.
  308. Scheme - Supplies the scheme.
  309. Return Value:
  310. NTSTATUS.
  311. --**************************************************************************/
  312. NTSTATUS
  313. UlpUnbindSchemeFromPort(
  314. IN BOOLEAN Secure,
  315. IN USHORT PortNumber
  316. )
  317. {
  318. LONG StartIndex;
  319. BOOLEAN bFound;
  320. NTSTATUS Status;
  321. //
  322. // Sanity check.
  323. //
  324. PAGED_CODE();
  325. //
  326. // Acquire lock exclusively.
  327. //
  328. UlAcquirePushLockExclusive(&g_PortSchemeTableLock);
  329. //
  330. // Find an existing scheme that is bound to PortNumber.
  331. //
  332. bFound = UlpFindPortNumberIndex(PortNumber, &StartIndex);
  333. if (bFound == FALSE)
  334. {
  335. //
  336. // There is no scheme bound to PortNumber.
  337. //
  338. ASSERT(FALSE); // catch this misuse
  339. Status = STATUS_OBJECT_NAME_NOT_FOUND;
  340. goto end;
  341. }
  342. //
  343. // Sanity check. StartIndex must be within bounds. PortNumber must match.
  344. //
  345. ASSERT(0 <= StartIndex && StartIndex < g_pPortSchemeTable->UsedCount);
  346. ASSERT(g_pPortSchemeTable->Table[StartIndex].PortNumber == PortNumber);
  347. //
  348. // Is the scheme bound to PortNumber same as Scheme?
  349. //
  350. if (g_pPortSchemeTable->Table[StartIndex].Secure != Secure)
  351. {
  352. //
  353. // Tried to unbind a scheme from a port and the port is not bound to
  354. // the scheme.
  355. //
  356. ASSERT(FALSE); // catch this misuse
  357. Status = STATUS_OBJECT_NAME_COLLISION;
  358. goto end;
  359. }
  360. //
  361. // Decrement the ref count.
  362. //
  363. ASSERT(g_pPortSchemeTable->Table[StartIndex].RefCount > 0);
  364. g_pPortSchemeTable->Table[StartIndex].RefCount--;
  365. //
  366. // If RefCount drops to zero, its time to cleanup that entry.
  367. //
  368. if (g_pPortSchemeTable->Table[StartIndex].RefCount == 0)
  369. {
  370. LONG NewTableSize = 0;
  371. PUL_PORT_SCHEME_TABLE pNewTable = NULL;
  372. BOOLEAN bContract = FALSE;
  373. //
  374. // Do we need to contract the table?
  375. //
  376. if (4 * (g_pPortSchemeTable->UsedCount - 1)
  377. <= g_pPortSchemeTable->AllocatedCount)
  378. {
  379. //
  380. // Current table is less than 25% used.
  381. //
  382. NewTableSize = g_pPortSchemeTable->AllocatedCount / 2;
  383. if (NewTableSize >= UL_DEFAULT_PORT_SCHEME_TABLE_SIZE)
  384. {
  385. //
  386. // Current table is at least twice bigger than the default
  387. // size.
  388. //
  389. pNewTable = UL_ALLOCATE_STRUCT_WITH_SPACE(
  390. PagedPool,
  391. UL_PORT_SCHEME_TABLE,
  392. sizeof(UL_PORT_SCHEME_PAIR) * NewTableSize,
  393. UL_PORT_SCHEME_TABLE_POOL_TAG
  394. );
  395. if (pNewTable != NULL)
  396. {
  397. //
  398. // Could allocate memory for a smaller table.
  399. //
  400. bContract = TRUE;
  401. }
  402. }
  403. }
  404. if (bContract)
  405. {
  406. //
  407. // We are going to contract the existing table.
  408. //
  409. ASSERT(pNewTable != NULL);
  410. ASSERT(NewTableSize >= UL_DEFAULT_PORT_SCHEME_TABLE_SIZE);
  411. ASSERT(NewTableSize >= g_pPortSchemeTable->UsedCount - 1);
  412. //
  413. // Initialize the new table.
  414. //
  415. pNewTable->UsedCount = g_pPortSchemeTable->UsedCount;
  416. pNewTable->AllocatedCount = NewTableSize;
  417. //
  418. // Copy all entries from 0 to (StartIndex - 1)
  419. // from the current table to the new table.
  420. //
  421. if (StartIndex > 0)
  422. {
  423. RtlCopyMemory(
  424. &pNewTable->Table[0],
  425. &g_pPortSchemeTable->Table[0],
  426. sizeof(UL_PORT_SCHEME_PAIR) * StartIndex
  427. );
  428. }
  429. //
  430. // Copy all entries from (StartIndex+1) to (UsedCount-1)
  431. // from the current table to the new table.
  432. //
  433. // Effectively, StartIndex entry is eliminated.
  434. //
  435. if (g_pPortSchemeTable->UsedCount - StartIndex - 1 > 0)
  436. {
  437. RtlCopyMemory(
  438. &pNewTable->Table[StartIndex],
  439. &g_pPortSchemeTable->Table[StartIndex+1],
  440. sizeof(UL_PORT_SCHEME_PAIR)
  441. * (g_pPortSchemeTable->UsedCount - StartIndex - 1)
  442. );
  443. }
  444. //
  445. // Free the current table.
  446. //
  447. UL_FREE_POOL(g_pPortSchemeTable, UL_PORT_SCHEME_TABLE_POOL_TAG);
  448. //
  449. // The new table becomes the current table.
  450. //
  451. g_pPortSchemeTable = pNewTable;
  452. }
  453. else
  454. {
  455. //
  456. // We are not going to contract the table but still have to
  457. // eliminate the unused table entry. Move all entries from
  458. // (StartIndex + 1) to (UsedCount - 1) one position up.
  459. //
  460. if (g_pPortSchemeTable->UsedCount - StartIndex - 1 > 0)
  461. {
  462. RtlMoveMemory(
  463. &g_pPortSchemeTable->Table[StartIndex],
  464. &g_pPortSchemeTable->Table[StartIndex+1],
  465. sizeof(UL_PORT_SCHEME_PAIR)
  466. * (g_pPortSchemeTable->UsedCount - StartIndex - 1)
  467. );
  468. }
  469. }
  470. g_pPortSchemeTable->UsedCount--;
  471. }
  472. Status = STATUS_SUCCESS;
  473. end:
  474. UlReleasePushLockExclusive(&g_PortSchemeTableLock);
  475. return Status;
  476. }
  477. /**************************************************************************++
  478. Routine Description:
  479. This routine adds (or deletes) a (url, security descriptor) pair to
  480. (or from) the registry.
  481. Arguments:
  482. Add - Supplies the operation, TRUE imples add and FALSE implies delete.
  483. pParsedUrl - Supplies the parsed url of the reservation.
  484. pSecurityDescriptor - Supplies the security descriptor.
  485. (It must be valid while adding and NULL while deleting.)
  486. SecurityDescriptorLength - Supplies the length of the security
  487. descriptor in bytes. (It must be non-zero when adding and
  488. zero when deleting.)
  489. Return Value:
  490. NTSTATUS.
  491. --**************************************************************************/
  492. NTSTATUS
  493. UlpUpdateReservationInRegistry(
  494. IN BOOLEAN Add,
  495. IN PHTTP_PARSED_URL pParsedUrl,
  496. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  497. IN ULONG SecurityDescriptorLength
  498. )
  499. {
  500. NTSTATUS Status;
  501. PWSTR pUrlToWrite = NULL;
  502. PWSTR pNewUrl = NULL;
  503. UNICODE_STRING UnicodeUrl;
  504. //
  505. // sanity check
  506. //
  507. PAGED_CODE();
  508. ASSERT(IS_VALID_HTTP_PARSED_URL(pParsedUrl));
  509. ASSERT(pParsedUrl->pFullUrl[pParsedUrl->UrlLength] == UNICODE_NULL);
  510. ASSERT(Add?(pSecurityDescriptor != NULL):(pSecurityDescriptor == NULL));
  511. ASSERT(Add?(SecurityDescriptorLength > 0):(SecurityDescriptorLength == 0));
  512. //
  513. // Do we have a valid handle to the registry key? It can be invalid,
  514. // for instance, if during driver initialization ZwCreateKey failed.
  515. //
  516. if (g_pUrlAclKeyHandle == NULL)
  517. {
  518. return STATUS_INVALID_HANDLE;
  519. }
  520. //
  521. // default error code
  522. //
  523. Status = STATUS_INVALID_PARAMETER;
  524. //
  525. // Do some special processing for literal ip address sites.
  526. //
  527. if (HttpUrlSite_IP == pParsedUrl->SiteType)
  528. {
  529. //
  530. // convert scheme://ip:port:ip/ to scheme://ip:port/
  531. //
  532. PWSTR pToken;
  533. PWSTR pLiteralAddr;
  534. SIZE_T UrlLength;
  535. //
  536. // length of original url in wchar (+1 for UNICODE_NULL)
  537. //
  538. UrlLength = (pParsedUrl->UrlLength + 1);
  539. pNewUrl = UL_ALLOCATE_ARRAY(
  540. PagedPool,
  541. WCHAR,
  542. UrlLength,
  543. URL_POOL_TAG
  544. );
  545. if (pNewUrl == NULL)
  546. {
  547. Status = STATUS_NO_MEMORY;
  548. goto end;
  549. }
  550. RtlCopyMemory(pNewUrl, pParsedUrl->pFullUrl, UrlLength*sizeof(WCHAR));
  551. //
  552. // skip ipv6 literal address if present
  553. //
  554. pToken = &pNewUrl[HTTP_PREFIX_COLON_INDEX + 3];
  555. if (pToken[0] == L'[' || pToken[1] == L'[')
  556. {
  557. pToken = wcschr(pToken, L']');
  558. if (pToken == NULL)
  559. {
  560. ASSERT(FALSE);
  561. goto end;
  562. }
  563. }
  564. //
  565. // skip to the port number
  566. //
  567. pToken = wcschr(pToken, L':');
  568. if (pToken == NULL)
  569. {
  570. ASSERT(FALSE);
  571. goto end;
  572. }
  573. //
  574. // skip ':'
  575. //
  576. pToken++;
  577. //
  578. // find the literal address
  579. //
  580. pToken = wcschr(pToken, L':');
  581. if (pToken == NULL)
  582. {
  583. ASSERT(FALSE);
  584. goto end;
  585. }
  586. pLiteralAddr = pToken;
  587. //
  588. // find begining of abs path
  589. //
  590. pToken = wcschr(pToken, L'/');
  591. if (pToken == NULL)
  592. {
  593. ASSERT(FALSE);
  594. goto end;
  595. }
  596. //
  597. // overwrite literal address. effectively convert
  598. // scheme://host:port:ip/abs_path -> scheme://host:port/abs_path
  599. //
  600. while (*pToken != L'\0')
  601. {
  602. *pLiteralAddr++ = *pToken++;
  603. }
  604. *pLiteralAddr = L'\0';
  605. //
  606. // use new url when writing to registry
  607. //
  608. pUrlToWrite = pNewUrl;
  609. }
  610. else
  611. {
  612. pUrlToWrite = pParsedUrl->pFullUrl;
  613. }
  614. ASSERT(pUrlToWrite != NULL);
  615. //
  616. // convert url to unicode for registry functions
  617. //
  618. Status = UlInitUnicodeStringEx(&UnicodeUrl, pUrlToWrite);
  619. if (!NT_SUCCESS(Status))
  620. {
  621. goto end;
  622. }
  623. if (Add)
  624. {
  625. //
  626. // write url and security descriptor to registry
  627. //
  628. Status = ZwSetValueKey(
  629. g_pUrlAclKeyHandle,
  630. &UnicodeUrl,
  631. 0, // title index; must be zero.
  632. REG_BINARY,
  633. pSecurityDescriptor,
  634. SecurityDescriptorLength
  635. );
  636. if (!NT_SUCCESS(Status))
  637. {
  638. //
  639. // too bad...can't write to registry. delete the old key value.
  640. // ignore the return status.
  641. //
  642. ZwDeleteValueKey(g_pUrlAclKeyHandle, &UnicodeUrl);
  643. }
  644. }
  645. else
  646. {
  647. //
  648. // delete url from the registry.
  649. //
  650. Status = ZwDeleteValueKey(g_pUrlAclKeyHandle, &UnicodeUrl);
  651. }
  652. end:
  653. if (pNewUrl != NULL)
  654. {
  655. UL_FREE_POOL(pNewUrl, URL_POOL_TAG);
  656. }
  657. return Status;
  658. }
  659. /**************************************************************************++
  660. Routine Description:
  661. This routine is called during namespace initialization if an error
  662. occurs while intializing the config group url tree using the entries
  663. in registry.
  664. Arguments:
  665. LogCount - Supplies the number of logs written in the past. Returns
  666. one more than the input value.
  667. LogStatus - Supplies the status to log in the event log.
  668. Return Value:
  669. NTSTATUS.
  670. --**************************************************************************/
  671. __inline
  672. NTSTATUS
  673. UlpLogGeneralInitFailure(
  674. IN NTSTATUS LogStatus
  675. )
  676. {
  677. NTSTATUS Status;
  678. //
  679. // Sanity check.
  680. //
  681. PAGED_CODE();
  682. //
  683. // Write an event log entry.
  684. //
  685. Status = UlWriteEventLogEntry(
  686. EVENT_HTTP_NAMESPACE_INIT_FAILED, // EventCode
  687. 0, // UniqueEventValue
  688. 0, // NumStrings
  689. NULL, // pStringArray
  690. sizeof(LogStatus), // DataSize
  691. &LogStatus // Data
  692. );
  693. return Status;
  694. }
  695. /**************************************************************************++
  696. Routine Description:
  697. This routine writes an event log message about a specific namespace
  698. reservation initialization failure. It logs the url present in the
  699. full info structure.
  700. Arguments:
  701. LogCount - Supplies the number of logs written in the past. Returns
  702. one more than the input value.
  703. pFullInfo - Supplies information read from registry.
  704. LogStatus - Supplies the error status to log.
  705. Return Value:
  706. NTSTATUS.
  707. --**************************************************************************/
  708. NTSTATUS
  709. UlpLogSpecificInitFailure(
  710. IN PKEY_VALUE_FULL_INFORMATION pFullInfo,
  711. IN NTSTATUS LogStatus
  712. )
  713. {
  714. NTSTATUS Status;
  715. PWSTR pMessage;
  716. //
  717. // Sanity check.
  718. //
  719. PAGED_CODE();
  720. ASSERT(pFullInfo != NULL);
  721. //
  722. // pFullInfo->Name contains the url to be written and it not
  723. // UNICODE_NULL terminated. Allocate memory to copy.
  724. //
  725. pMessage = UL_ALLOCATE_ARRAY(
  726. PagedPool,
  727. WCHAR,
  728. (pFullInfo->NameLength / sizeof(WCHAR)) + 1,
  729. URL_POOL_TAG
  730. );
  731. if (pMessage != NULL)
  732. {
  733. //
  734. // Copy url and null terminate it.
  735. //
  736. RtlCopyMemory(pMessage, pFullInfo->Name, pFullInfo->NameLength);
  737. pMessage[pFullInfo->NameLength / sizeof(WCHAR)] = UNICODE_NULL;
  738. //
  739. // Write event log entry.
  740. //
  741. Status = UlEventLogOneStringEntry(
  742. EVENT_HTTP_NAMESPACE_INIT2_FAILED,
  743. pMessage,
  744. TRUE,
  745. LogStatus
  746. );
  747. UL_FREE_POOL(pMessage, URL_POOL_TAG);
  748. }
  749. else
  750. {
  751. //
  752. // Could not allocate memory. Log just the error code.
  753. //
  754. Status = UlpLogGeneralInitFailure(LogStatus);
  755. }
  756. return Status;
  757. }
  758. /**************************************************************************++
  759. Routine Description:
  760. This routine validates registry key value name (url) and data (security
  761. descriptor). Called only during driver initialization.
  762. Arguments:
  763. pFullInfo - Supplies the registry key value name and data.
  764. ppSanitizeUrl - Returns sanitized url. Must be freed to paged pool.
  765. pParsedUrl - Returns parsed url information.
  766. Return Value:
  767. NTSTATUS.
  768. --**************************************************************************/
  769. NTSTATUS
  770. UlpValidateUrlSdPair(
  771. IN PKEY_VALUE_FULL_INFORMATION pFullInfo,
  772. OUT PWSTR * ppSanitizedUrl,
  773. OUT PHTTP_PARSED_URL pParsedUrl
  774. )
  775. {
  776. NTSTATUS Status;
  777. BOOLEAN Success;
  778. //
  779. // Sanity check.
  780. //
  781. PAGED_CODE();
  782. ASSERT(pFullInfo != NULL);
  783. ASSERT(ppSanitizedUrl != NULL);
  784. ASSERT(pParsedUrl != NULL);
  785. //
  786. // Key value type must be binary.
  787. //
  788. if (pFullInfo->Type != REG_BINARY)
  789. {
  790. return STATUS_INVALID_PARAMETER;
  791. }
  792. //
  793. // Then, validate security descriptor. It must be a self-relative
  794. // security descriptor.
  795. //
  796. Success = RtlValidRelativeSecurityDescriptor(
  797. (PUCHAR)pFullInfo + pFullInfo->DataOffset,
  798. pFullInfo->DataLength,
  799. 0
  800. );
  801. if (!Success)
  802. {
  803. return STATUS_INVALID_PARAMETER;
  804. }
  805. //
  806. // Value name must be at least one unicode char long.
  807. //
  808. if (pFullInfo->NameLength < sizeof(WCHAR))
  809. {
  810. return STATUS_INVALID_PARAMETER;
  811. }
  812. //
  813. // Then validate the url.
  814. //
  815. Status = UlSanitizeUrl(
  816. pFullInfo->Name,
  817. pFullInfo->NameLength / sizeof(WCHAR),
  818. TRUE, // trailing slash required
  819. ppSanitizedUrl,
  820. pParsedUrl
  821. );
  822. return Status;
  823. }
  824. /***************************************************************************++
  825. Routine Description:
  826. This function gets called from the Driver Load routine. It builds the
  827. URL ACLing information from the registry. If the URL ACLing key itself
  828. is not present, we'll add the defaults.
  829. If there are any bogus entries in the URIACL entry, we'll ignore them with
  830. and eventlog. The routine will return failure only on a major error.
  831. Not-reentrant.
  832. Arguments:
  833. None.
  834. Return Value:
  835. STATUS_SUCCESS.
  836. --***************************************************************************/
  837. NTSTATUS
  838. UlpReadReservations(
  839. VOID
  840. )
  841. {
  842. KEY_VALUE_FULL_INFORMATION fullInfo;
  843. PKEY_VALUE_FULL_INFORMATION pFullInfo = NULL;
  844. ULONG Length;
  845. ULONG Index;
  846. UNICODE_STRING BaseName;
  847. NTSTATUS Status;
  848. OBJECT_ATTRIBUTES objectAttributes;
  849. ULONG Disposition;
  850. ULONG bEventLog = TRUE;
  851. ULONG dataLength;
  852. //
  853. // Sanity check.
  854. //
  855. PAGED_CODE();
  856. //
  857. // Open the registry.
  858. //
  859. Status = UlInitUnicodeStringEx(&BaseName, REGISTRY_URLACL_INFORMATION);
  860. if (!NT_SUCCESS(Status))
  861. {
  862. //
  863. // Write an event log entry.
  864. //
  865. ASSERT(FALSE); // shouldn't happen!
  866. UlpLogGeneralInitFailure(Status);
  867. goto end;
  868. }
  869. InitializeObjectAttributes(
  870. &objectAttributes, // ObjectAttributes
  871. &BaseName, // ObjectName
  872. OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
  873. NULL, // RootDirectory
  874. NULL // SecurityDescriptor
  875. );
  876. Status = ZwCreateKey(
  877. &g_pUrlAclKeyHandle,
  878. KEY_READ | KEY_WRITE, // AccessMask
  879. &objectAttributes,
  880. 0, // TitleIndex
  881. NULL, // Class
  882. REG_OPTION_NON_VOLATILE,
  883. &Disposition
  884. );
  885. if (!NT_SUCCESS(Status))
  886. {
  887. //
  888. // Write an event log entry.
  889. //
  890. UlpLogGeneralInitFailure(Status);
  891. //
  892. // Make the handle NULL so that it is not used elsewhere accidentally.
  893. //
  894. g_pUrlAclKeyHandle = NULL;
  895. goto end;
  896. }
  897. if (Disposition == REG_CREATED_NEW_KEY)
  898. {
  899. //
  900. // we created the key, hence there is nothing to read!
  901. //
  902. goto end;
  903. }
  904. pFullInfo = &fullInfo;
  905. Length = sizeof(fullInfo);
  906. Index = 0;
  907. dataLength = 0;
  908. RtlZeroMemory(pFullInfo, Length);
  909. //
  910. // loop through all registry key values, making reservations for each
  911. //
  912. for (;;)
  913. {
  914. Status = ZwEnumerateValueKey(
  915. g_pUrlAclKeyHandle,
  916. Index,
  917. KeyValueFullInformation,
  918. (PVOID) pFullInfo,
  919. Length,
  920. &dataLength
  921. );
  922. if (Status == STATUS_SUCCESS)
  923. {
  924. PWSTR pSanitizedUrl;
  925. HTTP_PARSED_URL ParsedUrl;
  926. //
  927. // First validate the registry data.
  928. //
  929. Status = UlpValidateUrlSdPair(
  930. pFullInfo,
  931. &pSanitizedUrl,
  932. &ParsedUrl
  933. );
  934. if (NT_SUCCESS(Status))
  935. {
  936. //
  937. // Add this url to the CG url tree.
  938. //
  939. Status = UlpAddReservationEntry(
  940. &ParsedUrl,
  941. (PSECURITY_DESCRIPTOR)
  942. ((PUCHAR) pFullInfo + pFullInfo->DataOffset),
  943. pFullInfo->DataLength,
  944. (PACCESS_STATE)NULL,
  945. (ACCESS_MASK)0,
  946. KernelMode,
  947. FALSE
  948. );
  949. //
  950. // Free memory that was allocated by UlSanitizeUrl.
  951. //
  952. UL_FREE_POOL(pSanitizedUrl, URL_POOL_TAG);
  953. }
  954. else
  955. {
  956. Status = STATUS_REGISTRY_CORRUPT;
  957. }
  958. if (!NT_SUCCESS(Status))
  959. {
  960. //
  961. // Write an event log entry that an error occurred.
  962. // Ignore the error and continue processing.
  963. //
  964. if (bEventLog)
  965. {
  966. bEventLog = FALSE;
  967. UlpLogSpecificInitFailure(pFullInfo, Status);
  968. }
  969. }
  970. //
  971. // Move to the next value in registry.
  972. //
  973. Index ++;
  974. }
  975. else if (Status == STATUS_NO_MORE_ENTRIES)
  976. {
  977. //
  978. // We've reached the end, so this is a success.
  979. //
  980. break;
  981. }
  982. else if (Status == STATUS_BUFFER_OVERFLOW)
  983. {
  984. //
  985. // Sanity check.
  986. //
  987. ASSERT(dataLength >= pFullInfo->DataLength +
  988. pFullInfo->NameLength +
  989. FIELD_OFFSET(KEY_VALUE_FULL_INFORMATION, Name)
  990. );
  991. //
  992. // Remember how much memory to allocate.
  993. //
  994. Length = dataLength;
  995. //
  996. // If any memory was allocated in previous iterations, free it now.
  997. //
  998. if (pFullInfo != &fullInfo)
  999. {
  1000. UL_FREE_POOL(pFullInfo, UL_REGISTRY_DATA_POOL_TAG);
  1001. }
  1002. //
  1003. // Allocate memory.
  1004. //
  1005. pFullInfo = UL_ALLOCATE_POOL(
  1006. PagedPool,
  1007. dataLength,
  1008. UL_REGISTRY_DATA_POOL_TAG
  1009. );
  1010. if(!pFullInfo)
  1011. {
  1012. //
  1013. // Write an event log entry.
  1014. //
  1015. UlpLogGeneralInitFailure(STATUS_INSUFFICIENT_RESOURCES);
  1016. goto end;
  1017. }
  1018. //
  1019. // Initialize.
  1020. //
  1021. RtlZeroMemory(pFullInfo, dataLength);
  1022. }
  1023. else
  1024. {
  1025. //
  1026. // An unknown error occurred. Event log and get out.
  1027. //
  1028. UlpLogGeneralInitFailure(Status);
  1029. goto end;
  1030. }
  1031. }
  1032. end:
  1033. //
  1034. // Free pFullInfo structure if it was allocated above.
  1035. //
  1036. if (pFullInfo != &fullInfo && pFullInfo != NULL)
  1037. {
  1038. UL_FREE_POOL(pFullInfo, UL_REGISTRY_DATA_POOL_TAG);
  1039. }
  1040. return STATUS_SUCCESS;
  1041. }
  1042. /**************************************************************************++
  1043. Routine Description:
  1044. This routine initializes the namespace registration and reservation
  1045. support. Not re-entrant.
  1046. Arguments:
  1047. None.
  1048. Return Value:
  1049. NTSTATUS.
  1050. --**************************************************************************/
  1051. NTSTATUS
  1052. UlInitializeNamespace(
  1053. VOID
  1054. )
  1055. {
  1056. NTSTATUS Status = STATUS_SUCCESS;
  1057. //
  1058. // Sanity check.
  1059. //
  1060. PAGED_CODE();
  1061. ASSERT(!g_InitNamespace);
  1062. if (!g_InitNamespace)
  1063. {
  1064. //
  1065. // Allocate port scheme table.
  1066. //
  1067. g_pPortSchemeTable = UL_ALLOCATE_STRUCT_WITH_SPACE(
  1068. PagedPool,
  1069. UL_PORT_SCHEME_TABLE,
  1070. sizeof(UL_PORT_SCHEME_PAIR)
  1071. * UL_DEFAULT_PORT_SCHEME_TABLE_SIZE,
  1072. UL_PORT_SCHEME_TABLE_POOL_TAG
  1073. );
  1074. if (g_pPortSchemeTable == NULL)
  1075. {
  1076. Status = STATUS_NO_MEMORY;
  1077. goto end;
  1078. }
  1079. g_pPortSchemeTable->UsedCount = 0;
  1080. g_pPortSchemeTable->AllocatedCount = UL_DEFAULT_PORT_SCHEME_TABLE_SIZE;
  1081. //
  1082. // Initialize pushlock.
  1083. //
  1084. UlInitializePushLock(&g_PortSchemeTableLock,
  1085. "g_PortSchemeTableLock",
  1086. 0,
  1087. UL_PORT_SCHEME_TABLE_POOL_TAG
  1088. );
  1089. //
  1090. // Now add reservation entries from registry.
  1091. //
  1092. CG_LOCK_WRITE();
  1093. Status = UlpReadReservations();
  1094. CG_UNLOCK_WRITE();
  1095. if (!NT_SUCCESS(Status))
  1096. {
  1097. UL_FREE_POOL(g_pPortSchemeTable, UL_PORT_SCHEME_TABLE_POOL_TAG);
  1098. UlDeletePushLock(&g_PortSchemeTableLock);
  1099. goto end;
  1100. }
  1101. g_InitNamespace = TRUE;
  1102. }
  1103. end:
  1104. return Status;
  1105. }
  1106. /**************************************************************************++
  1107. Routine Description:
  1108. This routine terminates the namespace stuff. Not re-entrant.
  1109. Arguments:
  1110. None.
  1111. Return Value:
  1112. None.
  1113. --**************************************************************************/
  1114. VOID
  1115. UlTerminateNamespace(
  1116. VOID
  1117. )
  1118. {
  1119. //
  1120. // Sanity check.
  1121. //
  1122. PAGED_CODE();
  1123. if (g_InitNamespace)
  1124. {
  1125. //
  1126. // Delete pushlock.
  1127. //
  1128. UlDeletePushLock(&g_PortSchemeTableLock);
  1129. //
  1130. // Delete port scheme table.
  1131. //
  1132. ASSERT(g_pPortSchemeTable != NULL);
  1133. UL_FREE_POOL(g_pPortSchemeTable, UL_PORT_SCHEME_TABLE_POOL_TAG);
  1134. g_pPortSchemeTable = NULL;
  1135. //
  1136. // Delete the handle to registry key.
  1137. //
  1138. if(g_pUrlAclKeyHandle != NULL)
  1139. {
  1140. ZwClose(g_pUrlAclKeyHandle);
  1141. g_pUrlAclKeyHandle = NULL;
  1142. }
  1143. //
  1144. // Terminated.
  1145. //
  1146. g_InitNamespace = FALSE;
  1147. }
  1148. }
  1149. /**************************************************************************++
  1150. Routine Description:
  1151. This routine performs access check based on the supplied access state.
  1152. All access check succeeds for administrators and local system.
  1153. Note: If the access state is NULL, the function returns success.
  1154. USE AT YOUR OWN RISK!
  1155. Arguments:
  1156. pSecurityDescriptor - Supplies security descriptor protecting the
  1157. namespace.
  1158. AccessState - Supplies a pointer to the access state of the caller.
  1159. DesiredAccess - Supplies access mask.
  1160. RequestorMode - Supplies the requestor mode.
  1161. pObjectName - Supplies the namespace that is being access.
  1162. Return Value:
  1163. NTSTATUS.
  1164. --**************************************************************************/
  1165. NTSTATUS
  1166. UlpNamespaceAccessCheck(
  1167. IN PSECURITY_DESCRIPTOR pSecurityDescriptor,
  1168. IN PACCESS_STATE AccessState OPTIONAL,
  1169. IN ACCESS_MASK DesiredAccess OPTIONAL,
  1170. IN KPROCESSOR_MODE RequestorMode OPTIONAL,
  1171. IN PCWSTR pObjectName OPTIONAL
  1172. )
  1173. {
  1174. NTSTATUS Status;
  1175. //
  1176. // Sanity check.
  1177. //
  1178. PAGED_CODE();
  1179. ASSERT(pSecurityDescriptor != NULL);
  1180. ASSERT(RtlValidSecurityDescriptor(pSecurityDescriptor));
  1181. if (AccessState == NULL)
  1182. {
  1183. //
  1184. // No access check. USE EXTREME CAUTION!
  1185. //
  1186. return STATUS_SUCCESS;
  1187. }
  1188. //
  1189. // Check the access.
  1190. //
  1191. Status = UlAccessCheck(
  1192. pSecurityDescriptor,
  1193. AccessState,
  1194. DesiredAccess,
  1195. RequestorMode,
  1196. pObjectName
  1197. );
  1198. if (!NT_SUCCESS(Status))
  1199. {
  1200. //
  1201. // Access check failed. See if the caller has admin or system
  1202. // privileges.
  1203. //
  1204. Status = UlAccessCheck(
  1205. g_pAdminAllSystemAll,
  1206. AccessState,
  1207. DesiredAccess,
  1208. RequestorMode,
  1209. pObjectName
  1210. );
  1211. }
  1212. return Status;
  1213. }
  1214. /**************************************************************************++
  1215. Routine Description:
  1216. This routine allocates a namespace in the config group url tree. It is
  1217. mainly called during reservations and registrations.
  1218. It ensures that the caller is authorized to do the operation and there
  1219. are no duplicate reservations and registrations.
  1220. Arguments:
  1221. pParsedUrl - Supplies the parsed url of the namespace.
  1222. OperatorType - Supplies the operation being performed (either
  1223. registration or reservation.)
  1224. AccessState - Supplies the access state of the caller.
  1225. DesiredAccess - Supplies the access desired by the caller.
  1226. RequestorMode - Supplies the processor mode of the caller.
  1227. ppEntry - Returns the config group url tree entry for the namespace.
  1228. Return Value:
  1229. NTSTATUS.
  1230. --**************************************************************************/
  1231. NTSTATUS
  1232. UlpTreeAllocateNamespace(
  1233. IN PHTTP_PARSED_URL pParsedUrl,
  1234. IN HTTP_URL_OPERATOR_TYPE OperatorType,
  1235. IN PACCESS_STATE AccessState,
  1236. IN ACCESS_MASK DesiredAccess,
  1237. IN KPROCESSOR_MODE RequestorMode,
  1238. OUT PUL_CG_URL_TREE_ENTRY *ppEntry
  1239. )
  1240. {
  1241. NTSTATUS Status;
  1242. PUL_CG_URL_TREE_ENTRY pSiteEntry;
  1243. PUL_CG_URL_TREE_ENTRY pEntry;
  1244. PUL_CG_URL_TREE_ENTRY pReservation;
  1245. PWSTR pNextToken;
  1246. PSECURITY_DESCRIPTOR pSD;
  1247. //
  1248. // Sanity check.
  1249. //
  1250. PAGED_CODE();
  1251. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  1252. ASSERT(IS_VALID_HTTP_PARSED_URL(pParsedUrl));
  1253. ASSERT(ppEntry != NULL);
  1254. //
  1255. // Initialize return value.
  1256. //
  1257. *ppEntry = NULL;
  1258. //
  1259. // Find a matching site.
  1260. //
  1261. Status = UlpTreeFindSite(pParsedUrl->pFullUrl, &pNextToken, &pSiteEntry);
  1262. if (NT_SUCCESS(Status))
  1263. {
  1264. //
  1265. // Found a matching site.
  1266. //
  1267. //
  1268. // Find the longest matching reservation and exact matching entries.
  1269. //
  1270. Status = UlpTreeFindNodeHelper(
  1271. pSiteEntry,
  1272. pNextToken,
  1273. FNC_LONGEST_RESERVATION,
  1274. &pReservation,
  1275. &pEntry
  1276. );
  1277. if (NT_SUCCESS(Status))
  1278. {
  1279. //
  1280. // Found an exact match.
  1281. //
  1282. //
  1283. // Fail duplicate registrations and reservations.
  1284. //
  1285. ASSERT(IS_VALID_TREE_ENTRY(pEntry));
  1286. if (OperatorType == HttpUrlOperatorTypeRegistration)
  1287. {
  1288. if (pEntry->Registration == TRUE)
  1289. {
  1290. //
  1291. // Adding a registration when it already exists!
  1292. //
  1293. Status = STATUS_OBJECT_NAME_COLLISION;
  1294. goto end;
  1295. }
  1296. }
  1297. else if (OperatorType == HttpUrlOperatorTypeReservation)
  1298. {
  1299. if (pEntry->Reservation == TRUE)
  1300. {
  1301. //
  1302. // Adding a reservation when it already exists!
  1303. //
  1304. Status = STATUS_OBJECT_NAME_COLLISION;
  1305. goto end;
  1306. }
  1307. }
  1308. else
  1309. {
  1310. //
  1311. // Should not be here!
  1312. //
  1313. ASSERT(FALSE);
  1314. Status = STATUS_OBJECT_NAME_COLLISION;
  1315. goto end;
  1316. }
  1317. }
  1318. else
  1319. {
  1320. //
  1321. // Did not find an exact match.
  1322. //
  1323. pEntry = NULL;
  1324. }
  1325. //
  1326. // Find a security descriptor to check access against.
  1327. //
  1328. if (pReservation != NULL)
  1329. {
  1330. //
  1331. // Use the SD from the longest matching reservation entry.
  1332. //
  1333. ASSERT(IS_VALID_TREE_ENTRY(pReservation));
  1334. pSD = pReservation->pSecurityDescriptor;
  1335. }
  1336. else
  1337. {
  1338. //
  1339. // No longest matching reservations...use default SD.
  1340. //
  1341. pSD = g_pAdminAllSystemAll;
  1342. }
  1343. ASSERT(pSD != NULL && RtlValidSecurityDescriptor(pSD));
  1344. //
  1345. // Perform access check.
  1346. //
  1347. Status = UlpNamespaceAccessCheck(
  1348. pSD,
  1349. AccessState,
  1350. DesiredAccess,
  1351. RequestorMode,
  1352. pParsedUrl->pFullUrl
  1353. );
  1354. if (!NT_SUCCESS(Status))
  1355. {
  1356. //
  1357. // Ouch...
  1358. //
  1359. goto end;
  1360. }
  1361. }
  1362. else if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
  1363. {
  1364. //
  1365. // Adding a new site. Perform access check.
  1366. // Only admin and system can add new site.
  1367. //
  1368. Status = UlpNamespaceAccessCheck(
  1369. g_pAdminAllSystemAll,
  1370. AccessState,
  1371. DesiredAccess,
  1372. RequestorMode,
  1373. pParsedUrl->pFullUrl
  1374. );
  1375. if (!NT_SUCCESS(Status))
  1376. {
  1377. //
  1378. // Ouch...
  1379. //
  1380. goto end;
  1381. }
  1382. //
  1383. // The caller has permission to create a new site.
  1384. //
  1385. Status = UlpTreeCreateSite(
  1386. pParsedUrl->pFullUrl,
  1387. pParsedUrl->SiteType,
  1388. &pNextToken,
  1389. &pSiteEntry
  1390. );
  1391. if (!NT_SUCCESS(Status))
  1392. {
  1393. goto end;
  1394. }
  1395. //
  1396. // We have not found an exact entry.
  1397. // Note: If one tries to allocate http://site:80/ and site is not
  1398. // present, we'll create the site above. Now the pEntry
  1399. // is same as pSiteEntry. We don't handle the expection
  1400. // here and let the UlpTreeInsert() take care of it.
  1401. //
  1402. pEntry = NULL;
  1403. }
  1404. else
  1405. {
  1406. //
  1407. // Could not find the site for some reason.
  1408. //
  1409. goto end;
  1410. }
  1411. //
  1412. // If there is no exact matching entry, create one.
  1413. //
  1414. if (pEntry == NULL)
  1415. {
  1416. //
  1417. // Try to insert. This will cleanup dummy nodes and sites if it fails.
  1418. // Note: If UlpTreeInsert finds a existing entry, it just returns
  1419. // the existing entry and does not add a new one.
  1420. //
  1421. Status = UlpTreeInsert(
  1422. pParsedUrl->pFullUrl,
  1423. pParsedUrl->SiteType,
  1424. pNextToken,
  1425. pSiteEntry,
  1426. &pEntry
  1427. );
  1428. if (!NT_SUCCESS(Status))
  1429. {
  1430. goto end;
  1431. }
  1432. }
  1433. //
  1434. // Return the entry.
  1435. //
  1436. ASSERT(NT_SUCCESS(Status));
  1437. *ppEntry = pEntry;
  1438. end:
  1439. return Status;
  1440. }
  1441. /**************************************************************************++
  1442. Routine Description:
  1443. This routine reserves a namespace in the CG tree.
  1444. Arguments:
  1445. pParsedUrl - Supplies the parsed url of the namespace to be reserved.
  1446. pNextToken - Supplies the unparsed portion of the url (abs path.)
  1447. pUrlSD - Supplies the security descriptor to be applied to the
  1448. namespace.
  1449. pSiteEntry - Supplies the site level tree entry under which the
  1450. reservation will be made.
  1451. AccessState - Supplies the access state of the caller.
  1452. DesiredAccess - Supplies the access mask of the caller.
  1453. RequestorMode - Supplies the processor mode of the caller.
  1454. Retutn Value:
  1455. NTSTATUS.
  1456. --**************************************************************************/
  1457. NTSTATUS
  1458. UlpTreeReserveNamespace(
  1459. IN PHTTP_PARSED_URL pParsedUrl,
  1460. IN PSECURITY_DESCRIPTOR pUrlSD,
  1461. IN PACCESS_STATE AccessState,
  1462. IN ACCESS_MASK DesiredAccess,
  1463. IN KPROCESSOR_MODE RequestorMode
  1464. )
  1465. {
  1466. NTSTATUS Status;
  1467. PUL_CG_URL_TREE_ENTRY pEntry;
  1468. //
  1469. // Sanity check.
  1470. //
  1471. PAGED_CODE();
  1472. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  1473. ASSERT(IS_VALID_HTTP_PARSED_URL(pParsedUrl));
  1474. ASSERT(pUrlSD != NULL && RtlValidSecurityDescriptor(pUrlSD));
  1475. Status = UlpTreeAllocateNamespace(
  1476. pParsedUrl,
  1477. HttpUrlOperatorTypeReservation,
  1478. AccessState,
  1479. DesiredAccess,
  1480. RequestorMode,
  1481. &pEntry
  1482. );
  1483. if (!NT_SUCCESS(Status))
  1484. {
  1485. goto end;
  1486. }
  1487. //
  1488. // mark it as a reservation entry.
  1489. //
  1490. ASSERT(pEntry->Reservation == FALSE);
  1491. pEntry->Reservation = TRUE;
  1492. InsertTailList(&g_ReservationListHead, &pEntry->ReservationListEntry);
  1493. //
  1494. // add security descriptor.
  1495. //
  1496. ASSERT(pEntry->pSecurityDescriptor == NULL);
  1497. pEntry->pSecurityDescriptor = pUrlSD;
  1498. //
  1499. // all done
  1500. //
  1501. Status = STATUS_SUCCESS;
  1502. end:
  1503. return Status;
  1504. }
  1505. /**************************************************************************++
  1506. Routine Description:
  1507. The higher level routine calls helper routines to make a namespace
  1508. reservation.
  1509. Arguments:
  1510. pUrl - Supplies the namespace.
  1511. SiteType - Supplies the type of the url.
  1512. pUrlSD - Supplies the security descriptor to be applied to the
  1513. namespace.
  1514. AccessState - Supplies the access state of the caller.
  1515. DesiredAccess - Supplies the access mask of the caller.
  1516. RequestorMode - Supplies the processor mode of the caller.
  1517. Return Value:
  1518. NTSTATUS.
  1519. --**************************************************************************/
  1520. NTSTATUS
  1521. UlpReserveUrlNamespace(
  1522. IN PHTTP_PARSED_URL pParsedUrl,
  1523. IN PSECURITY_DESCRIPTOR pUrlSD,
  1524. IN PACCESS_STATE AccessState,
  1525. IN ACCESS_MASK DesiredAccess,
  1526. IN KPROCESSOR_MODE RequestorMode
  1527. )
  1528. {
  1529. NTSTATUS Status;
  1530. //
  1531. // Sanity check.
  1532. //
  1533. PAGED_CODE();
  1534. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  1535. ASSERT(pParsedUrl != NULL);
  1536. ASSERT(pUrlSD != NULL);
  1537. ASSERT(RtlValidSecurityDescriptor(pUrlSD));
  1538. //
  1539. // Don't allow reservation of urls with different schemes but same port
  1540. // number. For instance, if http://www.microsoft.com:80/ is reserved,
  1541. // then don't allow reservation of https://anyhostname:80/. Because
  1542. // these different schemes can not share the same port.
  1543. //
  1544. Status = UlpBindSchemeToPort(pParsedUrl->Secure, pParsedUrl->PortNumber);
  1545. if (!NT_SUCCESS(Status))
  1546. {
  1547. goto end;
  1548. }
  1549. //
  1550. // Proceed to the actual reservation.
  1551. //
  1552. Status = UlpTreeReserveNamespace(
  1553. pParsedUrl,
  1554. pUrlSD,
  1555. AccessState,
  1556. DesiredAccess,
  1557. RequestorMode
  1558. );
  1559. if (!NT_SUCCESS(Status))
  1560. {
  1561. //
  1562. // The reservation failed. Undo the binding done above.
  1563. //
  1564. NTSTATUS TempStatus;
  1565. TempStatus = UlpUnbindSchemeFromPort(
  1566. pParsedUrl->Secure,
  1567. pParsedUrl->PortNumber
  1568. );
  1569. ASSERT(NT_SUCCESS(TempStatus));
  1570. }
  1571. end:
  1572. return Status;
  1573. }
  1574. /**************************************************************************++
  1575. Routine Description:
  1576. This routine allocates a UL_DEFERRED_REMOVE_ITEM and initializes
  1577. it with port number and scheme. Caller must free it to the paged
  1578. pool.
  1579. Arguments:
  1580. pParsedUrl - Supplies the parsed url containing scheme and port number.
  1581. Return Value:
  1582. PUL_DEFERRED_REMOVE_ITEM - if successful.
  1583. NULL - otherwise.
  1584. --**************************************************************************/
  1585. __inline
  1586. PUL_DEFERRED_REMOVE_ITEM
  1587. UlpAllocateDeferredRemoveItem(
  1588. IN PHTTP_PARSED_URL pParsedUrl
  1589. )
  1590. {
  1591. PUL_DEFERRED_REMOVE_ITEM pWorker;
  1592. //
  1593. // Sanity check.
  1594. //
  1595. PAGED_CODE();
  1596. ASSERT(pParsedUrl != NULL);
  1597. //
  1598. // Allocate the structure.
  1599. //
  1600. pWorker = UL_ALLOCATE_STRUCT(
  1601. PagedPool,
  1602. UL_DEFERRED_REMOVE_ITEM,
  1603. UL_DEFERRED_REMOVE_ITEM_POOL_TAG
  1604. );
  1605. if (pWorker == NULL)
  1606. {
  1607. return NULL;
  1608. }
  1609. //
  1610. // Initialize the structure.
  1611. //
  1612. pWorker->Signature = UL_DEFERRED_REMOVE_ITEM_POOL_TAG;
  1613. pWorker->UrlSecure = pParsedUrl->Secure;
  1614. pWorker->UrlPort = pParsedUrl->PortNumber;
  1615. return pWorker;
  1616. }
  1617. /**************************************************************************++
  1618. Routine Description:
  1619. This routine does the actual reservation in the CG tree.
  1620. Arguments:
  1621. pParsedUrl - Supplies the parsed url of the namespace to be reserverd.
  1622. pNextToken - Supplies the unparsed portion of the url.
  1623. UrlContext - Supplies an opaque associated with this url.
  1624. pConfigObject - Supplies a pointer to the config group to which the
  1625. url belongs.
  1626. pSiteEntry - Supplies a pointer to the site node.
  1627. AccessState - Supplies access state of the caller.
  1628. DesiredAccess - Supplies access mask of the caller.
  1629. RequestorMode - Supplies the processor mode of the caller.
  1630. Return Value:
  1631. NTSTATUS.
  1632. --**************************************************************************/
  1633. NTSTATUS
  1634. UlpTreeRegisterNamespace(
  1635. IN PHTTP_PARSED_URL pParsedUrl,
  1636. IN HTTP_URL_CONTEXT UrlContext,
  1637. IN PUL_CONFIG_GROUP_OBJECT pConfigObject,
  1638. IN PACCESS_STATE AccessState,
  1639. IN ACCESS_MASK DesiredAccess,
  1640. IN KPROCESSOR_MODE RequestorMode
  1641. )
  1642. {
  1643. NTSTATUS Status;
  1644. PUL_CG_URL_TREE_ENTRY pEntry;
  1645. //
  1646. // Sanity check.
  1647. //
  1648. PAGED_CODE();
  1649. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  1650. ASSERT(pParsedUrl != NULL);
  1651. ASSERT(AccessState != NULL);
  1652. ASSERT(RequestorMode == UserMode);
  1653. Status = UlpTreeAllocateNamespace(
  1654. pParsedUrl,
  1655. HttpUrlOperatorTypeRegistration,
  1656. AccessState,
  1657. DesiredAccess,
  1658. RequestorMode,
  1659. &pEntry
  1660. );
  1661. if (!NT_SUCCESS(Status))
  1662. {
  1663. goto end;
  1664. }
  1665. //
  1666. // mark the site
  1667. //
  1668. ASSERT(pEntry->Registration == FALSE);
  1669. pEntry->Registration = TRUE;
  1670. //
  1671. // context associated with this url
  1672. //
  1673. pEntry->UrlContext = UrlContext;
  1674. //
  1675. // link the cfg group + the url
  1676. //
  1677. ASSERT(pEntry->pConfigGroup == NULL);
  1678. ASSERT(pEntry->ConfigGroupListEntry.Flink == NULL);
  1679. pEntry->pConfigGroup = pConfigObject;
  1680. InsertTailList(&pConfigObject->UrlListHead, &pEntry->ConfigGroupListEntry);
  1681. //
  1682. // Sanity check.
  1683. //
  1684. ASSERT(pEntry->pRemoveSiteWorkItem == NULL);
  1685. ASSERT(pEntry->SiteAddedToEndpoint == FALSE);
  1686. //
  1687. // Allocate a work item (initialization is done during allocation.)
  1688. //
  1689. Status = STATUS_INSUFFICIENT_RESOURCES;
  1690. pEntry->pRemoveSiteWorkItem = UlpAllocateDeferredRemoveItem(pParsedUrl);
  1691. if (pEntry->pRemoveSiteWorkItem != NULL)
  1692. {
  1693. //
  1694. // Allocation succeeded. Now add pEntry to endpoint list.
  1695. //
  1696. ASSERT(IS_VALID_DEFERRED_REMOVE_ITEM(pEntry->pRemoveSiteWorkItem));
  1697. Status = UlAddSiteToEndpointList(pParsedUrl);
  1698. if (NT_SUCCESS(Status))
  1699. {
  1700. //
  1701. // Remember that this entry was added to endpoint list.
  1702. //
  1703. pEntry->SiteAddedToEndpoint = TRUE;
  1704. }
  1705. }
  1706. if (!NT_SUCCESS(Status))
  1707. {
  1708. //
  1709. // Something went wrong. Need to cleanup this entry.
  1710. //
  1711. NTSTATUS TempStatus;
  1712. ASSERT(pEntry->SiteAddedToEndpoint == FALSE);
  1713. //
  1714. // Free work item.
  1715. //
  1716. if (pEntry->pRemoveSiteWorkItem != NULL)
  1717. {
  1718. ASSERT(IS_VALID_DEFERRED_REMOVE_ITEM(pEntry->pRemoveSiteWorkItem));
  1719. UL_FREE_POOL(
  1720. pEntry->pRemoveSiteWorkItem,
  1721. UL_DEFERRED_REMOVE_ITEM_POOL_TAG
  1722. );
  1723. pEntry->pRemoveSiteWorkItem = NULL;
  1724. pEntry->SiteAddedToEndpoint = FALSE;
  1725. }
  1726. //
  1727. // Delete the registration.
  1728. //
  1729. TempStatus = UlpTreeDeleteRegistration(pEntry);
  1730. ASSERT(NT_SUCCESS(TempStatus));
  1731. }
  1732. end:
  1733. return Status;
  1734. }
  1735. /**************************************************************************++
  1736. Routine Description:
  1737. This routine is called for registering a namespace.
  1738. Arguments:
  1739. pParsedUrl - Supplies the parsed url of the namespace to be reserverd.
  1740. UrlContext - Supplies an opaque associated with this url.
  1741. pConfigObject - Supplies a pointer to the config group to which the
  1742. url belongs.
  1743. AccessState - Supplies access state of the caller.
  1744. DesiredAccess - Supplies access mask of the caller.
  1745. RequestorMode - Supplies the processor mode of the caller.
  1746. Return Value:
  1747. --**************************************************************************/
  1748. NTSTATUS
  1749. UlpRegisterUrlNamespace(
  1750. IN PHTTP_PARSED_URL pParsedUrl,
  1751. IN HTTP_URL_CONTEXT UrlContext,
  1752. IN PUL_CONFIG_GROUP_OBJECT pConfigObject,
  1753. IN PACCESS_STATE AccessState,
  1754. IN ACCESS_MASK DesiredAccess,
  1755. IN KPROCESSOR_MODE RequestorMode
  1756. )
  1757. {
  1758. NTSTATUS Status;
  1759. BOOLEAN Secure;
  1760. //
  1761. // Sanity check.
  1762. //
  1763. PAGED_CODE();
  1764. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  1765. ASSERT(pParsedUrl != NULL);
  1766. ASSERT(pConfigObject != NULL);
  1767. ASSERT(AccessState != NULL);
  1768. ASSERT(RequestorMode == UserMode);
  1769. //
  1770. // If there are any reservations on for a different scheme on the same
  1771. // port, then fail this registration.
  1772. //
  1773. Status = UlpQuerySchemeForPort(pParsedUrl->PortNumber, &Secure);
  1774. if (NT_SUCCESS(Status) && Secure != pParsedUrl->Secure)
  1775. {
  1776. //
  1777. // Ouch...
  1778. //
  1779. Status = STATUS_OBJECT_NAME_COLLISION;
  1780. goto end;
  1781. }
  1782. //
  1783. // Add actual registration.
  1784. //
  1785. Status = UlpTreeRegisterNamespace(
  1786. pParsedUrl,
  1787. UrlContext,
  1788. pConfigObject,
  1789. AccessState,
  1790. DesiredAccess,
  1791. RequestorMode
  1792. );
  1793. end:
  1794. return Status;
  1795. }
  1796. /**************************************************************************++
  1797. Routine Description:
  1798. Given a security descriptor, this routine returns two security
  1799. descriptors. One (called captured security descriptor), is the
  1800. the caputured and validated version of the input security descriptor.
  1801. The other (call prepared security descriptor), is a copy of the
  1802. captured security descriptor with the generic access mask bits
  1803. in the DACL mapped.
  1804. Arguments:
  1805. pInSecurityDescriptor - Supplies the input security descriptor to
  1806. prepare.
  1807. RequestorMode - Supplies the processor mode of the caller.
  1808. ppPreparedSecurityDescriptor - Returns a security descriptor that is
  1809. captured and mapped.
  1810. ppCapturedSecurityDescriptor - Returns the captued security descriptor.
  1811. pCapturedSecurityDescriptorLength - Returns the length of the captured
  1812. security descriptor.
  1813. Return Value:
  1814. NTSTATUS.
  1815. --**************************************************************************/
  1816. NTSTATUS
  1817. UlpPrepareSecurityDescriptor(
  1818. IN PSECURITY_DESCRIPTOR pInSecurityDescriptor,
  1819. IN KPROCESSOR_MODE RequestorMode,
  1820. OUT PSECURITY_DESCRIPTOR * ppPreparedSecurityDescriptor,
  1821. OUT PSECURITY_DESCRIPTOR * ppCapturedSecurityDescriptor,
  1822. OUT PULONG pCapturedSecurityDescriptorLength
  1823. )
  1824. {
  1825. NTSTATUS Status;
  1826. PSECURITY_DESCRIPTOR pSD;
  1827. ULONG SDLength;
  1828. PSECURITY_DESCRIPTOR pPreparedSD;
  1829. //
  1830. // Sanity check.
  1831. //
  1832. PAGED_CODE();
  1833. ASSERT(pInSecurityDescriptor != NULL);
  1834. ASSERT(ppPreparedSecurityDescriptor != NULL);
  1835. ASSERT(ppCapturedSecurityDescriptor != NULL);
  1836. ASSERT(pCapturedSecurityDescriptorLength != NULL);
  1837. //
  1838. // Initialize locals.
  1839. //
  1840. pSD = NULL; // Caputured security descriptor
  1841. SDLength = 0; // Caputured security descriptor length
  1842. pPreparedSD = NULL;
  1843. //
  1844. // First capture the security descriptor.
  1845. //
  1846. Status = SeCaptureSecurityDescriptor(
  1847. pInSecurityDescriptor,
  1848. RequestorMode,
  1849. PagedPool,
  1850. TRUE, // force capture
  1851. &pSD
  1852. );
  1853. if (!NT_SUCCESS(Status))
  1854. {
  1855. pSD = NULL;
  1856. goto end;
  1857. }
  1858. //
  1859. // Now validate the security descriptor.
  1860. //
  1861. if (!RtlValidSecurityDescriptor(pSD))
  1862. {
  1863. Status = STATUS_INVALID_PARAMETER;
  1864. goto end;
  1865. }
  1866. //
  1867. // Calculate the length of the security descriptor.
  1868. //
  1869. SDLength = RtlLengthSecurityDescriptor(pSD);
  1870. //
  1871. // Make sure that the security descriptor is self-relative.
  1872. //
  1873. if (!RtlValidRelativeSecurityDescriptor(pSD, SDLength, 0))
  1874. {
  1875. Status = STATUS_INVALID_PARAMETER;
  1876. goto end;
  1877. }
  1878. //
  1879. // Make a copy of the captured security descriptor.
  1880. //
  1881. Status = SeCaptureSecurityDescriptor(
  1882. pSD,
  1883. KernelMode,
  1884. PagedPool,
  1885. TRUE, // force capture
  1886. &pPreparedSD
  1887. );
  1888. if (!NT_SUCCESS(Status))
  1889. {
  1890. pPreparedSD = NULL;
  1891. goto end;
  1892. }
  1893. //
  1894. // Map generic access to url namespace specific rights.
  1895. //
  1896. Status = UlMapGenericMask(pPreparedSD);
  1897. if (!NT_SUCCESS(Status))
  1898. {
  1899. goto end;
  1900. }
  1901. end:
  1902. if (!NT_SUCCESS(Status))
  1903. {
  1904. //
  1905. // If necessary, cleanup.
  1906. //
  1907. if (pSD != NULL)
  1908. {
  1909. SeReleaseSecurityDescriptor(pSD, RequestorMode, TRUE);
  1910. }
  1911. if (pPreparedSD != NULL)
  1912. {
  1913. SeReleaseSecurityDescriptor(pPreparedSD, KernelMode, TRUE);
  1914. }
  1915. *ppPreparedSecurityDescriptor = NULL;
  1916. *ppCapturedSecurityDescriptor = NULL;
  1917. *pCapturedSecurityDescriptorLength = 0;
  1918. }
  1919. else
  1920. {
  1921. //
  1922. // Return values.
  1923. //
  1924. *ppPreparedSecurityDescriptor = pPreparedSD;
  1925. *ppCapturedSecurityDescriptor = pSD;
  1926. *pCapturedSecurityDescriptorLength = SDLength;
  1927. }
  1928. return Status;
  1929. }
  1930. /***************************************************************************++
  1931. Routine Description:
  1932. This routine adds a reservation entry to the CG tree and optionally to
  1933. registry.
  1934. Arguments:
  1935. pParsedUrl - Supplies the parsed url of the namespace to be reserved.
  1936. pUserSecurityDescriptor - Supplies the security descriptor to be applied
  1937. to the namespace.
  1938. SecurityDescriptorLength - Supplies the length of the security
  1939. descriptor.
  1940. AccessState - Supplies the access state of the caller.
  1941. DesiredAccess - Supplies the access mask of the caller.
  1942. RequestorMode - Supplies the mode of the caller.
  1943. bPersiste - Supplies the flag to force a write to the registry.
  1944. Return Value:
  1945. NTSTATUS.
  1946. --***************************************************************************/
  1947. NTSTATUS
  1948. UlpAddReservationEntry(
  1949. IN PHTTP_PARSED_URL pParsedUrl,
  1950. IN PSECURITY_DESCRIPTOR pUserSecurityDescriptor,
  1951. IN ULONG SecurityDescriptorLength,
  1952. IN PACCESS_STATE AccessState,
  1953. IN ACCESS_MASK DesiredAccess,
  1954. IN KPROCESSOR_MODE RequestorMode,
  1955. IN BOOLEAN bPersist
  1956. )
  1957. {
  1958. NTSTATUS Status;
  1959. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  1960. PSECURITY_DESCRIPTOR pCapturedSecurityDescriptor;
  1961. ULONG CapturedSecurityDescriptorLength;
  1962. UNREFERENCED_PARAMETER(SecurityDescriptorLength);
  1963. //
  1964. // Sanity check.
  1965. //
  1966. PAGED_CODE();
  1967. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  1968. ASSERT(IS_VALID_HTTP_PARSED_URL(pParsedUrl));
  1969. //
  1970. // Prepare security descriptor.
  1971. //
  1972. Status = UlpPrepareSecurityDescriptor(
  1973. pUserSecurityDescriptor,
  1974. RequestorMode,
  1975. &pSecurityDescriptor,
  1976. &pCapturedSecurityDescriptor,
  1977. &CapturedSecurityDescriptorLength
  1978. );
  1979. if (!NT_SUCCESS(Status))
  1980. {
  1981. pSecurityDescriptor = NULL;
  1982. pCapturedSecurityDescriptor = NULL;
  1983. CapturedSecurityDescriptorLength = 0;
  1984. goto Cleanup;
  1985. }
  1986. //
  1987. // Try reserving for the namespace.
  1988. //
  1989. Status = UlpReserveUrlNamespace(
  1990. pParsedUrl,
  1991. pSecurityDescriptor,
  1992. AccessState,
  1993. DesiredAccess,
  1994. RequestorMode
  1995. );
  1996. if (!NT_SUCCESS(Status))
  1997. {
  1998. goto Cleanup;
  1999. }
  2000. //
  2001. // Security descriptor will be freed with the reservation entry.
  2002. //
  2003. pSecurityDescriptor = NULL;
  2004. //
  2005. // If we are required to write this entry to registry, do it now.
  2006. //
  2007. if (bPersist)
  2008. {
  2009. //
  2010. // Use the captured security descriptor while writing to the
  2011. // registry.
  2012. //
  2013. Status = UlpUpdateReservationInRegistry(
  2014. TRUE,
  2015. pParsedUrl,
  2016. pCapturedSecurityDescriptor,
  2017. CapturedSecurityDescriptorLength
  2018. );
  2019. if (!NT_SUCCESS(Status))
  2020. {
  2021. //
  2022. // failed to write to registry. now delete reservation.
  2023. //
  2024. UlpDeleteReservationEntry(
  2025. pParsedUrl,
  2026. AccessState,
  2027. DesiredAccess,
  2028. RequestorMode
  2029. );
  2030. }
  2031. else
  2032. {
  2033. //
  2034. // Successful reservation. Write an event log entry.
  2035. //
  2036. UlEventLogOneStringEntry(
  2037. EVENT_HTTP_NAMESPACE_RESERVED,
  2038. pParsedUrl->pFullUrl,
  2039. FALSE, // don't write error code
  2040. STATUS_SUCCESS // don't care
  2041. );
  2042. }
  2043. }
  2044. Cleanup:
  2045. if (!NT_SUCCESS(Status) && pSecurityDescriptor != NULL)
  2046. {
  2047. SeReleaseSecurityDescriptor(pSecurityDescriptor, RequestorMode, TRUE);
  2048. }
  2049. if (pCapturedSecurityDescriptor != NULL)
  2050. {
  2051. SeReleaseSecurityDescriptor(
  2052. pCapturedSecurityDescriptor,
  2053. KernelMode,
  2054. TRUE
  2055. );
  2056. }
  2057. return Status;
  2058. }
  2059. /**************************************************************************++
  2060. Routine Description:
  2061. This routine delete a valid reservation both from CG tree and registry.
  2062. Arguments:
  2063. pParsedUrl - Supplies parsed url of the reservation to be deleted.
  2064. AccessState - Supplies the access state of the caller.
  2065. DesiredAccess - Supplies the access mask of the caller.
  2066. RequestorMode - Supplies the processor mode of the caller.
  2067. Return Value:
  2068. NTSTATUS.
  2069. --**************************************************************************/
  2070. NTSTATUS
  2071. UlpDeleteReservationEntry(
  2072. IN PHTTP_PARSED_URL pParsedUrl,
  2073. IN PACCESS_STATE AccessState,
  2074. IN ACCESS_MASK DesiredAccess,
  2075. IN KPROCESSOR_MODE RequestorMode
  2076. )
  2077. {
  2078. NTSTATUS Status;
  2079. PUL_CG_URL_TREE_ENTRY pEntry;
  2080. PUL_CG_URL_TREE_ENTRY pAncestor;
  2081. PSECURITY_DESCRIPTOR pSD;
  2082. //
  2083. // Sanity check.
  2084. //
  2085. PAGED_CODE();
  2086. ASSERT(IS_CG_LOCK_OWNED_WRITE());
  2087. ASSERT(IS_VALID_HTTP_PARSED_URL(pParsedUrl));
  2088. ASSERT(AccessState != NULL);
  2089. ASSERT(RequestorMode == UserMode);
  2090. //
  2091. // Find the reservation entry.
  2092. //
  2093. Status = UlpTreeFindReservationNode(pParsedUrl->pFullUrl, &pEntry);
  2094. if (!NT_SUCCESS(Status))
  2095. {
  2096. //
  2097. // Too bad...did not find a matching entry.
  2098. //
  2099. goto end;
  2100. }
  2101. //
  2102. // Sanity check.
  2103. //
  2104. ASSERT(IS_VALID_TREE_ENTRY(pEntry));
  2105. ASSERT(pEntry->Reservation == TRUE);
  2106. //
  2107. // Find the closest ancestor that is a reservation.
  2108. //
  2109. pAncestor = pEntry->pParent;
  2110. while (pAncestor != NULL && pAncestor->Reservation == FALSE)
  2111. {
  2112. pAncestor = pAncestor->pParent;
  2113. }
  2114. //
  2115. // Did we find a suitable ancestor?
  2116. //
  2117. if (pAncestor == NULL)
  2118. {
  2119. //
  2120. // Nope. Assume the default security descriptor.
  2121. //
  2122. pSD = g_pAdminAllSystemAll;
  2123. }
  2124. else
  2125. {
  2126. //
  2127. // Good. We found an ancestor reservation. Pick sd from there.
  2128. //
  2129. ASSERT(IS_VALID_TREE_ENTRY(pAncestor));
  2130. ASSERT(pAncestor->Reservation == TRUE);
  2131. ASSERT(pAncestor->pSecurityDescriptor != NULL);
  2132. pSD = pAncestor->pSecurityDescriptor;
  2133. }
  2134. //
  2135. // Sanity check.
  2136. //
  2137. ASSERT(pSD != NULL && RtlValidSecurityDescriptor(pSD));
  2138. //
  2139. // Perform access check.
  2140. //
  2141. Status = UlpNamespaceAccessCheck(
  2142. pSD,
  2143. AccessState,
  2144. DesiredAccess,
  2145. RequestorMode,
  2146. pParsedUrl->pFullUrl
  2147. );
  2148. if (NT_SUCCESS(Status))
  2149. {
  2150. //
  2151. // Permission granted. Delete the reservation from registry.
  2152. //
  2153. Status = UlpUpdateReservationInRegistry(
  2154. FALSE, // delete
  2155. pParsedUrl, // url to delete
  2156. NULL, // must be NULL
  2157. 0 // must be 0
  2158. );
  2159. if (NT_SUCCESS(Status))
  2160. {
  2161. //
  2162. // Remove the reservation from the CG url tree.
  2163. //
  2164. Status = UlpTreeDeleteReservation(pEntry);
  2165. ASSERT(NT_SUCCESS(Status));
  2166. //
  2167. // Successful deletion. Now unbind the scheme from port.
  2168. //
  2169. Status = UlpUnbindSchemeFromPort(
  2170. pParsedUrl->Secure,
  2171. pParsedUrl->PortNumber
  2172. );
  2173. ASSERT(NT_SUCCESS(Status));
  2174. //
  2175. // Successful deletion. Write an event log entry.
  2176. //
  2177. UlEventLogOneStringEntry(
  2178. EVENT_HTTP_NAMESPACE_DERESERVED,
  2179. pParsedUrl->pFullUrl,
  2180. FALSE, // don't write error code
  2181. STATUS_SUCCESS // unused
  2182. );
  2183. }
  2184. }
  2185. end:
  2186. return Status;
  2187. }