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.

672 lines
16 KiB

  1. /*++
  2. Copyright (c) 1998 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. MCourage 05-Jan-1997 Moved to cache2 directory for cache rewrite
  22. SaurabN 07-Oct-1998 Reimplement using LKRHash.
  23. --*/
  24. /************************************************************
  25. * Include Headers
  26. ************************************************************/
  27. #include <tsunami.hxx>
  28. #include "TsunamiP.Hxx"
  29. #pragma hdrstop
  30. #include <mbstring.h>
  31. #include <rpc.h>
  32. #include <rpcndr.h>
  33. #include "dbgutil.h"
  34. #include <string.h>
  35. #include <refb.hxx>
  36. #include <imd.h>
  37. #include <mb.hxx>
  38. #include <iiscnfg.h>
  39. #include <malloc.h>
  40. IIS_VROOT_TABLE::IIS_VROOT_TABLE(
  41. VOID
  42. )
  43. :
  44. CLKRHashTable("IISVRootTable",
  45. ExtractKey,
  46. CalcKeyHash,
  47. EqualKeys,
  48. AddRefRecord,
  49. DFLT_LK_INITSIZE,
  50. LK_SMALL_TABLESIZE),
  51. m_nVroots (0 )
  52. {
  53. } // IIS_VROOT_TABLE::IIS_VROOT_TABLE
  54. IIS_VROOT_TABLE::~IIS_VROOT_TABLE(
  55. VOID
  56. )
  57. {
  58. RemoveVirtualRoots( );
  59. DBG_ASSERT( m_nVroots == 0 );
  60. } // IIS_VROOT_TABLE::~IIS_VROOT_TABLE
  61. BOOL
  62. IIS_VROOT_TABLE::AddVirtualRoot(
  63. PCHAR pszRoot,
  64. PCHAR pszDirectory,
  65. DWORD dwAccessMask,
  66. PCHAR pszAccountName,
  67. HANDLE hImpersonationToken,
  68. DWORD dwFileSystem,
  69. BOOL fDoCache
  70. )
  71. /*++
  72. Description:
  73. This function adds a symbolic link root and directory mapping
  74. part to the virtual root list
  75. We always strip trailing slashes from the root and directory name.
  76. If the root is "\" or "/", then the effective root will be zero
  77. length and will always be placed last in the list. Thus if a lookup
  78. can't find a match, it will always match the last entry.
  79. Arguments:
  80. pszRoot - Virtual symbolic link root
  81. pszDirectory - Physical directory
  82. dwAccessMask - Type of access allowed on this virtual root
  83. pszAccountName - User name to impersonate if UNC (only gets stored
  84. for RPC apis)
  85. hImpersonationToken - Impersonation token to use for UNC
  86. directory paths
  87. dwFileSystem - DWORD containing the file system type
  88. ( symbolic constant)
  89. fDoCache - Should we cache the vdir
  90. Returns:
  91. TRUE on success and FALSE if any failure.
  92. --*/
  93. {
  94. PVIRTUAL_ROOT_MAPPING pVrm, pVrmOld;
  95. PLIST_ENTRY pEntry;
  96. BOOL fRet = FALSE;
  97. BOOL fUNC;
  98. DWORD cchRoot;
  99. if ( !pszRoot || !pszDirectory || !*pszDirectory )
  100. {
  101. SetLastError( ERROR_INVALID_PARAMETER );
  102. return FALSE;
  103. }
  104. //
  105. // Disallow allow UNC roots if we don't have an impersonation token and
  106. // this isn't a placeholder
  107. //
  108. fUNC = (BOOL)((pszDirectory[0] == '\\') && (pszDirectory[1] == '\\'));
  109. //
  110. // Strip the trailing '/' from the virtual root
  111. //
  112. cchRoot = strlen( pszRoot );
  113. if ( IS_CHAR_TERM_A( pszRoot, cchRoot - 1))
  114. {
  115. pszRoot[--cchRoot] = '\0';
  116. }
  117. //
  118. // Look in the current list and see if the root is already there.
  119. // If the directory is the same, we just return success. If the
  120. // directory is different, we remove the old item and add the new one.
  121. //
  122. LockShared();
  123. if (LK_SUCCESS == FindKey((DWORD_PTR) pszRoot, (const void **)&pVrm))
  124. {
  125. //
  126. // Key exists
  127. //
  128. if ( !lstrcmpi( pszDirectory, pVrm->pszDirectoryA ) &&
  129. IS_CHAR_TERM_A( pszDirectory, pVrm->cchDirectoryA ))
  130. {
  131. //
  132. // This root is already in the list
  133. //
  134. Unlock();
  135. return TRUE;
  136. }
  137. else
  138. {
  139. //
  140. // A root is having its directory entry changed
  141. //
  142. Unlock();
  143. SetLastError( ERROR_NOT_SUPPORTED );
  144. return FALSE;
  145. }
  146. }
  147. //
  148. // Add a new key
  149. //
  150. pVrm = ( PVIRTUAL_ROOT_MAPPING )ALLOC( sizeof( VIRTUAL_ROOT_MAPPING ) );
  151. if ( pVrm == NULL )
  152. {
  153. SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  154. Unlock();
  155. return FALSE;
  156. }
  157. //
  158. // Initialize the new root item
  159. //
  160. pVrm->Signature = VIRT_ROOT_SIGNATURE;
  161. pVrm->cchRootA = strlen( pszRoot );
  162. if (pVrm->cchRootA > MAX_LENGTH_VIRTUAL_ROOT)
  163. {
  164. SetLastError( ERROR_BAD_PATHNAME );
  165. Unlock();
  166. return FALSE;
  167. }
  168. pVrm->cchDirectoryA = strlen( pszDirectory );
  169. if (pVrm->cchDirectoryA > MAX_PATH)
  170. {
  171. SetLastError( ERROR_BAD_PATHNAME );
  172. Unlock();
  173. return FALSE;
  174. }
  175. pVrm->dwFileSystem = dwFileSystem;
  176. pVrm->dwAccessMask = dwAccessMask;
  177. pVrm->fUNC = (BOOLEAN)fUNC;
  178. pVrm->hImpersonationToken = hImpersonationToken;
  179. //
  180. // The old cache design used APCs to do change notification, the new cache
  181. // uses the CDirMon class so we don't need any refcounting.
  182. //
  183. strcpy( pVrm->pszRootA, pszRoot );
  184. strcpy( pVrm->pszDirectoryA, pszDirectory );
  185. strcpy( pVrm->pszAccountName, pszAccountName ? pszAccountName : "" );
  186. //
  187. // Strip trailing slashes from the root and directory
  188. //
  189. if ( (pVrm->cchRootA != 0) &&
  190. IS_CHAR_TERM_A( pVrm->pszRootA, pVrm->cchRootA - 1 ))
  191. {
  192. pVrm->pszRootA[--pVrm->cchRootA] = '\0';
  193. }
  194. if ( IS_CHAR_TERM_A( pVrm->pszDirectoryA, pVrm->cchDirectoryA - 1))
  195. {
  196. //
  197. // Note we assume virtual directories always begin with a '/...' to
  198. // provide the necessary path separator between the root directory
  199. // path and the remaining virtual directory
  200. //
  201. pVrm->pszDirectoryA[--pVrm->cchDirectoryA] = '\0';
  202. }
  203. //
  204. // Add the item to the list
  205. //
  206. LockConvertExclusive();
  207. fRet = (LK_SUCCESS == InsertRecord(pVrm));
  208. if (fRet)
  209. {
  210. fRet = fDoCache ? DcmAddRoot( pVrm ) : TRUE;
  211. if (!fRet)
  212. {
  213. DeleteRecord(pVrm);
  214. }
  215. }
  216. if ( fRet)
  217. {
  218. m_nVroots++;
  219. IF_DEBUG( VIRTUAL_ROOTS )
  220. DBGPRINTF(( DBG_CONTEXT,
  221. "Successfully added Vroot - %s => %s\n",
  222. pVrm->pszRootA,
  223. pVrm->pszDirectoryA ));
  224. }
  225. else
  226. {
  227. FREE( pVrm );
  228. /*
  229. //
  230. // this memory was already released!
  231. //
  232. DBGPRINTF(( DBG_CONTEXT,
  233. " Error %d adding Vroot - %s => %s\n",
  234. GetLastError(),
  235. pVrm->pszRootA,
  236. pVrm->pszDirectoryA ));
  237. */
  238. }
  239. Unlock();
  240. return fRet;
  241. } // IIS_VROOT_TABLE::AddVirtualRoot
  242. BOOL
  243. IIS_VROOT_TABLE::LookupVirtualRoot(
  244. IN const CHAR * pszVirtPath,
  245. OUT CHAR * pszDirectory,
  246. IN OUT LPDWORD lpcbSize,
  247. OUT LPDWORD lpdwAccessMask, // Optional
  248. OUT LPDWORD pcchDirRoot, // Optional
  249. OUT LPDWORD pcchVRoot, // Optional
  250. OUT HANDLE * phImpersonationToken, // Optional
  251. OUT LPDWORD lpdwFileSystem // Optional
  252. )
  253. /*++
  254. Description:
  255. This function looks in the map list for the specified root
  256. and returns the corresponding directory
  257. Arguments:
  258. pszVirtPath - Virtual symbolic link path
  259. pszDirectory - receives Physical directory.
  260. This is of the size specified by lpcbSize
  261. lpcbSize - pointer to DWORD containing the size of buffer pszDirectory
  262. On retur contains the number of bytes written
  263. lpdwAccessMask - The access mask for this root
  264. pcchDirRoot - Number of characters of the directory this virtual
  265. root maps to (i.e., /foo/ ==> c:\root, lookup "/foo/bar/abc.htm"
  266. this value returns the length of "c:\root")
  267. pcchVRoot - Number of characters that made up the found virtual root
  268. (i.e., returns the lenght of "/foo/")
  269. phImpersonationToken - pointer to handle object that will contain
  270. the handle to be used for impersonation for UNC/secure virtual roots
  271. lpdwFileSystem - on successful return will contain the file system
  272. type for the directory matched with root specified.
  273. Returns:
  274. TRUE on success and FALSE if any failure.
  275. History:
  276. MuraliK 28-Apr-1995 Improved robustness
  277. MuraliK 18-Jan-1996 Support imperonstaion token
  278. Note:
  279. This function is growing in the number of parameters returned.
  280. Maybe we should expose the VIRTUAL_ROOT_MAPPING structure
  281. and return a pointer to this object and allow the callers to
  282. extract all required pieces of data.
  283. --*/
  284. {
  285. DWORD dwError = NO_ERROR;
  286. PVIRTUAL_ROOT_MAPPING pVrm = NULL;
  287. DBG_ASSERT( pszDirectory != NULL);
  288. DBG_ASSERT( lpcbSize != NULL);
  289. DWORD cchPath = strlen( pszVirtPath );
  290. char * pszPath = (char *)_alloca(cchPath); // make local copy that we can modify
  291. strcpy(pszPath, pszVirtPath);
  292. //
  293. // Strip the trailing '/' from the virtual path
  294. //
  295. if ( IS_CHAR_TERM_A( pszPath, cchPath - 1))
  296. {
  297. pszPath[--cchPath] = '\0';
  298. }
  299. char * pCh = pszPath;
  300. LockShared();
  301. while(pCh != NULL)
  302. {
  303. if (LK_SUCCESS == FindKey((DWORD_PTR) pszPath, (const void **)&pVrm))
  304. {
  305. break;
  306. }
  307. else
  308. {
  309. //
  310. // Trim the VRoot path from the right to the next /
  311. //
  312. pCh = (char *)IISstrrchr( (const UCHAR *)pszPath, '/');
  313. if (pCh)
  314. {
  315. *pCh = '\0'; // truncate search string
  316. }
  317. }
  318. }
  319. if (pVrm)
  320. {
  321. //
  322. // we found a match. return all requested parameters.
  323. //
  324. DBG_ASSERT( pVrm->Signature == VIRT_ROOT_SIGNATURE );
  325. DWORD cbReqd = ( pVrm->cchDirectoryA +
  326. strlen(pszVirtPath + pVrm->cchRootA));
  327. if ( cbReqd <= *lpcbSize)
  328. {
  329. PCHAR pathStart = pszDirectory + pVrm->cchDirectoryA;
  330. //
  331. // Copy the physical directory base then append the rest of
  332. // the non-matching virtual path
  333. //
  334. CopyMemory(
  335. pszDirectory,
  336. pVrm->pszDirectoryA,
  337. pVrm->cchDirectoryA
  338. );
  339. strcpy( pathStart,
  340. pszVirtPath + pVrm->cchRootA );
  341. if ( lpdwFileSystem != NULL) {
  342. *lpdwFileSystem = pVrm->dwFileSystem;
  343. }
  344. if ( pcchDirRoot ) {
  345. *pcchDirRoot = pVrm->cchDirectoryA;
  346. }
  347. if ( pcchVRoot ) {
  348. *pcchVRoot = pVrm->cchRootA;
  349. }
  350. if ( lpdwAccessMask != NULL) {
  351. *lpdwAccessMask = pVrm->dwAccessMask;
  352. }
  353. if ( phImpersonationToken != NULL) {
  354. // Should we increment refcount of the impersonation token?
  355. *phImpersonationToken = pVrm->hImpersonationToken;
  356. }
  357. Unlock();
  358. FlipSlashes( pathStart );
  359. *lpcbSize = cbReqd;
  360. return(TRUE);
  361. } else {
  362. dwError = ERROR_INSUFFICIENT_BUFFER;
  363. }
  364. *lpcbSize = cbReqd;
  365. }
  366. if ( lpdwAccessMask ) {
  367. *lpdwAccessMask = 0;
  368. }
  369. if ( lpdwFileSystem != NULL) {
  370. *lpdwFileSystem = FS_ERROR;
  371. }
  372. if ( phImpersonationToken != NULL) {
  373. *phImpersonationToken = NULL;
  374. }
  375. if ( dwError == NO_ERROR) {
  376. dwError = ERROR_PATH_NOT_FOUND;
  377. }
  378. SetLastError( dwError );
  379. Unlock();
  380. return FALSE;
  381. } // IIS_VROOT_TABLE::LookupVirtualRoot
  382. BOOL
  383. IIS_VROOT_TABLE::RemoveVirtualRoots(
  384. VOID
  385. )
  386. /*++
  387. Description:
  388. Removes all of the virtual roots for the instance
  389. Arguments:
  390. None.
  391. Returns:
  392. TRUE on success and FALSE if any failure.
  393. --*/
  394. {
  395. PVIRTUAL_ROOT_MAPPING pVrm;
  396. CIterator iter;
  397. DWORD dwValue;
  398. LockExclusive();
  399. LK_RETCODE lkrc = InitializeIterator(&iter);
  400. while (LK_SUCCESS == lkrc)
  401. {
  402. pVrm = (PVIRTUAL_ROOT_MAPPING) iter.Record();
  403. DBG_ASSERT( pVrm->Signature == VIRT_ROOT_SIGNATURE );
  404. //
  405. // Increment the iterator before removing the record from the Hash
  406. // Table else we hit an Assert in the increment.
  407. //
  408. lkrc = IncrementIterator(&iter);
  409. DeleteVRootEntry(pVrm); // Removes from Hash Table Also
  410. }
  411. CloseIterator(&iter);
  412. Clear();
  413. Unlock();
  414. return TRUE;
  415. } // TsRemoveVirtualRoots
  416. BOOL
  417. IIS_VROOT_TABLE::RemoveVirtualRoot(
  418. IN PCHAR pszVirtPath
  419. )
  420. /*++
  421. Description:
  422. Removes the virtual roots named pszVirtPath for the instance.
  423. Arguments:
  424. pszVirtPath - Name of the virtual root to remove.
  425. Returns:
  426. TRUE on success and FALSE if any failure.
  427. --*/
  428. {
  429. PVIRTUAL_ROOT_MAPPING pVrm;
  430. BOOL bSuccess = FALSE;
  431. DWORD cchPath = strlen( pszVirtPath );
  432. //
  433. // Strip the trailing '/' from the virtual path
  434. //
  435. if ( IS_CHAR_TERM_A( pszVirtPath, cchPath - 1))
  436. {
  437. pszVirtPath[--cchPath] = '\0';
  438. }
  439. LockExclusive();
  440. if (LK_SUCCESS == FindKey((DWORD_PTR) pszVirtPath, (const void **)&pVrm))
  441. {
  442. //
  443. // Found a match
  444. //
  445. DeleteRecord(pVrm); // Remove Entry from Hash Table
  446. DeleteVRootEntry(pVrm);
  447. bSuccess = TRUE;
  448. }
  449. Unlock();
  450. return bSuccess;
  451. }
  452. VOID
  453. IIS_VROOT_TABLE::DeleteVRootEntry(
  454. IN PVOID pEntry
  455. )
  456. {
  457. DBG_ASSERT(NULL != pEntry);
  458. PVIRTUAL_ROOT_MAPPING pVrm = (PVIRTUAL_ROOT_MAPPING)pEntry;
  459. DBG_ASSERT(pVrm->Signature == VIRT_ROOT_SIGNATURE );
  460. m_nVroots--;
  461. IF_DEBUG( DIRECTORY_CHANGE )
  462. DBGPRINTF(( DBG_CONTEXT,
  463. "Removing root %s\n",
  464. pVrm->pszDirectoryA ));
  465. //
  466. // Remove reference to Dir Monitor
  467. //
  468. DcmRemoveRoot( pVrm );
  469. //
  470. // We need to close the impersonation token, if one exists.
  471. //
  472. if ( pVrm->hImpersonationToken != NULL)
  473. {
  474. DBG_REQUIRE( CloseHandle( pVrm->hImpersonationToken ));
  475. pVrm->hImpersonationToken = NULL;
  476. }
  477. pVrm->Signature = 0;
  478. FREE( pVrm );
  479. }
  480. const DWORD_PTR
  481. IIS_VROOT_TABLE::ExtractKey(const void* pvRecord)
  482. {
  483. PVIRTUAL_ROOT_MAPPING pVrm = (PVIRTUAL_ROOT_MAPPING)pvRecord;
  484. return (DWORD_PTR)pVrm->pszRootA;
  485. }
  486. DWORD
  487. IIS_VROOT_TABLE::CalcKeyHash(const DWORD_PTR pnKey)
  488. {
  489. return HashStringNoCase((LPCSTR)pnKey);
  490. }
  491. bool
  492. IIS_VROOT_TABLE::EqualKeys(const DWORD_PTR pnKey1, const DWORD_PTR pnKey2)
  493. {
  494. return ( IISstricmp((UCHAR *)pnKey1, (UCHAR *)pnKey2) == 0);
  495. }