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.

528 lines
14 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. sink.cxx
  5. Abstract:
  6. IIS Services IISADMIN Extension
  7. Unicode Metadata Sink.
  8. Author:
  9. Michael W. Thomas 16-Sep-97
  10. --*/
  11. #include <cominc.hxx>
  12. //extern HANDLE hevtDone;
  13. #define REG_FP_LOAD_VALUE "NewFPWebCmdLine"
  14. #define REG_FP_UNLOAD_VALUE "DelFPWebCmdLine"
  15. #ifdef _NO_TRACING_
  16. DECLARE_DEBUG_PRINTS_OBJECT();
  17. #endif
  18. CSvcExtImpIMDCOMSINK::CSvcExtImpIMDCOMSINK(IMDCOM * pcCom):
  19. m_dwRefCount(1),
  20. m_pcCom(pcCom)
  21. {
  22. }
  23. CSvcExtImpIMDCOMSINK::~CSvcExtImpIMDCOMSINK()
  24. {
  25. }
  26. HRESULT
  27. CSvcExtImpIMDCOMSINK::QueryInterface(REFIID riid, void **ppObject) {
  28. if (riid==IID_IUnknown || riid==IID_IMDCOMSINK_W) {
  29. *ppObject = (IMDCOMSINKW *) this;
  30. }
  31. else {
  32. return E_NOINTERFACE;
  33. }
  34. AddRef();
  35. return NO_ERROR;
  36. }
  37. ULONG
  38. CSvcExtImpIMDCOMSINK::AddRef()
  39. {
  40. DWORD dwRefCount;
  41. dwRefCount = InterlockedIncrement((long *)&m_dwRefCount);
  42. return dwRefCount;
  43. }
  44. ULONG
  45. CSvcExtImpIMDCOMSINK::Release()
  46. {
  47. DWORD dwRefCount;
  48. dwRefCount = InterlockedDecrement((long *)&m_dwRefCount);
  49. if (dwRefCount == 0) {
  50. delete this;
  51. }
  52. return dwRefCount;
  53. }
  54. #define SCHEMA_PATH_PREFIX IIS_MD_ADSI_SCHEMA_PATH_W L"/"
  55. HRESULT STDMETHODCALLTYPE
  56. CSvcExtImpIMDCOMSINK::ComMDSinkNotify(
  57. /* [in] */ METADATA_HANDLE hMDHandle,
  58. /* [in] */ DWORD dwMDNumElements,
  59. /* [size_is][in] */ MD_CHANGE_OBJECT __RPC_FAR pcoChangeList[ ])
  60. {
  61. DWORD i, j;
  62. for (i = 0; i < dwMDNumElements; i++) {
  63. if (((pcoChangeList[i].dwMDChangeType | MD_CHANGE_TYPE_SET_DATA) != 0) &&
  64. //
  65. // If this is a schema change, then don't do anything
  66. //
  67. (_wcsnicmp(pcoChangeList[i].pszMDPath,
  68. SCHEMA_PATH_PREFIX,
  69. ((sizeof(SCHEMA_PATH_PREFIX) / sizeof(WCHAR)) - 1)) != 0)) {
  70. for (j = 0; j < pcoChangeList[i].dwMDNumDataIDs; j++) {
  71. switch (pcoChangeList[i].pdwMDDataIDs[j]) {
  72. case MD_FRONTPAGE_WEB:
  73. {
  74. RegisterFrontPage( pcoChangeList[i].pszMDPath );
  75. break;
  76. }
  77. case MD_SERVER_COMMAND:
  78. {
  79. ProcessServerCommand(pcoChangeList[i].pszMDPath);
  80. break;
  81. }
  82. default:
  83. ;
  84. //
  85. // No specific action for this command
  86. //
  87. }
  88. }
  89. }
  90. }
  91. return S_OK;
  92. }
  93. #define REG_KEY_W3SVC_VROOTS TEXT("SYSTEM\\CurrentControlSet\\Services\\W3SVC\\Parameters\\Virtual Roots")
  94. #define REG_KEY_MSFTPSVC_VROOTS TEXT("SYSTEM\\CurrentControlSet\\Services\\MSFTPSVC\\Parameters\\Virtual Roots")
  95. HRESULT STDMETHODCALLTYPE
  96. CSvcExtImpIMDCOMSINK::ComMDEventNotify(
  97. /* [in] */ DWORD dwMDEvent)
  98. {
  99. DWORD err;
  100. if (dwMDEvent == MD_EVENT_MID_RESTORE) {
  101. //
  102. // Blow away registry VRoots so they won't be brought back to life
  103. //
  104. err = RegDeleteKey(HKEY_LOCAL_MACHINE, REG_KEY_W3SVC_VROOTS);
  105. if ( err != ERROR_SUCCESS ) {
  106. DBGINFOW((DBG_CONTEXT,
  107. L"[ComMDEventNotify] (%x) Couldn't remove W3SVC VRoot key\n",
  108. err ));
  109. }
  110. err = RegDeleteKey(HKEY_LOCAL_MACHINE, REG_KEY_MSFTPSVC_VROOTS);
  111. if ( err != ERROR_SUCCESS ) {
  112. DBGINFOW((DBG_CONTEXT,
  113. L"[ComMDEventNotify] (%x) Couldn't remove MSFTPSVC VRoot key\n",
  114. err ));
  115. }
  116. }
  117. //
  118. // Sync up the user accounts with those from the metabase
  119. //
  120. UpdateUsers( TRUE );
  121. return S_OK;
  122. }
  123. //
  124. // This must be in a non-Unicode file so that registry reads on Win95 work.
  125. //
  126. VOID
  127. CSvcExtImpIMDCOMSINK::RegisterFrontPage(
  128. LPWSTR pszPath
  129. )
  130. {
  131. HKEY hkey = NULL;
  132. CHAR buff[255];
  133. CHAR cmd[512];
  134. CHAR achPath[512];
  135. LPSTR pszOp;
  136. DWORD cbBuff = sizeof( buff );
  137. DWORD dwType;
  138. DWORD dwValue;
  139. DWORD dwRequiredDataLen;
  140. HRESULT hresReturn;
  141. METADATA_RECORD mdrData;
  142. MD_SET_DATA_RECORD_EXT(&mdrData,
  143. MD_FRONTPAGE_WEB,
  144. METADATA_NO_ATTRIBUTES,
  145. ALL_METADATA,
  146. DWORD_METADATA,
  147. sizeof(DWORD),
  148. (PBYTE)&dwValue)
  149. hresReturn = m_pcCom->ComMDGetMetaData(METADATA_MASTER_ROOT_HANDLE,
  150. pszPath,
  151. &mdrData,
  152. &dwRequiredDataLen);
  153. if (FAILED(hresReturn)) {
  154. if (hresReturn != MD_ERROR_DATA_NOT_FOUND) {
  155. DBGINFOW((DBG_CONTEXT,
  156. L"[RegisterFrontPage] GetData Failed, return code = %X\n",
  157. hresReturn));
  158. }
  159. }
  160. else {
  161. DBGINFOW(( DBG_CONTEXT,
  162. L"[RegisterFrontPage] Value - %d, Path - %S\n",
  163. dwValue,
  164. pszPath ));
  165. //
  166. // PREFIX
  167. // ComMDGetMetaData should not return success without setting the data
  168. // value pointed to by dwValue. I'm not sure if PREFIX is incapable of
  169. // recognizing the extra level of indirection or if there is some path
  170. // that I missed in reviewing ComMDGetMetaData. I'm going to shut down
  171. // this warning, but I'll open an issue with the PREFIX guys.
  172. //
  173. /* INTRINSA suppress = uninitialized */
  174. pszOp = dwValue ? REG_FP_LOAD_VALUE : REG_FP_UNLOAD_VALUE;
  175. if ( !RegOpenKeyExA( HKEY_LOCAL_MACHINE,
  176. REG_FP_PATH,
  177. 0,
  178. KEY_READ,
  179. &hkey ) &&
  180. !RegQueryValueExA( hkey,
  181. pszOp,
  182. NULL,
  183. &dwType,
  184. (BYTE *) &buff,
  185. &cbBuff ))
  186. {
  187. if ( WideCharToMultiByte( CP_ACP,
  188. 0,
  189. pszPath,
  190. -1,
  191. achPath,
  192. sizeof(achPath),
  193. NULL,
  194. NULL ) == 0 )
  195. {
  196. DBGINFOW((DBG_CONTEXT,
  197. L"Failed to convert path to Ansi, error = %d\n",
  198. GetLastError() ));
  199. }
  200. else {
  201. //
  202. // FrontPage cannot handle trailing slash, so remove it.
  203. // Need to restore as this is not a local copy of path.
  204. //
  205. DWORD dwPathLen = strlen(achPath);
  206. DBG_ASSERT(achPath[dwPathLen - 1] == '/');
  207. achPath[dwPathLen - 1] = '\0';
  208. if ( (strlen( buff ) + (dwPathLen - 1)) < sizeof( cmd ) )
  209. {
  210. STARTUPINFOA StartupInfo;
  211. PROCESS_INFORMATION ProcessInformation;
  212. BOOL CreateProcessStatus;
  213. DWORD ErrorCode;
  214. sprintf( cmd, buff, achPath );
  215. RtlZeroMemory(&StartupInfo,sizeof(StartupInfo));
  216. StartupInfo.cb = sizeof(StartupInfo);
  217. StartupInfo.dwFlags = 0;
  218. StartupInfo.wShowWindow = 0;
  219. CreateProcessStatus = CreateProcessA(
  220. NULL,
  221. cmd,
  222. NULL,
  223. NULL,
  224. FALSE,
  225. 0,
  226. NULL,
  227. NULL,
  228. &StartupInfo,
  229. &ProcessInformation );
  230. if ( CreateProcessStatus )
  231. {
  232. DBG_REQUIRE( CloseHandle(ProcessInformation.hProcess) );
  233. DBG_REQUIRE( CloseHandle(ProcessInformation.hThread) );
  234. }
  235. else
  236. {
  237. DBGPRINTF(( DBG_CONTEXT,
  238. "[RegisterFrontPage] CreateProcess returned %d for %s\n",
  239. GetLastError(),
  240. cmd ));
  241. }
  242. }
  243. }
  244. } else {
  245. DBGINFOW((DBG_CONTEXT,
  246. L"[RegisterFrontPage] Failed to open reg or read value\n"));
  247. }
  248. if ( hkey )
  249. {
  250. RegCloseKey( hkey );
  251. }
  252. }
  253. }
  254. VOID
  255. CSvcExtImpIMDCOMSINK::ProcessServerCommand(
  256. LPWSTR pszPath
  257. )
  258. {
  259. HKEY hkey = NULL;
  260. WCHAR pszServiceName[METADATA_MAX_NAME_LEN];
  261. DWORD dwType;
  262. DWORD dwValue;
  263. DWORD dwRequiredDataLen;
  264. HRESULT hresReturn;
  265. METADATA_RECORD mdrData;
  266. MD_SET_DATA_RECORD_EXT(&mdrData,
  267. MD_SERVER_COMMAND,
  268. METADATA_NO_ATTRIBUTES,
  269. ALL_METADATA,
  270. DWORD_METADATA,
  271. sizeof(DWORD),
  272. (PBYTE)&dwValue)
  273. hresReturn = m_pcCom->ComMDGetMetaData(METADATA_MASTER_ROOT_HANDLE,
  274. pszPath,
  275. &mdrData,
  276. &dwRequiredDataLen);
  277. if (FAILED(hresReturn)) {
  278. DBGINFOW((DBG_CONTEXT,
  279. L"[ProcessServerCommand] GetData Failed, return code = %X\n",
  280. hresReturn));
  281. }
  282. else {
  283. //
  284. // PREFIX
  285. // ComMDGetMetaData should not return success without setting the data
  286. // value pointed to by dwValue. I'm not sure if PREFIX is incapable of
  287. // recognizing the extra level of indirection or if there is some path
  288. // that I missed in reviewing ComMDGetMetaData. I'm going to shut down
  289. // this warning, but I'll open an issue with the PREFIX guys.
  290. //
  291. /* INTRINSA suppress = uninitialized */
  292. if (dwValue == MD_SERVER_COMMAND_START) {
  293. if (GetServiceNameFromPath(pszPath,
  294. pszServiceName)) {
  295. StartIISService(pszServiceName);
  296. }
  297. }
  298. }
  299. }
  300. #define SERVICE_NAME_PREFIX L"/LM/"
  301. BOOL
  302. GetServiceNameFromPath(
  303. LPWSTR pszPath,
  304. LPWSTR pszServiceName
  305. )
  306. /*++
  307. Routine Description:
  308. Start an IIS service
  309. Arguments:
  310. pszPath - path spcifying which IIS service to start
  311. pszServiceName - updated with service name
  312. Return Value:
  313. TRUE - Success
  314. FALSE - Failure
  315. --*/
  316. {
  317. LPWSTR pszPathIndex;
  318. UINT cS;
  319. DBG_ASSERT(pszPath != NULL);
  320. DBG_ASSERT(pszServiceName != NULL);
  321. pszPathIndex = pszPath;
  322. if ((_wcsnicmp( pszPathIndex, \
  323. SERVICE_NAME_PREFIX,
  324. ((sizeof(SERVICE_NAME_PREFIX) / sizeof(WCHAR)) - 1)) == 0) &&
  325. (pszPath[(sizeof(SERVICE_NAME_PREFIX) / sizeof(WCHAR)) - 1] != (WCHAR)'\0')) {
  326. pszPathIndex += ((sizeof(SERVICE_NAME_PREFIX) / sizeof(WCHAR)) -1);
  327. //
  328. // copy to temp buffer until path delim
  329. //
  330. for ( cS = 0 ; cS < METADATA_MAX_NAME_LEN-1 &&
  331. (*pszPathIndex != (WCHAR)'/'); )
  332. {
  333. pszServiceName[cS++] = *pszPathIndex++;
  334. }
  335. pszServiceName[cS] = (WCHAR)'\0';
  336. return TRUE;
  337. }
  338. return FALSE;
  339. }
  340. VOID
  341. StartIISService(
  342. LPWSTR pszServiceName
  343. )
  344. /*++
  345. Routine Description:
  346. Start an IIS service
  347. Arguments:
  348. pszServiceName - specify which IIS service to start
  349. Return Value:
  350. TRUE - Success
  351. FALSE - Failure
  352. --*/
  353. {
  354. SC_HANDLE scManagerHandle;
  355. SC_HANDLE serviceHandle;
  356. DWORD errorCode;
  357. DWORD iPoll;
  358. SERVICE_STATUS ss;
  359. DBG_ASSERT(pszServiceName != NULL);
  360. if ( IISGetPlatformType() == PtWindows95 )
  361. {
  362. //
  363. // Start service Win95-style
  364. //
  365. if ( !IsInetinfoRunning() )
  366. {
  367. if ( _wcsicmp( pszServiceName, L"W3SVC" ) == 0 )
  368. {
  369. // We only can start W3SVC on Win95
  370. if ( !W95StartW3SVC() )
  371. {
  372. DBGINFOW((DBG_CONTEXT,
  373. L"[StartIISService] W95StartW3SVC Failed\n"));
  374. }
  375. }
  376. }
  377. }
  378. else
  379. {
  380. //
  381. // Start service WinNT-style
  382. //
  383. //
  384. // Open the service control manager
  385. //
  386. scManagerHandle = OpenSCManager( NULL, // local machine
  387. NULL, // ServicesActive database
  388. SC_MANAGER_ALL_ACCESS ); // all access
  389. if ( scManagerHandle != NULL ) {
  390. //
  391. // Open the service
  392. //
  393. serviceHandle = OpenService( scManagerHandle,
  394. pszServiceName,
  395. SERVICE_START );
  396. if ( serviceHandle != NULL ) {
  397. //
  398. // Make sure the service is running
  399. //
  400. if (!StartService( serviceHandle,
  401. 0,
  402. NULL) &&
  403. (GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)) {
  404. DBGINFOW(( DBG_CONTEXT,
  405. L"[StartIISService] StartService(%s) Failed, Error = %X\n",
  406. pszServiceName,
  407. GetLastError()));
  408. }
  409. CloseServiceHandle( serviceHandle );
  410. }
  411. //
  412. // Close open handle
  413. //
  414. CloseServiceHandle( scManagerHandle);
  415. }
  416. }
  417. return;
  418. }