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.

2513 lines
63 KiB

  1. /*++
  2. Copyright (c) 1992-1997 Microsoft Corporation
  3. Module Name:
  4. iis.c
  5. Abstract:
  6. Resource DLL for IIS. This DLL supports the following IIS services
  7. WWW
  8. FTP
  9. GOPHER
  10. Each instance of a resouce is an IIS Virtual Roots. A
  11. Virtual root may have dependencies on IP Addresses, Names, Physical Disks, or UNC names.
  12. Known Limitations
  13. 1. The current version expects that the IIS "Virtual Root" information is created
  14. using the Inet manager tool (inetmgr). The "Cluster" resource contains
  15. . Root Name
  16. . Directory
  17. . IP Address [OPTIONAL]
  18. Currently, this dll does not support Virtual Roots containing access information
  19. (i.e. password)
  20. 2. The IIS management interfaces update the "Virtual Root" information in the registry. This
  21. means the OPEN call needs to remove any "Virtual Root" managed by the cluster. Otherwise,
  22. the it's possible for the resource to be incorrectly online after the Open (i.e., the
  23. cluster crashed without doing a offline).
  24. Author:
  25. Pete Benoit (v-pbenoi) 12-SEP-1996
  26. Revision History:
  27. Pete Benoit (v-pbenoi) 10-MAR-1997
  28. Updated to use clusres utility functions, add more error codes,
  29. get rid of routines replaced by clusres, added global mutext so
  30. iis resource dll's running in separate resource monitors have controled
  31. access to virtual root updates (NOTE: the IIS Management utility still
  32. breaks this exclusion)
  33. --*/
  34. #include "iisutil.h"
  35. #include "resmonp.h"
  36. //
  37. // Names used to start service
  38. //
  39. LPCWSTR ActualServiceName[] = {
  40. L"W3SVC", // WWW
  41. L"MSFTPSVC", // FTP
  42. L"GOPHERSVC" // GOPHER
  43. };
  44. #define IIS_SEMAPHORE_NAME L"$$$IIS$VIRTUAL$ROOT$MODIFY$SEMAPHORE$"
  45. #define PARAM_NAME__SERVICENAME L"ServiceName"
  46. #define PARAM_NAME__ALIAS L"Alias"
  47. #define PARAM_NAME__DIRECTORY L"Directory"
  48. #define PARAM_NAME__ACCESSMASK L"AccessMask"
  49. /* Remove for the first release
  50. #define PARAM_NAME__ACCOUNTNAME L"AccountName"
  51. #define PARAM_NAME__PASSWORD L"Password"
  52. */
  53. #define PARAM_MIN__ACCESSMASK 0
  54. #define PARAM_MAX__ACCESSMASK 0xFFFFFFFF
  55. #define PARAM_DEFAULT__ACCESSMASK 0
  56. //
  57. // Global data.
  58. //
  59. // The current IIS management (2-3.0) interface does not have
  60. // an API to get/remove a single virtual root entry. Each update requires
  61. // a read (all virtual roots) modify (a virtual root) write (all virtual roots) sequence.
  62. // This mutex guards a read/modify/write sequence.
  63. //
  64. // This is a global mutex to guard for multiple iis resources (i.e., ones running in
  65. // separate resource monitors) NOTE: This does not solve potential
  66. // conflicts with the inetmgr application modifying a root at the same time
  67. //
  68. HANDLE g_hIISUpdateVirtualRootLock = NULL;
  69. LPIIS_RESOURCE g_IISTable[MAX_IIS_RESOURCES] = { 0 };
  70. PLOG_EVENT_ROUTINE g_IISLogEvent = NULL;
  71. PSET_RESOURCE_STATUS_ROUTINE g_IISSetResourceStatus = NULL;
  72. extern CLRES_FUNCTION_TABLE IISFunctionTable;
  73. //
  74. // IIS resource private read-write parameters.
  75. //
  76. RESUTIL_PROPERTY_ITEM
  77. IISResourcePrivateProperties[] = {
  78. { PARAM_NAME__SERVICENAME, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(IIS_PARAMS,ServiceName) },
  79. { PARAM_NAME__ALIAS, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, RESUTIL_PROPITEM_REQUIRED, FIELD_OFFSET(IIS_PARAMS,Alias) },
  80. { PARAM_NAME__DIRECTORY, NULL, CLUSPROP_FORMAT_SZ, 0, 0, 0, 0, FIELD_OFFSET(IIS_PARAMS,Directory) },
  81. { PARAM_NAME__ACCESSMASK, NULL, CLUSPROP_FORMAT_DWORD, 0, PARAM_MIN__ACCESSMASK, PARAM_MAX__ACCESSMASK, 0, FIELD_OFFSET(IIS_PARAMS,AccessMask) },
  82. { 0 }
  83. };
  84. //
  85. // Forward routines
  86. //
  87. DWORD
  88. OnlineVirtualRootExclusive(
  89. IN LPIIS_RESOURCE ResourceEntry
  90. );
  91. DWORD
  92. OfflineVirtualRootExclusive(
  93. IN LPIIS_RESOURCE ResourceEntry
  94. );
  95. BOOL
  96. WINAPI
  97. IISIsAlive(
  98. IN RESID Resource
  99. );
  100. LPIIS_RESOURCE
  101. GetValidResource(
  102. IN RESID Resource,
  103. IN LPWSTR RoutineName
  104. );
  105. DWORD
  106. IISReadParameters(
  107. IN OUT LPIIS_RESOURCE ResourceEntry
  108. );
  109. DWORD
  110. IISGetPrivateResProperties(
  111. IN OUT LPIIS_RESOURCE ResourceEntry,
  112. OUT PVOID OutBuffer,
  113. IN DWORD OutBufferSize,
  114. OUT LPDWORD BytesReturned
  115. );
  116. DWORD
  117. IISValidatePrivateResProperties(
  118. IN OUT LPIIS_RESOURCE ResourceEntry,
  119. IN PVOID InBuffer,
  120. IN DWORD InBufferSize,
  121. OUT PIIS_PARAMS Params
  122. );
  123. DWORD
  124. IISSetPrivateResProperties(
  125. IN OUT LPIIS_RESOURCE ResourceEntry,
  126. IN PVOID InBuffer,
  127. IN DWORD InBufferSize
  128. );
  129. //
  130. // Function definitions
  131. //
  132. BOOLEAN
  133. IISInit(
  134. VOID
  135. )
  136. {
  137. IISLoadMngtDll();
  138. g_hIISUpdateVirtualRootLock = CreateSemaphoreW(
  139. NULL,
  140. 0,
  141. 1,
  142. IIS_SEMAPHORE_NAME);
  143. if (g_hIISUpdateVirtualRootLock == NULL) {
  144. return(FALSE);
  145. }
  146. if ( GetLastError() != ERROR_ALREADY_EXISTS ) {
  147. // set initial state to 1 if it didn't exist
  148. ReleaseSemaphore(g_hIISUpdateVirtualRootLock, 1, NULL);
  149. }
  150. return(TRUE);
  151. }
  152. VOID
  153. IISCleanup()
  154. {
  155. if (g_hIISUpdateVirtualRootLock) {
  156. CloseHandle(g_hIISUpdateVirtualRootLock);
  157. }
  158. IISUnloadMngtDll();
  159. }
  160. BOOLEAN
  161. WINAPI
  162. IISDllEntryPoint(
  163. IN HINSTANCE DllHandle,
  164. IN DWORD Reason,
  165. IN LPVOID Reserved
  166. )
  167. {
  168. switch( Reason ) {
  169. case DLL_PROCESS_ATTACH:
  170. if ( !IISInit() ) {
  171. return(FALSE);
  172. }
  173. break;
  174. case DLL_PROCESS_DETACH:
  175. IISCleanup();
  176. break;
  177. default:
  178. break;
  179. }
  180. return(TRUE);
  181. } // IISShareDllEntryPoint
  182. DWORD
  183. WINAPI
  184. Startup(
  185. IN LPCWSTR ResourceType,
  186. IN DWORD MinVersionSupported,
  187. IN DWORD MaxVersionSupported,
  188. IN PSET_RESOURCE_STATUS_ROUTINE SetResourceStatus,
  189. IN PLOG_EVENT_ROUTINE LogEvent,
  190. OUT PCLRES_FUNCTION_TABLE *FunctionTable
  191. )
  192. /*++
  193. Routine Description:
  194. Startup a particular resource type. This means verifying the version
  195. requested, and returning the function table for this resource type.
  196. Arguments:
  197. ResourceType - Supplies the type of resource.
  198. MinVersionSupported - The minimum version number supported by the cluster
  199. service on this system.
  200. MaxVersionSupported - The maximum version number supported by the cluster
  201. service on this system.
  202. FunctionTable - Returns the Function Table for this resource type.
  203. Return Value:
  204. ERROR_SUCCESS if successful.
  205. A Win32 error code on failure.
  206. --*/
  207. {
  208. DWORD serviceType = MAX_SERVICE;
  209. DWORD i;
  210. //
  211. // Search for a valid service name supported by this DLL
  212. //
  213. if ( lstrcmpiW( ResourceType, IIS_RESOURCE_NAME ) != 0 ) {
  214. return(ERROR_UNKNOWN_REVISION);
  215. }
  216. g_IISLogEvent = LogEvent;
  217. g_IISSetResourceStatus = SetResourceStatus;
  218. if ( (MinVersionSupported <= CLRES_VERSION_V1_00) &&
  219. (MaxVersionSupported >= CLRES_VERSION_V1_00) ) {
  220. *FunctionTable = &IISFunctionTable;
  221. return(ERROR_SUCCESS);
  222. }
  223. return(ERROR_REVISION_MISMATCH);
  224. } // Startup
  225. DWORD
  226. IISOpenThread(
  227. IN PCLUS_WORKER pWorker,
  228. IN LPIIS_RESOURCE ResourceEntry
  229. )
  230. /*++
  231. Routine Description:
  232. Performs some additional initialization for the IIS service.
  233. 1. Makes sure the service is running
  234. 2. Make sure that any virtual roots contained in this resource are
  235. offline (i.e., removed from the IIS).
  236. Arguments:
  237. PWorker - Worker thread structure
  238. ResourceEntry - A pointer to a IIS_RESOURCE block for this resource
  239. Returns:
  240. ERROR_SUCCESS if successful.
  241. Win32 error code on failure.
  242. --*/
  243. {
  244. DWORD status;
  245. DWORD retry = MAX_OPEN_RETRY;
  246. //
  247. //HACKHACK:
  248. // The IIS mngt API updates the registry every time the resource
  249. // is brought online. This means that if the cluster terminated abnormally
  250. // (i.e., did not do offline), then the resource potentially could be
  251. // incorrectly ONLINE after the OPEN.
  252. //
  253. // Until the IIS mngt changes, filter out the "Virtual Root" managed by
  254. // the Cluster
  255. //
  256. //
  257. // Make sure the IIS is installed
  258. //
  259. status = IsIISMngtDllLoaded();
  260. if (status != ERROR_SUCCESS) {
  261. goto error_exit;
  262. }
  263. while (retry--) {
  264. //
  265. // Check to see if we were requested to terminate.
  266. // If so do so cleanly (i.e, no locks held)
  267. //
  268. if (ClusWorkerCheckTerminate(pWorker)){
  269. status = ERROR_OPERATION_ABORTED;
  270. break;
  271. }
  272. //
  273. // Read the Parameter specific information from the registry
  274. //
  275. // CAVEAT: Normally this is done in the online routine.
  276. // We do it here to make sure that the resource comes up
  277. // in an OFFLINE state. The problem is that any iis change
  278. // updates the registry. So its possible that if the cluster
  279. // did not terminate normall that a resource could be incorrectly
  280. // brought up in an ONLINE state.
  281. //
  282. //
  283. status = IISReadParameters(ResourceEntry);
  284. if (status == ERROR_SUCCESS){
  285. //
  286. // Try to offline the virtual roots.
  287. //
  288. status = OfflineVirtualRootExclusive(ResourceEntry);
  289. if (status == ERROR_SUCCESS) {
  290. break;
  291. }
  292. if ( ( status == ERROR_SERVICE_NOT_ACTIVE ) ||
  293. ( status == RPC_S_SERVER_UNAVAILABLE ) ) {
  294. //
  295. // Try to start the service
  296. //
  297. ResUtilStartResourceService( ResourceEntry->Params.ServiceName,
  298. NULL );
  299. //
  300. // Cleanup for next retry
  301. //
  302. DestructVR(ResourceEntry->VirtualRoot);
  303. ResourceEntry->VirtualRoot = NULL;
  304. } else {
  305. break;
  306. }
  307. } else { //END (status == ERROR_SUCCESS)
  308. //
  309. // ERROR_RESOURCE_NOT_FOUND indicates that the IP Address
  310. // dependency could not be found. We may have to wait a bit
  311. // for the other resources to come online before this will succeed
  312. //
  313. // All other errors are non-recoverable and we should exit
  314. //
  315. if (status != ERROR_RESOURCE_NOT_FOUND) {
  316. goto error_exit;
  317. }
  318. }
  319. //
  320. // Check to see if we were requested to terminate.
  321. // If so do so cleanly (i.e, no locks held)
  322. //
  323. if (ClusWorkerCheckTerminate(pWorker)){
  324. status = ERROR_OPERATION_ABORTED;
  325. break;
  326. }
  327. status = ERROR_TIMEOUT;
  328. //
  329. // Give the service time to start
  330. //
  331. Sleep(SERVER_START_DELAY);
  332. }
  333. error_exit:
  334. if (status != ERROR_SUCCESS) {
  335. (g_IISLogEvent)(
  336. ResourceEntry->ResourceHandle,
  337. LOG_INFORMATION,
  338. L"[IISOpenthread] NON-CRITICAL Unable to initialize or offline virtual root Error: %1!u!.\n",
  339. status );
  340. }
  341. //
  342. // The online thread will block until the openthread completes. The online
  343. // thread re-reads the parameters key so free up the storage here.
  344. //
  345. DestructVR(ResourceEntry->VirtualRoot);
  346. ResourceEntry->VirtualRoot = NULL;
  347. return(status);
  348. } // END IISOpenThread
  349. RESID
  350. WINAPI
  351. IISOpen(
  352. IN LPCWSTR ResourceName,
  353. IN HKEY ResourceKey,
  354. IN RESOURCE_HANDLE ResourceHandle
  355. )
  356. /*++
  357. Routine Description:
  358. Open routine for IIS resource.
  359. Arguments:
  360. ResourceName - supplies the resource name
  361. ResourceKey - Supplies handle to resource's cluster registry key.
  362. ResourceHandle - the resource handle to be supplied with SetResourceStatus
  363. is called.
  364. Return Value:
  365. RESID of created resource
  366. Zero on failure
  367. --*/
  368. {
  369. DWORD status;
  370. LPIIS_RESOURCE ResourceEntry;
  371. IIS_RESOURCE tmpResourceEntry;
  372. DWORD count = 0;
  373. DWORD Index = 0;
  374. DWORD serviceType = MAX_SERVICE;
  375. DWORD threadId;
  376. LPCWSTR ResourceType;
  377. HCLUSTER hCluster;
  378. ZeroMemory( &tmpResourceEntry, sizeof(tmpResourceEntry) );
  379. //
  380. // Set the resource handle for logging and init the virtual root entry
  381. //
  382. tmpResourceEntry.ResourceHandle = ResourceHandle;
  383. tmpResourceEntry.VirtualRoot = NULL;
  384. tmpResourceEntry.State = ClusterResourceOffline;
  385. //
  386. // Open the cluster.
  387. //
  388. hCluster = OpenCluster(NULL);
  389. if ( hCluster == NULL ) {
  390. status = GetLastError();
  391. (g_IISLogEvent)(
  392. ResourceHandle,
  393. LOG_ERROR,
  394. L"[IISOpen] Unable to open cluster. Error: %1!u!.\n",
  395. status );
  396. goto error_exit;
  397. }
  398. tmpResourceEntry.hResource = OpenClusterResource( hCluster,
  399. ResourceName );
  400. CloseCluster(hCluster);
  401. if ( tmpResourceEntry.hResource == NULL ) {
  402. status = GetLastError();
  403. (g_IISLogEvent)(
  404. ResourceHandle,
  405. LOG_ERROR,
  406. L"[IISOpen] Unable to open cluster resource handle. Error: %1!u!.\n",
  407. status );
  408. goto error_exit;
  409. }
  410. //
  411. // Open the Parameters key for this resource.
  412. //
  413. status = ClusterRegOpenKey( ResourceKey,
  414. L"Parameters",
  415. KEY_READ,
  416. &tmpResourceEntry.ParametersKey );
  417. if ( status != ERROR_SUCCESS ) {
  418. (g_IISLogEvent)(
  419. ResourceHandle,
  420. LOG_ERROR,
  421. L"[IISOpen] Unable to open parameters key for resource. Error: %1!u!.\n",
  422. status );
  423. goto error_exit;
  424. }
  425. //
  426. // Find a free slot in the resource table
  427. //
  428. for ( count = 1; count <= MAX_IIS_RESOURCES; count++ ) {
  429. if ( g_IISTable[count-1] == NULL ) {
  430. break;
  431. }
  432. }
  433. if ( count > MAX_IIS_RESOURCES ) {
  434. (g_IISLogEvent)(
  435. ResourceHandle,
  436. LOG_ERROR,
  437. L"[IISOpen] No more IIS Resources available.\n");
  438. status = ERROR_RESOURCE_NOT_FOUND;
  439. goto error_exit;
  440. }
  441. //
  442. // Allocate a ResourceEntry
  443. //
  444. ResourceEntry = LocalAlloc( LPTR, sizeof(IIS_RESOURCE) );
  445. if ( ResourceEntry == NULL ) {
  446. (g_IISLogEvent)(
  447. ResourceHandle,
  448. LOG_ERROR,
  449. L"[IISOpen] Unable to allocate IIS resource structure.\n");
  450. status = ERROR_NOT_ENOUGH_MEMORY;
  451. goto error_exit;
  452. }
  453. //
  454. // Save resource in the resource table
  455. //
  456. g_IISTable[count-1] = ResourceEntry;
  457. //
  458. // Copy the tmp resource entry
  459. //
  460. CopyMemory(ResourceEntry,&tmpResourceEntry,sizeof(IIS_RESOURCE));
  461. ResourceEntry->Index = count;
  462. //
  463. // Make sure that the virtual roots contained in this resource
  464. // are offline. The IISOpenThread function performs this task.
  465. //
  466. status = ClusWorkerCreate( &ResourceEntry->OpenThread,
  467. IISOpenThread,
  468. ResourceEntry );
  469. if ( status != ERROR_SUCCESS ) {
  470. ResourceEntry->State = ClusterResourceFailed;
  471. (g_IISLogEvent)(
  472. ResourceEntry->ResourceHandle,
  473. LOG_ERROR,
  474. L"[IISOpen] Unable to create open worker thread, status %1!u!.\n",
  475. status
  476. );
  477. goto error_exit;
  478. }
  479. //
  480. // Log success
  481. //
  482. (g_IISLogEvent)(
  483. ResourceHandle,
  484. LOG_INFORMATION,
  485. L"[IISOpen] Open request succeeded with id = %1!u!.\n",
  486. ResourceEntry->Index);
  487. return((RESID)ResourceEntry->Index);
  488. error_exit:
  489. if (count > 0){
  490. g_IISTable[count -1] = NULL;
  491. }
  492. if (tmpResourceEntry.ParametersKey != NULL){
  493. ClusterRegCloseKey( tmpResourceEntry.ParametersKey );
  494. }
  495. if (tmpResourceEntry.hResource != NULL) {
  496. CloseClusterResource( tmpResourceEntry.hResource );
  497. }
  498. if (ResourceEntry != 0){
  499. DestructIISResource(ResourceEntry);
  500. } else {
  501. FreeIISResource(&tmpResourceEntry);
  502. }
  503. (g_IISLogEvent)(
  504. ResourceHandle,
  505. LOG_ERROR,
  506. L"[IISOpen] Error %1!u! opening iis resource %2!ws!.\n",
  507. status,
  508. ResourceName );
  509. SetLastError(status);
  510. return((RESID)(0));
  511. } // IISOpen
  512. DWORD
  513. IISOnlineThread(
  514. IN PCLUS_WORKER pWorker,
  515. IN LPIIS_RESOURCE ResourceEntry
  516. )
  517. /*++
  518. Routine Description:
  519. Brings a share resource online.
  520. Arguments:
  521. pWorker - Supplies the worker structure
  522. ResourceEntry - A pointer to a IIS_RESOURCE block for this resource
  523. Returns:
  524. ERROR_SUCCESS if successful.
  525. Win32 error code on failure.
  526. --*/
  527. {
  528. DWORD status;
  529. DWORD retry;
  530. RESOURCE_STATUS resourceStatus;
  531. ResUtilInitializeResourceStatus( &resourceStatus );
  532. resourceStatus.ResourceState = ClusterResourceOnlinePending;
  533. //resourceStatus.WaitHint = 0;
  534. resourceStatus.CheckPoint = 1;
  535. ResourceEntry->State = ClusterResourceOnlinePending;
  536. //
  537. // See if the open worker thread has terminated
  538. //
  539. retry = MAX_OPEN_RETRY*2;
  540. while (retry--) {
  541. //
  542. // Check to see if we were requested to terminate.
  543. // If so do so cleanly (i.e, no locks held)
  544. //
  545. if (ClusWorkerCheckTerminate(pWorker)){
  546. status = ERROR_OPERATION_ABORTED;
  547. goto error_exit;
  548. }
  549. //
  550. // See if the open thread terminated
  551. //
  552. if (ClusWorkerCheckTerminate(&ResourceEntry->OpenThread)){
  553. status = ERROR_SUCCESS;
  554. break;
  555. }
  556. //
  557. // Wait for a bit
  558. //
  559. status = ERROR_TIMEOUT;
  560. Sleep(SERVER_START_DELAY);
  561. } // END retry
  562. #if 0
  563. if (status != ERROR_SUCCESS) {
  564. (g_IISLogEvent)(
  565. ResourceEntry->ResourceHandle,
  566. LOG_ERROR,
  567. L"ERROR [OnLineThread] TIMEOUT waiting for open thread to terminate \n");
  568. }
  569. #endif
  570. //
  571. // Try to Read the Parameter specific information from
  572. // the registry. This must defer this till after open thread terminates
  573. // i.e., because open also reads the parameters
  574. status = IISReadParameters( ResourceEntry );
  575. if (status != ERROR_SUCCESS){
  576. (g_IISLogEvent)(
  577. ResourceEntry->ResourceHandle,
  578. LOG_ERROR,
  579. L"ERROR [OnLineThread] Could not read resource parameters\n");
  580. goto error_exit;
  581. }
  582. retry = MAX_ONLINE_RETRY;
  583. while (retry--) {
  584. //
  585. // Check to see if we were requested to terminate.
  586. // If so do so cleanly (i.e, no locks held)
  587. //
  588. if (ClusWorkerCheckTerminate(pWorker)){
  589. status = ERROR_OPERATION_ABORTED;
  590. break;
  591. }
  592. #if 0
  593. (g_IISLogEvent)(
  594. ResourceEntry->ResourceHandle,
  595. LOG_INFORMATION,
  596. L"INFO [OnLineThread] Root = %1!ws! IP = %2!ws! Dir = %3!ws! Mask = %4!u!\n",
  597. ResourceEntry->VirtualRoot->pszRoot,
  598. ResourceEntry->VirtualRoot->pszAddress,
  599. ResourceEntry->VirtualRoot->pszDirectory,
  600. ResourceEntry->VirtualRoot->dwMask);
  601. #endif
  602. //
  603. // Try to Online the resources
  604. status = OnlineVirtualRootExclusive(ResourceEntry);
  605. #if 0
  606. (g_IISLogEvent)(
  607. ResourceEntry->ResourceHandle,
  608. LOG_INFORMATION,
  609. L"INFO [OnLineThread] OnLineVirtualRoot status = %1!u!\n",
  610. status);
  611. #endif
  612. if ( status == ERROR_SUCCESS) {
  613. break;
  614. }
  615. //
  616. // Check to see if we were requested to terminate.
  617. // If so do so cleanly (i.e, no locks held)
  618. //
  619. if (ClusWorkerCheckTerminate(pWorker)){
  620. status = ERROR_OPERATION_ABORTED;
  621. break;
  622. }
  623. //
  624. // If we failed for any reason except
  625. // the service is not active then fail
  626. //
  627. if ( ( status == ERROR_SERVICE_NOT_ACTIVE ) ||
  628. ( status == RPC_S_SERVER_UNAVAILABLE ) ) {
  629. //
  630. // Try to start the service
  631. //
  632. ResUtilStartResourceService( ResourceEntry->Params.ServiceName,
  633. NULL );
  634. } else {
  635. goto error_exit;
  636. }
  637. //
  638. // We restarted the service. It's possible that the service terminated
  639. // abnormally. If the resource is online, leave it and return success
  640. //
  641. if (VerifyIISService(ResourceEntry,FALSE,g_IISLogEvent)) {
  642. status = ERROR_SUCCESS;
  643. goto error_exit;
  644. }
  645. //
  646. // Check to see if we were requested to terminate.
  647. // If so do so cleanly (i.e, no locks held)
  648. //
  649. if (ClusWorkerCheckTerminate(pWorker)){
  650. status = ERROR_OPERATION_ABORTED;
  651. break;
  652. }
  653. status = ERROR_TIMEOUT;
  654. //
  655. // Give the service time to start
  656. //
  657. Sleep(SERVER_START_DELAY);
  658. } // END While retry--
  659. error_exit:
  660. if ( status != ERROR_SUCCESS ) {
  661. //
  662. // Error
  663. //
  664. (g_IISLogEvent)(
  665. ResourceEntry->ResourceHandle,
  666. LOG_ERROR,
  667. L"[IISOnlineThread] Error %1!u! cannot bring resource online.\n",
  668. status );
  669. resourceStatus.ResourceState = ClusterResourceFailed;
  670. ResourceEntry->State = ClusterResourceFailed;
  671. } else {
  672. //
  673. // Success, update state, log message
  674. //
  675. resourceStatus.ResourceState = ClusterResourceOnline;
  676. ResourceEntry->State = ClusterResourceOnline;
  677. #if 0
  678. (g_IISLogEvent)(
  679. ResourceEntry->ResourceHandle,
  680. LOG_INFORMATION,
  681. L"[IISOnlineThread] Success bringing resource online.\n" );
  682. #endif
  683. }
  684. //
  685. // Set the state of the resource
  686. //
  687. (g_IISSetResourceStatus)( ResourceEntry->ResourceHandle,
  688. &resourceStatus );
  689. return(status);
  690. } // IISOnlineThread
  691. DWORD
  692. WINAPI
  693. IISOnline(
  694. IN RESID Resource,
  695. IN OUT PHANDLE EventHandle
  696. )
  697. /*++
  698. Routine Description:
  699. Online routine for IIS resource.
  700. Arguments:
  701. Resource - supplies resource id to be brought online
  702. EventHandle - supplies a pointer to a handle to signal on error.
  703. Return Value:
  704. ERROR_SUCCESS if successful.
  705. ERROR_RESOURCE_NOT_FOUND if RESID is not valid.
  706. ERROR_RESOURCE_NOT_AVAILABLE if resource was arbitrated but failed to
  707. ERROR_SERVICE_NOT_ACTIVE if it could not find the IIS management DLL
  708. acquire 'ownership'.
  709. Win32 error code if other failure.
  710. --*/
  711. {
  712. LPIIS_RESOURCE ResourceEntry = NULL;
  713. DWORD threadId;
  714. DWORD status;
  715. //
  716. // Get a valid resource
  717. //
  718. ResourceEntry = GetValidResource(Resource,L"OnLine");
  719. if (ResourceEntry == NULL) {
  720. return(ERROR_RESOURCE_NOT_FOUND);
  721. }
  722. #if 0
  723. (g_IISLogEvent)(
  724. ResourceEntry->ResourceHandle,
  725. LOG_INFORMATION,
  726. L"[IISOnline] Online request for IIS Resource %1!u!.\n",
  727. Resource );
  728. #endif
  729. // Initialize the state to offline
  730. ResourceEntry->State = ClusterResourceOffline;
  731. // Terminate (or wait) for workers
  732. ClusWorkerTerminate( &ResourceEntry->OnlineThread );
  733. // Make sure the IIS is installed
  734. status = IsIISMngtDllLoaded();
  735. if (status != ERROR_SUCCESS) {
  736. // Set the state to failed AND log event
  737. ResourceEntry->State = ClusterResourceFailed;
  738. (g_IISLogEvent)(
  739. ResourceEntry->ResourceHandle,
  740. LOG_ERROR,
  741. L"[IISOnline] Error loading IIS mngt dll or one of its functions error status: %1!u!\n",
  742. status);
  743. return(ERROR_SERVICE_NOT_ACTIVE);
  744. }
  745. // Create new online thread
  746. status = ClusWorkerCreate( &ResourceEntry->OnlineThread,
  747. IISOnlineThread,
  748. ResourceEntry );
  749. if (status != ERROR_SUCCESS){
  750. // Set the state to failed AND log event
  751. ResourceEntry->State = ClusterResourceFailed;
  752. (g_IISLogEvent)(
  753. ResourceEntry->ResourceHandle,
  754. LOG_ERROR,
  755. L"[IISOnline] Unable to create cluster worker thread, status %1!u!.\n",
  756. status
  757. );
  758. } else {
  759. status = ERROR_IO_PENDING;
  760. }
  761. return(status);
  762. } // IISOnline
  763. VOID
  764. WINAPI
  765. IISTerminate(
  766. IN RESID Resource
  767. )
  768. /*++
  769. Routine Description:
  770. Terminate routine for IIS resource.
  771. Arguments:
  772. Resource - supplies resource id to be terminated
  773. Return Value:
  774. None.
  775. --*/
  776. {
  777. DWORD status;
  778. LPIIS_RESOURCE ResourceEntry;
  779. //
  780. // Get a valid resource entry, return on error
  781. //
  782. ResourceEntry = GetValidResource(Resource,L"Terminate");
  783. if (ResourceEntry == NULL) {
  784. return;
  785. } else {
  786. status = ERROR_SUCCESS;
  787. }
  788. #if 0
  789. (g_IISLogEvent)(
  790. ResourceEntry->ResourceHandle,
  791. LOG_INFORMATION,
  792. L"[IISTerminate] Terminate or offline request for Resource%1!u!.\n",
  793. Resource );
  794. #endif
  795. ClusWorkerTerminate( &ResourceEntry->OnlineThread );
  796. ClusWorkerTerminate( &ResourceEntry->OpenThread );
  797. //
  798. // Try to take the resources offline, dont return if an error since
  799. // the resources may be offline when terminate called
  800. //
  801. if ((ResourceEntry->State == ClusterResourceOnlinePending) ||
  802. (ResourceEntry->State == ClusterResourceOnline)) {
  803. status = OfflineVirtualRootExclusive(ResourceEntry);
  804. }
  805. if ( status != ERROR_SUCCESS ) {
  806. (g_IISLogEvent)(
  807. ResourceEntry->ResourceHandle,
  808. LOG_ERROR,
  809. L"[IISTerminate] Error terminating Resource. NT Status %1!u!. Service. %2!ws!\n",
  810. status,
  811. ResourceEntry->Params.ServiceName);
  812. }
  813. //
  814. // Set status to offline
  815. //
  816. ResourceEntry->State = ClusterResourceOffline;
  817. //
  818. // Reclaim storage for parameters, close handles
  819. //
  820. DestructVR(ResourceEntry->VirtualRoot);
  821. ResourceEntry->VirtualRoot = NULL;
  822. } // IISTerminate
  823. DWORD
  824. WINAPI
  825. IISOffline(
  826. IN RESID Resource
  827. )
  828. /*++
  829. Routine Description:
  830. Offline routine for IIS resource.
  831. Arguments:
  832. Resource - supplies the resource it to be taken offline
  833. Return Value:
  834. ERROR_SUCCESS - always successful.
  835. --*/
  836. {
  837. LPIIS_RESOURCE ResourceEntry;
  838. //
  839. // Get a valid resource entry, return on error
  840. //
  841. ResourceEntry = GetValidResource(Resource,L"Offline");
  842. if (ResourceEntry == NULL) {
  843. return(ERROR_RESOURCE_NOT_FOUND);
  844. }
  845. #if 0
  846. (g_IISLogEvent)(
  847. ResourceEntry->ResourceHandle,
  848. LOG_INFORMATION,
  849. L"[IISOffline] Offline request for Resource%1!u!.\n",
  850. Resource );
  851. #endif
  852. IISTerminate(Resource);
  853. return(ERROR_SUCCESS);
  854. } // IISOffline
  855. BOOL
  856. WINAPI
  857. IISIsAlive(
  858. IN RESID Resource
  859. )
  860. /*++
  861. Routine Description:
  862. IsAlive routine for IIS service resource.
  863. Arguments:
  864. Resource - supplies the resource id to be polled.
  865. Return Value:
  866. TRUE - if service is running
  867. FALSE - if service is in any other state
  868. --*/
  869. {
  870. LPIIS_RESOURCE ResourceEntry;
  871. //
  872. // Get a valid resource
  873. //
  874. ResourceEntry = GetValidResource(Resource,L"IsAlive");
  875. if (ResourceEntry == NULL) {
  876. return(FALSE);
  877. }
  878. //
  879. // Verify the resource
  880. //
  881. return( VerifyIISService( ResourceEntry, TRUE, g_IISLogEvent ));
  882. } // IISIsAlive
  883. BOOL
  884. WINAPI
  885. IISLooksAlive(
  886. IN RESID Resource
  887. )
  888. /*++
  889. Routine Description:
  890. LooksAlive routine for IIS resource.
  891. Arguments:
  892. Resource - supplies the resource id to be polled.
  893. Return Value:
  894. TRUE - Resource looks like it is alive and well
  895. FALSE - Resource looks like it is toast.
  896. --*/
  897. {
  898. LPIIS_RESOURCE ResourceEntry;
  899. HANDLE serviceHandle;
  900. HANDLE scManagerHandle;
  901. DWORD status;
  902. SERVICE_STATUS serviceStatus;
  903. //
  904. // Get a valid resource
  905. //
  906. ResourceEntry = GetValidResource(Resource,L"LooksAlive");
  907. if (ResourceEntry == NULL) {
  908. return(FALSE);
  909. }
  910. //
  911. // Query the status of the server
  912. //
  913. scManagerHandle = OpenSCManager( NULL, // local machine
  914. NULL, // ServicesActive database
  915. SC_MANAGER_ALL_ACCESS ); // all access
  916. if ( scManagerHandle == NULL ) {
  917. status = GetLastError();
  918. #if 0
  919. (g_IISLogEvent)(
  920. ResourceEntry->ResourceHandle,
  921. LOG_INFORMATION,
  922. L"[IISLooksAlive] Cannot access service controller '%1!ws!' status = %2!u!\n",
  923. ResourceEntry->Params.ServiceName,
  924. status);
  925. #endif
  926. return(FALSE);
  927. }
  928. serviceHandle = OpenService( scManagerHandle,
  929. ResourceEntry->Params.ServiceName,
  930. SERVICE_ALL_ACCESS );
  931. //
  932. // CLOSE Service Manager Handle
  933. //
  934. CloseServiceHandle( scManagerHandle );
  935. if ( serviceHandle == NULL ) {
  936. status = GetLastError();
  937. #if 0
  938. (g_IISLogEvent)(
  939. ResourceEntry->ResourceHandle,
  940. LOG_INFORMATION,
  941. L"[IISLooksAlive] Cannot open service '%1!ws!' status = %2!u!\n",
  942. ResourceEntry->Params.ServiceName,
  943. status);
  944. #endif
  945. return(FALSE);
  946. }
  947. if ( !QueryServiceStatus(serviceHandle, &serviceStatus) ) {
  948. status = GetLastError();
  949. #if 0
  950. (g_IISLogEvent)(
  951. ResourceEntry->ResourceHandle,
  952. LOG_INFORMATION,
  953. L"[IISLooksAlive] Error querying service '%1!ws!' status = %2!u!\n",
  954. ResourceEntry->Params.ServiceName,
  955. status);
  956. #endif
  957. CloseServiceHandle( serviceHandle );
  958. return FALSE;
  959. }
  960. //
  961. // CLOSE Service Handle
  962. //
  963. CloseServiceHandle( serviceHandle );
  964. if ( serviceStatus.dwCurrentState == SERVICE_RUNNING ) {
  965. return TRUE;
  966. }
  967. #if 1
  968. (g_IISLogEvent)(
  969. ResourceEntry->ResourceHandle,
  970. LOG_INFORMATION,
  971. L"[IISLooksAlive] Service not running '%1!ws!' state = %2!u!\n",
  972. ResourceEntry->Params.ServiceName,
  973. serviceStatus.dwCurrentState);
  974. #endif
  975. return FALSE;
  976. } // IISLooksAlive
  977. VOID
  978. WINAPI
  979. IISClose(
  980. IN RESID Resource
  981. )
  982. /*++
  983. Routine Description:
  984. Close routine for IIS resource.
  985. Arguments:
  986. Resource - supplies resource id to be closed
  987. Return Value:
  988. None.
  989. --*/
  990. {
  991. LPIIS_RESOURCE ResourceEntry = NULL;
  992. //
  993. // Get a valid resource
  994. //
  995. ResourceEntry = GetValidResource( Resource, L"Close");
  996. if (ResourceEntry == NULL) {
  997. return; // this should not happen
  998. }
  999. #if 0
  1000. (g_IISLogEvent)(
  1001. ResourceEntry->ResourceHandle,
  1002. LOG_INFORMATION,
  1003. L"[IISClose] Close request for Service '%1!ws!' \n",
  1004. ResourceEntry->Params.ServiceName);
  1005. #endif
  1006. //
  1007. // Clear the table entry
  1008. //
  1009. g_IISTable[ResourceEntry->Index -1] = NULL;
  1010. DestructIISResource(ResourceEntry);
  1011. } // IISClose
  1012. DWORD
  1013. OnlineVirtualRootExclusive(
  1014. IN LPIIS_RESOURCE ResourceEntry
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. This routine performs an atomic read modify write operation to
  1019. ONline a virtual root
  1020. Arguments:
  1021. ResourceEntry - Supplies the resource to offline
  1022. Return Value:
  1023. ERROR_SUCCESS if successful.
  1024. A Win32 error code on failure.
  1025. --*/
  1026. {
  1027. DWORD status;
  1028. WaitForSingleObject(g_hIISUpdateVirtualRootLock, INFINITE);
  1029. status = OnLineVirtualRoot(ResourceEntry, g_IISLogEvent);
  1030. ReleaseSemaphore( g_hIISUpdateVirtualRootLock, 1, 0);
  1031. return status;
  1032. }
  1033. DWORD
  1034. OfflineVirtualRootExclusive(
  1035. IN LPIIS_RESOURCE ResourceEntry
  1036. )
  1037. /*++
  1038. Routine Description:
  1039. This routine performs an atomic read modify write operation to
  1040. offline a virtual root
  1041. Arguments:
  1042. ResourceEntry - Supplies the resource to offline
  1043. Return Value:
  1044. ERROR_SUCCESS if successful.
  1045. A Win32 error code on failure.
  1046. --*/
  1047. {
  1048. DWORD status;
  1049. WaitForSingleObject(g_hIISUpdateVirtualRootLock,INFINITE);
  1050. status = OffLineVirtualRoot(ResourceEntry, g_IISLogEvent);
  1051. ReleaseSemaphore( g_hIISUpdateVirtualRootLock, 1, 0);
  1052. return status;
  1053. }
  1054. LPIIS_RESOURCE
  1055. GetValidResource(
  1056. IN RESID Resource,
  1057. IN LPWSTR RoutineName
  1058. )
  1059. /*++
  1060. Routine Description:
  1061. Validate the resource ID, log any error, return valid resource
  1062. Arguments:
  1063. Resource - the resource to validate
  1064. RoutineName - the routine that is requesting the validation
  1065. Return Value:
  1066. Success - ResourceEntry
  1067. NULL - Error
  1068. --*/
  1069. {
  1070. DWORD Index;
  1071. LPIIS_RESOURCE ResourceEntry;
  1072. //
  1073. // Validate the resource id is in the correct range
  1074. //
  1075. Index = (DWORD)Resource -1;
  1076. if ( Index > MAX_IIS_RESOURCES) {
  1077. (g_IISLogEvent)(
  1078. NULL,
  1079. LOG_ERROR,
  1080. L"[%1!ws!] Invalid resource id (out of range) Resource Id = %2!u!\n",
  1081. RoutineName,
  1082. Index);
  1083. return(NULL);
  1084. }
  1085. ResourceEntry = g_IISTable[Index];
  1086. //
  1087. // Check for a valid
  1088. //
  1089. if ( ResourceEntry == NULL ) {
  1090. (g_IISLogEvent)(
  1091. NULL,
  1092. LOG_ERROR,
  1093. L"[%1!ws!] Resource Entry is NULL for Resource Id = %2!u!\n",
  1094. RoutineName,
  1095. Index);
  1096. return(NULL);
  1097. }
  1098. //
  1099. // Sanity check the resource id
  1100. //
  1101. if ( ResourceEntry->Index != (DWORD)Resource ) {
  1102. (g_IISLogEvent)(
  1103. ResourceEntry->ResourceHandle,
  1104. LOG_ERROR,
  1105. L"[%1!ws!] IIS Resource index sanity checked failed! Index = %2!u!.\n",
  1106. RoutineName,
  1107. Resource );
  1108. return(NULL);
  1109. }
  1110. return(ResourceEntry);
  1111. } // END GetValidResource
  1112. LPWSTR
  1113. GetResourceParameter(
  1114. IN HRESOURCE hResource,
  1115. IN LPCWSTR ValueName
  1116. )
  1117. /*++
  1118. Routine Description:
  1119. Opens the parameter key for the resource. Then Queries a REG_SZ parameter
  1120. out of the registry and allocates the necessary storage for it.
  1121. Arguments:
  1122. hResource - the resource to query
  1123. ValueName - Supplies the name of the value.
  1124. Return Value:
  1125. A pointer to a buffer containing the parameter if successful.
  1126. NULL if unsuccessful.
  1127. --*/
  1128. {
  1129. HKEY hKey = NULL;
  1130. HKEY hParametersKey = NULL;
  1131. DWORD status;
  1132. LPWSTR paramValue = NULL;
  1133. //
  1134. // Get Resource key
  1135. //
  1136. hKey = GetClusterResourceKey(hResource,KEY_READ);
  1137. if (hKey == NULL) {
  1138. return(NULL);
  1139. }
  1140. //
  1141. // Get parameters key
  1142. //
  1143. status = ClusterRegOpenKey(hKey,
  1144. L"Parameters",
  1145. KEY_READ,
  1146. &hParametersKey );
  1147. if (status != ERROR_SUCCESS) {
  1148. goto error_exit;
  1149. }
  1150. paramValue = ResUtilGetSzValue( hParametersKey,
  1151. ValueName );
  1152. error_exit:
  1153. if (hParametersKey != NULL) {
  1154. ClusterRegCloseKey(hParametersKey);
  1155. }
  1156. if (hKey != NULL) {
  1157. ClusterRegCloseKey(hKey);
  1158. }
  1159. return(paramValue);
  1160. } // GetResourceParameter
  1161. DWORD
  1162. IISReadParameters(
  1163. IN OUT LPIIS_RESOURCE ResourceEntry
  1164. )
  1165. /*++
  1166. Routine Description:
  1167. Reads all the parameters for a resource.
  1168. Arguments:
  1169. ResourceEntry - Entry in the resource table.
  1170. Return Value:
  1171. ERROR_SUCCESS - Success
  1172. RECOVERABLE ERROR
  1173. ERROR_RESOURCE_NOT_FOUND - The IP Address dependency was not found try again later
  1174. FATAL ERRORS
  1175. ERROR_INVALID_PARAMETER - One of the required parameters was incorrect or NULL
  1176. ERROR_NOT_ENOUGH_MEMORY - Could not satisfy the memory request
  1177. ERROR_INVALID_SERVICENAME - Service name is invalid for this resource dll
  1178. ERROR_DUP_NAME - Duplicate exclusive parameter name found
  1179. --*/
  1180. {
  1181. DWORD status;
  1182. LPCTSTR password = NULL;
  1183. LPINET_INFO_VIRTUAL_ROOT_ENTRY tmpVr;
  1184. DWORD accessMask;
  1185. HRESOURCE hResource = NULL;
  1186. INT iServiceType;
  1187. DWORD length;
  1188. LPWSTR nameOfPropInError;
  1189. //
  1190. // Each offline (or at end of OpenThread) frees the VirtualRoot
  1191. // Make sure the entry is NULL
  1192. //
  1193. if ( ResourceEntry->VirtualRoot != NULL ) {
  1194. (g_IISLogEvent)(
  1195. ResourceEntry->ResourceHandle,
  1196. LOG_ERROR,
  1197. L"[IISReadParameters] NON-Empty virtual root entry.\n" );
  1198. }
  1199. //
  1200. // Allocate memory for the virtual root
  1201. //
  1202. tmpVr = LocalAlloc( LPTR, sizeof(INET_INFO_VIRTUAL_ROOT_ENTRY) );
  1203. if ( tmpVr == NULL ) {
  1204. (g_IISLogEvent)(
  1205. ResourceEntry->ResourceHandle,
  1206. LOG_ERROR,
  1207. L"[IISReadParameters] Cannot allocate storage for virtual root for resource\n" );
  1208. return( ERROR_NOT_ENOUGH_MEMORY );
  1209. }
  1210. //
  1211. // Read the parameters for the resource.
  1212. //
  1213. status = ResUtilGetPropertiesToParameterBlock( ResourceEntry->ParametersKey,
  1214. IISResourcePrivateProperties,
  1215. (LPBYTE) &ResourceEntry->Params,
  1216. TRUE, // CheckForRequiredProperties
  1217. &nameOfPropInError );
  1218. if ( status != ERROR_SUCCESS ) {
  1219. (g_IISLogEvent)(
  1220. ResourceEntry->ResourceHandle,
  1221. LOG_ERROR,
  1222. L"Unable to read the '%1' property. Error: %2!u!.\n",
  1223. (nameOfPropInError == NULL ? L"" : nameOfPropInError),
  1224. status );
  1225. goto error_exit;
  1226. }
  1227. //
  1228. // Make sure we got passed a valid service name
  1229. //
  1230. for ( iServiceType = 0 ; iServiceType < MAX_SERVICE ; iServiceType++ ) {
  1231. if ( lstrcmpiW( ResourceEntry->Params.ServiceName, ActualServiceName[iServiceType] ) == 0 ) {
  1232. break;
  1233. }
  1234. }
  1235. if ( iServiceType >= MAX_SERVICE ) {
  1236. (g_IISLogEvent)(
  1237. ResourceEntry->ResourceHandle,
  1238. LOG_ERROR,
  1239. L"[IISReadParameters] Service name %1!ws! not supported or found\n",
  1240. ResourceEntry->Params.ServiceName );
  1241. status = ERROR_INVALID_SERVICENAME;
  1242. goto error_exit;
  1243. }
  1244. ResourceEntry->ServiceType = iServiceType;
  1245. //
  1246. // Copy the parameters to where they are used.
  1247. //
  1248. tmpVr->pszRoot = LocalAlloc( LMEM_FIXED, (lstrlenW( ResourceEntry->Params.Alias ) + 1) * sizeof(WCHAR) );
  1249. if ( tmpVr->pszRoot == NULL ) {
  1250. status = GetLastError();
  1251. goto error_exit;
  1252. }
  1253. lstrcpyW( tmpVr->pszRoot, ResourceEntry->Params.Alias );
  1254. tmpVr->pszDirectory = LocalAlloc( LMEM_FIXED, (lstrlenW( ResourceEntry->Params.Directory ) + 1) * sizeof(WCHAR) );
  1255. if ( tmpVr->pszDirectory == NULL ) {
  1256. status = GetLastError();
  1257. goto error_exit;
  1258. }
  1259. lstrcpyW( tmpVr->pszDirectory, ResourceEntry->Params.Directory );
  1260. //
  1261. // Get the Access Mask
  1262. //
  1263. if ( ResourceEntry->ServiceType != GOPHER_SERVICE ) {
  1264. status = ResUtilGetDwordValue( ResourceEntry->ParametersKey,
  1265. PARAM_NAME__ACCESSMASK,
  1266. &accessMask,
  1267. 0 );
  1268. if (status != ERROR_SUCCESS ) {
  1269. (g_IISLogEvent)(
  1270. ResourceEntry->ResourceHandle,
  1271. LOG_ERROR,
  1272. L"[IISReadParameters] Unable to read virtual root Access Mask\n" );
  1273. status = ERROR_INVALID_PARAMETER;
  1274. goto error_exit;
  1275. }
  1276. tmpVr->dwMask = accessMask;
  1277. } // END != GOPHER_SERVICE
  1278. if ( ResourceEntry->ServiceType == WWW_SERVICE ) {
  1279. //
  1280. // Get the IP Address
  1281. //
  1282. hResource = ResUtilGetResourceDependency( ResourceEntry->hResource,
  1283. IP_ADDRESS_RESOURCE_NAME );
  1284. if ( hResource == NULL ) {
  1285. status = GetLastError();
  1286. (g_IISLogEvent)(
  1287. ResourceEntry->ResourceHandle,
  1288. LOG_ERROR,
  1289. L"[IISReadParameters] Unable to find IP Address dependency status =%1!u!\n",
  1290. status
  1291. );
  1292. //
  1293. // A status of ERROR_NO_DATA indicates that
  1294. // there were no dependencies for this resource
  1295. //
  1296. if (status == ERROR_NO_DATA) {
  1297. status = ERROR_INVALID_PARAMETER;
  1298. } else {
  1299. status = ERROR_RESOURCE_NOT_FOUND;
  1300. }
  1301. goto error_exit;
  1302. }
  1303. tmpVr->pszAddress = GetResourceParameter( hResource, L"Address" );
  1304. if ( tmpVr->pszAddress == NULL ) {
  1305. (g_IISLogEvent)(
  1306. ResourceEntry->ResourceHandle,
  1307. LOG_ERROR,
  1308. L"[IISReadParameters] Unable to get TPC/IP Address from Cluster Reg\n" );
  1309. status = ERROR_INVALID_PARAMETER;
  1310. goto error_exit;
  1311. }
  1312. } else { // ELSE NOT WWW_SERVICE
  1313. //
  1314. // Allocate memory for NULL ip address field
  1315. //
  1316. tmpVr->pszAddress = LocalAlloc( LPTR, sizeof(WCHAR)*10 );
  1317. if (tmpVr->pszAddress == NULL) {
  1318. (g_IISLogEvent)(
  1319. ResourceEntry->ResourceHandle,
  1320. LOG_ERROR,
  1321. L"[IISReadParameters] Cannot allocate storage for NULL (GOPHER, FTP) IP Address" );
  1322. status = ERROR_NOT_ENOUGH_MEMORY;
  1323. goto error_exit;
  1324. } // end pszAddress == NULL
  1325. //
  1326. // Copy a NULL character
  1327. //
  1328. lstrcpyW( tmpVr->pszAddress, L"\0" );
  1329. } // END IF WWW_SERVICE
  1330. //HACK HACK
  1331. //make sure the password field is null terminated
  1332. //
  1333. lstrcpyW( tmpVr->AccountPassword, L"\0" );
  1334. //
  1335. // Get the [optional] AccountName
  1336. //
  1337. /*BUGBUG
  1338. //This version does not support protecting UNC physical directories
  1339. //with an account name and password...
  1340. /*BUGBUG
  1341. tmpVr->pszAccountName = ResUtilGetSzValue( ResourceEntry->ParametersKey,
  1342. PARAM_NAME__ACCOUNTNAME );
  1343. */
  1344. if ( tmpVr->pszAccountName == NULL ) {
  1345. #if 0
  1346. (g_IISLogEvent)(
  1347. ResourceEntry->ResourceHandle,
  1348. LOG_INFORMATION,
  1349. L"[IISReadParameters] NO Account name entered set to NULL\n" );
  1350. #endif
  1351. tmpVr->pszAccountName = LocalAlloc( LPTR, sizeof(WCHAR)*2 );
  1352. //
  1353. // Make sure we can still allocate memory
  1354. //
  1355. if ( tmpVr->pszAccountName == NULL ) {
  1356. (g_IISLogEvent)(
  1357. ResourceEntry->ResourceHandle,
  1358. LOG_ERROR,
  1359. L"[IISReadParameters] Cannot allocate memory for Account Name\n" );
  1360. status = ERROR_NOT_ENOUGH_MEMORY;
  1361. goto error_exit;
  1362. } //END pszAccountName == NULL
  1363. //
  1364. // Copy a NULL character
  1365. //
  1366. lstrcpyW( tmpVr->pszAccountName, L"\0" );
  1367. } else {
  1368. //
  1369. // Get the [optional] Account password
  1370. //
  1371. //
  1372. /* BUGBUG Add password after encryption in registry available
  1373. password = ResUtilGetSzValue( ResourceEntry->ParametersKey,
  1374. PARAM_NAME__PASSWORD );
  1375. */
  1376. if ( password == NULL ) {
  1377. #if 0
  1378. (g_IISLogEvent)(
  1379. ResourceEntry->ResourceHandle,
  1380. LOG_ERROR,
  1381. L"[IISReadParameters] No password specified\n" );
  1382. #endif
  1383. } else {
  1384. lstrcpyW( tmpVr->AccountPassword, password );
  1385. } // END password == NULL
  1386. } // END else pszAccountName == NULL
  1387. status = ERROR_SUCCESS;
  1388. ResourceEntry->VirtualRoot = tmpVr;
  1389. error_exit:
  1390. if (password != NULL) {
  1391. LocalFree((PVOID)password);
  1392. }
  1393. if (status != ERROR_SUCCESS) {
  1394. DestructVR(tmpVr);
  1395. }
  1396. if (hResource != NULL) {
  1397. CloseClusterResource(hResource);
  1398. }
  1399. return(status);
  1400. } // IISReadParameters
  1401. DWORD
  1402. IISGetRequiredDependencies(
  1403. OUT PVOID OutBuffer,
  1404. IN DWORD OutBufferSize,
  1405. OUT LPDWORD BytesReturned
  1406. )
  1407. /*++
  1408. Routine Description:
  1409. Processes the CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES control function
  1410. for resources of type IIS Virtual Root.
  1411. Arguments:
  1412. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1413. OutBufferSize - Supplies the size, in bytes, of the available space
  1414. pointed to by OutBuffer.
  1415. BytesReturned - Returns the number of bytes of OutBuffer actually
  1416. filled in by the resource. If OutBuffer is too small, BytesReturned
  1417. contains the total number of bytes for the operation to succeed.
  1418. Return Value:
  1419. ERROR_SUCCESS - The function completed successfully.
  1420. ERROR_MORE_DATA - The output buffer is too small to return the data.
  1421. BytesReturned contains the required size.
  1422. Win32 error code - The function failed.
  1423. --*/
  1424. {
  1425. typedef struct DEP_DATA {
  1426. CLUSPROP_SZ_DECLARE( ipaddrEntry, sizeof(IP_ADDRESS_RESOURCE_NAME) / sizeof(WCHAR) );
  1427. CLUSPROP_SYNTAX endmark;
  1428. } DEP_DATA, *PDEP_DATA;
  1429. PDEP_DATA pdepdata = (PDEP_DATA)OutBuffer;
  1430. DWORD status;
  1431. *BytesReturned = sizeof(DEP_DATA);
  1432. if ( OutBufferSize < sizeof(DEP_DATA) ) {
  1433. if ( OutBuffer == NULL ) {
  1434. status = ERROR_SUCCESS;
  1435. } else {
  1436. status = ERROR_MORE_DATA;
  1437. }
  1438. } else {
  1439. ZeroMemory( pdepdata, sizeof(DEP_DATA) );
  1440. pdepdata->ipaddrEntry.Syntax.dw = CLUSPROP_SYNTAX_NAME;
  1441. pdepdata->ipaddrEntry.cbLength = sizeof(IP_ADDRESS_RESOURCE_NAME);
  1442. lstrcpyW( pdepdata->ipaddrEntry.sz, IP_ADDRESS_RESOURCE_NAME );
  1443. pdepdata->endmark.dw = CLUSPROP_SYNTAX_ENDMARK;
  1444. status = ERROR_SUCCESS;
  1445. }
  1446. return status;
  1447. } // IISGetRequiredDependencies
  1448. DWORD
  1449. IISResourceControl(
  1450. IN RESID ResourceId,
  1451. IN DWORD ControlCode,
  1452. IN PVOID InBuffer,
  1453. IN DWORD InBufferSize,
  1454. OUT PVOID OutBuffer,
  1455. IN DWORD OutBufferSize,
  1456. OUT LPDWORD BytesReturned
  1457. )
  1458. /*++
  1459. Routine Description:
  1460. ResourceControl routine for IIS Virtual Root resources.
  1461. Perform the control request specified by ControlCode on the specified
  1462. resource.
  1463. Arguments:
  1464. ResourceId - Supplies the resource id for the specific resource.
  1465. ControlCode - Supplies the control code that defines the action
  1466. to be performed.
  1467. InBuffer - Supplies a pointer to a buffer containing input data.
  1468. InBufferSize - Supplies the size, in bytes, of the data pointed
  1469. to by InBuffer.
  1470. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1471. OutBufferSize - Supplies the size, in bytes, of the available space
  1472. pointed to by OutBuffer.
  1473. BytesReturned - Returns the number of bytes of OutBuffer actually
  1474. filled in by the resource. If OutBuffer is too small, BytesReturned
  1475. contains the total number of bytes for the operation to succeed.
  1476. Return Value:
  1477. ERROR_SUCCESS - The function completed successfully.
  1478. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1479. In some cases, this allows the cluster software to perform the work.
  1480. Win32 error code - The function failed.
  1481. --*/
  1482. {
  1483. DWORD status;
  1484. LPIIS_RESOURCE resourceEntry = NULL;
  1485. DWORD required;
  1486. //
  1487. // Get a valid resource
  1488. //
  1489. resourceEntry = GetValidResource( ResourceId, L"Close");
  1490. if ( resourceEntry == NULL ) {
  1491. return(ERROR_RESOURCE_NOT_FOUND); // this should not happen
  1492. }
  1493. switch ( ControlCode ) {
  1494. case CLUSCTL_RESOURCE_UNKNOWN:
  1495. *BytesReturned = 0;
  1496. status = ERROR_SUCCESS;
  1497. break;
  1498. case CLUSCTL_RESOURCE_GET_REQUIRED_DEPENDENCIES:
  1499. status = IISGetRequiredDependencies( OutBuffer,
  1500. OutBufferSize,
  1501. BytesReturned
  1502. );
  1503. break;
  1504. case CLUSCTL_RESOURCE_ENUM_PRIVATE_PROPERTIES:
  1505. status = ResUtilEnumProperties( IISResourcePrivateProperties,
  1506. OutBuffer,
  1507. OutBufferSize,
  1508. BytesReturned,
  1509. &required );
  1510. if ( status == ERROR_MORE_DATA ) {
  1511. *BytesReturned = required;
  1512. }
  1513. break;
  1514. case CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES:
  1515. status = IISGetPrivateResProperties( resourceEntry,
  1516. OutBuffer,
  1517. OutBufferSize,
  1518. BytesReturned );
  1519. break;
  1520. case CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES:
  1521. status = IISValidatePrivateResProperties( resourceEntry,
  1522. InBuffer,
  1523. InBufferSize,
  1524. NULL );
  1525. break;
  1526. case CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES:
  1527. status = IISSetPrivateResProperties( resourceEntry,
  1528. InBuffer,
  1529. InBufferSize );
  1530. break;
  1531. default:
  1532. status = ERROR_INVALID_FUNCTION;
  1533. break;
  1534. }
  1535. return(status);
  1536. } // IISResourceControl
  1537. DWORD
  1538. IISResourceTypeControl(
  1539. IN LPCWSTR ResourceTypeName,
  1540. IN DWORD ControlCode,
  1541. IN PVOID InBuffer,
  1542. IN DWORD InBufferSize,
  1543. OUT PVOID OutBuffer,
  1544. IN DWORD OutBufferSize,
  1545. OUT LPDWORD BytesReturned
  1546. )
  1547. /*++
  1548. Routine Description:
  1549. ResourceTypeControl routine for IIS Virtual Root resources.
  1550. Perform the control request specified by ControlCode.
  1551. Arguments:
  1552. ResourceTypeName - Supplies the name of the resource type.
  1553. ControlCode - Supplies the control code that defines the action
  1554. to be performed.
  1555. InBuffer - Supplies a pointer to a buffer containing input data.
  1556. InBufferSize - Supplies the size, in bytes, of the data pointed
  1557. to by InBuffer.
  1558. OutBuffer - Supplies a pointer to the output buffer to be filled in.
  1559. OutBufferSize - Supplies the size, in bytes, of the available space
  1560. pointed to by OutBuffer.
  1561. BytesReturned - Returns the number of bytes of OutBuffer actually
  1562. filled in by the resource. If OutBuffer is too small, BytesReturned
  1563. contains the total number of bytes for the operation to succeed.
  1564. Return Value:
  1565. ERROR_SUCCESS - The function completed successfully.
  1566. ERROR_INVALID_FUNCTION - The requested control code is not supported.
  1567. In some cases, this allows the cluster software to perform the work.
  1568. Win32 error code - The function failed.
  1569. --*/
  1570. {
  1571. DWORD status;
  1572. DWORD required;
  1573. switch ( ControlCode ) {
  1574. case CLUSCTL_RESOURCE_TYPE_UNKNOWN:
  1575. *BytesReturned = 0;
  1576. status = ERROR_SUCCESS;
  1577. break;
  1578. case CLUSCTL_RESOURCE_TYPE_ENUM_PRIVATE_PROPERTIES:
  1579. status = ResUtilEnumProperties( IISResourcePrivateProperties,
  1580. OutBuffer,
  1581. OutBufferSize,
  1582. BytesReturned,
  1583. &required );
  1584. if ( status == ERROR_MORE_DATA ) {
  1585. *BytesReturned = required;
  1586. }
  1587. break;
  1588. case CLUSCTL_RESOURCE_TYPE_GET_REQUIRED_DEPENDENCIES:
  1589. status = IISGetRequiredDependencies( OutBuffer,
  1590. OutBufferSize,
  1591. BytesReturned
  1592. );
  1593. break;
  1594. default:
  1595. status = ERROR_INVALID_FUNCTION;
  1596. break;
  1597. }
  1598. return(status);
  1599. } // IISResourceTypeControl
  1600. DWORD
  1601. IISGetPrivateResProperties(
  1602. IN OUT LPIIS_RESOURCE ResourceEntry,
  1603. OUT PVOID OutBuffer,
  1604. IN DWORD OutBufferSize,
  1605. OUT LPDWORD BytesReturned
  1606. )
  1607. /*++
  1608. Routine Description:
  1609. Processes the CLUSCTL_RESOURCE_GET_PRIVATE_PROPERTIES control function
  1610. for resources of type IIS.
  1611. Arguments:
  1612. ResourceEntry - Supplies the resource entry on which to operate.
  1613. OutBuffer - Returns the output data.
  1614. OutBufferSize - Supplies the size, in bytes, of the data pointed
  1615. to by OutBuffer.
  1616. BytesReturned - The number of bytes returned in OutBuffer.
  1617. Return Value:
  1618. ERROR_SUCCESS - The function completed successfully.
  1619. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1620. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1621. Win32 error code - The function failed.
  1622. --*/
  1623. {
  1624. DWORD status;
  1625. DWORD required;
  1626. status = ResUtilGetAllProperties( ResourceEntry->ParametersKey,
  1627. IISResourcePrivateProperties,
  1628. OutBuffer,
  1629. OutBufferSize,
  1630. BytesReturned,
  1631. &required );
  1632. if ( status == ERROR_MORE_DATA ) {
  1633. *BytesReturned = required;
  1634. }
  1635. return(status);
  1636. } // IISGetPrivateResProperties
  1637. DWORD
  1638. IISValidateUniqueProperties(
  1639. IN HRESOURCE hSelf,
  1640. IN HRESOURCE hResource,
  1641. PIIS_PARAMS pParams
  1642. )
  1643. /*++
  1644. Routine Description:
  1645. Callback function to validate that a resources properties are unique.
  1646. For the IIS resource the ALIAS property must be unique for a virtual
  1647. server (i.e., same IP Address dependency)
  1648. Arguments:
  1649. hSelf - A handle to the original resource.
  1650. hResource - A handle to a resource of the same Type. Check against this to make sure
  1651. the new properties do not conflict.
  1652. pParams - Contains the properties for this resource
  1653. Return Value:
  1654. ERROR_SUCCESS - The function completed successfully, the name is unique
  1655. ERROR_DUP_NAME - The name is not unique (i.e., already claimed by another resource)
  1656. Win32 error code - The function failed.
  1657. --*/
  1658. {
  1659. DWORD dwError;
  1660. LPWSTR lpszAlias = NULL;
  1661. LPWSTR lpszService = NULL;
  1662. BYTE szDependsName[MAX_DEFAULT_WSTRING_SIZE];
  1663. HKEY hKey = NULL;
  1664. HKEY hParamKey = NULL;
  1665. DWORD dwSize;
  1666. DWORD dwRetSize;
  1667. HRESOURCE hSelfDepends = NULL;
  1668. HRESOURCE hResDepends = NULL;
  1669. hKey = GetClusterResourceKey( hResource, KEY_READ );
  1670. if( !hKey ){
  1671. return(GetLastError());
  1672. }
  1673. dwSize = MAX_DEFAULT_WSTRING_SIZE;
  1674. dwError = ClusterRegOpenKey( hKey, L"Parameters", KEY_READ, &hParamKey);
  1675. if (dwError != ERROR_SUCCESS) {
  1676. goto error_exit;
  1677. }
  1678. if ( !pParams->Alias ||
  1679. !pParams->ServiceName ) {
  1680. dwError = ERROR_INVALID_PARAMETER;
  1681. goto error_exit;
  1682. }
  1683. lpszAlias = ResUtilGetSzValue(hParamKey, PARAM_NAME__ALIAS);
  1684. if (!lpszAlias) {
  1685. dwError = GetLastError();
  1686. goto error_exit;
  1687. }
  1688. lpszService = ResUtilGetSzValue(hParamKey, PARAM_NAME__SERVICENAME);
  1689. if (!lpszService) {
  1690. dwError = GetLastError();
  1691. goto error_exit;
  1692. }
  1693. // Assume success
  1694. dwError = ERROR_SUCCESS;
  1695. //
  1696. // An Alias property must be unique in a group (i.e., ip address),
  1697. // and service (i.e., WWW, FTP, GOPHER)
  1698. //
  1699. if ( !(_wcsicmp( lpszAlias, pParams->Alias) ) &&
  1700. !(_wcsicmp( lpszService, pParams->ServiceName ) ) ){
  1701. //
  1702. // Get the dependent IP_ADDRESS resource for the callee
  1703. //
  1704. hSelfDepends = ResUtilGetResourceDependency(hSelf,
  1705. IP_ADDRESS_RESOURCE_NAME);
  1706. if (!hSelfDepends) {
  1707. dwError = GetLastError();
  1708. goto error_exit;
  1709. }
  1710. //
  1711. // Get the dependent IP_ADDRESS resource for hResource
  1712. //
  1713. dwError = ClusterResourceControl(
  1714. hResource, //Handle to the resource
  1715. NULL, //Don't care about node
  1716. CLUSCTL_RESOURCE_GET_NAME, //Get the name
  1717. 0, // &InBuffer
  1718. 0, // nInBufferSize,
  1719. &szDependsName, // &OutBuffer
  1720. MAX_DEFAULT_WSTRING_SIZE, // OutBufferSize,
  1721. &dwRetSize ); // returned size
  1722. if (dwError != ERROR_SUCCESS) {
  1723. goto error_exit;
  1724. }
  1725. hResDepends = ResUtilGetResourceNameDependency((LPWSTR)&szDependsName,
  1726. IP_ADDRESS_RESOURCE_NAME);
  1727. if (!hResDepends) {
  1728. dwError = GetLastError();
  1729. CloseClusterResource( hSelfDepends);
  1730. goto error_exit;
  1731. }
  1732. //
  1733. // See if the name of the IP_ADDRESS dependencies match. If so
  1734. // then we have a duplicate IIS VR
  1735. //
  1736. if ( ResUtilResourcesEqual( hSelfDepends, hResDepends) ) {
  1737. dwError = ERROR_DUP_NAME;
  1738. }
  1739. CloseClusterResource( hResDepends );
  1740. CloseClusterResource( hSelfDepends );
  1741. }
  1742. error_exit:
  1743. if (hKey) ClusterRegCloseKey(hKey);
  1744. if (hParamKey) ClusterRegCloseKey(hParamKey);
  1745. if (lpszService) LocalFree(lpszService);
  1746. if (lpszAlias) LocalFree(lpszAlias);
  1747. return( dwError );
  1748. }//IISValidateUniqueProperties
  1749. DWORD
  1750. IISValidatePrivateResProperties(
  1751. IN OUT LPIIS_RESOURCE ResourceEntry,
  1752. IN PVOID InBuffer,
  1753. IN DWORD InBufferSize,
  1754. OUT PIIS_PARAMS Params
  1755. )
  1756. /*++
  1757. Routine Description:
  1758. Processes the CLUSCTL_RESOURCE_VALIDATE_PRIVATE_PROPERTIES control
  1759. function for resources of type IIS Virtual Root.
  1760. Arguments:
  1761. ResourceEntry - Supplies the resource entry on which to operate.
  1762. InBuffer - Supplies a pointer to a buffer containing input data.
  1763. InBufferSize - Supplies the size, in bytes, of the data pointed
  1764. to by InBuffer.
  1765. Params - Supplies the parameter block to fill in.
  1766. Return Value:
  1767. ERROR_SUCCESS - The function completed successfully.
  1768. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1769. ERROR_INVALID_DATA - Parameter data was invalid.
  1770. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1771. Win32 error code - The function failed.
  1772. --*/
  1773. {
  1774. DWORD status;
  1775. IIS_PARAMS params;
  1776. PIIS_PARAMS pParams;
  1777. //
  1778. // Check if there is input data.
  1779. //
  1780. if ( (InBuffer == NULL) ||
  1781. (InBufferSize < sizeof(DWORD)) ) {
  1782. return(ERROR_INVALID_DATA);
  1783. }
  1784. //
  1785. // Duplicate the resource parameter block.
  1786. //
  1787. if ( Params == NULL ) {
  1788. pParams = &params;
  1789. } else {
  1790. pParams = Params;
  1791. }
  1792. ZeroMemory( pParams, sizeof(params) );
  1793. status = ResUtilDupParameterBlock( (LPBYTE) pParams,
  1794. (LPBYTE) &ResourceEntry->Params,
  1795. IISResourcePrivateProperties );
  1796. if ( status != ERROR_SUCCESS ) {
  1797. return(status);
  1798. }
  1799. //
  1800. // Parse and validate the properties.
  1801. //
  1802. status = ResUtilVerifyPropertyTable( IISResourcePrivateProperties,
  1803. NULL,
  1804. TRUE, // Allow unknowns
  1805. InBuffer,
  1806. InBufferSize,
  1807. (LPBYTE) pParams );
  1808. if ( status == ERROR_SUCCESS ) {
  1809. //
  1810. // BUGBUG: Validate the parameter values.
  1811. //
  1812. if ( (pParams->Alias == NULL) ||
  1813. (pParams->Alias[0] != L'/') ) {
  1814. status = ERROR_INVALID_DATA;
  1815. }
  1816. //
  1817. // Check for Unique Alias name within virtual server
  1818. //
  1819. status = ResUtilEnumResources(ResourceEntry->hResource,
  1820. IIS_RESOURCE_NAME,
  1821. IISValidateUniqueProperties,
  1822. pParams);
  1823. if (status != ERROR_SUCCESS) {
  1824. (g_IISLogEvent)(
  1825. ResourceEntry->ResourceHandle,
  1826. LOG_ERROR,
  1827. L"[IISValidatePrivateResourceProperty] status = %1!d!\n",
  1828. status);
  1829. status = ERROR_INVALID_DATA;
  1830. }
  1831. }
  1832. //
  1833. // Cleanup our parameter block.
  1834. //
  1835. if ( pParams == &params ) {
  1836. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1837. (LPBYTE) &ResourceEntry->Params,
  1838. IISResourcePrivateProperties );
  1839. }
  1840. return(status);
  1841. } // IISValidatePrivateResProperties
  1842. DWORD
  1843. IISSetPrivateResProperties(
  1844. IN OUT LPIIS_RESOURCE ResourceEntry,
  1845. IN PVOID InBuffer,
  1846. IN DWORD InBufferSize
  1847. )
  1848. /*++
  1849. Routine Description:
  1850. Processes the CLUSCTL_RESOURCE_SET_PRIVATE_PROPERTIES control function
  1851. for resources of type IIS Virtual Root.
  1852. Arguments:
  1853. ResourceEntry - Supplies the resource entry on which to operate.
  1854. InBuffer - Supplies a pointer to a buffer containing input data.
  1855. InBufferSize - Supplies the size, in bytes, of the data pointed
  1856. to by InBuffer.
  1857. Return Value:
  1858. ERROR_SUCCESS - The function completed successfully.
  1859. ERROR_INVALID_PARAMETER - The data is formatted incorrectly.
  1860. ERROR_NOT_ENOUGH_MEMORY - An error occurred allocating memory.
  1861. Win32 error code - The function failed.
  1862. --*/
  1863. {
  1864. DWORD status;
  1865. IIS_PARAMS params;
  1866. ZeroMemory( &params, sizeof(IIS_PARAMS) );
  1867. //
  1868. // Parse and validate the properties.
  1869. //
  1870. status = IISValidatePrivateResProperties( ResourceEntry,
  1871. InBuffer,
  1872. InBufferSize,
  1873. &params );
  1874. if ( status != ERROR_SUCCESS ) {
  1875. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1876. (LPBYTE) &ResourceEntry->Params,
  1877. IISResourcePrivateProperties );
  1878. return(status);
  1879. }
  1880. //
  1881. // Save the parameter values.
  1882. //
  1883. status = ResUtilSetPropertyParameterBlock( ResourceEntry->ParametersKey,
  1884. IISResourcePrivateProperties,
  1885. NULL,
  1886. (LPBYTE) &params,
  1887. InBuffer,
  1888. InBufferSize,
  1889. (LPBYTE) &ResourceEntry->Params );
  1890. ResUtilFreeParameterBlock( (LPBYTE) &params,
  1891. (LPBYTE) &ResourceEntry->Params,
  1892. IISResourcePrivateProperties );
  1893. //
  1894. // If the resource is online, return a non-success status.
  1895. //
  1896. if (status == ERROR_SUCCESS) {
  1897. if ( (ResourceEntry->State == ClusterResourceOnline) ||
  1898. (ResourceEntry->State == ClusterResourceOnlinePending) ) {
  1899. status = ERROR_RESOURCE_PROPERTIES_STORED;
  1900. } else {
  1901. status = ERROR_SUCCESS;
  1902. }
  1903. }
  1904. return status;
  1905. } // IISSetPrivateResProperties
  1906. //***********************************************************
  1907. //
  1908. // Define Function Table
  1909. //
  1910. //***********************************************************
  1911. // Define entry points
  1912. CLRES_V1_FUNCTION_TABLE( IISFunctionTable,
  1913. CLRES_VERSION_V1_00,
  1914. IIS,
  1915. NULL,
  1916. NULL,
  1917. IISResourceControl,
  1918. IISResourceTypeControl );