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.

761 lines
20 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Module Name:
  4. config.cpp
  5. Abstract:
  6. This file implements metabase access routines for virtual directories.
  7. --*/
  8. #include "precomp.h"
  9. StringHandle
  10. VDirConfig::GetFullPath( StringHandle Path )
  11. {
  12. StringHandle ParsedPath;
  13. CHAR *FilePart = NULL;
  14. DWORD BufferLength = MAX_PATH;
  15. while( 1 )
  16. {
  17. CHAR *PathBuffer = ParsedPath.AllocBuffer( BufferLength );
  18. DWORD Result =
  19. GetFullPathName(
  20. Path,
  21. BufferLength,
  22. PathBuffer,
  23. &FilePart );
  24. if ( Result > BufferLength )
  25. {
  26. BufferLength = Result;
  27. continue;
  28. }
  29. if ( !Result )
  30. {
  31. Log( LOG_ERROR, "Unable to get the full path name for %s, error 0x%8.8X",
  32. (const char*)Path, HRESULT_FROM_WIN32( GetLastError() ) );
  33. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  34. }
  35. ParsedPath.SetStringSize();
  36. break;
  37. }
  38. return ParsedPath;
  39. }
  40. VDirConfig::VDirConfig(
  41. StringHandle Path,
  42. SmartMetabasePointer AdminBase
  43. ) :
  44. m_Refs(1)
  45. {
  46. //
  47. // Read in all the metabase configuration for the virtual directory.
  48. //
  49. HRESULT Hr;
  50. METADATA_HANDLE MdVDirKey = NULL;
  51. GetSystemTimeAsFileTime( &m_LastLookup );
  52. try
  53. {
  54. m_Path = Path;
  55. StringHandleW UnicodePath = Path;
  56. Hr = AdminBase->OpenKey(
  57. METADATA_MASTER_ROOT_HANDLE,
  58. (const WCHAR*)UnicodePath,
  59. METADATA_PERMISSION_READ,
  60. METABASE_OPEN_KEY_TIMEOUT,
  61. &MdVDirKey );
  62. if ( FAILED(Hr) )
  63. throw ServerException( Hr );
  64. m_PhysicalPath =
  65. GetMetaDataString(
  66. AdminBase.Get(),
  67. MdVDirKey,
  68. NULL,
  69. MD_VR_PATH,
  70. "" );
  71. m_PhysicalPath = GetFullPath( m_PhysicalPath );
  72. DWORD UploadEnabled =
  73. GetMetaDataDWORD(
  74. AdminBase.Get(),
  75. MdVDirKey,
  76. NULL,
  77. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_UPLOAD_ENABLED ),
  78. 0);
  79. m_UploadEnabled = UploadEnabled ? true : false;
  80. m_ConnectionsDir =
  81. GetMetaDataString(
  82. AdminBase.Get(),
  83. MdVDirKey,
  84. NULL,
  85. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_CONNECTION_DIR ),
  86. MD_DEFAULT_BITS_CONNECTION_DIRA );
  87. m_SessionDir = m_PhysicalPath + StringHandle( "\\" ) + m_ConnectionsDir;
  88. m_RequestsDir = m_SessionDir + StringHandle( "\\" ) + StringHandle( REQUESTS_DIR_NAME );
  89. m_RepliesDir = m_SessionDir + StringHandle( "\\" ) + StringHandle( REPLIES_DIR_NAME );
  90. m_NoProgressTimeout =
  91. GetMetaDataDWORD(
  92. AdminBase.Get(),
  93. MdVDirKey,
  94. NULL,
  95. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_NO_PROGRESS_TIMEOUT ),
  96. MD_DEFAULT_NO_PROGESS_TIMEOUT );
  97. StringHandle MaxFilesizeString =
  98. GetMetaDataString(
  99. AdminBase.Get(),
  100. MdVDirKey,
  101. NULL,
  102. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_MAX_FILESIZE ),
  103. MD_DEFAULT_BITS_MAX_FILESIZEA );
  104. if ( MaxFilesizeString.Size() == 0 )
  105. {
  106. m_MaxFileSize = 0xFFFFFFFFFFFFFFFF;
  107. }
  108. else
  109. {
  110. UINT64 MaxFileSize;
  111. int ScanRet = sscanf( (const char*)MaxFilesizeString, "%I64u", &MaxFileSize );
  112. if ( 1 != ScanRet )
  113. throw ServerException( E_INVALIDARG );
  114. m_MaxFileSize = MaxFileSize;
  115. }
  116. DWORD NotificationType =
  117. GetMetaDataDWORD(
  118. AdminBase.Get(),
  119. MdVDirKey,
  120. NULL,
  121. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_NOTIFICATION_URL_TYPE ),
  122. MD_DEFAULT_BITS_NOTIFICATION_URL_TYPE );
  123. if ( NotificationType > BITS_NOTIFICATION_TYPE_MAX )
  124. throw ServerException( E_INVALIDARG );
  125. m_NotificationType = (BITS_SERVER_NOTIFICATION_TYPE)NotificationType;
  126. m_NotificationURL =
  127. GetMetaDataString(
  128. AdminBase.Get(),
  129. MdVDirKey,
  130. NULL,
  131. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_NOTIFICATION_URL ),
  132. MD_DEFAULT_BITS_NOTIFICATION_URLA );
  133. m_HostId =
  134. GetMetaDataString(
  135. AdminBase.Get(),
  136. MdVDirKey,
  137. NULL,
  138. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_HOSTID ),
  139. MD_DEFAULT_BITS_HOSTIDA );
  140. m_HostIdFallbackTimeout =
  141. GetMetaDataDWORD(
  142. AdminBase.Get(),
  143. MdVDirKey,
  144. NULL,
  145. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_HOSTID_FALLBACK_TIMEOUT ),
  146. MD_DEFAULT_HOSTID_FALLBACK_TIMEOUT );
  147. m_ExecutePermissions =
  148. GetMetaDataDWORD(
  149. AdminBase.Get(),
  150. MdVDirKey,
  151. NULL,
  152. MD_ACCESS_PERM,
  153. MD_ACCESS_READ );
  154. #if defined( ALLOW_OVERWRITES )
  155. m_AllowOverwrites =
  156. !!GetMetaDataDWORD(
  157. AdminBase.Get(),
  158. MdVDirKey,
  159. NULL,
  160. g_PropertyMan->GetPropertyMetabaseID( MD_BITS_ALLOW_OVERWRITES ),
  161. MD_DEFAULT_BITS_ALLOW_OVERWRITES );
  162. #else
  163. m_AllowOverwrites = false;
  164. #endif
  165. AdminBase->CloseKey( MdVDirKey );
  166. }
  167. catch( const ComError & )
  168. {
  169. if ( MdVDirKey )
  170. AdminBase->CloseKey( MdVDirKey );
  171. throw;
  172. }
  173. }
  174. ConfigurationManager::ConfigurationManager()
  175. {
  176. bool CSInitialize = false;
  177. memset( m_PathCacheEntries, 0, sizeof( m_PathCacheEntries ) );
  178. memset( m_MapCacheEntries, 0, sizeof( m_MapCacheEntries ) );
  179. HRESULT Hr =
  180. CoInitializeEx( NULL, COINIT_MULTITHREADED );
  181. if ( FAILED(Hr) )
  182. throw ServerException( Hr );
  183. try
  184. {
  185. if ( !InitializeCriticalSectionAndSpinCount( &m_CacheCS, 0x80000100 ) )
  186. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  187. CSInitialize = true;
  188. Hr =
  189. CoCreateInstance(
  190. GETAdminBaseCLSID(TRUE),
  191. NULL,
  192. CLSCTX_SERVER,
  193. __uuidof( IMSAdminBase ),
  194. (LPVOID*)m_IISAdminBase.GetRecvPointer() );
  195. if ( FAILED(Hr) )
  196. throw ServerException( Hr );
  197. Hr = m_IISAdminBase->GetSystemChangeNumber( &m_ChangeNumber );
  198. if ( FAILED(Hr))
  199. throw ServerException( Hr );
  200. CoUninitialize();
  201. }
  202. catch( const ComError & )
  203. {
  204. if ( CSInitialize )
  205. DeleteCriticalSection( &m_CacheCS );
  206. CoUninitialize();
  207. throw;
  208. }
  209. }
  210. ConfigurationManager::~ConfigurationManager()
  211. {
  212. FlushCache();
  213. DeleteCriticalSection( &m_CacheCS );
  214. }
  215. void
  216. ConfigurationManager::FlushCache()
  217. {
  218. for( unsigned int i = 0; i < PATH_CACHE_ENTRIES; i++ )
  219. {
  220. if ( m_PathCacheEntries[i] )
  221. m_PathCacheEntries[i].Clear();
  222. }
  223. for( unsigned int i = 0; i < MAP_CACHE_ENTRIES; i++ )
  224. {
  225. delete m_MapCacheEntries[i];
  226. m_MapCacheEntries[i] = NULL;
  227. }
  228. }
  229. SmartVDirConfig
  230. ConfigurationManager::Lookup(
  231. StringHandle Path )
  232. {
  233. for( unsigned int i=0; i < PATH_CACHE_ENTRIES; i++ )
  234. {
  235. if ( m_PathCacheEntries[i] )
  236. {
  237. if ( _stricmp( (const char*)m_PathCacheEntries[i]->m_Path, (const char*)Path) == 0 )
  238. {
  239. SmartVDirConfig ReturnVal = m_PathCacheEntries[i];
  240. GetSystemTimeAsFileTime( &ReturnVal->m_LastLookup );
  241. return ReturnVal;
  242. }
  243. }
  244. }
  245. return SmartVDirConfig();
  246. }
  247. void
  248. ConfigurationManager::Insert(
  249. SmartVDirConfig NewConfig )
  250. {
  251. //
  252. // Insert a new virtual directory configuration into the
  253. // virtual directory cache. Expire an old entry if needed.
  254. //
  255. int BestSlot = 0;
  256. FILETIME WorstTime;
  257. memset( &WorstTime, 0xFF, sizeof( WorstTime ) );
  258. for( unsigned int i=0; i < PATH_CACHE_ENTRIES; i++ )
  259. {
  260. if ( !m_PathCacheEntries[i] )
  261. {
  262. BestSlot = i;
  263. break;
  264. }
  265. else if ( CompareFileTime( &m_PathCacheEntries[i]->m_LastLookup, &WorstTime ) < 0 )
  266. {
  267. WorstTime = m_PathCacheEntries[i]->m_LastLookup;
  268. BestSlot = i;
  269. }
  270. }
  271. m_PathCacheEntries[BestSlot] = NewConfig;
  272. }
  273. SmartVDirConfig
  274. ConfigurationManager::Lookup(
  275. StringHandle InstanceMetabasePath,
  276. StringHandle URL,
  277. DWORD *pURLDepth )
  278. {
  279. //
  280. // Find the virtual directories configuration in the cache.
  281. //
  282. for( unsigned int i=0; i < MAP_CACHE_ENTRIES; i++ )
  283. {
  284. MapCacheEntry* CacheEntry = m_MapCacheEntries[i];
  285. if ( CacheEntry )
  286. {
  287. if ( ( _stricmp( (const char*)CacheEntry->m_InstanceMetabasePath,
  288. (const char*)InstanceMetabasePath) == 0 ) &&
  289. ( _stricmp( (const char*)CacheEntry->m_URL,
  290. (const char*)URL ) == 0 ) )
  291. {
  292. GetSystemTimeAsFileTime( &CacheEntry->m_LastLookup );
  293. *pURLDepth = CacheEntry->m_URLDepth;
  294. return CacheEntry->m_Config;
  295. }
  296. }
  297. }
  298. return SmartVDirConfig();
  299. }
  300. SmartVDirConfig
  301. ConfigurationManager::GetVDirConfig(
  302. StringHandle Path )
  303. {
  304. SmartVDirConfig Config = Lookup( Path );
  305. if ( !Config.Get() )
  306. {
  307. *Config.GetRecvPointer() = new VDirConfig( Path, m_IISAdminBase );
  308. Insert( Config );
  309. }
  310. return Config;
  311. }
  312. SmartVDirConfig
  313. ConfigurationManager::Insert(
  314. StringHandle InstanceMetabasePath,
  315. StringHandle URL,
  316. StringHandle Path,
  317. DWORD URLDepth )
  318. {
  319. SmartVDirConfig Config = GetVDirConfig( Path );
  320. MapCacheEntry* CacheEntry =
  321. new MapCacheEntry(
  322. InstanceMetabasePath,
  323. URL,
  324. Config,
  325. URLDepth );
  326. int BestSlot = 0;
  327. FILETIME WorstTime;
  328. memset( &WorstTime, 0xFF, sizeof( WorstTime ) );
  329. for( unsigned int i=0; i < MAP_CACHE_ENTRIES; i++ )
  330. {
  331. if ( !m_MapCacheEntries[i] )
  332. {
  333. BestSlot = i;
  334. break;
  335. }
  336. else if ( CompareFileTime( &m_MapCacheEntries[i]->m_LastLookup, &WorstTime ) < 0 )
  337. {
  338. WorstTime = m_MapCacheEntries[i]->m_LastLookup;
  339. BestSlot = i;
  340. }
  341. }
  342. if ( m_MapCacheEntries[BestSlot] )
  343. delete m_MapCacheEntries[BestSlot];
  344. m_MapCacheEntries[BestSlot] = CacheEntry;
  345. return Config;
  346. }
  347. StringHandle
  348. ConfigurationManager::GetVDirPath(
  349. StringHandle InstanceMetabasePath,
  350. StringHandle URL,
  351. DWORD *pURLDepth )
  352. {
  353. //
  354. // Find the virtual directory that coresponds to the URL.
  355. // Do this by matching the URL up with the metabase keys. Keep
  356. // pruning off the URL untill the longest metabase path is found
  357. // that is a virtual directory.
  358. //
  359. StringHandleW InstanceMetabasePathW = InstanceMetabasePath;
  360. StringHandleW URLW = URL;
  361. WCHAR *Path = NULL;
  362. METADATA_HANDLE MdVDirKey = NULL;
  363. *pURLDepth = 0;
  364. try
  365. {
  366. WCHAR *PathEnd = NULL;
  367. WCHAR *CurrentEnd = NULL;
  368. WCHAR RootString[] = L"/Root";
  369. SIZE_T InstancePathSize = InstanceMetabasePathW.Size();
  370. SIZE_T URLSize = URLW.Size();
  371. SIZE_T RootStringSize = ( sizeof( RootString ) / sizeof( *RootString ) ) - 1;
  372. Path = new WCHAR[ InstancePathSize + URLSize + RootStringSize + 1 ];
  373. memcpy( Path, (const WCHAR*)InstanceMetabasePathW, InstancePathSize * sizeof( WCHAR ) );
  374. PathEnd = Path + InstancePathSize;
  375. memcpy( PathEnd, RootString, RootStringSize * sizeof( WCHAR ) );
  376. memcpy( PathEnd + RootStringSize, (const WCHAR*)URLW, ( URLSize + 1 )* sizeof( WCHAR ) );
  377. CurrentEnd = PathEnd + RootStringSize + URLSize;
  378. while( 1 )
  379. {
  380. HRESULT Hr =
  381. m_IISAdminBase->OpenKey(
  382. METADATA_MASTER_ROOT_HANDLE, //metabase handle.
  383. Path, //path to the key, relative to hMDHandle.
  384. METADATA_PERMISSION_READ, //specifies read and write permissions.
  385. METABASE_OPEN_KEY_TIMEOUT, //the time, in milliseconds, before the method times out.
  386. &MdVDirKey //receives the handle to the opened key.
  387. );
  388. if ( SUCCEEDED( Hr ) )
  389. {
  390. //
  391. // Check if this is a virtual directory
  392. //
  393. WCHAR NodeName[ 255 ];
  394. DWORD RequiredDataLen;
  395. METADATA_RECORD MDRecord;
  396. MDRecord.dwMDIdentifier = MD_KEY_TYPE;
  397. MDRecord.dwMDAttributes = METADATA_NO_ATTRIBUTES;
  398. MDRecord.dwMDUserType = IIS_MD_UT_SERVER;
  399. MDRecord.dwMDDataType = STRING_METADATA;
  400. MDRecord.dwMDDataLen = sizeof( NodeName );
  401. MDRecord.pbMDData = (unsigned char*)NodeName;
  402. MDRecord.dwMDDataTag = 0;
  403. Hr = m_IISAdminBase->GetData(
  404. MdVDirKey,
  405. NULL,
  406. &MDRecord,
  407. &RequiredDataLen );
  408. if ( FAILED(Hr) && ( Hr != MD_ERROR_DATA_NOT_FOUND ) &&
  409. ( Hr != HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER ) ) )
  410. throw ServerException( Hr );
  411. if ( SUCCEEDED( Hr ) && wcscmp( L"IIsWebVirtualDir", NodeName ) == 0 )
  412. {
  413. // Found the path, so return the data
  414. StringHandle VDirPath = Path;
  415. delete[] Path;
  416. m_IISAdminBase->CloseKey( MdVDirKey );
  417. return VDirPath;
  418. }
  419. }
  420. else if ( Hr != HRESULT_FROM_WIN32( ERROR_PATH_NOT_FOUND ) )
  421. {
  422. throw ServerException( Hr );
  423. }
  424. //
  425. // If this is the end of the URL, then nothing else can be done
  426. //
  427. if ( CurrentEnd == PathEnd )
  428. throw ServerException( E_INVALIDARG );
  429. m_IISAdminBase->CloseKey( MdVDirKey );
  430. MdVDirKey = NULL;
  431. // Chop off the rightmost subpart
  432. while( CurrentEnd != PathEnd && *CurrentEnd != L'/' &&
  433. *CurrentEnd != L'\\' )
  434. CurrentEnd--;
  435. if ( *CurrentEnd == L'/' || *CurrentEnd == L'\\' )
  436. *CurrentEnd = L'\0';
  437. (*pURLDepth)++;
  438. // Attempt another round
  439. }
  440. }
  441. catch( const ComError & )
  442. {
  443. delete[] Path;
  444. if ( MdVDirKey )
  445. m_IISAdminBase->CloseKey( MdVDirKey );
  446. throw;
  447. }
  448. }
  449. bool
  450. ConfigurationManager::HandleCacheConsistency()
  451. {
  452. //
  453. // Handle cache consistency. This is done my calling IIS to check the change number.
  454. // If the current change number is different then the change number for the last lookup,
  455. // then flush the cache.
  456. //
  457. DWORD ChangeNumber;
  458. HRESULT Hr = m_IISAdminBase->GetSystemChangeNumber( &ChangeNumber );
  459. if ( FAILED(Hr) )
  460. {
  461. throw ServerException( Hr );
  462. }
  463. if ( ChangeNumber == m_ChangeNumber )
  464. return true; // cache is consistent
  465. FlushCache();
  466. m_ChangeNumber = ChangeNumber;
  467. return false; // cache was flushed.
  468. }
  469. SmartVDirConfig
  470. ConfigurationManager::GetConfig2(
  471. StringHandle InstanceMetabasePath,
  472. StringHandle URL,
  473. DWORD * pURLDepth )
  474. {
  475. //
  476. // Toplevel function to do everything to lookup the configuration to use for an URL.
  477. //
  478. METADATA_HANDLE MdVDirKey = NULL;
  479. SmartVDirConfig Config;
  480. HANDLE ImpersonationToken = NULL;
  481. bool DidRevertToSelf = false;
  482. try
  483. {
  484. EnterCriticalSection( &m_CacheCS );
  485. if ( HandleCacheConsistency() )
  486. {
  487. // The cache was consistent. Chances are good
  488. // that the lookup will succeed
  489. Config = Lookup( InstanceMetabasePath, URL, pURLDepth );
  490. if ( Config.Get() )
  491. {
  492. LeaveCriticalSection( &m_CacheCS );
  493. return Config;
  494. }
  495. }
  496. StringHandle Path = GetVDirPath( InstanceMetabasePath, URL, pURLDepth );
  497. Config = Insert( InstanceMetabasePath, URL, Path, *pURLDepth );
  498. LeaveCriticalSection( &m_CacheCS );
  499. return Config;
  500. }
  501. catch( const ComError & )
  502. {
  503. if ( MdVDirKey )
  504. m_IISAdminBase->CloseKey( MdVDirKey );
  505. LeaveCriticalSection( &m_CacheCS );
  506. throw;
  507. }
  508. }
  509. SmartVDirConfig
  510. ConfigurationManager::GetConfig(
  511. StringHandle InstanceMetabasePath,
  512. StringHandle URL,
  513. DWORD * pURLDepth )
  514. {
  515. bool DidRevertToSelf = false;
  516. bool ComInitialized = false;
  517. HANDLE ImpersonationToken = NULL;
  518. SmartVDirConfig ReturnVal;
  519. HRESULT Hr =
  520. CoInitializeEx( NULL, COINIT_MULTITHREADED );
  521. if ( FAILED(Hr) )
  522. throw ServerException( Hr );
  523. ComInitialized = true;
  524. try
  525. {
  526. // Need to revert to the system process
  527. // to address the metabase
  528. if ( !OpenThreadToken(
  529. GetCurrentThread(),
  530. TOKEN_ALL_ACCESS,
  531. TRUE,
  532. &ImpersonationToken ) )
  533. {
  534. DWORD dwError = GetLastError();
  535. if (dwError != ERROR_NO_TOKEN)
  536. throw ServerException( HRESULT_FROM_WIN32( dwError ) );
  537. }
  538. else
  539. {
  540. if ( !RevertToSelf() )
  541. throw ServerException( HRESULT_FROM_WIN32( GetLastError() ) );
  542. DidRevertToSelf = true;
  543. }
  544. ReturnVal =
  545. GetConfig2(
  546. InstanceMetabasePath,
  547. URL,
  548. pURLDepth );
  549. if ( DidRevertToSelf )
  550. {
  551. BITSSetCurrentThreadToken( ImpersonationToken );
  552. }
  553. if ( ImpersonationToken )
  554. CloseHandle( ImpersonationToken );
  555. CoUninitialize();
  556. return ReturnVal;
  557. }
  558. catch( ComError & )
  559. {
  560. if ( DidRevertToSelf )
  561. BITSSetCurrentThreadToken( ImpersonationToken );
  562. if ( ImpersonationToken )
  563. CloseHandle( ImpersonationToken );
  564. throw;
  565. }
  566. }