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.

777 lines
22 KiB

  1. /*****************************************************************************\
  2. * MODULE: inet.cxx
  3. *
  4. * The module contains routines for the setting up the WWW Printer Service during spooler start up.
  5. *
  6. * The entry point here should be called by localspl\init.c\InitializePrintProvidor() once it is done
  7. * with its work.
  8. *
  9. * Copyright (C) 1996 Microsoft Corporation
  10. *
  11. * History:
  12. * Dec-1996 BabakJ Wrote it for IIS 2.0.
  13. * June-1997 BabakJ Rewrote to use IIS 4.0's new Metabase interface
  14. * Feb-1998 Weihaic Modify the URL in default.htm
  15. * Feb 1999 BabakJ Made metabase interface a global to avoi calling too many CoCreateInstance() for perfrmance.
  16. \*****************************************************************************/
  17. //
  18. //
  19. // Note: We cannot use precomp.h here since we requrie ATL which can only be included in C++ source files.
  20. //
  21. //
  22. #define INITGUID // Needed to do it to get GUID_NULL defined.
  23. #include "precomp.h"
  24. #pragma hdrstop
  25. #include <iadmw.h> // Interface header
  26. #include <iiscnfg.h> // MD_ & IIS_MD_ defines
  27. #define MY_META_TIMEOUT 1000
  28. TCHAR const cszW3SvcRootPath[] = TEXT("/LM/W3svc/1/Root");
  29. TCHAR const cszPrinters[] = TEXT("Printers");
  30. TCHAR const cszW3SvcReg[] = TEXT("System\\CurrentControlSet\\Services\\W3SVC");
  31. typedef enum
  32. {
  33. kWebPrintingStateUnknown,
  34. kWebPrintingStateNotInstalled,
  35. kWebPrintingStateInstalled
  36. } EWebPrintingState;
  37. EWebPrintingState WebPrintingInstalled = kWebPrintingStateUnknown; // Gobal flag telling if WebPrinting is currently installed
  38. class CWebShareData
  39. {
  40. public:
  41. LPWSTR m_pszShareName;
  42. BOOL m_bSharePrinter;
  43. BOOL m_bValid;
  44. public:
  45. CWebShareData (LPWSTR pszShareName, BOOL bSharePrinter);
  46. ~CWebShareData ();
  47. int Compare (CWebShareData *pSecond)
  48. {
  49. return 0;
  50. };
  51. };
  52. class CWebShareList :
  53. public CSingleList<CWebShareData*>
  54. {
  55. public:
  56. CWebShareList ()
  57. {
  58. };
  59. ~CWebShareList ()
  60. {
  61. };
  62. void WebSharePrinterList (IMSAdminBase *pIMetaBase);
  63. };
  64. HRESULT
  65. AccessMetaBase(
  66. OUT IMSAdminBase** ppIMetaBase
  67. );
  68. void
  69. ReleaseMetaBase(
  70. IN IMSAdminBase** ppIMetaBase
  71. );
  72. DWORD
  73. ManageAllWebShares(
  74. IN IMSAdminBase* pIMetaBase,
  75. IN PINISPOOLER pIniSpooler,
  76. IN BOOL bEnableWebShares
  77. );
  78. void
  79. WebShareManagement(
  80. IN LPWSTR pShareName,
  81. IN BOOL bShare // If TRUE, will share it, else unshare it.
  82. );
  83. HRESULT
  84. IsWebPrintingInstalled(
  85. IN IMSAdminBase* pIMetaBase
  86. );
  87. HRESULT
  88. ProcessWebShare(
  89. IN IMSAdminBase* pIMetaBase,
  90. IN LPWSTR pShareName,
  91. IN BOOL bCreateShare
  92. );
  93. HRESULT
  94. CreateVirtualDirForPrinterShare(
  95. IN IMSAdminBase *pIMetaBase,
  96. IN LPWSTR pShareName
  97. );
  98. HRESULT
  99. RemoveVirtualDirForPrinterShare(
  100. IN IMSAdminBase *pIMetaBase,
  101. IN LPWSTR pShareName
  102. );
  103. DWORD
  104. CheckWebPrinting(
  105. BOOL* pbWebPrintingInstalled
  106. )
  107. {
  108. HRESULT hr = S_OK;
  109. IMSAdminBase* pIMetaBase = NULL;
  110. *pbWebPrintingInstalled = FALSE;
  111. //
  112. // If this is the first time we have called a Web function
  113. // init the installed variable.
  114. //
  115. if (WebPrintingInstalled == kWebPrintingStateUnknown)
  116. {
  117. //
  118. // First get a MetaBase interface
  119. //
  120. hr = AccessMetaBase( &pIMetaBase );
  121. if (SUCCEEDED(hr))
  122. {
  123. hr = IsWebPrintingInstalled(pIMetaBase);
  124. }
  125. //
  126. // If we have a MetaBase interface free it and uninit COM.
  127. //
  128. ReleaseMetaBase(&pIMetaBase);
  129. }
  130. if (SUCCEEDED(hr))
  131. {
  132. *pbWebPrintingInstalled = (WebPrintingInstalled == kWebPrintingStateInstalled);
  133. }
  134. else
  135. {
  136. // Something failed so just set thstate to uninstalled but don't change the saved state,
  137. // so we will look again the next time this function is called
  138. *pbWebPrintingInstalled = FALSE;
  139. }
  140. return ERROR_SUCCESS;
  141. }
  142. DWORD
  143. WebShareManager(
  144. IN PINISPOOLER pIniSpooler,
  145. IN BOOL bEnableWebShares
  146. )
  147. {
  148. IMSAdminBase* pIMetaBase = NULL;
  149. HRESULT hr;
  150. DWORD dwRet = ERROR_SUCCESS;
  151. //
  152. // The IniSpooler needs to be from the local server
  153. //
  154. if ((pIniSpooler != NULL) &&
  155. (pIniSpooler != pLocalIniSpooler) )
  156. {
  157. dwRet = ERROR_INVALID_PARAMETER;
  158. }
  159. else
  160. {
  161. //
  162. // Get an interface for the MetaBase
  163. //
  164. hr = AccessMetaBase( &pIMetaBase );
  165. if (SUCCEEDED(hr))
  166. {
  167. dwRet = ManageAllWebShares( pIMetaBase, pIniSpooler, bEnableWebShares );
  168. if (dwRet == ERROR_SUCCESS)
  169. {
  170. if (bEnableWebShares)
  171. WebPrintingInstalled = kWebPrintingStateInstalled;
  172. else
  173. WebPrintingInstalled = kWebPrintingStateNotInstalled;
  174. }
  175. }
  176. else
  177. {
  178. //
  179. // Did we fail beause the WWW Service is gone??
  180. //
  181. HKEY hKey;
  182. if( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE, cszW3SvcReg, 0, KEY_READ, &hKey))
  183. {
  184. RegCloseKey( hKey );
  185. dwRet = HRESULT_CODE(hr);
  186. }
  187. else
  188. {
  189. WebPrintingInstalled = kWebPrintingStateNotInstalled;
  190. dwRet = ERROR_SUCCESS;
  191. }
  192. }
  193. ReleaseMetaBase(&pIMetaBase);
  194. }
  195. return dwRet;
  196. }
  197. /*++
  198. Routine Name:
  199. AccessMetaBase
  200. Routine Description:
  201. Open an interface handle to the IIS MetaBase
  202. Arguments:
  203. ppIMetaBase - The Address of a MetaBase Interface pointer
  204. Return Value:
  205. HRESULT
  206. --*/
  207. HRESULT
  208. AccessMetaBase(
  209. OUT IMSAdminBase** ppIMetaBase
  210. )
  211. {
  212. HRESULT hr;
  213. hr = CoInitializeEx( NULL, COINIT_MULTITHREADED );
  214. if ( SUCCEEDED(hr) )
  215. {
  216. hr = ::CoCreateInstance(CLSID_MSAdminBase,
  217. NULL,
  218. CLSCTX_ALL,
  219. IID_IMSAdminBase,
  220. (void **)ppIMetaBase);
  221. if (FAILED(hr))
  222. {
  223. CoUninitialize();
  224. *ppIMetaBase = NULL;
  225. }
  226. }
  227. return hr;
  228. }
  229. /*++
  230. Routine Name:
  231. ReleaseMetaBase
  232. Routine Description:
  233. Release an open interface handle to the IIS MetaBase and
  234. uninit COM.
  235. Arguments:
  236. pIMetaBase - A MetaBase Interface pointer
  237. Return Value:
  238. --*/
  239. void
  240. ReleaseMetaBase(
  241. IN OUT IMSAdminBase** ppIMetaBase
  242. )
  243. {
  244. if (*ppIMetaBase)
  245. {
  246. (*ppIMetaBase)->Release();
  247. *ppIMetaBase = NULL;
  248. CoUninitialize();
  249. }
  250. }
  251. DWORD
  252. ManageAllWebShares(
  253. IMSAdminBase* pIMetaBase,
  254. PINISPOOLER pIniSpooler,
  255. BOOL bEnableWebShares
  256. )
  257. {
  258. CWebShareList *pWebShareList = NULL;
  259. BOOL bProcessedEntry = FALSE;
  260. PINIPRINTER pIniPrinter;
  261. DWORD dwRet = ERROR_SUCCESS;
  262. if ( pWebShareList = new CWebShareList () )
  263. {
  264. EnterSplSem();
  265. //
  266. // Update VDIRs for each shared printers.
  267. // Either add or delete the VDIRS based on bEnableWebShares
  268. //
  269. for ( pIniPrinter = pIniSpooler->pIniPrinter;
  270. pIniPrinter;
  271. pIniPrinter = pIniPrinter->pNext )
  272. {
  273. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED )
  274. {
  275. CWebShareData *pData = new CWebShareData (pIniPrinter->pShareName, bEnableWebShares);
  276. if ( pData && pData->m_bValid &&
  277. pWebShareList->Insert (pData) )
  278. {
  279. bProcessedEntry = TRUE;
  280. continue;
  281. }
  282. else
  283. {
  284. if ( pData )
  285. {
  286. delete pData;
  287. }
  288. break;
  289. }
  290. }
  291. }
  292. LeaveSplSem ();
  293. if ( bProcessedEntry )
  294. {
  295. pWebShareList->WebSharePrinterList (pIMetaBase);
  296. }
  297. delete pWebShareList;
  298. }
  299. else
  300. dwRet = GetLastError();
  301. return dwRet;
  302. }
  303. //=====================================================================================================
  304. //=====================================================================================================
  305. //=====================================================================================================
  306. //
  307. // Adding printer shares:
  308. //
  309. // To support http://<server>/<share>, we create a virtual directory with a redirect property.
  310. //
  311. //
  312. //=====================================================================================================
  313. //=====================================================================================================
  314. //=====================================================================================================
  315. //=====================================================================================================
  316. //
  317. // This function may be called during initialization time after fW3SvcInstalled is set,
  318. // which means, a printer maybe webshared twice (once in InstallWebPrnSvcWorkerThread,
  319. // and the other time when WebShare () is calleb by ShareThisPrinter() in net.c by
  320. // FinalInitAfterRouterInitCompleteThread () during localspl initialization time.
  321. //
  322. //=====================================================================================================
  323. void
  324. WebShare(
  325. LPWSTR pShareName
  326. )
  327. {
  328. WebShareManagement( pShareName, TRUE );
  329. }
  330. //=====================================================================================================
  331. //=====================================================================================================
  332. //=====================================================================================================
  333. //
  334. // Removing printer shares
  335. //
  336. //
  337. //=====================================================================================================
  338. //=====================================================================================================
  339. //=====================================================================================================
  340. void
  341. WebUnShare(
  342. LPWSTR pShareName
  343. )
  344. {
  345. WebShareManagement( pShareName, FALSE );
  346. }
  347. void
  348. WebShareManagement(
  349. LPWSTR pShareName,
  350. BOOL bShare // If TRUE, will share it, else unshare it.
  351. )
  352. {
  353. HRESULT hr = S_OK;
  354. IMSAdminBase* pIMetaBase = NULL;
  355. //
  356. // If this is the first time we have called a Web function
  357. // init the installed variable.
  358. //
  359. if (WebPrintingInstalled == kWebPrintingStateUnknown)
  360. {
  361. //
  362. // First get a MetaBase interface
  363. //
  364. hr = AccessMetaBase( &pIMetaBase );
  365. if (SUCCEEDED(hr))
  366. {
  367. hr = IsWebPrintingInstalled( pIMetaBase );
  368. }
  369. }
  370. if (SUCCEEDED(hr) &&
  371. (WebPrintingInstalled == kWebPrintingStateInstalled))
  372. {
  373. // If we don't have a metabase interface yet
  374. if (!pIMetaBase)
  375. hr = AccessMetaBase( &pIMetaBase );
  376. if (SUCCEEDED(hr))
  377. hr = ProcessWebShare( pIMetaBase, pShareName, bShare );
  378. }
  379. //
  380. // If we have a MetaBase interface free it and uninit COM.
  381. //
  382. ReleaseMetaBase(&pIMetaBase);
  383. }
  384. HRESULT
  385. IsWebPrintingInstalled(
  386. IMSAdminBase* pIMetaBase
  387. )
  388. {
  389. BOOL bInstalled = FALSE;
  390. WCHAR szVirPath[MAX_PATH];
  391. HRESULT hr; // com error status
  392. METADATA_HANDLE hMeta = NULL; // handle to metabase
  393. DWORD dwMDRequiredDataLen;
  394. METADATA_RECORD mr;
  395. // open key to ROOT on website #1 (default)
  396. hr = pIMetaBase->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  397. cszW3SvcRootPath,
  398. METADATA_PERMISSION_READ,
  399. MY_META_TIMEOUT,
  400. &hMeta);
  401. if ( SUCCEEDED( hr ) )
  402. {
  403. mr.dwMDIdentifier = MD_VR_PATH;
  404. mr.dwMDAttributes = 0;
  405. mr.dwMDUserType = IIS_MD_UT_FILE;
  406. mr.dwMDDataType = STRING_METADATA;
  407. mr.dwMDDataLen = sizeof( szVirPath );
  408. mr.pbMDData = reinterpret_cast<unsigned char *>(szVirPath);
  409. // Read LM/W3Svc/1/Root/Printers see if MD_VR_PATH exists.
  410. hr = pIMetaBase->GetData( hMeta, cszPrinters, &mr, &dwMDRequiredDataLen );
  411. if ( SUCCEEDED(hr) )
  412. {
  413. WebPrintingInstalled = kWebPrintingStateInstalled;
  414. }
  415. else if ( HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND )
  416. {
  417. WebPrintingInstalled = kWebPrintingStateNotInstalled;
  418. hr = S_OK;
  419. }
  420. //
  421. // Close the Web Server Key
  422. //
  423. pIMetaBase->CloseKey( hMeta );
  424. }
  425. return hr;
  426. }
  427. HRESULT
  428. ProcessWebShare(
  429. IMSAdminBase* pIMetaBase,
  430. LPWSTR pShareName,
  431. BOOL bCreateShare
  432. )
  433. {
  434. HRESULT hr; // com error status
  435. if (bCreateShare)
  436. hr = CreateVirtualDirForPrinterShare( pIMetaBase, pShareName );
  437. else
  438. hr = RemoveVirtualDirForPrinterShare( pIMetaBase, pShareName );
  439. if (SUCCEEDED(hr))
  440. {
  441. // Flush out the changes and close
  442. // Call SaveData() after making bulk changes, do not call it on each update
  443. hr = pIMetaBase->SaveData();
  444. }
  445. return hr;
  446. }
  447. HRESULT
  448. CreateVirtualDirForPrinterShare(
  449. IMSAdminBase *pIMetaBase,
  450. LPWSTR pShareName
  451. )
  452. {
  453. METADATA_HANDLE hMeta = NULL; // handle to metabase
  454. WCHAR szOldURL[MAX_PATH];
  455. WCHAR szPath[MAX_PATH];
  456. DWORD dwMDRequiredDataLen;
  457. DWORD dwAccessPerm;
  458. METADATA_RECORD mr;
  459. HRESULT hr;
  460. BOOL fRet;
  461. // Attempt to open the virtual dir set on Web server #1 (default server)
  462. hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  463. cszW3SvcRootPath,
  464. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  465. MY_META_TIMEOUT,
  466. &hMeta );
  467. // Create the key if it does not exist.
  468. if ( SUCCEEDED( hr ) )
  469. {
  470. mr.dwMDIdentifier = MD_HTTP_REDIRECT;
  471. mr.dwMDAttributes = 0;
  472. mr.dwMDUserType = IIS_MD_UT_FILE;
  473. mr.dwMDDataType = STRING_METADATA;
  474. mr.dwMDDataLen = sizeof( szOldURL );
  475. mr.pbMDData = reinterpret_cast<unsigned char *>(szOldURL);
  476. // Read LM/W3Svc/1/Root/Printers to see if MD_HTTP_REDIRECT exists.
  477. // Note that we are only concerned with the presence of the vir dir,
  478. // not any properties it might have.
  479. //
  480. hr = pIMetaBase->GetData( hMeta, pShareName, &mr, &dwMDRequiredDataLen );
  481. if ( FAILED( hr ) )
  482. {
  483. // Notice if the virtual dir exists, we won't touch it. One scenario is
  484. // if there is a name collision between a printer sharename and an existing,
  485. // unrelated virtual dir.
  486. if ( HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND )
  487. {
  488. // Write both the key and the values if GetData() failed with any of the two errors.
  489. pIMetaBase->AddKey( hMeta, pShareName );
  490. dwAccessPerm = MD_ACCESS_READ;
  491. mr.dwMDIdentifier = MD_ACCESS_PERM;
  492. mr.dwMDAttributes = 0; // no need for inheritence
  493. mr.dwMDUserType = IIS_MD_UT_FILE;
  494. mr.dwMDDataType = DWORD_METADATA;
  495. mr.dwMDDataLen = sizeof(DWORD);
  496. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerm);
  497. // Write MD_ACCESS_PERM value
  498. hr = pIMetaBase->SetData( hMeta, pShareName, &mr );
  499. if (SUCCEEDED( hr ))
  500. {
  501. PWCHAR szKeyType = IIS_CLASS_WEB_VDIR_W;
  502. mr.dwMDIdentifier = MD_KEY_TYPE;
  503. mr.dwMDAttributes = 0; // no need for inheritence
  504. mr.dwMDUserType = IIS_MD_UT_FILE;
  505. mr.dwMDDataType = STRING_METADATA;
  506. mr.dwMDDataLen = (wcslen(szKeyType) + 1) * sizeof(WCHAR);
  507. mr.pbMDData = reinterpret_cast<unsigned char *>(szKeyType);
  508. // Write MD_DEFAULT_LOAD_FILE value
  509. hr = pIMetaBase->SetData( hMeta, pShareName, &mr );
  510. }
  511. if (SUCCEEDED( hr ))
  512. {
  513. WCHAR szURL[MAX_PATH];
  514. hr = StringCchPrintf(szURL, COUNTOF(szURL), L"/printers/%ws/.printer", pShareName );
  515. if ( SUCCEEDED(hr) )
  516. {
  517. mr.dwMDIdentifier = MD_HTTP_REDIRECT;
  518. mr.dwMDAttributes = 0; // no need for inheritence
  519. mr.dwMDUserType = IIS_MD_UT_FILE;
  520. mr.dwMDDataType = STRING_METADATA;
  521. mr.dwMDDataLen = (wcslen(szURL) + 1) * sizeof(WCHAR);
  522. mr.pbMDData = reinterpret_cast<unsigned char *>(szURL);
  523. // Write MD_DEFAULT_LOAD_FILE value
  524. hr = pIMetaBase->SetData( hMeta, pShareName, &mr );
  525. }
  526. }
  527. }
  528. }
  529. pIMetaBase->CloseKey( hMeta );
  530. }
  531. return hr;
  532. }
  533. HRESULT
  534. RemoveVirtualDirForPrinterShare(
  535. IMSAdminBase *pIMetaBase,
  536. LPWSTR pShareName
  537. )
  538. {
  539. METADATA_HANDLE hMeta = NULL; // handle to metabase
  540. HRESULT hr;
  541. // Attempt to open the virtual dir set on Web server #1 (default server)
  542. hr = pIMetaBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  543. cszW3SvcRootPath,
  544. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  545. MY_META_TIMEOUT,
  546. &hMeta );
  547. // Create the key if it does not exist.
  548. if ( SUCCEEDED( hr ) )
  549. {
  550. pIMetaBase->DeleteKey( hMeta, pShareName ); // We don't check the retrun value since the key may already not exist and we could get an error for that reason.
  551. pIMetaBase->CloseKey( hMeta );
  552. }
  553. return hr;
  554. }
  555. CWebShareData::CWebShareData (LPWSTR pszShareName, BOOL bSharePrinter)
  556. {
  557. m_bValid = FALSE;
  558. m_pszShareName = NULL;
  559. m_bSharePrinter = bSharePrinter;
  560. DWORD cchShareLen = lstrlen (pszShareName) +1;
  561. if ( m_pszShareName = new WCHAR[cchShareLen] )
  562. {
  563. StringCchCopy(m_pszShareName, cchShareLen, pszShareName);
  564. m_bValid = TRUE;
  565. }
  566. }
  567. CWebShareData::~CWebShareData ()
  568. {
  569. if ( m_pszShareName )
  570. {
  571. delete [] m_pszShareName;
  572. }
  573. }
  574. void CWebShareList::WebSharePrinterList ( IMSAdminBase *pIMetaBase )
  575. {
  576. CSingleItem<CWebShareData*> * pItem = m_Dummy.GetNext();
  577. CWebShareData * pData = NULL;
  578. while ( pItem && (pData = pItem->GetData ()) && pData->m_bValid )
  579. {
  580. (VOID) ProcessWebShare(pIMetaBase, pData->m_pszShareName, pData->m_bSharePrinter);
  581. pItem = pItem->GetNext ();
  582. }
  583. }
  584. PWSTR
  585. GetPrinterUrl(
  586. PSPOOL pSpool
  587. )
  588. {
  589. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  590. DWORD cb;
  591. PWSTR pszURL = NULL;
  592. PWSTR pszServerName = NULL;
  593. LPWSTR pszMachineName = NULL;
  594. HRESULT hr;
  595. SplInSem();
  596. // http://machine/share
  597. if ( !pIniPrinter->pShareName )
  598. {
  599. goto error;
  600. }
  601. // Get FQDN of this machine
  602. //
  603. // Since we should not make a network call while holding the critical section, we
  604. // shall save all the needed variables and leave the CS, make the call and take it
  605. // back.
  606. //
  607. pszMachineName = AllocSplStr(pIniPrinter->pIniSpooler->pMachineName);
  608. if ( !pszMachineName )
  609. {
  610. goto error;
  611. }
  612. LeaveSplSem();
  613. SplOutSem();
  614. hr = GetDNSMachineName(pszMachineName+2, &pszServerName);
  615. EnterSplSem();
  616. if ( FAILED(hr) )
  617. {
  618. SetLastError(HRESULT_CODE(hr));
  619. goto error;
  620. }
  621. cb = 7 + wcslen(pszServerName); // http://machine
  622. cb += 1 + wcslen(pIniPrinter->pShareName) + 1; // /share + NULL
  623. cb *= sizeof(WCHAR);
  624. if ( pszURL = (PWSTR) AllocSplMem(cb) )
  625. {
  626. StringCbPrintf(pszURL, cb, L"http://%ws/%ws", pszServerName, pIniPrinter->pShareName);
  627. }
  628. error:
  629. FreeSplStr(pszServerName);
  630. FreeSplStr(pszMachineName);
  631. return pszURL;
  632. }