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

659 lines
18 KiB

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name :
  4. virtroot.cxx
  5. Abstract:
  6. This module defines functions for managing virtual roots.
  7. Author:
  8. ??? ( ???) ??-??-1994/5
  9. Environment:
  10. User Mode -- Win32
  11. Project:
  12. TSunami DLL for Internet Services
  13. Functions Exported:
  14. Revision History:
  15. MuraliK Added File System type to information stored about
  16. each virtual root.
  17. MuraliK Modified TsLookupVirtualRoot() to support variable
  18. length buffer and hence check for invalid writes
  19. MuraliK 22-Jan-1996 Cache & return UNC virtual root impersonation
  20. token.
  21. --*/
  22. /************************************************************
  23. * Include Headers
  24. ************************************************************/
  25. #include "TsunamiP.Hxx"
  26. #pragma hdrstop
  27. #include <mbstring.h>
  28. #include <rpc.h>
  29. #include <rpcndr.h>
  30. #include "dbgutil.h"
  31. #include <string.h>
  32. #include <refb.hxx>
  33. #include <imd.h>
  34. #include <mb.hxx>
  35. #include <iiscnfg.h>
  36. IIS_VROOT_TABLE::IIS_VROOT_TABLE(
  37. VOID
  38. )
  39. :
  40. m_nVroots (0 )
  41. {
  42. InitializeCriticalSection( &m_csLock );
  43. InitializeListHead( &m_vrootListHead );
  44. } // IIS_VROOT_TABLE::IIS_VROOT_TABLE
  45. IIS_VROOT_TABLE::~IIS_VROOT_TABLE(
  46. VOID
  47. )
  48. {
  49. RemoveVirtualRoots( );
  50. DeleteCriticalSection( &m_csLock );
  51. DBG_ASSERT( m_nVroots == 0 );
  52. DBG_ASSERT( IsListEmpty( &m_vrootListHead ) );
  53. } // IIS_VROOT_TABLE::~IIS_VROOT_TABLE
  54. BOOL
  55. IIS_VROOT_TABLE::AddVirtualRoot(
  56. PCHAR pszRoot,
  57. PCHAR pszDirectory,
  58. DWORD dwAccessMask,
  59. PCHAR pszAccountName,
  60. HANDLE hImpersonationToken,
  61. DWORD dwFileSystem
  62. )
  63. /*++
  64. Description:
  65. This function adds a symbolic link root and directory mapping
  66. part to the virtual root list
  67. We always strip trailing slashes from the root and directory name.
  68. If the root is "\" or "/", then the effective root will be zero
  69. length and will always be placed last in the list. Thus if a lookup
  70. can't find a match, it will always match the last entry.
  71. Arguments:
  72. pszRoot - Virtual symbolic link root
  73. pszDirectory - Physical directory
  74. dwAccessMask - Type of access allowed on this virtual root
  75. pszAccountName - User name to impersonate if UNC (only gets stored
  76. for RPC apis)
  77. hImpersonationToken - Impersonation token to use for UNC
  78. directory paths
  79. dwFileSystem - DWORD containing the file system type
  80. ( symbolic constant)
  81. Returns:
  82. TRUE on success and FALSE if any failure.
  83. --*/
  84. {
  85. PVIRTUAL_ROOT_MAPPING pVrm, pVrmOld;
  86. PDIRECTORY_CACHING_INFO pDci;
  87. PLIST_ENTRY pEntry;
  88. BOOL fRet = FALSE;
  89. BOOL fUNC;
  90. DWORD cchRoot;
  91. if ( !pszRoot || !*pszRoot || !pszDirectory || !*pszDirectory )
  92. {
  93. SetLastError( ERROR_INVALID_PARAMETER );
  94. return FALSE;
  95. }
  96. //
  97. // Disallow allow UNC roots if we don't have an impersonation token and
  98. // this isn't a placeholder
  99. //
  100. fUNC = (BOOL)((pszDirectory[0] == '\\') && (pszDirectory[1] == '\\'));
  101. //
  102. // Strip the trailing '/' from the virtual root
  103. //
  104. cchRoot = strlen( pszRoot );
  105. if ( IS_CHAR_TERM_A( pszRoot, cchRoot - 1))
  106. {
  107. pszRoot[--cchRoot] = '\0';
  108. }
  109. //
  110. // Look in the current list and see if the root is already there.
  111. // If the directory is the same, we just return success. If the
  112. // directory is different, we remove the old item and add the new one.
  113. //
  114. LockTable();
  115. for ( pEntry = m_vrootListHead.Flink;
  116. pEntry != &m_vrootListHead;
  117. pEntry = pEntry->Flink )
  118. {
  119. pVrm = CONTAINING_RECORD( pEntry, VIRTUAL_ROOT_MAPPING, TableListEntry );
  120. //
  121. // If we have a match up to the length of the previously added root
  122. // and the new item is a true match (as opposed to a matching prefix)
  123. // and the matching item isn't the default root (which matches against
  124. // everything cause it's zero length)
  125. //
  126. if ( (cchRoot == pVrm->cchRootA) &&
  127. !_mbsnicmp( (PUCHAR)pszRoot, (PUCHAR)pVrm->pszRootA, _mbslen((PUCHAR)pVrm->pszRootA) ) &&
  128. IS_CHAR_TERM_A( pszRoot, pVrm->cchRootA ) &&
  129. ((pVrm->cchRootA != 0) || (cchRoot == 0)) )
  130. {
  131. if ( !lstrcmpi( pszDirectory, pVrm->pszDirectoryA ) &&
  132. IS_CHAR_TERM_A( pszDirectory, pVrm->cchDirectoryA ))
  133. {
  134. //
  135. // This root is already in the list
  136. //
  137. UnlockTable();
  138. return TRUE;
  139. } else{
  140. //
  141. // A root is having its directory entry changed
  142. //
  143. //
  144. // If last item on this dir, need to remove from list(s?),
  145. // free dir handle, free memory
  146. //
  147. UnlockTable();
  148. SetLastError( ERROR_NOT_SUPPORTED );
  149. return FALSE;
  150. }
  151. }
  152. }
  153. UnlockTable();
  154. pVrm = ( PVIRTUAL_ROOT_MAPPING )ALLOC( sizeof( VIRTUAL_ROOT_MAPPING ) +
  155. sizeof( DIRECTORY_CACHING_INFO ));
  156. pDci = ( PDIRECTORY_CACHING_INFO)( pVrm+1 );
  157. if ( pVrm == NULL )
  158. {
  159. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  160. return FALSE;
  161. }
  162. //
  163. // Initialize the new root item
  164. //
  165. pVrm->Signature = VIRT_ROOT_SIGNATURE;
  166. pVrm->cchRootA = strlen( pszRoot );
  167. pVrm->cchDirectoryA = strlen( pszDirectory );
  168. pVrm->dwFileSystem = dwFileSystem;
  169. pVrm->dwAccessMask = dwAccessMask;
  170. InitializeListHead(&pVrm->GlobalListEntry);
  171. pDci->hDirectoryFile = NULL;
  172. pDci->fOnSystemNotifyList = FALSE;
  173. pVrm->fCachingAllowed = FALSE;
  174. pVrm->fUNC = fUNC;
  175. pVrm->fDeleted = FALSE;
  176. pVrm->hImpersonationToken = hImpersonationToken;
  177. //
  178. // Set the initial reference count to 2. Once when TsRemoveVirtualRoots
  179. // is called and once when the Apc completes
  180. //
  181. pVrm->cRef = 2;
  182. strcpy( pVrm->pszRootA, pszRoot );
  183. strcpy( pVrm->pszDirectoryA, pszDirectory );
  184. strcpy( pVrm->pszAccountName, pszAccountName ? pszAccountName : "" );
  185. //
  186. // Strip trailing slashes from the root and directory
  187. //
  188. if ( (pVrm->cchRootA != 0) &&
  189. IS_CHAR_TERM_A( pVrm->pszRootA, pVrm->cchRootA - 1 ))
  190. {
  191. pVrm->pszRootA[--pVrm->cchRootA] = '\0';
  192. }
  193. if ( IS_CHAR_TERM_A( pVrm->pszDirectoryA, pVrm->cchDirectoryA - 1))
  194. {
  195. //
  196. // Note we assume virtual directories always begin with a '/...' to
  197. // provide the necessary path separator between the root directory
  198. // path and the remaining virtual directory
  199. //
  200. pVrm->pszDirectoryA[--pVrm->cchDirectoryA] = '\0';
  201. }
  202. //
  203. // Add the item to the list
  204. //
  205. LockTable();
  206. //
  207. // If the root is zero length, then it will match all occurrences so put
  208. // it last. Note this is useful for default root entries (such as "/").
  209. //
  210. if ( pVrm->cchRootA == 0 ) {
  211. //
  212. // Roots that specify an address go in front of roots that do not
  213. // thus giving precedence to matching roots w/ addresses
  214. //
  215. InsertTailList( &m_vrootListHead, &pVrm->TableListEntry );
  216. } else {
  217. //
  218. // Insert the virtual root in descending length of their
  219. // virtual root name, i.e.,
  220. //
  221. // /abc/123, /abc/12, /abc, /a
  222. //
  223. // This ensures matches occur on the longest possible virtual root
  224. //
  225. for ( pEntry = m_vrootListHead.Flink;
  226. pEntry != &m_vrootListHead;
  227. pEntry = pEntry->Flink )
  228. {
  229. pVrmOld = CONTAINING_RECORD( pEntry,
  230. VIRTUAL_ROOT_MAPPING,
  231. TableListEntry );
  232. if ( pVrmOld->cchRootA < pVrm->cchRootA )
  233. {
  234. pVrm->TableListEntry.Flink = pEntry;
  235. pVrm->TableListEntry.Blink = pEntry->Blink;
  236. pEntry->Blink->Flink = &pVrm->TableListEntry;
  237. pEntry->Blink = &pVrm->TableListEntry;
  238. goto Added;
  239. }
  240. }
  241. //
  242. // There aren't any named roots so put this root
  243. // at the beginning
  244. //
  245. InsertHeadList( &m_vrootListHead, &pVrm->TableListEntry );
  246. }
  247. Added:
  248. if ( !(fRet = DcmAddRoot( pVrm ))) {
  249. RemoveEntryList( &pVrm->TableListEntry );
  250. UnlockTable();
  251. goto Failure;
  252. }
  253. m_nVroots++;
  254. UnlockTable();
  255. IF_DEBUG( VIRTUAL_ROOTS )
  256. DBGPRINTF(( DBG_CONTEXT,
  257. " - %s => %s\n",
  258. pVrm->pszRootA,
  259. pVrm->pszDirectoryA ));
  260. return TRUE;
  261. Failure:
  262. DBGPRINTF(( DBG_CONTEXT,
  263. " Error %d adding - %s => %s\n",
  264. GetLastError(),
  265. pVrm->pszRootA,
  266. pVrm->pszDirectoryA ));
  267. FREE( pVrm );
  268. return fRet;
  269. } // IIS_VROOT_TABLE::AddVirtualRoot
  270. BOOL
  271. IIS_VROOT_TABLE::LookupVirtualRoot(
  272. IN const CHAR * pszVirtPath,
  273. OUT CHAR * pszDirectory,
  274. IN OUT LPDWORD lpcbSize,
  275. OUT LPDWORD lpdwAccessMask, // Optional
  276. OUT LPDWORD pcchDirRoot, // Optional
  277. OUT LPDWORD pcchVRoot, // Optional
  278. OUT HANDLE * phImpersonationToken, // Optional
  279. OUT LPDWORD lpdwFileSystem // Optional
  280. )
  281. /*++
  282. Description:
  283. This function looks in the map list for the specified root
  284. and returns the corresponding directory
  285. Arguments:
  286. pszVirtPath - Virtual symbolic link path
  287. pszDirectory - receives Physical directory.
  288. This is of the size specified by lpcbSize
  289. lpcbSize - pointer to DWORD containing the size of buffer pszDirectory
  290. On retur contains the number of bytes written
  291. lpdwAccessMask - The access mask for this root
  292. pcchDirRoot - Number of characters of the directory this virtual
  293. root maps to (i.e., /foo/ ==> c:\root, lookup "/foo/bar/abc.htm"
  294. this value returns the length of "c:\root")
  295. pcchVRoot - Number of characters that made up the found virtual root
  296. (i.e., returns the lenght of "/foo/")
  297. phImpersonationToken - pointer to handle object that will contain
  298. the handle to be used for impersonation for UNC/secure virtual roots
  299. lpdwFileSystem - on successful return will contain the file system
  300. type for the directory matched with root specified.
  301. Returns:
  302. TRUE on success and FALSE if any failure.
  303. History:
  304. MuraliK 28-Apr-1995 Improved robustness
  305. MuraliK 18-Jan-1996 Support imperonstaion token
  306. Note:
  307. This function is growing in the number of parameters returned.
  308. Maybe we should expose the VIRTUAL_ROOT_MAPPING structure
  309. and return a pointer to this object and allow the callers to
  310. extract all required pieces of data.
  311. --*/
  312. {
  313. DWORD dwError = NO_ERROR;
  314. PVIRTUAL_ROOT_MAPPING pVrm;
  315. PLIST_ENTRY pEntry;
  316. DBG_ASSERT( pszDirectory != NULL);
  317. DBG_ASSERT( lpcbSize != NULL);
  318. LockTable();
  319. for ( pEntry = m_vrootListHead.Flink;
  320. pEntry != &m_vrootListHead;
  321. pEntry = pEntry->Flink )
  322. {
  323. pVrm = CONTAINING_RECORD( pEntry, VIRTUAL_ROOT_MAPPING, TableListEntry );
  324. ASSERT( pVrm->Signature == VIRT_ROOT_SIGNATURE );
  325. //
  326. // If the virtual paths match and (the addresses match
  327. // or this is a global address for this service)
  328. //
  329. if ( !_mbsnicmp( (PUCHAR)pszVirtPath,
  330. (PUCHAR)pVrm->pszRootA,
  331. _mbslen( (PUCHAR)pVrm->pszRootA ) ) &&
  332. IS_CHAR_TERM_A( pszVirtPath, pVrm->cchRootA ) )
  333. {
  334. //
  335. // we found a match. return all requested parameters.
  336. //
  337. DWORD cbReqd = ( pVrm->cchDirectoryA +
  338. strlen(pszVirtPath + pVrm->cchRootA));
  339. if ( cbReqd <= *lpcbSize) {
  340. PCHAR pathStart = pszDirectory + pVrm->cchDirectoryA;
  341. //
  342. // Copy the physical directory base then append the rest of
  343. // the non-matching virtual path
  344. //
  345. CopyMemory(
  346. pszDirectory,
  347. pVrm->pszDirectoryA,
  348. pVrm->cchDirectoryA
  349. );
  350. strcpy( pathStart,
  351. pszVirtPath + pVrm->cchRootA );
  352. if ( lpdwFileSystem != NULL) {
  353. *lpdwFileSystem = pVrm->dwFileSystem;
  354. }
  355. if ( pcchDirRoot ) {
  356. *pcchDirRoot = pVrm->cchDirectoryA;
  357. }
  358. if ( pcchVRoot ) {
  359. *pcchVRoot = pVrm->cchRootA;
  360. }
  361. if ( lpdwAccessMask != NULL) {
  362. *lpdwAccessMask = pVrm->dwAccessMask;
  363. }
  364. if ( phImpersonationToken != NULL) {
  365. // Should we increment refcount of the impersonation token?
  366. *phImpersonationToken = pVrm->hImpersonationToken;
  367. }
  368. UnlockTable();
  369. FlipSlashes( pathStart );
  370. *lpcbSize = cbReqd;
  371. return(TRUE);
  372. } else {
  373. dwError = ERROR_INSUFFICIENT_BUFFER;
  374. }
  375. *lpcbSize = cbReqd;
  376. break;
  377. }
  378. } // for
  379. UnlockTable();
  380. if ( lpdwAccessMask ) {
  381. *lpdwAccessMask = 0;
  382. }
  383. if ( lpdwFileSystem != NULL) {
  384. *lpdwFileSystem = FS_ERROR;
  385. }
  386. if ( phImpersonationToken != NULL) {
  387. *phImpersonationToken = NULL;
  388. }
  389. if ( dwError == NO_ERROR) {
  390. dwError = ERROR_PATH_NOT_FOUND;
  391. }
  392. SetLastError( dwError );
  393. return FALSE;
  394. } // IIS_VROOT_TABLE::LookupVirtualRoot
  395. BOOL
  396. IIS_VROOT_TABLE::RemoveVirtualRoots(
  397. VOID
  398. )
  399. /*++
  400. Description:
  401. Removes all of the virtual roots for the instance
  402. Arguments:
  403. None.
  404. Returns:
  405. TRUE on success and FALSE if any failure.
  406. --*/
  407. {
  408. PVIRTUAL_ROOT_MAPPING pVrm;
  409. PLIST_ENTRY pEntry;
  410. PLIST_ENTRY pEntryFile;
  411. PLIST_ENTRY pNextEntry;
  412. PCACHE_OBJECT pCache;
  413. PDIRECTORY_CACHING_INFO pDci;
  414. BOOL bSuccess;
  415. //
  416. // If both locks are going to be taken, taken the cache table lock first
  417. // to avoid deadlock with the change notification thread.
  418. //
  419. // Note the table lock (m_csLock) needs to be taken before the
  420. // csVirtualRoots lock. We must take csVirtualRoots lock to synchronize
  421. // with the ChangeWaitThread().
  422. //
  423. EnterCriticalSection( &CacheTable.CriticalSection );
  424. LockTable();
  425. EnterCriticalSection( &csVirtualRoots );
  426. for ( pEntry = m_vrootListHead.Flink;
  427. pEntry != &m_vrootListHead;
  428. pEntry = pEntry->Flink )
  429. {
  430. pVrm = CONTAINING_RECORD( pEntry, VIRTUAL_ROOT_MAPPING, TableListEntry );
  431. ASSERT( pVrm->Signature == VIRT_ROOT_SIGNATURE );
  432. pDci = (PDIRECTORY_CACHING_INFO) (pVrm + 1);
  433. if ( pVrm->fCachingAllowed )
  434. {
  435. //
  436. // Indicate this root is deleted before we close the dir
  437. // handle. When the APC notification of the aborted IO
  438. // completes, it will dereference all deleted items
  439. //
  440. pVrm->fDeleted = TRUE;
  441. CLOSE_DIRECTORY_HANDLE( pDci );
  442. //
  443. // Close any open files on this virtual root
  444. //
  445. if ( !TsDecacheVroot( pDci ) ) {
  446. DBGPRINTF(( DBG_CONTEXT,
  447. "Warning - TsDecacheVroot failed!\n" ));
  448. }
  449. }
  450. else
  451. {
  452. CLOSE_DIRECTORY_HANDLE( pDci );
  453. }
  454. pEntry = pEntry->Blink;
  455. RemoveEntryList( pEntry->Flink );
  456. m_nVroots--;
  457. IF_DEBUG( DIRECTORY_CHANGE )
  458. DBGPRINTF(( DBG_CONTEXT,
  459. "Removing root %s\n",
  460. pVrm->pszDirectoryA ));
  461. //
  462. // Remove from global list too
  463. //
  464. DcmRemoveRoot( pVrm );
  465. DereferenceRootMapping( pVrm );
  466. }
  467. LeaveCriticalSection( &csVirtualRoots );
  468. UnlockTable();
  469. LeaveCriticalSection( &CacheTable.CriticalSection );
  470. return TRUE;
  471. } // TsRemoveVirtualRoots
  472. VOID
  473. DereferenceRootMapping(
  474. IN OUT PVIRTUAL_ROOT_MAPPING pVrm
  475. )
  476. {
  477. if ( !InterlockedDecrement( &pVrm->cRef )) {
  478. // DBGPRINTF((DBG_CONTEXT,"*** Deleting VRM memory ***\n"));
  479. //
  480. // We need to close the impersonation token, if one exists.
  481. //
  482. if ( pVrm->hImpersonationToken != NULL) {
  483. DBG_REQUIRE( CloseHandle( pVrm->hImpersonationToken ));
  484. pVrm->hImpersonationToken = NULL;
  485. }
  486. pVrm->Signature = 0;
  487. FREE( pVrm );
  488. }
  489. return;
  490. } // DereferenceRootMapping
  491.