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.

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