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.

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