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.

1376 lines
37 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 // babakj: (see comments in objbase.h) 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. #include "..\spllib\webutil.hxx"
  28. #define MY_META_TIMEOUT 1000
  29. PWCHAR szW3SvcRootPath = L"/LM/W3svc/1/Root";
  30. BOOL fW3SvcInstalled = FALSE; // Gobal flag telling if IIS or "Peer eb Server" is installed on the local machine.
  31. PWCHAR szW3Root = NULL; // The WWWRoot dir, e.g. d:\inetpub\wwwroot
  32. static CRITICAL_SECTION ClientCS;
  33. static CRITICAL_SECTION ServerCS;
  34. static HANDLE hMetaBaseThdReady;
  35. static IMSAdminBase *pIMeta = NULL; // Metabase interface pointer
  36. class CWebShareData {
  37. public:
  38. LPWSTR m_pszShareName;
  39. BOOL m_bValid;
  40. public:
  41. CWebShareData (LPWSTR pszShareName);
  42. ~CWebShareData ();
  43. int Compare (CWebShareData *pSecond) {return 0;};
  44. };
  45. class CWebShareList :
  46. public CSingleList<CWebShareData*>
  47. {
  48. public:
  49. CWebShareList () {};
  50. ~CWebShareList () {};
  51. void WebSharePrinterList (void);
  52. };
  53. LPWSTR
  54. mystrstrni(
  55. LPWSTR pSrc,
  56. LPWSTR pSearch
  57. );
  58. BOOL
  59. CopyWebPrnFile(
  60. VOID
  61. );
  62. BOOL
  63. SetupWebPrnSvc(
  64. IMSAdminBase *pIMSAdminBase,
  65. BOOL fWebPrnDesired,
  66. BOOL *pfW3SvcInstalled
  67. );
  68. BOOL
  69. AddWebPrnSvc(
  70. IMSAdminBase *pIMSAdminBase,
  71. BOOL *pfW3SvcInstalled
  72. );
  73. BOOL
  74. RemoveWebPrnSvc(
  75. IMSAdminBase *pIMSAdminBase
  76. );
  77. BOOL
  78. RemoveScript(
  79. IMSAdminBase *pIMSAdminBase
  80. );
  81. BOOL
  82. RemoveVirtualDir(
  83. IMSAdminBase *pIMSAdminBase
  84. );
  85. BOOL
  86. InstallWebPrnSvcWorker(
  87. void
  88. );
  89. void
  90. InstallWebPrnSvcWorkerThread(
  91. PINISPOOLER pIniSpooler
  92. );
  93. BOOL
  94. AddScriptAtPrinterVDir(
  95. IMSAdminBase *pIMSAdminBase
  96. );
  97. BOOL
  98. AddVirtualDir(
  99. IMSAdminBase *pIMSAdminBase
  100. );
  101. void
  102. WebShareWorker(
  103. LPWSTR pShareName
  104. );
  105. BOOL
  106. CreateVirtualDirForPrinterShare(
  107. IMSAdminBase *pIMSAdminBase,
  108. LPWSTR pShareName
  109. );
  110. void
  111. WebUnShareWorker(
  112. LPWSTR pShareName
  113. );
  114. BOOL
  115. RemoveVirtualDirForPrinterShare(
  116. IMSAdminBase *pIMSAdminBase,
  117. LPWSTR pShareName
  118. );
  119. void
  120. WebShareAllPrinters(
  121. PINISPOOLER pIniSpooler
  122. );
  123. //
  124. // This routine is called from init.c at localspl init time to kick start the whole thing.
  125. //
  126. // Make the COM activation on a separate thread in order not to slow down LocalSpl init process
  127. //
  128. void
  129. InstallWebPrnSvc(
  130. PINISPOOLER pIniSpooler
  131. )
  132. {
  133. HANDLE ThreadHandle;
  134. DWORD ThreadId;
  135. HRESULT hr; // com error status
  136. // Init the sync objects needed for device arrival thread management
  137. InitializeCriticalSection( &ClientCS );
  138. InitializeCriticalSection( &ServerCS );
  139. hMetaBaseThdReady = CreateEvent( NULL, FALSE, FALSE, NULL); // Auto reset, non-signaled state
  140. if (ThreadHandle = CreateThread( NULL,
  141. INITIAL_STACK_COMMIT,
  142. (LPTHREAD_START_ROUTINE)InstallWebPrnSvcWorkerThread,
  143. pIniSpooler, 0, &ThreadId )) {
  144. CloseHandle( ThreadHandle );
  145. }
  146. }
  147. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  148. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  149. //
  150. // We cannot free our interface pointer becasue loading and unloading ADMWPROX.DLL is very slow.
  151. // So we have to keep the interface pointer around. But due to COM Apt limitation, the thread that creates the interface has
  152. // to be alive for other threads to be able to use the pointer. So here we are with this fancy thread management code:
  153. //
  154. // The thread stays alive for a while. Then it goes away. Then future WebShare/Unshare would invoke it again.
  155. // So This thread could be invoked 2 ways: First by spooler init code (only once!), then by WebShare/Unshare code.
  156. //
  157. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  158. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  159. #define EnterClient() EnterCriticalSection( &ClientCS );
  160. #define EnterServer() EnterCriticalSection( &ServerCS );
  161. #define LeaveClient() LeaveCriticalSection( &ClientCS );
  162. #define LeaveServer() LeaveCriticalSection( &ServerCS );
  163. static BOOL ThdAlive = FALSE;
  164. ///
  165. /// Begin threading work
  166. ///
  167. void
  168. InstallWebPrnSvcWorkerThread(
  169. PINISPOOLER pIniSpooler
  170. )
  171. {
  172. IMSAdminBase *pILocalMetaBase = NULL;
  173. SPLASSERT( (pIniSpooler == NULL) || (pIniSpooler == pLocalIniSpooler) ); // We only expect local pIniSpooler here!
  174. EnterServer();
  175. if( ThdAlive ) {
  176. SPLASSERT( FALSE );
  177. LeaveServer();
  178. return;
  179. }
  180. if( FAILED (CoInitializeEx( NULL, COINIT_MULTITHREADED )) ||
  181. FAILED (::CoCreateInstance(CLSID_MSAdminBase,
  182. NULL,
  183. CLSCTX_ALL,
  184. IID_IMSAdminBase,
  185. (void **)&pIMeta))) {
  186. if( fW3SvcInstalled )
  187. SetEvent( hMetaBaseThdReady ); // We must have a client thread waiting in WebShare/UnShare, signal it!
  188. LeaveServer();
  189. return;
  190. }
  191. if( !fW3SvcInstalled ) { // must be the first time we are being called.
  192. if (InstallWebPrnSvcWorker()) {
  193. WebShareAllPrinters( pIniSpooler );
  194. fW3SvcInstalled = TRUE; // Once this is set, we never unset it. It is an indication that the WEb init code has succeeded.
  195. }
  196. }
  197. else
  198. SetEvent( hMetaBaseThdReady ); // event reset after a waiting thread is released.
  199. ThdAlive = TRUE;
  200. LeaveServer();
  201. Sleep( 15 * 60 * 1000 ); // Allow other threads to use the COM pointer for 15 minutes
  202. //
  203. // Now tear down the IISADMIN object and self terminate thread. Ensure that
  204. // we do not release the pointer inside the CS since this could take a long
  205. // time, this could potentially cause a large number of WorkerThreads queueing
  206. // up and doing the Release(), but that cannot be helped.
  207. //
  208. EnterServer();
  209. pILocalMetaBase = pIMeta;
  210. //
  211. // The client thread expects valid pointers to be non-NULL!
  212. //
  213. pIMeta = NULL;
  214. ThdAlive = FALSE;
  215. LeaveServer();
  216. pILocalMetaBase->Release();
  217. CoUninitialize();
  218. return;
  219. }
  220. void
  221. WebShareManagement(
  222. LPWSTR pShareName,
  223. BOOL bShare // If TRUE, will share it, else unshare it.
  224. ) {
  225. HANDLE ThreadHandle;
  226. DWORD ThreadId;
  227. if( !fW3SvcInstalled ) {
  228. return;
  229. }
  230. if(FAILED (CoInitializeEx( NULL, COINIT_MULTITHREADED )))
  231. return;
  232. EnterClient();
  233. EnterServer();
  234. if( !ThdAlive ) {
  235. LeaveServer();
  236. if (ThreadHandle = CreateThread(NULL,
  237. INITIAL_STACK_COMMIT,
  238. (LPTHREAD_START_ROUTINE)InstallWebPrnSvcWorkerThread,
  239. NULL,
  240. 0,
  241. &ThreadId)) // sending NULL pIniSpooler since there is no need for it.
  242. CloseHandle( ThreadHandle );
  243. else {
  244. LeaveClient();
  245. return;
  246. }
  247. WaitForSingleObject( hMetaBaseThdReady, INFINITE ); // automatic reset event, so it is reset after a waiting thd released.
  248. EnterServer();
  249. }
  250. // Now do the real work
  251. if (pIMeta) {
  252. if( bShare)
  253. WebShareWorker( pShareName );
  254. else
  255. WebUnShareWorker( pShareName );
  256. }
  257. LeaveServer();
  258. LeaveClient();
  259. // No need to CoUninitialize();
  260. }
  261. ///
  262. /// End threading work
  263. ///
  264. void
  265. WebShareAllPrinters(
  266. PINISPOOLER pIniSpooler
  267. )
  268. {
  269. CWebShareList *pWebShareList = NULL;
  270. BOOL bRet = TRUE;
  271. PINIPRINTER pIniPrinter;
  272. if (pWebShareList = new CWebShareList ()) {
  273. // Go down the list of printers and share it out
  274. EnterSplSem();
  275. //
  276. // Re-share all shared printers.
  277. //
  278. for( pIniPrinter = pIniSpooler->pIniPrinter;
  279. pIniPrinter;
  280. pIniPrinter = pIniPrinter->pNext ) {
  281. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  282. CWebShareData *pData = new CWebShareData (pIniPrinter->pShareName);
  283. if (pData && pData->m_bValid &&
  284. pWebShareList->Insert (pData)) {
  285. continue;
  286. }
  287. else {
  288. if (pData) {
  289. delete pData;
  290. }
  291. bRet = FALSE;
  292. break;
  293. }
  294. }
  295. }
  296. LeaveSplSem ();
  297. if (bRet) {
  298. pWebShareList->WebSharePrinterList ();
  299. }
  300. delete pWebShareList;
  301. }
  302. }
  303. PWSTR
  304. GetPrinterUrl(
  305. PSPOOL pSpool
  306. )
  307. {
  308. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  309. DWORD cb;
  310. PWSTR pszURL = NULL;
  311. PWSTR pszServerName = NULL;
  312. HRESULT hr;
  313. SplInSem();
  314. // http://machine/share
  315. if (!pIniPrinter->pShareName)
  316. goto error;
  317. // Get FQDN of this machine
  318. hr = GetDNSMachineName(pIniPrinter->pIniSpooler->pMachineName + 2, &pszServerName);
  319. if (FAILED(hr)) {
  320. SetLastError(HRESULT_CODE(hr));
  321. goto error;
  322. }
  323. cb = 7 + wcslen(pszServerName); // http://machine
  324. cb += 1 + wcslen(pIniPrinter->pShareName) + 1; // /share + NULL
  325. cb *= sizeof(WCHAR);
  326. if (pszURL = (PWSTR) AllocSplMem(cb)) {
  327. wsprintf(pszURL, L"http://%ws/%ws", pszServerName, pIniPrinter->pShareName);
  328. }
  329. error:
  330. FreeSplStr(pszServerName);
  331. return pszURL;
  332. }
  333. //
  334. //
  335. // Reads the policy bit. Returns TRUE if Web Printing wanted, FASLE if not.
  336. //
  337. //
  338. BOOL
  339. IsWebPrintingDesired(
  340. VOID
  341. )
  342. {
  343. static PWCHAR szRegPolicyBitForDisableWebPrinting = L"Software\\Policies\\Microsoft\\Windows NT\\Printers";
  344. HKEY hKey;
  345. DWORD dwType;
  346. DWORD cbData;
  347. DWORD dwDataValue;
  348. BOOL fRet = TRUE;
  349. if( ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  350. szRegPolicyBitForDisableWebPrinting, 0, KEY_READ, &hKey)) {
  351. cbData = sizeof(dwDataValue);
  352. if( RegQueryValueEx(hKey, L"DisableWebPrinting" , NULL, &dwType, (LPBYTE)&dwDataValue, &cbData) == ERROR_SUCCESS ) {
  353. // As long as the value does not exist, it means that web printing is enabled
  354. // If the value is a DWORD, then if it is TRUE, Web Printing is Disabled
  355. if (dwType == REG_DWORD && dwDataValue) fRet = FALSE;
  356. }
  357. RegCloseKey( hKey );
  358. }
  359. return fRet;
  360. }
  361. BOOL
  362. InstallWebPrnSvcWorker(
  363. VOID
  364. )
  365. {
  366. WCHAR szTmpData[MAX_PATH];
  367. HRESULT hr; // com error status
  368. METADATA_HANDLE hMeta = NULL; // handle to metabase
  369. BOOL fW3Svc = FALSE;
  370. DWORD dwMDRequiredDataLen;
  371. METADATA_RECORD mr;
  372. // open key to ROOT on website #1 (default)
  373. hr = pIMeta->OpenKey(METADATA_MASTER_ROOT_HANDLE,
  374. L"/LM/W3svc/1",
  375. METADATA_PERMISSION_READ,
  376. MY_META_TIMEOUT,
  377. &hMeta);
  378. if( SUCCEEDED( hr )) {
  379. // Get the physical path for the WWWROOT
  380. mr.dwMDIdentifier = MD_VR_PATH;
  381. mr.dwMDAttributes = 0;
  382. mr.dwMDUserType = IIS_MD_UT_FILE;
  383. mr.dwMDDataType = STRING_METADATA;
  384. mr.dwMDDataLen = sizeof( szTmpData );
  385. mr.pbMDData = reinterpret_cast<unsigned char *>(szTmpData);
  386. hr = pIMeta->GetData( hMeta, L"/ROOT", &mr, &dwMDRequiredDataLen );
  387. pIMeta->CloseKey( hMeta );
  388. if( SUCCEEDED( hr )) {
  389. szW3Root = AllocSplStr( szTmpData );
  390. // Pass the inner dumb pointer for the callee to use
  391. if( SetupWebPrnSvc( pIMeta, IsWebPrintingDesired(), &fW3Svc ))
  392. DBGMSG(DBG_INFO, ("Setup of WWW Print Service successful.\n"));
  393. else
  394. DBGMSG(DBG_INFO, ("Setup of WWW Print Service failed.\n"));
  395. }
  396. }
  397. return fW3Svc;
  398. }
  399. //
  400. // Given that the WWW server is installed on local machine, it installs/removes the Web Printing service.
  401. //
  402. // Won't reinstall if it is already installed.
  403. //
  404. // Installation involves:
  405. //
  406. // - Add msw3prt as .printer. Just need to get the Win\sys dir.
  407. // - Add the virtual dis .printer
  408. //
  409. // Uninstall means the removal of the above two.
  410. //
  411. //
  412. BOOL
  413. SetupWebPrnSvc(
  414. IMSAdminBase *pIMSAdminBase,
  415. BOOL fWebPrnDesired, // whether Web Printing is desired by the caller
  416. BOOL *pfW3SvcInstalled // Whether Web Printing actually got installed by this routine.
  417. )
  418. {
  419. if( fWebPrnDesired ) {
  420. return AddWebPrnSvc( pIMSAdminBase, pfW3SvcInstalled );
  421. }
  422. else {
  423. *pfW3SvcInstalled = FALSE;
  424. return RemoveWebPrnSvc( pIMSAdminBase );
  425. }
  426. }
  427. BOOL
  428. AddWebPrnSvc(
  429. IMSAdminBase *pIMSAdminBase,
  430. BOOL *pfW3SvcInstalled // Whether Web Printing actually got installed by this routine.
  431. )
  432. {
  433. HRESULT hr; // com error status
  434. *pfW3SvcInstalled = FALSE; // Assume failure
  435. //
  436. // This is to remove the .printer script from the root
  437. //
  438. if( !RemoveScript( pIMSAdminBase ))
  439. return FALSE;
  440. if( !AddVirtualDir( pIMSAdminBase ))
  441. return FALSE;
  442. //
  443. // Add ".printer" as a script map to the printers virtual directory
  444. //
  445. if( !AddScriptAtPrinterVDir( pIMSAdminBase ))
  446. return FALSE;
  447. // Flush out the changes and close
  448. // Call SaveData() after making bulk changes, do not call it on each update
  449. hr = pIMSAdminBase->SaveData();
  450. if( FAILED( hr ))
  451. return FALSE;
  452. return( *pfW3SvcInstalled = TRUE ); // Web Printing installed.
  453. }
  454. BOOL
  455. RemoveWebPrnSvc(
  456. IMSAdminBase *pIMSAdminBase
  457. )
  458. {
  459. HRESULT hr; // com error status
  460. // Remove ".printer" as a script map from the website #1 (default)
  461. if( !RemoveScript( pIMSAdminBase ))
  462. return FALSE;
  463. if( !RemoveVirtualDir( pIMSAdminBase ))
  464. return FALSE;
  465. // Flush out the changes and close
  466. // Call SaveData() after making bulk changes, do not call it on each update
  467. hr = pIMSAdminBase->SaveData();
  468. if( FAILED( hr ))
  469. return FALSE;
  470. return( TRUE ); // Web Printing removed
  471. }
  472. //
  473. //
  474. // Finds the string pSearch in pSrc buffer and returns a ptr to the occurance of pSearch in pSrc.
  475. //
  476. //
  477. LPWSTR mystrstrni( LPWSTR pSrc, LPWSTR pSearch )
  478. {
  479. UINT uSearchSize = wcslen( pSearch );
  480. UINT uSrcSize = wcslen( pSrc );
  481. LPCTSTR pEnd;
  482. if( uSrcSize < uSearchSize )
  483. return(NULL);
  484. pEnd = pSrc + uSrcSize - uSearchSize;
  485. for( ; pSrc <= pEnd; ++pSrc ) {
  486. if( !_wcsnicmp( pSrc, pSearch, uSearchSize ))
  487. return((LPWSTR)pSrc);
  488. }
  489. return(NULL);
  490. }
  491. //
  492. // Determines if the string pSearch can be found inside of a MULTI_SZ string. If it can, it retunrs a
  493. // pointer to the beginning of the string in multi-sz that contains pSearch.
  494. //
  495. LPWSTR IsStrInMultiSZ( LPWSTR pMultiSzSrc, LPWSTR pSearch )
  496. {
  497. LPWSTR pTmp = pMultiSzSrc;
  498. while( TRUE ) {
  499. if( mystrstrni( pTmp, pSearch )) // See pSearch (i.e. ".printer" appears anywhere within this string. If it does, it must be ours.
  500. return pTmp;
  501. pTmp = pTmp + (wcslen(pTmp) + 1); // Point to the beginning of the next string in the MULTI_SZ
  502. if( !*pTmp )
  503. return FALSE; // reached the end of the MULTI_SZ string.
  504. }
  505. }
  506. #define W3SVC L"w3svc"
  507. /*++
  508. Routine Name:
  509. AddScriptAtPrinterVDir
  510. Description:
  511. Add the .printer and .asp script mapping at printers virtual directory
  512. Arguments:
  513. pIMSAdminBase - Pointer to the IIS Admin base
  514. Returns:
  515. An HRESULT
  516. --*/
  517. BOOL
  518. AddScriptAtPrinterVDir(
  519. IMSAdminBase *pIMSAdminBase
  520. )
  521. {
  522. static WCHAR szScritMapFmt[] = L"%ws%c.printer,%ws\\msw3prt.dll,1,GET,POST%c";
  523. static WCHAR szPrinterVDir[] = L"w3svc/1/root/printers";
  524. METADATA_HANDLE hMeta = NULL; // handle to metabase
  525. PWCHAR szFullFormat = NULL;
  526. DWORD dwMDRequiredDataLen;
  527. METADATA_RECORD mr;
  528. HRESULT hr = S_OK;
  529. DWORD nLen;
  530. WCHAR szSystemDir[MAX_PATH];
  531. PWCHAR pAspMapping = NULL;
  532. DWORD dwMapingLen = 0;
  533. PWCHAR pScriptMap = NULL;
  534. //
  535. // Read any script map set at the top, on LM\w3svc where all other default ones are (e.g. .asp, etc.)
  536. //
  537. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  538. L"/LM",
  539. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  540. MY_META_TIMEOUT,
  541. &hMeta);
  542. if(SUCCEEDED(hr))
  543. {
  544. mr.dwMDIdentifier = MD_SCRIPT_MAPS;
  545. mr.dwMDAttributes = 0;
  546. mr.dwMDUserType = IIS_MD_UT_FILE;
  547. mr.dwMDDataType = MULTISZ_METADATA;
  548. mr.dwMDDataLen = 0;
  549. mr.pbMDData = NULL;
  550. hr = pIMSAdminBase->GetData( hMeta, W3SVC, &mr, &dwMDRequiredDataLen );
  551. hr = hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER) ? S_OK : E_FAIL;
  552. }
  553. if(SUCCEEDED(hr))
  554. {
  555. //
  556. // allocate for existing stuff plus our new script map.
  557. //
  558. szFullFormat = new WCHAR[dwMDRequiredDataLen];
  559. hr = szFullFormat? S_OK : E_OUTOFMEMORY;
  560. }
  561. if(SUCCEEDED(hr))
  562. {
  563. mr.dwMDIdentifier = MD_SCRIPT_MAPS;
  564. mr.dwMDAttributes = 0;
  565. mr.dwMDUserType = IIS_MD_UT_FILE;
  566. mr.dwMDDataType = MULTISZ_METADATA;
  567. mr.dwMDDataLen = dwMDRequiredDataLen * sizeof (WCHAR);
  568. mr.pbMDData = reinterpret_cast<unsigned char *>(szFullFormat);
  569. hr = pIMSAdminBase->GetData( hMeta, W3SVC, &mr, &dwMDRequiredDataLen );
  570. }
  571. if(SUCCEEDED(hr))
  572. {
  573. pAspMapping = IsStrInMultiSZ( szFullFormat, L".asp" );
  574. hr = pAspMapping? S_OK: E_FAIL;
  575. }
  576. if(SUCCEEDED(hr))
  577. {
  578. nLen = COUNTOF (szScritMapFmt) + MAX_PATH + lstrlen (pAspMapping);
  579. pScriptMap = new WCHAR[nLen];
  580. hr = pScriptMap ? S_OK : E_OUTOFMEMORY;
  581. }
  582. if(SUCCEEDED(hr))
  583. {
  584. //
  585. // Return value is the length in chars w/o null char.
  586. //
  587. hr = GetSystemDirectory( szSystemDir, COUNTOF (szSystemDir)) > 0 ? S_OK : E_FAIL;
  588. }
  589. if(SUCCEEDED(hr))
  590. {
  591. dwMapingLen = wsprintf( pScriptMap, szScritMapFmt, pAspMapping, L'\0', szSystemDir, L'\0');
  592. hr = dwMapingLen > COUNTOF (szScritMapFmt) ? S_OK : E_FAIL;
  593. }
  594. if (SUCCEEDED(hr))
  595. {
  596. //
  597. // Write the new SCRIPT value
  598. //
  599. mr.dwMDIdentifier = MD_SCRIPT_MAPS;
  600. mr.dwMDAttributes = METADATA_INHERIT;
  601. mr.dwMDUserType = IIS_MD_UT_FILE;
  602. mr.dwMDDataType = MULTISZ_METADATA;
  603. mr.dwMDDataLen = sizeof (WCHAR) * (dwMapingLen + 1) ;
  604. mr.pbMDData = reinterpret_cast<unsigned char *>(pScriptMap);
  605. hr = pIMSAdminBase->SetData( hMeta, szPrinterVDir, &mr );
  606. }
  607. if (hMeta)
  608. {
  609. pIMSAdminBase->CloseKey( hMeta );
  610. hMeta = NULL;
  611. }
  612. delete [] pScriptMap;
  613. delete [] szFullFormat;
  614. return SUCCEEDED (hr);
  615. }
  616. //
  617. //
  618. // Finds and removed our script map from the multi_sz, and writes it back to the metabase.
  619. //
  620. //
  621. BOOL
  622. WriteStrippedScriptValue(
  623. IMSAdminBase *pIMSAdminBase,
  624. METADATA_HANDLE hMeta, // Handle to /LM tree
  625. PWCHAR szFullFormat // MULTI_SZ string already there
  626. )
  627. {
  628. LPWSTR pStrToKill, pNextStr;
  629. HRESULT hr;
  630. DBGMSG(DBG_INFO, ("Removing our script if already added.\n"));
  631. // See if our script map is already there.
  632. if( !(pStrToKill = IsStrInMultiSZ( szFullFormat, L".printer" )))
  633. return TRUE;
  634. // Find the next string (could be the final NULL char)
  635. pNextStr = pStrToKill + (wcslen(pStrToKill) + 1);
  636. if( !*pNextStr )
  637. *pStrToKill = 0; // Our scipt map was at the end of multi_sz. Write the 2nd NULL char and we are done.
  638. else
  639. CopyMemory( pStrToKill, // Remove our script map by copying the remainder of the multi_sz on top of the string containing the map.
  640. pNextStr,
  641. GetMultiSZLen(pNextStr) * sizeof(WCHAR));
  642. // Write the new SCRIPT value
  643. METADATA_RECORD mr;
  644. mr.dwMDIdentifier = MD_SCRIPT_MAPS;
  645. mr.dwMDAttributes = METADATA_INHERIT;
  646. mr.dwMDUserType = IIS_MD_UT_FILE;
  647. mr.dwMDDataType = MULTISZ_METADATA;
  648. mr.dwMDDataLen = GetMultiSZLen(szFullFormat) * sizeof(WCHAR);
  649. mr.pbMDData = reinterpret_cast<unsigned char *>(szFullFormat);
  650. hr = pIMSAdminBase->SetData( hMeta, W3SVC, &mr );
  651. return( SUCCEEDED( hr ));
  652. }
  653. //
  654. //
  655. // Removes ".printer" as a script map from the website #1 (default) if alreaedy there
  656. //
  657. //
  658. BOOL
  659. RemoveScript(
  660. IMSAdminBase *pIMSAdminBase
  661. )
  662. {
  663. METADATA_HANDLE hMeta = NULL; // handle to metabase
  664. PWCHAR szFullFormat;
  665. DWORD dwMDRequiredDataLen;
  666. METADATA_RECORD mr;
  667. HRESULT hr;
  668. BOOL fRet = FALSE;
  669. // Read any script map set at the top, on LM\w3svc where all other default ones are (e.g. .asp, etc.)
  670. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  671. L"/LM",
  672. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  673. MY_META_TIMEOUT,
  674. &hMeta);
  675. if( SUCCEEDED( hr )) {
  676. mr.dwMDIdentifier = MD_SCRIPT_MAPS;
  677. mr.dwMDAttributes = 0;
  678. mr.dwMDUserType = IIS_MD_UT_FILE;
  679. mr.dwMDDataType = MULTISZ_METADATA;
  680. mr.dwMDDataLen = 0;
  681. mr.pbMDData = NULL;
  682. hr = pIMSAdminBase->GetData( hMeta, W3SVC, &mr, &dwMDRequiredDataLen );
  683. if( FAILED( hr )) {
  684. if( HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER ) {
  685. if( szFullFormat = (PWCHAR)AllocSplMem( dwMDRequiredDataLen )) { // allocate for existing stuff plus our new script map.
  686. mr.dwMDIdentifier = MD_SCRIPT_MAPS;
  687. mr.dwMDAttributes = 0;
  688. mr.dwMDUserType = IIS_MD_UT_FILE;
  689. mr.dwMDDataType = MULTISZ_METADATA;
  690. mr.dwMDDataLen = dwMDRequiredDataLen;
  691. mr.pbMDData = reinterpret_cast<unsigned char *>(szFullFormat);
  692. hr = pIMSAdminBase->GetData( hMeta, W3SVC, &mr, &dwMDRequiredDataLen );
  693. if( SUCCEEDED( hr ))
  694. fRet = WriteStrippedScriptValue( pIMSAdminBase, hMeta, szFullFormat ); // Remove the .printer map from the multi_sz if there;
  695. FreeSplMem( szFullFormat );
  696. }
  697. }
  698. }
  699. pIMSAdminBase->CloseKey( hMeta );
  700. }
  701. return fRet;
  702. }
  703. /////////////////////////////////////////////////////////////////////////////////////////////////
  704. static PWCHAR szPrinters = L"Printers";
  705. #define PRINTERS szPrinters // Name of Printers virtual dir.
  706. BOOL
  707. AddVirtualDir(
  708. IMSAdminBase *pIMSAdminBase
  709. )
  710. {
  711. METADATA_HANDLE hMeta = NULL; // handle to metabase
  712. WCHAR szVirPath[MAX_PATH];
  713. WCHAR szPath[MAX_PATH];
  714. DWORD dwMDRequiredDataLen;
  715. DWORD dwAccessPerm;
  716. METADATA_RECORD mr;
  717. HRESULT hr;
  718. BOOL fRet;
  719. // Attempt to open the virtual dir set on Web server #1 (default server)
  720. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  721. szW3SvcRootPath,
  722. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  723. MY_META_TIMEOUT,
  724. &hMeta );
  725. // Create the key if it does not exist.
  726. if( FAILED( hr ))
  727. return FALSE;
  728. fRet = TRUE;
  729. mr.dwMDIdentifier = MD_VR_PATH;
  730. mr.dwMDAttributes = 0;
  731. mr.dwMDUserType = IIS_MD_UT_FILE;
  732. mr.dwMDDataType = STRING_METADATA;
  733. mr.dwMDDataLen = sizeof( szVirPath );
  734. mr.pbMDData = reinterpret_cast<unsigned char *>(szVirPath);
  735. // Read LM/W3Svc/1/Root/Printers see if MD_VR_PATH exists.
  736. hr = pIMSAdminBase->GetData( hMeta, PRINTERS, &mr, &dwMDRequiredDataLen );
  737. if( FAILED( hr )) {
  738. fRet = FALSE;
  739. if( hr == MD_ERROR_DATA_NOT_FOUND ||
  740. HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND ) {
  741. // Write both the key and the values if GetData() failed with any of the two errors.
  742. pIMSAdminBase->AddKey( hMeta, PRINTERS );
  743. if( GetWindowsDirectory( szPath, sizeof(szPath) / sizeof (TCHAR))) { // Return value is the length in chars w/o null char.
  744. DBGMSG(DBG_INFO, ("Writing our virtual dir.\n"));
  745. wsprintf( szVirPath, L"%ws\\web\\printers", szPath );
  746. mr.dwMDIdentifier = MD_VR_PATH;
  747. mr.dwMDAttributes = METADATA_INHERIT;
  748. mr.dwMDUserType = IIS_MD_UT_FILE;
  749. mr.dwMDDataType = STRING_METADATA;
  750. mr.dwMDDataLen = (wcslen(szVirPath) + 1) * sizeof(WCHAR);
  751. mr.pbMDData = reinterpret_cast<unsigned char *>(szVirPath);
  752. // Write MD_VR_PATH value
  753. hr = pIMSAdminBase->SetData( hMeta, PRINTERS, &mr );
  754. fRet = SUCCEEDED( hr );
  755. // Set the default authentication method
  756. if( fRet ) {
  757. DWORD dwAuthorization = MD_AUTH_NT; // NTLM only.
  758. mr.dwMDIdentifier = MD_AUTHORIZATION;
  759. mr.dwMDAttributes = METADATA_INHERIT; // need to inherit so that all subdirs are also protected.
  760. mr.dwMDUserType = IIS_MD_UT_FILE;
  761. mr.dwMDDataType = DWORD_METADATA;
  762. mr.dwMDDataLen = sizeof(DWORD);
  763. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAuthorization);
  764. // Write MD_AUTHORIZATION value
  765. hr = pIMSAdminBase->SetData( hMeta, PRINTERS, &mr );
  766. fRet = SUCCEEDED( hr );
  767. }
  768. }
  769. }
  770. }
  771. // In the following, do the stuff that we always want to do to the virtual dir, regardless of Admin's setting.
  772. if( fRet ) {
  773. dwAccessPerm = MD_ACCESS_READ | MD_ACCESS_SCRIPT;
  774. mr.dwMDIdentifier = MD_ACCESS_PERM;
  775. mr.dwMDAttributes = METADATA_INHERIT; // Make it inheritable so all subdirectories will have the same rights.
  776. mr.dwMDUserType = IIS_MD_UT_FILE;
  777. mr.dwMDDataType = DWORD_METADATA;
  778. mr.dwMDDataLen = sizeof(DWORD);
  779. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerm);
  780. // Write MD_ACCESS_PERM value
  781. hr = pIMSAdminBase->SetData( hMeta, PRINTERS, &mr );
  782. fRet = SUCCEEDED( hr );
  783. }
  784. if( fRet ) {
  785. PWCHAR szDefLoadFile = L"ipp_0001.asp";
  786. mr.dwMDIdentifier = MD_DEFAULT_LOAD_FILE;
  787. mr.dwMDAttributes = METADATA_INHERIT;
  788. mr.dwMDUserType = IIS_MD_UT_FILE;
  789. mr.dwMDDataType = STRING_METADATA;
  790. mr.dwMDDataLen = (wcslen(szDefLoadFile) + 1) * sizeof(WCHAR);
  791. mr.pbMDData = reinterpret_cast<unsigned char *>(szDefLoadFile);
  792. // Write MD_DEFAULT_LOAD_FILE value
  793. hr = pIMSAdminBase->SetData( hMeta, PRINTERS, &mr );
  794. fRet = SUCCEEDED( hr );
  795. }
  796. if( fRet ) {
  797. PWCHAR szKeyType = IIS_CLASS_WEB_VDIR_W;
  798. mr.dwMDIdentifier = MD_KEY_TYPE;
  799. mr.dwMDAttributes = METADATA_INHERIT;
  800. mr.dwMDUserType = IIS_MD_UT_SERVER;
  801. mr.dwMDDataType = STRING_METADATA;
  802. mr.dwMDDataLen = (wcslen(szKeyType) + 1) * sizeof(WCHAR);
  803. mr.pbMDData = reinterpret_cast<unsigned char *>(szKeyType);
  804. // Write MD_DEFAULT_LOAD_FILE value
  805. hr = pIMSAdminBase->SetData( hMeta, PRINTERS, &mr );
  806. fRet = SUCCEEDED( hr );
  807. }
  808. pIMSAdminBase->CloseKey( hMeta );
  809. return fRet;
  810. }
  811. //
  812. //
  813. // Removes "printers" virtual dir from IIS metabase ws3vc\1\root\printers
  814. //
  815. //
  816. BOOL
  817. RemoveVirtualDir(
  818. IMSAdminBase *pIMSAdminBase
  819. )
  820. {
  821. METADATA_HANDLE hMeta = NULL; // handle to metabase
  822. HRESULT hr;
  823. // Attempt to open the virtual dir set on Web server #1 (default server)
  824. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  825. szW3SvcRootPath,
  826. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  827. MY_META_TIMEOUT,
  828. &hMeta );
  829. // Create the key if it does not exist.
  830. if( FAILED( hr ))
  831. return FALSE;
  832. pIMSAdminBase->DeleteKey( hMeta, PRINTERS ); // We don't check the retrun value since the key may already not exist and we could get an error for that reason.
  833. pIMSAdminBase->CloseKey( hMeta );
  834. return TRUE;
  835. }
  836. //=====================================================================================================
  837. //=====================================================================================================
  838. //=====================================================================================================
  839. //
  840. // Adding printer shares:
  841. //
  842. // To support http://<server>/<share>, we create a virtual directory with a redirect property.
  843. //
  844. //
  845. //=====================================================================================================
  846. //=====================================================================================================
  847. //=====================================================================================================
  848. //=====================================================================================================
  849. //
  850. // This function may be called during initialization time after fW3SvcInstalled is set,
  851. // which means, a printer maybe webshared twice (once in InstallWebPrnSvcWorkerThread,
  852. // and the other time when WebShare () is calleb by ShareThisPrinter() in net.c by
  853. // FinalInitAfterRouterInitCompleteThread () during localspl initialization time.
  854. //
  855. //=====================================================================================================
  856. void
  857. WebShare(
  858. LPWSTR pShareName
  859. )
  860. {
  861. WebShareManagement( pShareName, TRUE );
  862. }
  863. void
  864. WebShareWorker(
  865. LPWSTR pShareName
  866. )
  867. {
  868. HRESULT hr; // com error status
  869. SPLASSERT( pIMeta != NULL );
  870. // Pass the inner dumb pointer for the callee to use
  871. if( CreateVirtualDirForPrinterShare( pIMeta, pShareName ))
  872. // Flush out the changes and close
  873. // Call SaveData() after making bulk changes, do not call it on each update
  874. hr = pIMeta->SaveData();
  875. }
  876. BOOL
  877. CreateVirtualDirForPrinterShare(
  878. IMSAdminBase *pIMSAdminBase,
  879. LPWSTR pShareName
  880. )
  881. {
  882. METADATA_HANDLE hMeta = NULL; // handle to metabase
  883. WCHAR szOldURL[MAX_PATH];
  884. WCHAR szPath[MAX_PATH];
  885. DWORD dwMDRequiredDataLen;
  886. DWORD dwAccessPerm;
  887. METADATA_RECORD mr;
  888. HRESULT hr;
  889. BOOL fRet;
  890. // Attempt to open the virtual dir set on Web server #1 (default server)
  891. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  892. szW3SvcRootPath,
  893. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  894. MY_META_TIMEOUT,
  895. &hMeta );
  896. // Create the key if it does not exist.
  897. if( FAILED( hr ))
  898. return FALSE;
  899. fRet = TRUE;
  900. mr.dwMDIdentifier = MD_HTTP_REDIRECT;
  901. mr.dwMDAttributes = 0;
  902. mr.dwMDUserType = IIS_MD_UT_FILE;
  903. mr.dwMDDataType = STRING_METADATA;
  904. mr.dwMDDataLen = sizeof( szOldURL );
  905. mr.pbMDData = reinterpret_cast<unsigned char *>(szOldURL);
  906. // Read LM/W3Svc/1/Root/Printers to see if MD_HTTP_REDIRECT exists.
  907. // Note that we are only concerned with the presence of the vir dir,
  908. // not any properties it might have.
  909. //
  910. hr = pIMSAdminBase->GetData( hMeta, pShareName, &mr, &dwMDRequiredDataLen );
  911. if( FAILED( hr )) {
  912. fRet = FALSE;
  913. // Notice if the virtual dir exists, we won't touch it. One scenario is
  914. // if there is a name collision between a printer sharename and an existing,
  915. // unrelated virtual dir.
  916. if( HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND ) {
  917. // Write both the key and the values if GetData() failed with any of the two errors.
  918. pIMSAdminBase->AddKey( hMeta, pShareName );
  919. dwAccessPerm = MD_ACCESS_READ;
  920. mr.dwMDIdentifier = MD_ACCESS_PERM;
  921. mr.dwMDAttributes = 0; // no need for inheritence
  922. mr.dwMDUserType = IIS_MD_UT_FILE;
  923. mr.dwMDDataType = DWORD_METADATA;
  924. mr.dwMDDataLen = sizeof(DWORD);
  925. mr.pbMDData = reinterpret_cast<unsigned char *>(&dwAccessPerm);
  926. // Write MD_ACCESS_PERM value
  927. hr = pIMSAdminBase->SetData( hMeta, pShareName, &mr );
  928. fRet = SUCCEEDED( hr );
  929. if( fRet ) {
  930. PWCHAR szKeyType = IIS_CLASS_WEB_VDIR_W;
  931. mr.dwMDIdentifier = MD_KEY_TYPE;
  932. mr.dwMDAttributes = 0; // no need for inheritence
  933. mr.dwMDUserType = IIS_MD_UT_FILE;
  934. mr.dwMDDataType = STRING_METADATA;
  935. mr.dwMDDataLen = (wcslen(szKeyType) + 1) * sizeof(WCHAR);
  936. mr.pbMDData = reinterpret_cast<unsigned char *>(szKeyType);
  937. // Write MD_DEFAULT_LOAD_FILE value
  938. hr = pIMSAdminBase->SetData( hMeta, pShareName, &mr );
  939. fRet = SUCCEEDED( hr );
  940. }
  941. if( fRet ) {
  942. WCHAR szURL[MAX_PATH];
  943. wsprintf( szURL, L"/printers/%ws/.printer", pShareName );
  944. mr.dwMDIdentifier = MD_HTTP_REDIRECT;
  945. mr.dwMDAttributes = 0; // no need for inheritence
  946. mr.dwMDUserType = IIS_MD_UT_FILE;
  947. mr.dwMDDataType = STRING_METADATA;
  948. mr.dwMDDataLen = (wcslen(szURL) + 1) * sizeof(WCHAR);
  949. mr.pbMDData = reinterpret_cast<unsigned char *>(szURL);
  950. // Write MD_DEFAULT_LOAD_FILE value
  951. hr = pIMSAdminBase->SetData( hMeta, pShareName, &mr );
  952. fRet = SUCCEEDED( hr );
  953. }
  954. }
  955. }
  956. pIMSAdminBase->CloseKey( hMeta );
  957. return fRet;
  958. }
  959. //=====================================================================================================
  960. //=====================================================================================================
  961. //=====================================================================================================
  962. //
  963. // Removing printer shares
  964. //
  965. //
  966. //=====================================================================================================
  967. //=====================================================================================================
  968. //=====================================================================================================
  969. void
  970. WebUnShare(
  971. LPWSTR pShareName
  972. )
  973. {
  974. WebShareManagement( pShareName, FALSE );
  975. }
  976. void
  977. WebUnShareWorker(
  978. LPWSTR pShareName
  979. )
  980. {
  981. HRESULT hr; // com error status
  982. SPLASSERT( pIMeta != NULL );
  983. // Pass the inner dumb pointer for the callee to use
  984. if( RemoveVirtualDirForPrinterShare( pIMeta, pShareName ))
  985. // Flush out the changes and close
  986. // Call SaveData() after making bulk changes, do not call it on each update
  987. hr = pIMeta->SaveData();
  988. }
  989. BOOL
  990. RemoveVirtualDirForPrinterShare(
  991. IMSAdminBase *pIMSAdminBase,
  992. LPWSTR pShareName
  993. )
  994. {
  995. METADATA_HANDLE hMeta = NULL; // handle to metabase
  996. HRESULT hr;
  997. // Attempt to open the virtual dir set on Web server #1 (default server)
  998. hr = pIMSAdminBase->OpenKey( METADATA_MASTER_ROOT_HANDLE,
  999. szW3SvcRootPath,
  1000. METADATA_PERMISSION_READ | METADATA_PERMISSION_WRITE,
  1001. MY_META_TIMEOUT,
  1002. &hMeta );
  1003. // Create the key if it does not exist.
  1004. if( FAILED( hr ))
  1005. return FALSE;
  1006. pIMSAdminBase->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.
  1007. pIMSAdminBase->CloseKey( hMeta );
  1008. return TRUE;
  1009. }
  1010. CWebShareData::CWebShareData (LPWSTR pszShareName)
  1011. {
  1012. m_bValid = FALSE;
  1013. m_pszShareName = NULL;
  1014. if (m_pszShareName = new WCHAR[lstrlen (pszShareName) +1]) {
  1015. lstrcpy (m_pszShareName, pszShareName);
  1016. m_bValid = TRUE;
  1017. }
  1018. }
  1019. CWebShareData::~CWebShareData ()
  1020. {
  1021. if (m_pszShareName) {
  1022. delete [] m_pszShareName;
  1023. }
  1024. }
  1025. void CWebShareList::WebSharePrinterList ()
  1026. {
  1027. CSingleItem<CWebShareData*> * pItem = m_Dummy.GetNext();
  1028. CWebShareData * pData = NULL;
  1029. while (pItem && (pData = pItem->GetData ()) && pData->m_bValid) {
  1030. WebShareWorker (pData->m_pszShareName);
  1031. pItem = pItem->GetNext ();
  1032. }
  1033. }