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.

3847 lines
108 KiB

  1. /*++
  2. Copyright (c) 1990 - 1996 Microsoft Corporation
  3. Module Name:
  4. printer.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to Printer
  7. management for the Local Print Providor
  8. SplAddPrinter
  9. LocalAddPrinter
  10. SplDeletePrinter
  11. SplResetPrinter
  12. Author:
  13. Dave Snipp (DaveSn) 15-Mar-1991
  14. Revision History:
  15. Matthew A Felton (Mattfe) 27-June-1994
  16. Allow Multiple pIniSpoolers
  17. MattFe Jan5 Cleanup SplAddPrinter & UpdatePrinterIni
  18. Steve Wilson (NT) - Dec 1996 added DeleteThisKey
  19. --*/
  20. #include <precomp.h>
  21. #pragma hdrstop
  22. #include "clusspl.h"
  23. #define PRINTER_NO_CONTROL 0x00
  24. extern WCHAR *szNull;
  25. WCHAR *szKMPrintersAreBlocked = L"KMPrintersAreBlocked";
  26. WCHAR *szIniDevices = L"devices";
  27. WCHAR *szIniPrinterPorts = L"PrinterPorts";
  28. DWORD NetPrinterDecayPeriod = 1000*60*60; // 1 hour
  29. DWORD FirstAddNetPrinterTickCount = 0;
  30. extern GENERIC_MAPPING GenericMapping[SPOOLER_OBJECT_COUNT];
  31. VOID
  32. FixDevModeDeviceName(
  33. LPWSTR pPrinterName,
  34. PDEVMODE pDevMode,
  35. DWORD cbDevMode
  36. );
  37. VOID
  38. CheckAndUpdatePrinterRegAll(
  39. PINISPOOLER pIniSpooler,
  40. LPWSTR pszPrinterName,
  41. LPWSTR pszPort,
  42. BOOL bDelete
  43. )
  44. {
  45. // Print Providers if they are simulating network connections
  46. // will have the Win.INI setting taken care of by the router
  47. // so don't do they update if they request it.
  48. if ( pIniSpooler->SpoolerFlags & SPL_UPDATE_WININI_DEVICES ) {
  49. UpdatePrinterRegAll( pszPrinterName, pszPort, bDelete );
  50. }
  51. }
  52. DWORD
  53. ValidatePrinterAttributes(
  54. DWORD SourceAttributes,
  55. DWORD OriginalAttributes,
  56. LPWSTR pDatatype,
  57. LPBOOL pbValid,
  58. BOOL bSettableOnly
  59. )
  60. /*++
  61. Function Description: Validates the printer attributes to weed out incompatible settings
  62. Parameters: SourceAttributes - new attributes
  63. OriginalAttributes - old attributes
  64. pDatatype - default datatype on the printer
  65. pbValid - flag to indicate invalid combination of settings
  66. bSettableOnly - flag for SplAddPrinter
  67. Return Values: pbValid is set to TRUE if successful and new attributes are returned
  68. pbValid is set to FALSE otherwise and 0 is returned
  69. --*/
  70. {
  71. //
  72. // Let only settable attributes be set, as well as the other bits that are already set in the printer.
  73. //
  74. DWORD TargetAttributes = (SourceAttributes & PRINTER_ATTRIBUTE_SETTABLE) |
  75. (OriginalAttributes & ~PRINTER_ATTRIBUTE_SETTABLE);
  76. if (pbValid) *pbValid = TRUE;
  77. //
  78. // If the printer is set to spool RAW only, the Default datatype should be a
  79. // ValidRawDatatype (RAW, RAW FF, ....)
  80. //
  81. if ((TargetAttributes & PRINTER_ATTRIBUTE_RAW_ONLY) &&
  82. (pDatatype != NULL) &&
  83. !ValidRawDatatype(pDatatype)) {
  84. if (pbValid) *pbValid = FALSE;
  85. SetLastError(ERROR_INVALID_DATATYPE);
  86. return 0;
  87. }
  88. // This is for use by SplAddPrinter() to let it set these attributes for a new printer if needed.
  89. if ( !bSettableOnly ) {
  90. if( SourceAttributes & PRINTER_ATTRIBUTE_LOCAL )
  91. TargetAttributes |= PRINTER_ATTRIBUTE_LOCAL;
  92. /* Don't accept PRINTER_ATTRIBUTE_NETWORK
  93. * unless the PRINTER_ATTRIBUTE_LOCAL bit is set also.
  94. * This is a special case of a local printer masquerading
  95. * as a network printer.
  96. * Otherwise PRINTER_ATTRIBUTE_NETWORK should be set only
  97. * by win32spl.
  98. */
  99. if( ( SourceAttributes & PRINTER_ATTRIBUTE_NETWORK )
  100. &&( SourceAttributes & PRINTER_ATTRIBUTE_LOCAL ) )
  101. TargetAttributes |= PRINTER_ATTRIBUTE_NETWORK;
  102. //
  103. // If it is a Fax Printer, set that bit.
  104. //
  105. if ( SourceAttributes & PRINTER_ATTRIBUTE_FAX )
  106. TargetAttributes |= PRINTER_ATTRIBUTE_FAX;
  107. if ( SourceAttributes & PRINTER_ATTRIBUTE_TS )
  108. TargetAttributes |= PRINTER_ATTRIBUTE_TS;
  109. }
  110. /* If both queued and direct, knock out direct:
  111. */
  112. if((TargetAttributes &
  113. (PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT)) ==
  114. (PRINTER_ATTRIBUTE_QUEUED | PRINTER_ATTRIBUTE_DIRECT)) {
  115. TargetAttributes &= ~PRINTER_ATTRIBUTE_DIRECT;
  116. }
  117. //
  118. // For direct printing the default data type must be RAW
  119. //
  120. if ((TargetAttributes & PRINTER_ATTRIBUTE_DIRECT) &&
  121. (pDatatype != NULL) &&
  122. !ValidRawDatatype(pDatatype)) {
  123. if (pbValid) *pbValid = FALSE;
  124. SetLastError(ERROR_INVALID_DATATYPE);
  125. return 0;
  126. }
  127. /* If both direct and keep-printed-jobs, knock out keep-printed-jobs
  128. */
  129. if((TargetAttributes &
  130. (PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS | PRINTER_ATTRIBUTE_DIRECT)) ==
  131. (PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS | PRINTER_ATTRIBUTE_DIRECT)) {
  132. TargetAttributes &= ~PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS;
  133. }
  134. return TargetAttributes;
  135. }
  136. BOOL
  137. CreatePrinterEntry(
  138. LPPRINTER_INFO_2 pPrinter,
  139. PINIPRINTER pIniPrinter,
  140. PBOOL pAccessSystemSecurity
  141. )
  142. {
  143. BOOL bError = FALSE;
  144. if( !( pIniPrinter->pSecurityDescriptor =
  145. CreatePrinterSecurityDescriptor( pPrinter->pSecurityDescriptor ) )) {
  146. return FALSE;
  147. }
  148. *pAccessSystemSecurity = FALSE;
  149. pIniPrinter->signature = IP_SIGNATURE;
  150. pIniPrinter->pName = AllocSplStr(pPrinter->pPrinterName);
  151. if (!pIniPrinter->pName) {
  152. DBGMSG(DBG_WARNING, ("CreatePrinterEntry: Could not allocate PrinterName string\n" ));
  153. bError = TRUE;
  154. }
  155. if (pPrinter->pShareName) {
  156. pIniPrinter->pShareName = AllocSplStr(pPrinter->pShareName);
  157. if (!pIniPrinter->pShareName) {
  158. DBGMSG(DBG_WARNING, ("CreatePrinterEntry: Could not allocate ShareName string\n" ));
  159. bError = TRUE;
  160. }
  161. } else {
  162. pIniPrinter->pShareName = NULL;
  163. }
  164. if (pPrinter->pDatatype) {
  165. pIniPrinter->pDatatype = AllocSplStr(pPrinter->pDatatype);
  166. if (!pIniPrinter->pDatatype) {
  167. DBGMSG(DBG_WARNING, ("CreatePrinterEntry: Could not allocate Datatype string\n" ));
  168. bError = TRUE;
  169. }
  170. } else {
  171. #if DBG
  172. //
  173. // Error: the datatype should never be NULL
  174. // point.
  175. //
  176. SplLogEvent( pIniPrinter->pIniSpooler,
  177. LOG_ERROR,
  178. MSG_SHARE_FAILED,
  179. TRUE,
  180. L"CreatePrinterEntry",
  181. pIniPrinter->pName ?
  182. pIniPrinter->pName :
  183. L"(Nonep)",
  184. pIniPrinter->pShareName ?
  185. pIniPrinter->pShareName :
  186. L"(Nones)",
  187. L"NULL datatype",
  188. NULL );
  189. #endif
  190. pIniPrinter->pDatatype = NULL;
  191. }
  192. //
  193. // If we have failed somewhere, clean up and exit.
  194. //
  195. if (bError) {
  196. FreeSplStr(pIniPrinter->pName);
  197. FreeSplStr(pIniPrinter->pShareName);
  198. FreeSplStr(pIniPrinter->pDatatype);
  199. return FALSE;
  200. }
  201. pIniPrinter->Priority = pPrinter->Priority ? pPrinter->Priority
  202. : DEF_PRIORITY;
  203. pIniPrinter->Attributes = ValidatePrinterAttributes(pPrinter->Attributes,
  204. pIniPrinter->Attributes,
  205. NULL,
  206. NULL,
  207. FALSE);
  208. pIniPrinter->StartTime = pPrinter->StartTime;
  209. pIniPrinter->UntilTime = pPrinter->UntilTime;
  210. pIniPrinter->pParameters = AllocSplStr(pPrinter->pParameters);
  211. pIniPrinter->pSepFile = AllocSplStr(pPrinter->pSepFile);
  212. pIniPrinter->pComment = AllocSplStr(pPrinter->pComment);
  213. pIniPrinter->pLocation = AllocSplStr(pPrinter->pLocation);
  214. if (pPrinter->pDevMode) {
  215. pIniPrinter->cbDevMode = pPrinter->pDevMode->dmSize +
  216. pPrinter->pDevMode->dmDriverExtra;
  217. SPLASSERT(pIniPrinter->cbDevMode);
  218. if (pIniPrinter->pDevMode = AllocSplMem(pIniPrinter->cbDevMode)) {
  219. //
  220. // This is OK because the pPrinter->pDevmode is validated to be
  221. // encapsulated in its Rpc buffer by the server.
  222. //
  223. memcpy(pIniPrinter->pDevMode,
  224. pPrinter->pDevMode,
  225. pIniPrinter->cbDevMode);
  226. FixDevModeDeviceName( pIniPrinter->pName,
  227. pIniPrinter->pDevMode,
  228. pIniPrinter->cbDevMode );
  229. }
  230. } else {
  231. pIniPrinter->cbDevMode = 0;
  232. pIniPrinter->pDevMode = NULL;
  233. }
  234. pIniPrinter->DefaultPriority = pPrinter->DefaultPriority;
  235. pIniPrinter->pIniFirstJob = pIniPrinter->pIniLastJob = NULL;
  236. pIniPrinter->cJobs = pIniPrinter->AveragePPM = 0;
  237. pIniPrinter->GenerateOnClose = 0;
  238. // At present no API can set this up, the user has to use the
  239. // registry. LATER we should enhance the API to take this.
  240. pIniPrinter->pSpoolDir = NULL;
  241. // Initialize Status Information
  242. pIniPrinter->cTotalJobs = 0;
  243. pIniPrinter->cTotalBytes.LowPart = 0;
  244. pIniPrinter->cTotalBytes.HighPart = 0;
  245. GetSystemTime(&pIniPrinter->stUpTime);
  246. pIniPrinter->MaxcRef = 0;
  247. pIniPrinter->cTotalPagesPrinted = 0;
  248. pIniPrinter->cSpooling = 0;
  249. pIniPrinter->cMaxSpooling = 0;
  250. pIniPrinter->cErrorOutOfPaper = 0;
  251. pIniPrinter->cErrorNotReady = 0;
  252. pIniPrinter->cJobError = 0;
  253. pIniPrinter->DsKeyUpdate = 0;
  254. pIniPrinter->DsKeyUpdateForeground = 0;
  255. pIniPrinter->pszObjectGUID = NULL;
  256. pIniPrinter->pszCN = NULL;
  257. pIniPrinter->pszDN = NULL;
  258. //
  259. // Start from a Semi Random Number
  260. // That way if someone deletes and creates a printer of
  261. // the same name it is unlikely to have the same unique ID
  262. pIniPrinter->cChangeID = GetTickCount();
  263. if (pIniPrinter->cChangeID == 0 )
  264. pIniPrinter->cChangeID++;
  265. //
  266. // Initialize the masq printer cache, we just start with optimistic values
  267. //
  268. pIniPrinter->MasqCache.cJobs = 0;
  269. pIniPrinter->MasqCache.dwError = ERROR_SUCCESS;
  270. pIniPrinter->MasqCache.Status = 0;
  271. pIniPrinter->MasqCache.bThreadRunning = FALSE;
  272. return TRUE;
  273. }
  274. BOOL
  275. UpdateWinIni(
  276. PINIPRINTER pIniPrinter
  277. )
  278. {
  279. PINIPORT pIniPort;
  280. DWORD i;
  281. BOOL bGenerateNetId = FALSE;
  282. LPWSTR pszPort;
  283. SplInSem();
  284. if( !( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_UPDATE_WININI_DEVICES )){
  285. return TRUE;
  286. }
  287. //
  288. // Update win.ini for Win16 compatibility
  289. //
  290. if ( pIniPrinter->Status & PRINTER_PENDING_DELETION ) {
  291. CheckAndUpdatePrinterRegAll( pIniPrinter->pIniSpooler,
  292. pIniPrinter->pName,
  293. NULL,
  294. UPDATE_REG_DELETE );
  295. } else {
  296. //
  297. // Initialize in case there are no ports that match this printer.
  298. //
  299. pszPort = szNullPort;
  300. for( pIniPort = pIniPrinter->pIniSpooler->pIniPort;
  301. pIniPort;
  302. pIniPort = pIniPort->pNext ){
  303. for ( i = 0; i < pIniPort->cPrinters; i++ ) {
  304. if ( pIniPort->ppIniPrinter[i] == pIniPrinter ) {
  305. //
  306. // UpdatePrinterRegAll will automatically
  307. // convert "\\server\share" or ports with
  308. // spaces to Nexx:
  309. //
  310. pszPort = pIniPort->pName;
  311. break;
  312. }
  313. }
  314. }
  315. CheckAndUpdatePrinterRegAll( pIniPrinter->pIniSpooler,
  316. pIniPrinter->pName,
  317. pszPort,
  318. UPDATE_REG_CHANGE );
  319. }
  320. BroadcastChange( pIniPrinter->pIniSpooler,
  321. WM_WININICHANGE,
  322. PR_JOBSTATUS,
  323. (LPARAM)szIniDevices);
  324. return TRUE;
  325. }
  326. BOOL
  327. DeletePrinterIni(
  328. PINIPRINTER pIniPrinter
  329. )
  330. {
  331. DWORD Status;
  332. LPWSTR pSubkey;
  333. DWORD cbNeeded;
  334. LPWSTR pKeyName = NULL;
  335. HANDLE hToken;
  336. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  337. HKEY hPrinterKey;
  338. //
  339. // Only update if the spooler requests it.
  340. //
  341. if ((pIniSpooler->SpoolerFlags & SPL_NO_UPDATE_PRINTERINI) ||
  342. !pIniPrinter->pName) {
  343. return TRUE;
  344. }
  345. hToken = RevertToPrinterSelf();
  346. Status = hToken ? ERROR_SUCCESS : GetLastError();
  347. if (!(pKeyName = SubChar(pIniPrinter->pName, L'\\', L','))) {
  348. Status = GetLastError();
  349. goto error;
  350. }
  351. if ( Status == ERROR_SUCCESS ) {
  352. Status = SplRegOpenKey( pIniSpooler->hckPrinters,
  353. pKeyName,
  354. KEY_WRITE | KEY_READ | DELETE,
  355. &hPrinterKey,
  356. pIniSpooler );
  357. }
  358. if (Status == ERROR_SUCCESS) {
  359. // Delete hPrinterKey - on success this returns ERROR_SUCCESS
  360. Status = SplDeleteThisKey( pIniSpooler->hckPrinters,
  361. hPrinterKey,
  362. pKeyName,
  363. TRUE,
  364. pIniSpooler );
  365. if (Status != ERROR_SUCCESS) {
  366. DBGMSG(DBG_WARNING, ("DeletePrinterIni: DeleteThisKey returned %ld\n", Status ));
  367. }
  368. }
  369. //
  370. // If entries are in per h/w profile registries delete them.
  371. //
  372. DeletePrinterInAllConfigs(pIniPrinter);
  373. error:
  374. FreeSplStr(pKeyName);
  375. if ( hToken ) {
  376. if ( !ImpersonatePrinterClient(hToken) && Status == ERROR_SUCCESS ) {
  377. Status = GetLastError();
  378. }
  379. }
  380. return (Status == ERROR_SUCCESS);
  381. }
  382. //
  383. // DeleteThisKey - returns ERROR_SUCCESS on final successful return
  384. // deletes a key from Registry
  385. // SWilson Dec 96
  386. //
  387. DWORD
  388. SplDeleteThisKey(
  389. HKEY hParentKey, // handle to parent of key to delete
  390. HKEY hThisKey, // handle of key to delete
  391. LPWSTR pThisKeyName, // name of this key
  392. BOOL bDeleteNullKey, // if TRUE, then if pThisKeyName is NULL it is deleted
  393. PINISPOOLER pIniSpooler
  394. )
  395. {
  396. DWORD dwResult = ERROR_SUCCESS, rc;
  397. WCHAR Name[MAX_PATH];
  398. DWORD cchName;
  399. LPWSTR pName;
  400. HKEY hSubKey;
  401. //
  402. // If hThisKey is NULL , try to open it
  403. //
  404. if( hThisKey == NULL) {
  405. if((hParentKey != NULL) && ( pThisKeyName && *pThisKeyName ) ){
  406. dwResult = SplRegOpenKey( hParentKey,
  407. pThisKeyName,
  408. KEY_WRITE | KEY_READ | DELETE,
  409. &hThisKey,
  410. pIniSpooler );
  411. }
  412. }
  413. //
  414. // Exit if SplRegOpenKey failed or hParentKey or pThisKeyName are invalid
  415. //
  416. if( hThisKey == NULL ){
  417. return dwResult;
  418. }
  419. // Get This key's children & delete them, then delete this key
  420. while(dwResult == ERROR_SUCCESS) {
  421. pName = Name;
  422. cchName = COUNTOF( Name );
  423. dwResult = SplRegEnumKey( hThisKey,
  424. 0,
  425. pName,
  426. &cchName,
  427. NULL,
  428. pIniSpooler );
  429. if (dwResult == ERROR_MORE_DATA) {
  430. SPLASSERT(cchName > MAX_PATH);
  431. if (!(pName = AllocSplMem(cchName * sizeof( *pName )))) {
  432. dwResult = GetLastError();
  433. } else {
  434. dwResult = SplRegEnumKey( hThisKey,
  435. 0,
  436. pName,
  437. &cchName,
  438. NULL,
  439. pIniSpooler );
  440. }
  441. }
  442. if (dwResult == ERROR_SUCCESS) { // SubKey found
  443. dwResult = SplRegCreateKey( hThisKey, // Open SubKey
  444. pName,
  445. 0,
  446. KEY_WRITE | KEY_READ | DELETE,
  447. NULL,
  448. &hSubKey,
  449. NULL,
  450. pIniSpooler);
  451. if (dwResult == ERROR_SUCCESS) {
  452. // Delete This SubKey
  453. dwResult = SplDeleteThisKey( hThisKey,
  454. hSubKey,
  455. pName,
  456. bDeleteNullKey,
  457. pIniSpooler );
  458. }
  459. }
  460. if (pName != Name)
  461. FreeSplStr(pName);
  462. }
  463. rc = SplRegCloseKey(hThisKey, pIniSpooler);
  464. SPLASSERT(rc == ERROR_SUCCESS);
  465. if (dwResult == ERROR_NO_MORE_ITEMS) { // This Key has no children so can be deleted
  466. if ( (*pThisKeyName || bDeleteNullKey) && hParentKey != NULL ) {
  467. dwResult = SplRegDeleteKey(hParentKey, pThisKeyName, pIniSpooler);
  468. if (dwResult != ERROR_SUCCESS) {
  469. DBGMSG(DBG_WARNING, ("DeletePrinter: RegDeleteKey failed: %ld\n", dwResult));
  470. }
  471. }
  472. else
  473. {
  474. dwResult = ERROR_SUCCESS;
  475. }
  476. }
  477. return dwResult;
  478. }
  479. BOOL
  480. PrinterCreateKey(
  481. HKEY hKey,
  482. LPWSTR pSubKey,
  483. PHKEY phkResult,
  484. PDWORD pdwLastError,
  485. PINISPOOLER pIniSpooler
  486. )
  487. {
  488. BOOL bReturnValue;
  489. DWORD Status;
  490. Status = SplRegCreateKey( hKey,
  491. pSubKey,
  492. 0,
  493. KEY_READ | KEY_WRITE,
  494. NULL,
  495. phkResult,
  496. NULL,
  497. pIniSpooler );
  498. if ( Status != ERROR_SUCCESS ) {
  499. DBGMSG( DBG_WARNING, ( "PrinterCreateKey: SplRegCreateKey %ws error %d\n", pSubKey, Status ));
  500. *pdwLastError = Status;
  501. bReturnValue = FALSE;
  502. } else {
  503. bReturnValue = TRUE;
  504. }
  505. return bReturnValue;
  506. }
  507. BOOL
  508. UpdatePrinterIni(
  509. PINIPRINTER pIniPrinter,
  510. DWORD dwChangeID
  511. )
  512. {
  513. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  514. DWORD dwLastError = ERROR_SUCCESS;
  515. LPWSTR pKeyName = NULL;
  516. HANDLE hToken;
  517. DWORD dwTickCount;
  518. BOOL bReturnValue;
  519. DWORD cbData;
  520. DWORD cbNeeded;
  521. LPWSTR pszPorts;
  522. HANDLE hPrinterKey = NULL;
  523. HANDLE hBackUpPrinterKey = NULL;
  524. SplInSem();
  525. //
  526. // Only update if the spooler requests it.
  527. //
  528. if( pIniSpooler->SpoolerFlags & SPL_NO_UPDATE_PRINTERINI ){
  529. return TRUE;
  530. }
  531. try {
  532. hToken = RevertToPrinterSelf();
  533. if ( hToken == FALSE ) {
  534. DBGMSG( DBG_TRACE, ("UpdatePrinterIni failed RevertToPrinterSelf %x\n", GetLastError() ));
  535. }
  536. pKeyName = SubChar(pIniPrinter->pName, L'\\', L',');
  537. if (!pKeyName) {
  538. dwLastError = GetLastError();
  539. leave;
  540. }
  541. if ( !PrinterCreateKey( pIniSpooler->hckPrinters,
  542. pKeyName,
  543. &hPrinterKey,
  544. &dwLastError,
  545. pIniSpooler )) {
  546. leave;
  547. }
  548. if (dwChangeID == UPDATE_DS_ONLY) {
  549. RegSetDWord(hPrinterKey, szDsKeyUpdate, pIniPrinter->DsKeyUpdate, &dwLastError, pIniSpooler);
  550. RegSetDWord(hPrinterKey, szDsKeyUpdateForeground, pIniPrinter->DsKeyUpdateForeground, &dwLastError, pIniSpooler);
  551. leave;
  552. }
  553. if ( dwChangeID != KEEP_CHANGEID ) {
  554. //
  555. // WorkStation Caching requires a Unique ID so that they can quickly
  556. // tell if their Cache is up to date.
  557. //
  558. dwTickCount = GetTickCount();
  559. // Ensure Uniqueness
  560. if ( dwTickCount == 0 )
  561. dwTickCount++;
  562. if ( pIniPrinter->cChangeID == dwTickCount )
  563. dwTickCount++;
  564. pIniPrinter->cChangeID = dwTickCount;
  565. RegSetDWord( hPrinterKey, szTimeLastChange, pIniPrinter->cChangeID, &dwLastError, pIniSpooler );
  566. }
  567. if ( dwChangeID != CHANGEID_ONLY ) {
  568. RegSetDWord( hPrinterKey, szStatus, pIniPrinter->Status, &dwLastError, pIniSpooler );
  569. RegSetString( hPrinterKey, szName, pIniPrinter->pName, &dwLastError, pIniSpooler );
  570. if( hBackUpPrinterKey != NULL ){
  571. RegSetString( hBackUpPrinterKey, szName, pIniPrinter->pName, &dwLastError, pIniSpooler );
  572. }
  573. RegSetString( hPrinterKey, szShare, pIniPrinter->pShareName, &dwLastError, pIniSpooler );
  574. RegSetString( hPrinterKey, szPrintProcessor, pIniPrinter->pIniPrintProc->pName, &dwLastError, pIniSpooler );
  575. if ( !( pIniPrinter->Status & PRINTER_PENDING_DELETION )) {
  576. SPLASSERT( pIniPrinter->pDatatype != NULL );
  577. }
  578. RegSetString( hPrinterKey, szDatatype, pIniPrinter->pDatatype, &dwLastError, pIniSpooler );
  579. RegSetString( hPrinterKey, szParameters, pIniPrinter->pParameters, &dwLastError, pIniSpooler );
  580. RegSetDWord( hPrinterKey, szAction, pIniPrinter->dwAction, &dwLastError, pIniSpooler );
  581. RegSetString( hPrinterKey, szObjectGUID, pIniPrinter->pszObjectGUID, &dwLastError, pIniSpooler );
  582. RegSetDWord( hPrinterKey, szDsKeyUpdate, pIniPrinter->DsKeyUpdate, &dwLastError, pIniSpooler);
  583. RegSetDWord( hPrinterKey, szDsKeyUpdateForeground, pIniPrinter->DsKeyUpdateForeground, &dwLastError, pIniSpooler);
  584. RegSetString( hPrinterKey, szDescription, pIniPrinter->pComment, &dwLastError, pIniSpooler );
  585. RegSetString( hPrinterKey, szDriver, pIniPrinter->pIniDriver->pName, &dwLastError, pIniSpooler );
  586. if( hBackUpPrinterKey != NULL ){
  587. RegSetString( hBackUpPrinterKey, szDriver, pIniPrinter->pIniDriver->pName, &dwLastError, pIniSpooler );
  588. }
  589. if (pIniPrinter->pDevMode) {
  590. cbData = pIniPrinter->cbDevMode;
  591. } else {
  592. cbData = 0;
  593. }
  594. RegSetBinaryData( hPrinterKey, szDevMode, (LPBYTE)pIniPrinter->pDevMode, cbData, &dwLastError, pIniSpooler );
  595. if( hBackUpPrinterKey != NULL ){
  596. RegSetBinaryData( hBackUpPrinterKey, szDevMode, (LPBYTE)pIniPrinter->pDevMode, cbData, &dwLastError, pIniSpooler );
  597. }
  598. RegSetDWord( hPrinterKey, szPriority, pIniPrinter->Priority, &dwLastError, pIniSpooler );
  599. RegSetDWord( hPrinterKey, szDefaultPriority, pIniPrinter->DefaultPriority, &dwLastError, pIniSpooler );
  600. RegSetDWord(hPrinterKey, szStartTime, pIniPrinter->StartTime, &dwLastError, pIniSpooler );
  601. RegSetDWord( hPrinterKey, szUntilTime, pIniPrinter->UntilTime, &dwLastError, pIniSpooler );
  602. RegSetString( hPrinterKey, szSepFile, pIniPrinter->pSepFile, &dwLastError, pIniSpooler );
  603. RegSetString( hPrinterKey, szLocation, pIniPrinter->pLocation, &dwLastError, pIniSpooler );
  604. RegSetDWord( hPrinterKey, szAttributes, pIniPrinter->Attributes, &dwLastError, pIniSpooler );
  605. RegSetDWord( hPrinterKey, szTXTimeout, pIniPrinter->txTimeout, &dwLastError, pIniSpooler );
  606. RegSetDWord( hPrinterKey, szDNSTimeout, pIniPrinter->dnsTimeout, &dwLastError, pIniSpooler );
  607. if (pIniPrinter->pSecurityDescriptor) {
  608. cbData = GetSecurityDescriptorLength( pIniPrinter->pSecurityDescriptor );
  609. } else {
  610. cbData = 0;
  611. }
  612. RegSetBinaryData( hPrinterKey, szSecurity, pIniPrinter->pSecurityDescriptor, cbData, &dwLastError, pIniSpooler );
  613. RegSetString( hPrinterKey, szSpoolDir, pIniPrinter->pSpoolDir, &dwLastError, pIniSpooler );
  614. cbNeeded = 0;
  615. GetPrinterPorts( pIniPrinter, 0, &cbNeeded);
  616. if (!(pszPorts = AllocSplMem(cbNeeded))) {
  617. dwLastError = GetLastError();
  618. leave;
  619. }
  620. GetPrinterPorts(pIniPrinter, pszPorts, &cbNeeded);
  621. RegSetString( hPrinterKey, szPort, pszPorts, &dwLastError, pIniSpooler );
  622. if( hBackUpPrinterKey != NULL ){
  623. RegSetString( hBackUpPrinterKey, szPort, pszPorts, &dwLastError, pIniSpooler );
  624. }
  625. FreeSplMem(pszPorts);
  626. //
  627. // A Provider might want to Write Extra Data from Registry
  628. //
  629. if ( pIniSpooler->pfnWriteRegistryExtra != NULL ) {
  630. if ( !(*pIniSpooler->pfnWriteRegistryExtra)(pIniPrinter->pName, hPrinterKey, pIniPrinter->pExtraData)) {
  631. dwLastError = GetLastError();
  632. }
  633. }
  634. if ( ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) &&
  635. ( dwLastError == ERROR_SUCCESS ) ) {
  636. pIniPrinter->Status &= ~PRINTER_PENDING_CREATION;
  637. RegSetDWord( hPrinterKey, szStatus, pIniPrinter->Status, &dwLastError, pIniSpooler );
  638. }
  639. }
  640. } finally {
  641. if ( hPrinterKey )
  642. SplRegCloseKey( hPrinterKey, pIniSpooler);
  643. if ( hBackUpPrinterKey )
  644. SplRegCloseKey( hBackUpPrinterKey, pIniSpooler);
  645. if ( hToken )
  646. ImpersonatePrinterClient( hToken );
  647. }
  648. FreeSplStr(pKeyName);
  649. if ( dwLastError != ERROR_SUCCESS ) {
  650. SetLastError( dwLastError );
  651. bReturnValue = FALSE;
  652. } else {
  653. bReturnValue = TRUE;
  654. }
  655. return bReturnValue;
  656. }
  657. VOID
  658. RemoveOldNetPrinters(
  659. PPRINTER_INFO_1 pPrinterInfo1,
  660. PINISPOOLER pIniSpooler
  661. )
  662. {
  663. PININETPRINT *ppIniNetPrint = &pIniSpooler->pIniNetPrint;
  664. PININETPRINT pIniNetPrint;
  665. DWORD TickCount;
  666. TickCount = GetTickCount();
  667. //
  668. // Browse Information only becomes valid after this print server has been
  669. // up for the NetPrinterDecayPeriod.
  670. //
  671. if (( bNetInfoReady == FALSE ) &&
  672. (( TickCount - FirstAddNetPrinterTickCount ) > NetPrinterDecayPeriod )) {
  673. DBGMSG( DBG_TRACE, ("RemoveOldNetPrinters has a valid browse list\n" ));
  674. bNetInfoReady = TRUE;
  675. }
  676. while (*ppIniNetPrint) {
  677. //
  678. // If either the Tickcount has expired OR we want to delete this specific NetPrinter
  679. // ( because its no longer shared ).
  680. //
  681. if ( (( TickCount - (*ppIniNetPrint)->TickCount ) > NetPrinterDecayPeriod + TEN_MINUTES ) ||
  682. ( pPrinterInfo1 != NULL &&
  683. pPrinterInfo1->Flags & PRINTER_ATTRIBUTE_NETWORK &&
  684. !(pPrinterInfo1->Flags & PRINTER_ATTRIBUTE_SHARED ) &&
  685. _wcsicmp( pPrinterInfo1->pName, (*ppIniNetPrint)->pName ) == STRINGS_ARE_EQUAL)) {
  686. pIniNetPrint = *ppIniNetPrint;
  687. DBGMSG( DBG_TRACE, ("RemoveOldNetPrinters removing %ws not heard for %d millisconds\n",
  688. pIniNetPrint->pName, ( TickCount - (*ppIniNetPrint)->TickCount ) ));
  689. //
  690. // Remove this item, which also increments the pointer.
  691. //
  692. *ppIniNetPrint = pIniNetPrint->pNext;
  693. pIniSpooler->cNetPrinters--;
  694. FreeSplStr( pIniNetPrint->pName );
  695. FreeSplStr( pIniNetPrint->pDescription );
  696. FreeSplStr( pIniNetPrint->pComment );
  697. FreeSplMem( pIniNetPrint );
  698. } else {
  699. ppIniNetPrint = &(*ppIniNetPrint)->pNext;
  700. }
  701. }
  702. }
  703. HANDLE
  704. AddNetPrinter(
  705. LPBYTE pPrinterInfo,
  706. PINISPOOLER pIniSpooler
  707. )
  708. /*++
  709. Routine Description:
  710. Net Printers are created by remote machines calling AddPrinter( Level = 1, Printer_info_1 )
  711. ( see server.c ). They are used for browsing, someone can call EnumPrinters and ask to get
  712. back our browse list - ie all our net printers.
  713. The printers in this list are decayed out after 1 hour ( default ).
  714. See return value comment.
  715. Note client\winspool.c AddPrinterW doesn't allow PRINTER_INFO_1 ( NET printers ), so this can
  716. only come from system components.
  717. Arguments:
  718. pPrinterInfo - Point to a PRINTER_INFO_1 structure to add
  719. Return Value:
  720. NULL - it doesn't return a printer handle.
  721. LastError = ERROR_SUCCESS, or error code ( like out of memory ).
  722. NOTE before NT 3.51 it returned a printer handle of type PRINTER_HANDLE_NET, but since the
  723. only use of this handle was to close it ( which burnt up cpu / net traffic and RPC binding
  724. handles, we return a NULL handle now to make it more efficient. Apps ( Server.c ) if it
  725. cares could call GetLastError.
  726. --*/
  727. {
  728. PPRINTER_INFO_1 pPrinterInfo1 = (PPRINTER_INFO_1)pPrinterInfo;
  729. PININETPRINT pIniNetPrint = NULL;
  730. PININETPRINT *ppScan;
  731. SplInSem();
  732. //
  733. // Validate PRINTER_INFO_1
  734. // At minimum it must have a PrinterName. Each field in the pPrinterInfo1
  735. // must be of an appropriate size. Description is PrinterName,DriverName,Location.
  736. //
  737. if ( pPrinterInfo1->pName == NULL || wcslen(pPrinterInfo1->pName) > MAX_UNC_PRINTER_NAME ||
  738. (pPrinterInfo1->pComment && wcslen(pPrinterInfo1->pComment) > MAX_PATH) ||
  739. (pPrinterInfo1->pDescription && wcslen(pPrinterInfo1->pDescription) > MAX_PATH + MAX_PATH + MAX_UNC_PRINTER_NAME + 2))
  740. {
  741. DBGMSG( DBG_WARN, ("AddNetPrinter invalid printer parameters failed\n"));
  742. SetLastError( ERROR_INVALID_NAME );
  743. return NULL;
  744. }
  745. if ( FirstAddNetPrinterTickCount == 0 )
  746. {
  747. FirstAddNetPrinterTickCount = GetTickCount();
  748. }
  749. //
  750. // Decay out of the browse list any old printers
  751. //
  752. RemoveOldNetPrinters( pPrinterInfo1, pIniSpooler );
  753. //
  754. // Do Not Add and printer which is no longer shared.
  755. //
  756. if (pPrinterInfo1->Flags & PRINTER_ATTRIBUTE_NETWORK && !(pPrinterInfo1->Flags & PRINTER_ATTRIBUTE_SHARED))
  757. {
  758. SetLastError(ERROR_PRINTER_ALREADY_EXISTS);
  759. goto Done;
  760. }
  761. //
  762. // See if we already have this printer
  763. //
  764. pIniNetPrint = pIniSpooler->pIniNetPrint;
  765. while ( pIniNetPrint &&
  766. pIniNetPrint->pName &&
  767. lstrcmpi( pPrinterInfo1->pName, pIniNetPrint->pName ))
  768. {
  769. pIniNetPrint = pIniNetPrint->pNext;
  770. }
  771. //
  772. // If we didn't find this printer already Create one
  773. //
  774. if (pIniNetPrint == NULL)
  775. {
  776. //
  777. // If we haven't already reached our maximum number of printers, then
  778. // go ahead and add this one.
  779. //
  780. if (pIniSpooler->cNetPrinters < kMaximumNumberOfBrowsePrinters)
  781. {
  782. pIniNetPrint = AllocSplMem( sizeof(ININETPRINT));
  783. if (pIniNetPrint)
  784. {
  785. pIniNetPrint->signature = IN_SIGNATURE;
  786. pIniNetPrint->pName = AllocSplStr( pPrinterInfo1->pName );
  787. pIniNetPrint->pDescription = AllocSplStr( pPrinterInfo1->pDescription );
  788. pIniNetPrint->pComment = AllocSplStr( pPrinterInfo1->pComment );
  789. // Did Any of the above allocations fail ?
  790. if ( pIniNetPrint->pName == NULL ||
  791. ( pPrinterInfo1->pDescription != NULL && pIniNetPrint->pDescription == NULL ) ||
  792. ( pPrinterInfo1->pComment != NULL && pIniNetPrint->pComment == NULL ) )
  793. {
  794. // Failed - CleanUp
  795. FreeSplStr( pIniNetPrint->pComment );
  796. FreeSplStr( pIniNetPrint->pDescription );
  797. FreeSplStr( pIniNetPrint->pName );
  798. FreeSplMem( pIniNetPrint );
  799. pIniNetPrint = NULL;
  800. }
  801. else
  802. {
  803. DBGMSG( DBG_TRACE, ("AddNetPrinter(%ws) NEW\n", pPrinterInfo1->pName ));
  804. ppScan = &pIniSpooler->pIniNetPrint;
  805. // Scan through the current known printers, and insert the new one
  806. // in alphabetical order
  807. while( *ppScan && (lstrcmp((*ppScan)->pName, pIniNetPrint->pName) < 0))
  808. {
  809. ppScan = &(*ppScan)->pNext;
  810. }
  811. pIniNetPrint->pNext = *ppScan;
  812. *ppScan = pIniNetPrint;
  813. pIniSpooler->cNetPrinters++;
  814. }
  815. }
  816. }
  817. else
  818. {
  819. SetLastError(ERROR_OUTOFMEMORY);
  820. }
  821. } else
  822. {
  823. DBGMSG( DBG_TRACE, ("AddNetPrinter(%ws) elapsed since last notified %d milliseconds\n", pIniNetPrint->pName, ( GetTickCount() - pIniNetPrint->TickCount ) ));
  824. }
  825. if ( pIniNetPrint )
  826. {
  827. // Tickle the TickCount so this printer sticks around in the browse list
  828. pIniNetPrint->TickCount = GetTickCount();
  829. // Have to set some error code or RPC thinks ERROR_SUCCESS is good.
  830. SetLastError( ERROR_PRINTER_ALREADY_EXISTS );
  831. pIniSpooler->cAddNetPrinters++; // Status Only
  832. }
  833. Done:
  834. SPLASSERT( GetLastError() != ERROR_SUCCESS);
  835. return NULL;
  836. }
  837. /*++
  838. Routine Name:
  839. ValidatePortTokenList
  840. Routine Description:
  841. This routine ensures that the given set of ports in pKeyData are valid
  842. ports in the spooler and returns the buffer with the pointers to strings
  843. replaced with pointers ref-counted pIniPorts.
  844. The way we do this needs to be rethought. The overloaded PKEYDATA is confusing
  845. and unnecessary, we should simply return a new array of PINIPORTS. (It also
  846. pollutes the PKEYDATA with an unnecessary bFixPortRef member), Also, this
  847. code is both invoked for initialization and for Validation, but the logic is
  848. quite different. For initialization, we want to assume that everything in the
  849. registry is valid and start up with placeholder ports until the monitor can
  850. enumerate them (this could be because a USB printer is unplugged). In the other
  851. cases where this is being used for validation we want to fail. This implies that
  852. we might want to separate this into two functions.
  853. Arguments:
  854. pKeyData - The array of strings that gets turned into an array of
  855. ref-counted ports.
  856. pIniSpooler - The ini-spooler on which this is being added.
  857. bInitialize - If TRUE, this code is being invoked for initialization and
  858. not for validation.
  859. pbNoPorts - Optional, this will return TRUE if bInitialize is TRUE and
  860. none of the ports in the port list can be found. We will
  861. then set the printer- offline and log a message.
  862. Return Value:
  863. TRUE - if the ports were all all successfully created or validated.
  864. FALSE - otherwise.
  865. --*/
  866. BOOL
  867. ValidatePortTokenList(
  868. IN OUT PKEYDATA pKeyData,
  869. IN PINISPOOLER pIniSpooler,
  870. IN BOOL bInitialize,
  871. OUT BOOL *pbNoPorts OPTIONAL
  872. )
  873. {
  874. PINIPORT pIniPort = NULL;
  875. DWORD i = 0;
  876. DWORD j = 0;
  877. DWORD dwPorts = 0;
  878. DWORD Status = ERROR_SUCCESS;
  879. SplInSem();
  880. Status = !pKeyData ? ERROR_UNKNOWN_PORT : ERROR_SUCCESS;
  881. //
  882. // The logic remains the same for ports with only one token as for when we
  883. // initialize the ports for the first time.
  884. //
  885. if (Status == ERROR_SUCCESS)
  886. {
  887. bInitialize = pKeyData->cTokens == 1 ? TRUE : bInitialize;
  888. }
  889. //
  890. // We do not allow non-masc ports and masq ports to be combined. Moreover
  891. // only one non-masc port can be used for a printer -- can't do printer
  892. // pooling with masq printers
  893. //
  894. for ( i = 0 ; Status == ERROR_SUCCESS && i < pKeyData->cTokens ; i++ )
  895. {
  896. pIniPort = FindPort(pKeyData->pTokens[i], pIniSpooler);
  897. //
  898. // A port is valid if it is found and if it isn't in itself a
  899. // placeholder port.
  900. //
  901. if (pIniPort && !(pIniPort->Status & PP_PLACEHOLDER))
  902. {
  903. dwPorts++;
  904. }
  905. //
  906. // If we are initializing, or if there is only one port and if the
  907. // spooler allows it, then create a dummy port entry. This also
  908. // handles the masq port case.
  909. //
  910. if (bInitialize)
  911. {
  912. if (!pIniPort && pIniSpooler->SpoolerFlags & SPL_OPEN_CREATE_PORTS)
  913. {
  914. //
  915. // Note: there is a potential problem here, CreatePortEntry uses
  916. // a global initialization flag rather than the parameter that is
  917. // passed in to us.
  918. //
  919. pIniPort = CreatePortEntry(pKeyData->pTokens[i], NULL, pIniSpooler);
  920. }
  921. }
  922. //
  923. // If we don't have a port or if we are not initializing and there isn't
  924. // a monitor associated with the port. Then we have an error.
  925. //
  926. if (!pIniPort || (!(pIniPort->Status & PP_MONITOR) && !bInitialize))
  927. {
  928. Status = ERROR_UNKNOWN_PORT;
  929. }
  930. //
  931. // In case of duplicate portnames in pPortName field fail the call. This
  932. // can't happen if we went through the CreatePortEntry code path and it
  933. // succeeded
  934. //
  935. for ( j = 0 ; Status == ERROR_SUCCESS && j < i ; ++j )
  936. {
  937. if ( pIniPort == (PINIPORT)pKeyData->pTokens[j] )
  938. {
  939. Status = ERROR_UNKNOWN_PORT;
  940. }
  941. }
  942. //
  943. // Write the port in.
  944. //
  945. if (Status == ERROR_SUCCESS)
  946. {
  947. pKeyData->pTokens[i] = (LPWSTR)pIniPort;
  948. }
  949. }
  950. //
  951. // If everything is successful, addref all of the pIniPorts and set the flag
  952. // to indicate that this has happened for the cleanup code.
  953. //
  954. if (Status == ERROR_SUCCESS)
  955. {
  956. for ( i = 0 ; i < pKeyData->cTokens ; ++i ) {
  957. pIniPort = (PINIPORT)pKeyData->pTokens[i];
  958. INCPORTREF(pIniPort);
  959. }
  960. pKeyData->bFixPortRef = TRUE;
  961. }
  962. if (pbNoPorts)
  963. {
  964. *pbNoPorts = dwPorts == 0;
  965. }
  966. if (Status != ERROR_SUCCESS)
  967. {
  968. SetLastError(Status);
  969. }
  970. return Status == ERROR_SUCCESS;
  971. }
  972. DWORD
  973. ValidatePrinterName(
  974. LPWSTR pszNewName,
  975. PINISPOOLER pIniSpooler,
  976. PINIPRINTER pIniPrinter,
  977. LPWSTR *ppszLocalName
  978. )
  979. /*++
  980. Routine Description:
  981. Validates a printer name. Printer and share names exist in the same
  982. namespace, so validation is done against printer, share names.
  983. Arguments:
  984. pszNewName - printer name specified
  985. pIniSpooler - Spooler that owns printer
  986. pIniPrinter - could be null if the printer is getting created
  987. ppszLocalName - on success returns local name
  988. (\\servername stripped off if necessary).
  989. Return Value:
  990. DWORD error code.
  991. --*/
  992. {
  993. PINIPRINTER pIniTempPrinter, pIniNextPrinter;
  994. LPWSTR pszLocalNameTmp = NULL;
  995. WCHAR string[MAX_UNC_PRINTER_NAME];
  996. LPWSTR p;
  997. LPWSTR pLastSpace = NULL;
  998. //
  999. // The function ValidatePrinterName does too many things in one single routine.
  1000. // It checks for validity of the printer name, it isolates the printer name,
  1001. // it eliminates trailing white spaces from the printe name and validates
  1002. // that the printer name is unique.
  1003. //
  1004. // The function IsValidPrinterName ensures that the printer names contains
  1005. // valid characters and valid sequences of characters.
  1006. //
  1007. if (!IsValidPrinterName(pszNewName, MAX_UNC_PRINTER_NAME - 1))
  1008. {
  1009. return ERROR_INVALID_PRINTER_NAME;
  1010. }
  1011. if (*pszNewName == L'\\' && *(pszNewName + 1) == L'\\') {
  1012. p = wcschr(pszNewName + 2, L'\\');
  1013. if (p) {
  1014. //
  1015. // \\Server\Printer -> \\Server
  1016. //
  1017. StringCchCopy(string, (size_t) (p - pszNewName) + 1, pszNewName);
  1018. if (MyName(string, pIniSpooler))
  1019. pszLocalNameTmp = p + 1; // \\Server\Printer -> \Printer
  1020. }
  1021. }
  1022. if (!pszLocalNameTmp)
  1023. pszLocalNameTmp = pszNewName;
  1024. //
  1025. // Strip trailing spaces.
  1026. //
  1027. for( p = pszLocalNameTmp; *p; ++p ){
  1028. if( *p == L' ' ){
  1029. //
  1030. // If we haven't seen a continuous space, remember this
  1031. // position.
  1032. //
  1033. if( !pLastSpace ){
  1034. pLastSpace = p;
  1035. }
  1036. } else {
  1037. //
  1038. // Non-whitespace.
  1039. //
  1040. pLastSpace = NULL;
  1041. }
  1042. }
  1043. if( pLastSpace ){
  1044. *pLastSpace = 0;
  1045. }
  1046. //
  1047. // Limit PrinterNames to MAX_PATH length, also if the printer name is now
  1048. // empty as a result of stripping out all of the spaces, then the printer
  1049. // name is now invalid.
  1050. //
  1051. if ( wcslen( pszLocalNameTmp ) > MAX_PRINTER_NAME || !*pszLocalNameTmp ) {
  1052. return ERROR_INVALID_PRINTER_NAME;
  1053. }
  1054. //
  1055. // Now validate that printer names are unique. Printer names and
  1056. // share names reside in the same namespace (see net\dosprint\dosprtw.c).
  1057. //
  1058. for( pIniTempPrinter = pIniSpooler->pIniPrinter;
  1059. pIniTempPrinter;
  1060. pIniTempPrinter = pIniNextPrinter ){
  1061. //
  1062. // Get the next printer now in case we delete the current
  1063. // one in DeletePrinterCheck.
  1064. //
  1065. pIniNextPrinter = pIniTempPrinter->pNext;
  1066. //
  1067. // Skip ourselves, if we are passed in.
  1068. //
  1069. if( pIniTempPrinter == pIniPrinter ){
  1070. continue;
  1071. }
  1072. //
  1073. // Disallow common Printer/Share names.
  1074. //
  1075. if( !lstrcmpi( pszLocalNameTmp, pIniTempPrinter->pName ) ||
  1076. ( pIniTempPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED &&
  1077. !lstrcmpi( pszLocalNameTmp, pIniTempPrinter->pShareName ))){
  1078. if( !DeletePrinterCheck( pIniTempPrinter )){
  1079. return ERROR_PRINTER_ALREADY_EXISTS;
  1080. }
  1081. }
  1082. }
  1083. //
  1084. // Success, now update ppszLocalName from pszLocalNameTmp.
  1085. //
  1086. *ppszLocalName = pszLocalNameTmp;
  1087. return ERROR_SUCCESS;
  1088. }
  1089. DWORD
  1090. ValidatePrinterShareName(
  1091. LPWSTR pszNewShareName,
  1092. PINISPOOLER pIniSpooler,
  1093. PINIPRINTER pIniPrinter
  1094. )
  1095. /*++
  1096. Routine Description:
  1097. Validates the printer share name. Printer and share names exist in the
  1098. same namespace, so validation is done against printer, share names.
  1099. Arguments:
  1100. pszNewShareName - share name specified
  1101. pIniSpooler - Spooler that owns printer
  1102. pIniPrinter - could be null if the printer is getting created
  1103. Return Value:
  1104. DWORD error code.
  1105. --*/
  1106. {
  1107. PINIPRINTER pIniTempPrinter, pIniNextPrinter;
  1108. if ( !pszNewShareName || !*pszNewShareName || wcslen(pszNewShareName) > PATHLEN-1) {
  1109. return ERROR_INVALID_SHARENAME;
  1110. }
  1111. //
  1112. // Now validate that share names are unique. Share names and printer names
  1113. // reside in the same namespace (see net\dosprint\dosprtw.c).
  1114. //
  1115. for( pIniTempPrinter = pIniSpooler->pIniPrinter;
  1116. pIniTempPrinter;
  1117. pIniTempPrinter = pIniNextPrinter ) {
  1118. //
  1119. // Get the next printer now in case we delete the current
  1120. // one in DeletePrinterCheck.
  1121. //
  1122. pIniNextPrinter = pIniTempPrinter->pNext;
  1123. //
  1124. // Skip ourselves, if we are pssed in.
  1125. //
  1126. if( pIniTempPrinter == pIniPrinter ){
  1127. continue;
  1128. }
  1129. //
  1130. // Check our share name now.
  1131. //
  1132. if( !lstrcmpi(pszNewShareName, pIniTempPrinter->pName) ||
  1133. ( pIniTempPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED &&
  1134. !lstrcmpi(pszNewShareName, pIniTempPrinter->pShareName)) ) {
  1135. if( !DeletePrinterCheck( pIniTempPrinter )){
  1136. return ERROR_INVALID_SHARENAME;
  1137. }
  1138. }
  1139. }
  1140. return ERROR_SUCCESS;
  1141. }
  1142. DWORD
  1143. ValidatePrinterInfo(
  1144. IN PPRINTER_INFO_2 pPrinter,
  1145. IN PINISPOOLER pIniSpooler,
  1146. IN PINIPRINTER pIniPrinter OPTIONAL,
  1147. OUT LPWSTR* ppszLocalName OPTIONAL
  1148. )
  1149. /*++
  1150. Routine Description:
  1151. Validates that printer names/share do not collide. (Both printer and
  1152. share names exist in the same namespace.)
  1153. Note: Later, we should remove all this DeletePrinterCheck. As people
  1154. decrement ref counts, they should DeletePrinterCheck themselves (or
  1155. have it built into the decrement).
  1156. Arguments:
  1157. pPrinter - PrinterInfo2 structure to validate.
  1158. pIniSpooler - Spooler that owns printer
  1159. pIniPrinter - If printer already exists, don't check against itself.
  1160. ppszLocalName - Returned pointer to string buffer in pPrinter;
  1161. indicates local name (\\servername stripped off if necessary).
  1162. Valid only on SUCCESS return code.
  1163. Return Value:
  1164. DWORD error code.
  1165. --*/
  1166. {
  1167. LPWSTR pszNewLocalName;
  1168. DWORD dwLastError;
  1169. if( !CheckSepFile( pPrinter->pSepFile )) {
  1170. return ERROR_INVALID_SEPARATOR_FILE;
  1171. }
  1172. if( pPrinter->Priority != NO_PRIORITY &&
  1173. ( pPrinter->Priority > MAX_PRIORITY ||
  1174. pPrinter->Priority < MIN_PRIORITY )){
  1175. return ERROR_INVALID_PRIORITY;
  1176. }
  1177. if( pPrinter->StartTime >= ONEDAY || pPrinter->UntilTime >= ONEDAY){
  1178. return ERROR_INVALID_TIME;
  1179. }
  1180. if ( dwLastError = ValidatePrinterName(pPrinter->pPrinterName,
  1181. pIniSpooler,
  1182. pIniPrinter,
  1183. &pszNewLocalName) ) {
  1184. return dwLastError;
  1185. }
  1186. // Share name length validation
  1187. if(pPrinter->pShareName && wcslen(pPrinter->pShareName) > PATHLEN-1){
  1188. return ERROR_INVALID_SHARENAME;
  1189. }
  1190. if ( pPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ){
  1191. if ( dwLastError = ValidatePrinterShareName(pPrinter->pShareName,
  1192. pIniSpooler,
  1193. pIniPrinter) ) {
  1194. return dwLastError;
  1195. }
  1196. }
  1197. // Server name length validation
  1198. if ( pPrinter->pServerName && wcslen(pPrinter->pServerName) > MAX_PATH-1 ){
  1199. return ERROR_INVALID_PARAMETER;
  1200. }
  1201. // Comment length validation
  1202. if ( pPrinter->pComment && wcslen(pPrinter->pComment) > PATHLEN-1 ){
  1203. return ERROR_INVALID_PARAMETER;
  1204. }
  1205. // Location length validation
  1206. if ( pPrinter->pLocation && wcslen(pPrinter->pLocation) > MAX_PATH-1 ){
  1207. return ERROR_INVALID_PARAMETER;
  1208. }
  1209. // Parameters length validation
  1210. if ( pPrinter->pParameters && wcslen(pPrinter->pParameters) > MAX_PATH-1){
  1211. return ERROR_INVALID_PARAMETER;
  1212. }
  1213. // Datatype length validation
  1214. if ( pPrinter->pDatatype && wcslen(pPrinter->pDatatype) > MAX_PATH-1){
  1215. return ERROR_INVALID_DATATYPE;
  1216. }
  1217. if( ppszLocalName ){
  1218. *ppszLocalName = pszNewLocalName;
  1219. }
  1220. return ERROR_SUCCESS;
  1221. }
  1222. HANDLE
  1223. LocalAddPrinter(
  1224. LPWSTR pName,
  1225. DWORD Level,
  1226. LPBYTE pPrinterInfo
  1227. )
  1228. {
  1229. PINISPOOLER pIniSpooler;
  1230. HANDLE hReturn;
  1231. pIniSpooler = FindSpoolerByNameIncRef( pName, NULL );
  1232. if( !pIniSpooler ){
  1233. return ROUTER_UNKNOWN;
  1234. }
  1235. hReturn = SplAddPrinter( pName,
  1236. Level,
  1237. pPrinterInfo,
  1238. pIniSpooler,
  1239. NULL, NULL, 0);
  1240. FindSpoolerByNameDecRef( pIniSpooler );
  1241. return hReturn;
  1242. }
  1243. HANDLE
  1244. LocalAddPrinterEx(
  1245. LPWSTR pName,
  1246. DWORD Level,
  1247. LPBYTE pPrinterInfo,
  1248. LPBYTE pSplClientInfo,
  1249. DWORD dwSplClientLevel
  1250. )
  1251. {
  1252. PINISPOOLER pIniSpooler;
  1253. HANDLE hReturn;
  1254. pIniSpooler = FindSpoolerByNameIncRef(pName, NULL);
  1255. if( !pIniSpooler ){
  1256. return ROUTER_UNKNOWN;
  1257. }
  1258. hReturn = SplAddPrinter( pName, Level, pPrinterInfo,
  1259. pIniSpooler, NULL, pSplClientInfo,
  1260. dwSplClientLevel);
  1261. FindSpoolerByNameDecRef( pIniSpooler );
  1262. return hReturn;
  1263. }
  1264. VOID
  1265. RemovePrinterFromPort(
  1266. IN PINIPRINTER pIniPrinter,
  1267. IN PINIPORT pIniPort
  1268. )
  1269. /*++
  1270. Routine Description:
  1271. Remove a pIniPrinter structure from a pIniPort.
  1272. Note: This code used to be inside RemovePrinterFromAllPorts. It searches the
  1273. list of printers that uses the port for pIniPrinter. When it finds it,
  1274. it adjusts the list of printers by moving the elements so that a failure of
  1275. resizing the array won't affect the actual removing. RESIZEPORTPRINTERS
  1276. will try to allocate a new buffer of given size. If succeeds the allocation,
  1277. it will free the old buffer. If not, it will return NULL without freeing
  1278. anything.
  1279. Arguments:
  1280. pIniPrinter - must not be NULL
  1281. pIniPort - must not be NULL
  1282. Return Value:
  1283. VOID
  1284. --*/
  1285. {
  1286. DWORD j, k;
  1287. PINIPRINTER *ppIniPrinter;
  1288. SplInSem();
  1289. if(pIniPort && pIniPrinter) {
  1290. for ( j = 0 ; j < pIniPort->cPrinters ; ++j ) {
  1291. if ( pIniPort->ppIniPrinter[j] != pIniPrinter )
  1292. continue;
  1293. //
  1294. // Adjust the list of printers that use the port
  1295. //
  1296. for ( k = j + 1 ; k < pIniPort->cPrinters ; ++k )
  1297. pIniPort->ppIniPrinter[k-1] = pIniPort->ppIniPrinter[k];
  1298. ppIniPrinter = RESIZEPORTPRINTERS(pIniPort, -1);
  1299. //
  1300. // A memory allocation failure won't affect the actual removal
  1301. //
  1302. if ( ppIniPrinter != NULL )
  1303. pIniPort->ppIniPrinter = ppIniPrinter;
  1304. if ( !--pIniPort->cPrinters )
  1305. RemoveDeviceName(pIniPort);
  1306. break;
  1307. }
  1308. }
  1309. }
  1310. HANDLE
  1311. SplAddPrinter(
  1312. LPWSTR pName,
  1313. DWORD Level,
  1314. LPBYTE pPrinterInfo,
  1315. PINISPOOLER pIniSpooler,
  1316. LPBYTE pExtraData,
  1317. LPBYTE pSplClientInfo,
  1318. DWORD dwSplClientInfoLevel
  1319. )
  1320. {
  1321. PINIDRIVER pIniDriver = NULL;
  1322. PINIPRINTPROC pIniPrintProc;
  1323. PINIPRINTER pIniPrinter = NULL;
  1324. PINIPORT pIniPort;
  1325. PPRINTER_INFO_2 pPrinter=(PPRINTER_INFO_2)pPrinterInfo;
  1326. DWORD cbIniPrinter = sizeof(INIPRINTER);
  1327. BOOL bSucceeded = TRUE;
  1328. PKEYDATA pKeyData = NULL;
  1329. DWORD i;
  1330. HANDLE hPrinter = NULL;
  1331. DWORD TypeofHandle = PRINTER_HANDLE_PRINTER;
  1332. PRINTER_DEFAULTS Defaults;
  1333. PINIPORT pIniNetPort = NULL;
  1334. PINIVERSION pIniVersion = NULL;
  1335. HANDLE hPort = NULL;
  1336. BOOL bAccessSystemSecurity = FALSE, bDriverEventCalled = FALSE;
  1337. DWORD AccessRequested = 0;
  1338. DWORD dwLastError = ERROR_SUCCESS;
  1339. DWORD dwPrnEvntError = ERROR_SUCCESS;
  1340. PDEVMODE pNewDevMode = NULL;
  1341. PINIMONITOR pIniLangMonitor;
  1342. LPWSTR pszDeviceInstanceId = NULL;
  1343. // Quick Check Outside Critical Section
  1344. // Since it is common for the ServerThread to call
  1345. // AddPrinter Level 1, which we need to continue
  1346. // to route to other Print Providers
  1347. if (!MyName( pName, pIniSpooler )) {
  1348. return FALSE;
  1349. }
  1350. try {
  1351. EnterSplSem();
  1352. // PRINTER_INFO_1 is only used by printer browsing to replicate
  1353. // data between different print servers.
  1354. // Thus we add a Net printer for level 1.
  1355. if ( Level == 1 ) {
  1356. //
  1357. // All network printers reside in pLocalIniSpooler to avoid
  1358. // duplicates.
  1359. //
  1360. hPrinter = AddNetPrinter(pPrinterInfo, pLocalIniSpooler);
  1361. leave;
  1362. }
  1363. if ( !ValidateObjectAccess(SPOOLER_OBJECT_SERVER,
  1364. SERVER_ACCESS_ADMINISTER,
  1365. NULL, NULL, pIniSpooler )) {
  1366. leave;
  1367. }
  1368. if ( dwLastError = ValidatePrinterInfo( pPrinter,
  1369. pIniSpooler,
  1370. NULL,
  1371. NULL )){
  1372. leave;
  1373. }
  1374. if (!(pKeyData = CreateTokenList(pPrinter->pPortName))) {
  1375. dwLastError = ERROR_UNKNOWN_PORT;
  1376. leave;
  1377. }
  1378. if ( pName && pName[0] ) {
  1379. TypeofHandle |= PRINTER_HANDLE_REMOTE_DATA;
  1380. }
  1381. {
  1382. HRESULT hRes = CheckLocalCall();
  1383. if (hRes == S_FALSE)
  1384. {
  1385. TypeofHandle |= PRINTER_HANDLE_REMOTE_CALL;
  1386. }
  1387. else if (hRes != S_OK)
  1388. {
  1389. dwLastError = SCODE_CODE(hRes);
  1390. leave;
  1391. }
  1392. }
  1393. if (!ValidatePortTokenList(pKeyData, pIniSpooler, FALSE, NULL)) {
  1394. //
  1395. // ValidatePortTokenList sets the last error to ERROR_INVALID_PRINTER_NAME
  1396. // when port name is invalid. This is correct only for masquerading printers.
  1397. // Otherwise, it should be ERROR_UNKNOWN_PORT.
  1398. // Masq. Printer: both PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL are set.
  1399. //
  1400. if (!(pPrinter->Attributes & (PRINTER_ATTRIBUTE_NETWORK | PRINTER_ATTRIBUTE_LOCAL))) {
  1401. SetLastError(ERROR_UNKNOWN_PORT);
  1402. }
  1403. leave;
  1404. }
  1405. FindLocalDriverAndVersion(pIniSpooler, pPrinter->pDriverName, &pIniDriver, &pIniVersion);
  1406. if (!pIniDriver) {
  1407. dwLastError = ERROR_UNKNOWN_PRINTER_DRIVER;
  1408. leave;
  1409. }
  1410. //
  1411. // Check for blocked KM drivers
  1412. //
  1413. if (KMPrintersAreBlocked() &&
  1414. IniDriverIsKMPD(pIniSpooler,
  1415. FindEnvironment(szEnvironment, pIniSpooler),
  1416. pIniVersion,
  1417. pIniDriver)) {
  1418. SplLogEvent( pIniSpooler,
  1419. LOG_ERROR,
  1420. MSG_KM_PRINTERS_BLOCKED,
  1421. TRUE,
  1422. pPrinter->pPrinterName,
  1423. NULL );
  1424. dwLastError = ERROR_KM_DRIVER_BLOCKED;
  1425. leave;
  1426. }
  1427. if (!(pIniPrintProc = FindPrintProc(pPrinter->pPrintProcessor,
  1428. FindEnvironment(szEnvironment, pIniSpooler)))) {
  1429. dwLastError = ERROR_UNKNOWN_PRINTPROCESSOR;
  1430. leave;
  1431. }
  1432. if ( pPrinter->pDatatype && *pPrinter->pDatatype &&
  1433. !FindDatatype(pIniPrintProc, pPrinter->pDatatype) ) {
  1434. dwLastError = ERROR_INVALID_DATATYPE;
  1435. leave;
  1436. }
  1437. DBGMSG(DBG_TRACE, ("AddPrinter(%ws)\n", pPrinter->pPrinterName ?
  1438. pPrinter->pPrinterName : L"NULL"));
  1439. //
  1440. // Set up defaults for CreatePrinterHandle.
  1441. // If we create a printer we have Administer access to it:
  1442. //
  1443. Defaults.pDatatype = NULL;
  1444. Defaults.pDevMode = NULL;
  1445. Defaults.DesiredAccess = PRINTER_ALL_ACCESS;
  1446. pIniPrinter = (PINIPRINTER)AllocSplMem( cbIniPrinter );
  1447. if ( pIniPrinter == NULL ) {
  1448. leave;
  1449. }
  1450. pIniPrinter->signature = IP_SIGNATURE;
  1451. pIniPrinter->Status |= PRINTER_PENDING_CREATION;
  1452. pIniPrinter->pExtraData = pExtraData;
  1453. pIniPrinter->pIniSpooler = pIniSpooler;
  1454. pIniPrinter->dwPrivateFlag = 0;
  1455. // Give the printer a unique session ID to pass around in notifications
  1456. pIniPrinter->dwUniqueSessionID = dwUniquePrinterSessionID++;
  1457. //
  1458. // Reference count the pIniSpooler.
  1459. //
  1460. INCSPOOLERREF( pIniSpooler );
  1461. INCDRIVERREF(pIniDriver);
  1462. pIniPrinter->pIniDriver = pIniDriver;
  1463. pIniPrintProc->cRef++;
  1464. pIniPrinter->pIniPrintProc = pIniPrintProc;
  1465. pIniPrinter->dnsTimeout = DEFAULT_DNS_TIMEOUT;
  1466. pIniPrinter->txTimeout = DEFAULT_TX_TIMEOUT;
  1467. INCPRINTERREF( pIniPrinter );
  1468. if (!CreatePrinterEntry(pPrinter, pIniPrinter, &bAccessSystemSecurity)) {
  1469. leave;
  1470. }
  1471. pIniPrinter->ppIniPorts = AllocSplMem(pKeyData->cTokens * sizeof(INIPORT));
  1472. if ( !pIniPrinter->ppIniPorts ) {
  1473. leave;
  1474. }
  1475. if (!pIniPrinter->pDatatype) {
  1476. pIniPrinter->pDatatype = AllocSplStr(*((LPWSTR *)pIniPrinter->pIniPrintProc->pDatatypes));
  1477. if ( pIniPrinter->pDatatype == NULL )
  1478. leave;
  1479. }
  1480. // Add this printer to the global list for this machine
  1481. SplInSem();
  1482. pIniPrinter->pNext = pIniSpooler->pIniPrinter;
  1483. pIniSpooler->pIniPrinter = pIniPrinter;
  1484. //
  1485. // When a printer is created we will enable bidi by default
  1486. //
  1487. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
  1488. if ( pIniPrinter->pIniDriver->pIniLangMonitor ) {
  1489. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
  1490. }
  1491. for ( i = 0; i < pKeyData->cTokens; i++ ) {
  1492. pIniPort = (PINIPORT)pKeyData->pTokens[i];
  1493. if ( !AddIniPrinterToIniPort( pIniPort, pIniPrinter ) ) {
  1494. leave;
  1495. }
  1496. pIniPrinter->ppIniPorts[i] = pIniPort;
  1497. pIniPrinter->cPorts++;
  1498. // If there isn't a monitor for this port,
  1499. // it's a network printer.
  1500. // Make sure we can get a handle for it.
  1501. // This will attempt to open only the first one
  1502. // it finds. Any others will be ignored.
  1503. if (!(pIniPort->Status & PP_MONITOR) && !hPort) {
  1504. if(bSucceeded = OpenPrinterPortW(pIniPort->pName, &hPort, NULL)) {
  1505. // Store the address of the INIPORT structure
  1506. // that refers to the network share.
  1507. // This should correspond to pIniPort in any
  1508. // handles opened on this printer.
  1509. // Only the first INIPORT in the linked list
  1510. // is a valid network port.
  1511. pIniNetPort = pIniPort;
  1512. pIniPrinter->pIniNetPort = pIniNetPort;
  1513. //
  1514. // Clear the placeholder status from the pIniPort.
  1515. //
  1516. pIniPort->Status &= ~PP_PLACEHOLDER;
  1517. } else {
  1518. DBGMSG(DBG_WARNING,
  1519. ("SplAddPrinter OpenPrinterPort( %ws ) failed: Error %d\n",
  1520. pIniPort->pName,
  1521. GetLastError()));
  1522. leave;
  1523. }
  1524. }
  1525. else if (!pIniPort->hMonitorHandle)
  1526. {
  1527. LPTSTR pszPrinter;
  1528. TCHAR szFullPrinter[ MAX_UNC_PRINTER_NAME ];
  1529. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_BIDI )
  1530. pIniLangMonitor = pIniPrinter->pIniDriver->pIniLangMonitor;
  1531. else
  1532. pIniLangMonitor = NULL;
  1533. if( pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CLUSTER ){
  1534. pszPrinter = szFullPrinter;
  1535. if (!BoolFromHResult(StringCchPrintf(szFullPrinter,
  1536. COUNTOF(szFullPrinter),
  1537. L"%ws\\%ws",
  1538. pIniSpooler->pMachineName,
  1539. pIniPrinter->pName))){
  1540. leave;
  1541. }
  1542. } else {
  1543. pszPrinter = pIniPrinter->pName;
  1544. }
  1545. OpenMonitorPort(pIniPort, pIniLangMonitor, pszPrinter);
  1546. ReleaseMonitorPort(pIniPort);
  1547. }
  1548. }
  1549. if ( !UpdateWinIni( pIniPrinter ) ) {
  1550. leave;
  1551. }
  1552. if (bAccessSystemSecurity) {
  1553. Defaults.DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  1554. }
  1555. AccessRequested = Defaults.DesiredAccess;
  1556. SplInSem();
  1557. hPrinter = CreatePrinterHandle( pIniPrinter->pName,
  1558. pName ? pName : pIniSpooler->pMachineName,
  1559. pIniPrinter,
  1560. pIniPort,
  1561. pIniNetPort,
  1562. NULL,
  1563. TypeofHandle,
  1564. hPort,
  1565. &Defaults,
  1566. pIniSpooler,
  1567. AccessRequested,
  1568. pSplClientInfo,
  1569. dwSplClientInfoLevel,
  1570. INVALID_HANDLE_VALUE );
  1571. if ( hPrinter == NULL ) {
  1572. leave;
  1573. }
  1574. if ( !UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID )) {
  1575. dwLastError = GetLastError();
  1576. SplClosePrinter( hPrinter );
  1577. hPrinter = NULL;
  1578. leave;
  1579. }
  1580. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  1581. INC_PRINTER_ZOMBIE_REF(pIniPrinter);
  1582. //
  1583. // NOTE ShareThisPrinter will leave critical section and the
  1584. // server will call the spooler back again to OpenPrinter this
  1585. // printer. So this printer MUST be fully created at the point
  1586. // it is shared, so that Open can succeed.
  1587. //
  1588. bSucceeded = ShareThisPrinter(pIniPrinter,
  1589. pIniPrinter->pShareName,
  1590. TRUE
  1591. );
  1592. DEC_PRINTER_ZOMBIE_REF(pIniPrinter);
  1593. if ( !bSucceeded ) {
  1594. //
  1595. // We do not want to delete the existing share in DeletePrinterIni
  1596. //
  1597. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
  1598. DBGMSG( DBG_WARNING, ("LocalAddPrinter: %ws share failed %ws error %d\n",
  1599. pIniPrinter->pName,
  1600. pIniPrinter->pShareName,
  1601. GetLastError() ));
  1602. //
  1603. // With PRINTER_PENDING_CREATION turned on we will Delete this printer.
  1604. //
  1605. pIniPrinter->Status |= PRINTER_PENDING_CREATION;
  1606. dwLastError = GetLastError();
  1607. SPLASSERT( hPrinter );
  1608. SplClosePrinter( hPrinter );
  1609. hPrinter = NULL;
  1610. leave;
  1611. }
  1612. }
  1613. pIniPrinter->Status |= PRINTER_OK;
  1614. SplInSem();
  1615. // Call the DriverEvent with PRINTER_INITIALIZE while adding local printers
  1616. LeaveSplSem();
  1617. if (pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL) {
  1618. if (bDriverEventCalled = PrinterDriverEvent(pIniPrinter,
  1619. PRINTER_EVENT_INITIALIZE,
  1620. (LPARAM)NULL,
  1621. &dwPrnEvntError) == FALSE) {
  1622. dwLastError = dwPrnEvntError;
  1623. if (dwLastError != ERROR_PROC_NOT_FOUND) {
  1624. if (!dwLastError)
  1625. dwLastError = ERROR_CAN_NOT_COMPLETE;
  1626. EnterSplSem();
  1627. //
  1628. // With PRINTER_PENDING_CREATION turned on the printer will be deleted.
  1629. //
  1630. pIniPrinter->Status |= PRINTER_PENDING_CREATION;
  1631. SplClosePrinter( hPrinter );
  1632. hPrinter = NULL;
  1633. leave;
  1634. }
  1635. }
  1636. }
  1637. EnterSplSem();
  1638. //
  1639. // If no devmode is given get driver default, if a devmode is given
  1640. // convert it to current version
  1641. //
  1642. // Check if it's local (either pLocalIniSpooler or cluster).
  1643. //
  1644. if ( pIniSpooler->SpoolerFlags & SPL_TYPE_LOCAL ) {
  1645. if (!(pNewDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  1646. pIniPrinter->pDevMode,
  1647. NULL,
  1648. NULL,
  1649. CURRENT_VERSION))) {
  1650. dwLastError = GetLastError();
  1651. if (!dwLastError) {
  1652. dwLastError = ERROR_CAN_NOT_COMPLETE;
  1653. }
  1654. //
  1655. // With PRINTER_PENDING_CREATION turned on the printer will be deleted.
  1656. //
  1657. pIniPrinter->Status |= PRINTER_PENDING_CREATION;
  1658. SplClosePrinter( hPrinter );
  1659. hPrinter = NULL;
  1660. leave;
  1661. }
  1662. //
  1663. // If call is remote we must convert devmode before setting it
  1664. //
  1665. if ( pNewDevMode || (TypeofHandle & PRINTER_HANDLE_REMOTE_DATA) ) {
  1666. FreeSplMem(pIniPrinter->pDevMode);
  1667. pIniPrinter->pDevMode = pNewDevMode;
  1668. if ( pNewDevMode ) {
  1669. pIniPrinter->cbDevMode = pNewDevMode->dmSize
  1670. + pNewDevMode->dmDriverExtra;
  1671. SPLASSERT(pIniPrinter->cbDevMode);
  1672. } else {
  1673. pIniPrinter->cbDevMode = 0;
  1674. }
  1675. pNewDevMode = NULL;
  1676. }
  1677. }
  1678. if ( pIniPrinter->pDevMode ) {
  1679. //
  1680. // Fix up the DEVMODE.dmDeviceName field.
  1681. //
  1682. FixDevModeDeviceName(pIniPrinter->pName,
  1683. pIniPrinter->pDevMode,
  1684. pIniPrinter->cbDevMode);
  1685. }
  1686. //
  1687. // We need to write the new devmode to the registry
  1688. //
  1689. if (!UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID)) {
  1690. DBGMSG(DBG_WARNING,
  1691. ("SplAddPrinter: UpdatePrinterIni failed after devmode conversion\n"));
  1692. }
  1693. //
  1694. // For Masq printers, give the provider a chance to update the printer registry, if desired.
  1695. //
  1696. if( pIniNetPort ) {
  1697. static const WCHAR c_szHttp[] = L"http://";
  1698. static const WCHAR c_szHttps[] = L"https://";
  1699. if( !_wcsnicmp( pIniPort->pName, c_szHttp, lstrlen ( c_szHttp ) ) ||
  1700. !_wcsnicmp( pIniPort->pName, c_szHttps, lstrlen ( c_szHttps ) ) ) {
  1701. UpdatePrinterNetworkName(pIniPrinter, pIniPort->pName);
  1702. }
  1703. }
  1704. //
  1705. // DS: Create the DS keys
  1706. //
  1707. INCPRINTERREF(pIniPrinter);
  1708. LeaveSplSem();
  1709. RecreateDsKey(hPrinter, SPLDS_DRIVER_KEY);
  1710. RecreateDsKey(hPrinter, SPLDS_SPOOLER_KEY);
  1711. EnterSplSem();
  1712. DECPRINTERREF(pIniPrinter);
  1713. //
  1714. // From this point on we don't care if any of these fail
  1715. // we still keep the created printer.
  1716. //
  1717. SplLogEvent( pIniSpooler,
  1718. LOG_INFO,
  1719. MSG_PRINTER_CREATED,
  1720. TRUE,
  1721. pIniPrinter->pName,
  1722. NULL );
  1723. SetPrinterChange(pIniPrinter,
  1724. NULL,
  1725. NVPrinterAll,
  1726. PRINTER_CHANGE_ADD_PRINTER,
  1727. pIniSpooler);
  1728. } finally {
  1729. SplInSem();
  1730. if ( hPrinter == NULL ) {
  1731. // FAILURE CLEAN-UP
  1732. // If a subroutine we called failed
  1733. // then we should save its error incase it is
  1734. // altered during cleanup.
  1735. if ( dwLastError == ERROR_SUCCESS ) {
  1736. dwLastError = GetLastError();
  1737. }
  1738. if ( pIniPrinter == NULL ) {
  1739. // Allow a Print Provider to free its ExtraData
  1740. // associated with this printer.
  1741. if (( pIniSpooler->pfnFreePrinterExtra != NULL ) &&
  1742. ( pExtraData != NULL )) {
  1743. (*pIniSpooler->pfnFreePrinterExtra)( pExtraData );
  1744. }
  1745. } else if ( pIniPrinter->Status & PRINTER_PENDING_CREATION ) {
  1746. if (bDriverEventCalled) {
  1747. LeaveSplSem();
  1748. // Call Driver Event to report that the printer has been deleted
  1749. PrinterDriverEvent( pIniPrinter, PRINTER_EVENT_DELETE, (LPARAM)NULL, &dwPrnEvntError );
  1750. EnterSplSem();
  1751. }
  1752. DECPRINTERREF( pIniPrinter );
  1753. InternalDeletePrinter( pIniPrinter );
  1754. }
  1755. } else {
  1756. // Success
  1757. if ( pIniPrinter ) {
  1758. DECPRINTERREF( pIniPrinter );
  1759. }
  1760. }
  1761. FreePortTokenList(pKeyData);
  1762. LeaveSplSem();
  1763. SplOutSem();
  1764. FreeSplMem(pNewDevMode);
  1765. if ( hPrinter == NULL && Level != 1 ) {
  1766. DBGMSG(DBG_WARNING, ("SplAddPrinter failed error %d\n", dwLastError ));
  1767. SPLASSERT(dwLastError);
  1768. SetLastError ( dwLastError );
  1769. }
  1770. DBGMSG( DBG_TRACE, ("SplAddPrinter returned handle %x\n", hPrinter ));
  1771. }
  1772. //
  1773. // Make (HANDLE)-1 indicate ROUTER_STOP_ROUTING.
  1774. //
  1775. if( !hPrinter ){
  1776. hPrinter = (HANDLE)-1;
  1777. }
  1778. return hPrinter;
  1779. }
  1780. VOID
  1781. RemovePrinterFromAllPorts(
  1782. IN PINIPRINTER pIniPrinter,
  1783. IN BOOL bIsInitTime
  1784. )
  1785. /*++
  1786. Routine Description:
  1787. Remove a pIniPrinter structure from all pIniPort structures that it is
  1788. associated with.
  1789. Note: This code used to be inside RemovePrinterFromAllPorts. It searches
  1790. the list of printers that uses the port for pIniPrinter. When it finds it,
  1791. it adjust the list of printers by moving the elements so that a failure of
  1792. resizing the array won't affect the actual removing.
  1793. RESIZEPORTPRINTERS will try to allocate a new buffer of given size. If succeeds
  1794. the allocation, it will free the old buffer. If not, it will return NULL without
  1795. freeing anything.
  1796. Arguments:
  1797. pIniPrinter - must not be NULL
  1798. pIniPort - must not be NULL
  1799. Return Value:
  1800. VOID
  1801. --*/
  1802. {
  1803. DWORD i,j, k;
  1804. PINIPORT pIniPort;
  1805. PINIPRINTER *ppIniPrinter;
  1806. SplInSem();
  1807. for ( i = 0 ; i < pIniPrinter->cPorts ; ++i ) {
  1808. pIniPort = pIniPrinter->ppIniPorts[i];
  1809. RemovePrinterFromPort(pIniPrinter, pIniPort);
  1810. //
  1811. // Delete port if is initialization time , it doesn't have printers
  1812. // attached and it has no Monitor;
  1813. // This is a fix for the USBMON problem described below:
  1814. // USBMON doesn't enumerate the ports which are not used by a printer.
  1815. // Spooler doesn't enumerate printers which are in pending deletion state.
  1816. // Scenario: Spooler initializes , all printers that uses a
  1817. // certain USB_X port are in pending deletion state,
  1818. // the USB_X port doesn't get enumerated by USBMON,
  1819. // but it is created as a fake port by spooler since is still used by
  1820. // the printer in pending deletion state. Eventually the prinetr goes away,
  1821. // but we end up with this fake port.
  1822. //
  1823. if( bIsInitTime && !pIniPort->cPrinters && !pIniPort->pIniMonitor )
  1824. DeletePortEntry(pIniPort);
  1825. }
  1826. }
  1827. VOID
  1828. CloseMonitorsRestartOrphanJobs(
  1829. PINIPRINTER pIniPrinter
  1830. )
  1831. {
  1832. PINIPORT pIniPort;
  1833. DWORD i;
  1834. BOOL bFound;
  1835. SplInSem();
  1836. for ( pIniPort = pIniPrinter->pIniSpooler->pIniPort;
  1837. pIniPort != NULL;
  1838. pIniPort = pIniPort->pNext ) {
  1839. if ( pIniPort->pIniJob != NULL &&
  1840. pIniPort->pIniJob->pIniPrinter == pIniPrinter ) {
  1841. //
  1842. // If this printer is no longer associated with this port
  1843. // then restart that job.
  1844. //
  1845. for ( i = 0, bFound = FALSE;
  1846. i < pIniPort->cPrinters;
  1847. i++) {
  1848. if (pIniPort->ppIniPrinter[i] == pIniPrinter) {
  1849. bFound = TRUE;
  1850. }
  1851. }
  1852. if ( !bFound ) {
  1853. DBGMSG( DBG_WARNING, ("CloseMonitorsRestartOrphanJobs Restarting JobId %d\n", pIniPort->pIniJob->JobId ));
  1854. RestartJob( pIniPort->pIniJob );
  1855. }
  1856. }
  1857. if ( !pIniPort->cPrinters &&
  1858. !(pIniPort->Status & PP_THREADRUNNING) ) {
  1859. CloseMonitorPort(pIniPort);
  1860. }
  1861. }
  1862. }
  1863. //
  1864. // This really does delete the printer.
  1865. // It should be called only when the printer has no open handles
  1866. // and no jobs waiting to print
  1867. //
  1868. BOOL
  1869. DeletePrinterForReal(
  1870. PINIPRINTER pIniPrinter,
  1871. BOOL bIsInitTime
  1872. )
  1873. {
  1874. PINIPRINTER *ppIniPrinter;
  1875. DWORD i,j;
  1876. PINISPOOLER pIniSpooler;
  1877. LPWSTR pComma;
  1878. DWORD Status;
  1879. SplInSem();
  1880. SPLASSERT( pIniPrinter->pIniSpooler->signature == ISP_SIGNATURE );
  1881. pIniSpooler = pIniPrinter->pIniSpooler;
  1882. if ( pIniPrinter->pName != NULL ) {
  1883. DBGMSG( DBG_TRACE, ("Deleting %ws for real\n", pIniPrinter->pName ));
  1884. }
  1885. CheckAndUpdatePrinterRegAll( pIniSpooler,
  1886. pIniPrinter->pName,
  1887. NULL,
  1888. UPDATE_REG_DELETE );
  1889. DeleteIniPrinterDevNode(pIniPrinter);
  1890. DeletePrinterIni( pIniPrinter );
  1891. // Take this IniPrinter off the list of printers for
  1892. // this IniSpooler
  1893. SplInSem();
  1894. ppIniPrinter = &pIniSpooler->pIniPrinter;
  1895. while (*ppIniPrinter && *ppIniPrinter != pIniPrinter) {
  1896. ppIniPrinter = &(*ppIniPrinter)->pNext;
  1897. }
  1898. if (*ppIniPrinter)
  1899. *ppIniPrinter = pIniPrinter->pNext;
  1900. //
  1901. // Decrement useage counts for Print Processor & Driver
  1902. //
  1903. if ( pIniPrinter->pIniPrintProc )
  1904. pIniPrinter->pIniPrintProc->cRef--;
  1905. if ( pIniPrinter->pIniDriver )
  1906. DECDRIVERREF(pIniPrinter->pIniDriver);
  1907. RemovePrinterFromAllPorts(pIniPrinter, bIsInitTime);
  1908. CloseMonitorsRestartOrphanJobs( pIniPrinter );
  1909. DeletePrinterSecurity( pIniPrinter );
  1910. // When the printer is Zombied it gets a trailing comma
  1911. // Concatingated with the name ( see job.c deleteprintercheck ).
  1912. // Remove trailing , from printer name before we log it as deleted.
  1913. if ( pIniPrinter->pName != NULL ) {
  1914. pComma = wcsrchr( pIniPrinter->pName, *szComma );
  1915. if ( pComma != NULL ) {
  1916. *pComma = 0;
  1917. }
  1918. SplLogEvent( pIniSpooler,
  1919. LOG_WARNING,
  1920. MSG_PRINTER_DELETED,
  1921. TRUE,
  1922. pIniPrinter->pName,
  1923. NULL );
  1924. }
  1925. // Deleting the network port if it exists
  1926. if (pIniPrinter->pIniNetPort && pIniPrinter->pIniNetPort->pName) {
  1927. DeleteIniNetPort(pIniPrinter);
  1928. SplInSem();
  1929. }
  1930. FreeStructurePointers((LPBYTE) pIniPrinter, NULL, IniPrinterOffsets);
  1931. //
  1932. // Allow a Print Provider to free its ExtraData
  1933. // associated with this printer.
  1934. //
  1935. if (( pIniSpooler->pfnFreePrinterExtra != NULL ) &&
  1936. ( pIniPrinter->pExtraData != NULL )) {
  1937. (*pIniSpooler->pfnFreePrinterExtra)( pIniPrinter->pExtraData );
  1938. }
  1939. //
  1940. // Reference count the pIniSpooler.
  1941. //
  1942. DECSPOOLERREF( pIniPrinter->pIniSpooler );
  1943. FreeSplMem( pIniPrinter );
  1944. return TRUE;
  1945. }
  1946. VOID
  1947. DeleteIniNetPort(
  1948. PINIPRINTER pIniPrinter
  1949. )
  1950. {
  1951. LPWSTR pszName = NULL;
  1952. LPWSTR pszPortName = NULL;
  1953. HANDLE hXcv = NULL;
  1954. PRINTER_DEFAULTS Defaults = { NULL, NULL, SERVER_ACCESS_ADMINISTER };
  1955. static const TCHAR pszPrefix[] = TEXT(",XcvPort ");
  1956. BOOL bUsingXcvData = FALSE;
  1957. DWORD dwNeeded, dwStatus, dwSize;
  1958. SplInSem();
  1959. pszPortName = AllocSplStr(pIniPrinter->pIniNetPort->pName);
  1960. if (pszPortName)
  1961. {
  1962. LeaveSplSem();
  1963. SplOutSem();
  1964. if (ERROR_SUCCESS == StrCatAlloc(&pszName, pszPrefix, pszPortName, NULL))
  1965. {
  1966. //
  1967. // We try opening a transcieve handle to the port.
  1968. //
  1969. bUsingXcvData = OpenPrinterPortW(pszName, &hXcv, &Defaults);
  1970. if (bUsingXcvData)
  1971. {
  1972. dwSize = (lstrlen(pszPortName) + 1)*sizeof(TCHAR);
  1973. bUsingXcvData = XcvData(hXcv,
  1974. TEXT("DeletePort"),
  1975. (LPBYTE)pszPortName,
  1976. dwSize,
  1977. NULL,
  1978. 0,
  1979. &dwNeeded,
  1980. &dwStatus);
  1981. }
  1982. // If we fail to use XcvData to delete the port we try to do it using DeletePort.
  1983. if (!bUsingXcvData)
  1984. {
  1985. DeletePort(NULL, NULL, pszName);
  1986. }
  1987. if (hXcv)
  1988. {
  1989. ClosePrinter(hXcv);
  1990. }
  1991. }
  1992. FreeSplMem(pszName);
  1993. FreeSplStr(pszPortName);
  1994. EnterSplSem();
  1995. }
  1996. }
  1997. VOID
  1998. InternalDeletePrinter(
  1999. PINIPRINTER pIniPrinter
  2000. )
  2001. {
  2002. BOOL dwRet = FALSE;
  2003. DWORD dwPrnEvntError = ERROR_SUCCESS;
  2004. SPLASSERT( pIniPrinter->signature == IP_SIGNATURE );
  2005. SPLASSERT( pIniPrinter->pIniSpooler->signature == ISP_SIGNATURE );
  2006. //
  2007. // This Might be a partially created printer that has no name
  2008. //
  2009. if ( pIniPrinter->pName != NULL ) {
  2010. DBGMSG(DBG_TRACE, ("LocalDeletePrinter: %ws pending deletion: references = %d; jobs = %d\n",
  2011. pIniPrinter->pName, pIniPrinter->cRef, pIniPrinter->cJobs));
  2012. INCPRINTERREF( pIniPrinter );
  2013. SplLogEvent( pIniPrinter->pIniSpooler, LOG_WARNING, MSG_PRINTER_DELETION_PENDING,
  2014. TRUE, pIniPrinter->pName, NULL );
  2015. DECPRINTERREF( pIniPrinter );
  2016. }
  2017. //
  2018. // Mark the printer as "Don't accept any jobs" to make sure
  2019. // that no more are accepted while we are outside CS.
  2020. // Marking the printer in PRINTER_PENDING_DELETION also would
  2021. // prevent adding any jobs, but then the OpenPrinter calls that the
  2022. // driver does inside DrvDriverEvent will fail.
  2023. //
  2024. pIniPrinter->Status |= PRINTER_NO_MORE_JOBS;
  2025. if (pIniPrinter->cJobs == 0)
  2026. {
  2027. INCPRINTERREF(pIniPrinter);
  2028. LeaveSplSem();
  2029. SplOutSem();
  2030. PrinterDriverEvent( pIniPrinter, PRINTER_EVENT_DELETE, (LPARAM)NULL, &dwPrnEvntError );
  2031. EnterSplSem();
  2032. SplInSem();
  2033. DECPRINTERREF(pIniPrinter);
  2034. }
  2035. pIniPrinter->Status |= PRINTER_PENDING_DELETION;
  2036. if (!(pIniPrinter->Status & PRINTER_PENDING_CREATION)) {
  2037. SetPrinterChange(pIniPrinter,
  2038. NULL,
  2039. NVPrinterStatus,
  2040. PRINTER_CHANGE_DELETE_PRINTER,
  2041. pIniPrinter->pIniSpooler );
  2042. }
  2043. INC_PRINTER_ZOMBIE_REF( pIniPrinter );
  2044. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED ) {
  2045. dwRet = ShareThisPrinter(pIniPrinter, pIniPrinter->pShareName, FALSE);
  2046. if (!dwRet) {
  2047. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
  2048. pIniPrinter->Status |= PRINTER_WAS_SHARED;
  2049. CreateServerThread();
  2050. } else {
  2051. DBGMSG(DBG_WARNING, ("LocalDeletePrinter: Unsharing this printer failed %ws\n", pIniPrinter->pName));
  2052. }
  2053. }
  2054. DEC_PRINTER_ZOMBIE_REF( pIniPrinter );
  2055. //
  2056. // The printer doesn't get deleted until ClosePrinter is called
  2057. // on the last remaining handle.
  2058. //
  2059. UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID );
  2060. UpdateWinIni( pIniPrinter );
  2061. DeletePrinterCheck( pIniPrinter );
  2062. }
  2063. BOOL
  2064. SplDeletePrinter(
  2065. HANDLE hPrinter
  2066. )
  2067. {
  2068. PINIPRINTER pIniPrinter;
  2069. PSPOOL pSpool = (PSPOOL)hPrinter;
  2070. DWORD LastError = ERROR_SUCCESS;
  2071. PINISPOOLER pIniSpooler;
  2072. EnterSplSem();
  2073. pIniSpooler = pSpool->pIniSpooler;
  2074. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  2075. if ( ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER) ) {
  2076. pIniPrinter = pSpool->pIniPrinter;
  2077. DBGMSG( DBG_TRACE, ( "SplDeletePrinter: %s called\n", pIniPrinter->pName ));
  2078. if ( !AccessGranted(SPOOLER_OBJECT_PRINTER,
  2079. DELETE, pSpool) ) {
  2080. LastError = ERROR_ACCESS_DENIED;
  2081. } else if (pIniPrinter->cJobs && (pIniPrinter->Status & PRINTER_PAUSED)) {
  2082. // Don't allow a printer to be deleted that is paused and has
  2083. // jobs waiting, otherwise it'll never get deleted:
  2084. LastError = ERROR_PRINTER_HAS_JOBS_QUEUED;
  2085. } else {
  2086. if (!(pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE) &&
  2087. (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  2088. if (!pIniPrinter->bDsPendingDeletion) {
  2089. pIniPrinter->bDsPendingDeletion = TRUE;
  2090. INCPRINTERREF(pIniPrinter); // DECPRINTERREF is done in UnpublishByGUID
  2091. SetPrinterDs(hPrinter, DSPRINT_UNPUBLISH, FALSE);
  2092. }
  2093. }
  2094. InternalDeletePrinter( pIniPrinter );
  2095. (VOID) ObjectDeleteAuditAlarm( szSpooler, pSpool, pSpool->GenerateOnClose );
  2096. }
  2097. } else
  2098. LastError = ERROR_INVALID_HANDLE;
  2099. LeaveSplSem();
  2100. SplOutSem();
  2101. if (LastError) {
  2102. SetLastError(LastError);
  2103. return FALSE;
  2104. }
  2105. return TRUE;
  2106. }
  2107. BOOL
  2108. PurgePrinter(
  2109. PINIPRINTER pIniPrinter
  2110. )
  2111. {
  2112. PINIJOB pIniJob, pIniNextJob;
  2113. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  2114. SplInSem();
  2115. pIniNextJob = pIniPrinter->pIniFirstJob;
  2116. //
  2117. // We go through the list of all the jobs for the printer and delete them.
  2118. // The check for cRef == 0 or JOB_PENDING_DELETION is for optimization.
  2119. // We keep a refcount on the next job so that it doesnt get deleted when
  2120. // we leave the CS during DeleteJob. Any Jobs with status Spooling are just
  2121. // ignored because the spooler does not support deleting a job which is
  2122. // being spooled, as yet.
  2123. //
  2124. while (pIniNextJob)
  2125. {
  2126. pIniJob = pIniNextJob;
  2127. pIniNextJob = pIniJob->pIniNextJob;
  2128. if ( (pIniJob->cRef == 0) || !(pIniJob->Status & JOB_PENDING_DELETION))
  2129. {
  2130. // this job is going to be deleted
  2131. DBGMSG(DBG_TRACE, ("Job Address 0x%.8x Job Status 0x%.8x\n", pIniJob, pIniJob->Status));
  2132. InterlockedAnd((LONG*)&(pIniJob->Status), ~JOB_RESTART);
  2133. if (pIniNextJob)
  2134. {
  2135. INCJOBREF(pIniNextJob);
  2136. }
  2137. DeleteJob(pIniJob,NO_BROADCAST);
  2138. if (pIniNextJob)
  2139. {
  2140. DECJOBREF(pIniNextJob);
  2141. }
  2142. }
  2143. }
  2144. // When purging a printer we don't want to generate a spooler information
  2145. // message for each job being deleted becuase a printer might have a very
  2146. // large number of jobs being purged would lead to a large number of
  2147. // of unnessary and time consuming messages being generated.
  2148. // Since this is a information only message it shouldn't cause any problems
  2149. // Also Win 3.1 didn't have purge printer functionality and the printman
  2150. // generated this message on Win 3.1
  2151. if (dwEnableBroadcastSpoolerStatus) {
  2152. BroadcastChange( pIniSpooler,WM_SPOOLERSTATUS, PR_JOBSTATUS, (LPARAM)0);
  2153. }
  2154. return TRUE;
  2155. }
  2156. BOOL
  2157. SetPrinterPorts(
  2158. PSPOOL pSpool, // Caller's printer handle. May be NULL.
  2159. PINIPRINTER pIniPrinter,
  2160. PKEYDATA pKeyData
  2161. )
  2162. {
  2163. DWORD i,j;
  2164. PINIPORT pIniNetPort = NULL, pIniPort;
  2165. BOOL bReturnValue = TRUE;
  2166. PINIPRINTER *ppIniPrinter;
  2167. SPLASSERT( pIniPrinter != NULL );
  2168. SPLASSERT( pIniPrinter->signature == IP_SIGNATURE );
  2169. SPLASSERT( pIniPrinter->pIniSpooler != NULL );
  2170. SPLASSERT( pIniPrinter->pIniSpooler->signature == ISP_SIGNATURE );
  2171. //
  2172. // Can't change the port for a masq printer
  2173. //
  2174. if ( (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_LOCAL) &&
  2175. (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_NETWORK) ) {
  2176. if ( pKeyData->cTokens == 1 &&
  2177. pSpool->pIniNetPort == (PINIPORT)pKeyData->pTokens[0] )
  2178. return TRUE;
  2179. SetLastError(ERROR_INVALID_PARAMETER);
  2180. return FALSE;
  2181. }
  2182. //
  2183. // Can't change printer port to that of a masq printer
  2184. //
  2185. for ( i = 0 ; i < pKeyData->cTokens ; ++i )
  2186. if ( !(((PINIPORT) pKeyData->pTokens[i])->Status & PP_MONITOR) ) {
  2187. SetLastError(ERROR_INVALID_PARAMETER);
  2188. return FALSE;
  2189. }
  2190. //
  2191. // Remove the printer from all ports ; break the link from ports to printer
  2192. //
  2193. RemovePrinterFromAllPorts(pIniPrinter, NON_INIT_TIME);
  2194. //
  2195. // Remove all ports from printer; break the link from printer to ports
  2196. //
  2197. FreeSplMem(pIniPrinter->ppIniPorts);
  2198. pIniPrinter->ppIniPorts = NULL;
  2199. pIniPrinter->cPorts = 0;
  2200. //
  2201. // If we fail to add all the ports inside pKeyData, we'll leave the printer in this state
  2202. // where it's initials ports are gone and only part or none of the ports are added.
  2203. //
  2204. // Go through all the ports that this printer is connected to,
  2205. // and add build the bi-dir links between printer and ports.
  2206. for (i = 0; i < pKeyData->cTokens; i++ ) {
  2207. pIniPort = (PINIPORT)pKeyData->pTokens[i];
  2208. //
  2209. // Add pIniPrinter to pIniPort
  2210. //
  2211. if ( AddIniPrinterToIniPort( pIniPort, pIniPrinter ) ) {
  2212. //
  2213. // If we succeeded, add pIniPort to pIniPrinter
  2214. //
  2215. if ( !AddIniPortToIniPrinter( pIniPrinter, pIniPort ) ) {
  2216. //
  2217. // If fail, then remove pIniPrinter from pIniPort ;
  2218. // If we don't do this, pIniPort will point to invalid memory when piniPrinter gets deleted
  2219. //
  2220. RemovePrinterFromPort(pIniPrinter, pIniPort);
  2221. bReturnValue = FALSE;
  2222. goto Cleanup;
  2223. }
  2224. } else {
  2225. bReturnValue = FALSE;
  2226. goto Cleanup;
  2227. }
  2228. }
  2229. CloseMonitorsRestartOrphanJobs( pIniPrinter );
  2230. Cleanup:
  2231. return bReturnValue;
  2232. }
  2233. /*++
  2234. Routine Name:
  2235. AllocResetDevMode
  2236. Routine Description:
  2237. This routine makes a copy of the passed in devmode that can be associated
  2238. to the printer handle in the call to reset printer. The passed in devmode
  2239. can be null in this case the user does not want a devmode, this simplifies
  2240. the caller. This routine also takes care of a few special cases. If
  2241. pDevMode is -1 it returns the printers default devmode. If the printers
  2242. default devmode is null this function will succeed.
  2243. Arguments:
  2244. pIniPrinter - pointer to ini printer structure for the specified printer
  2245. pDevMode, - pointer to devmode to allocation, this is optional
  2246. *ppDevMode - pointer where to return new allocated devmode
  2247. Return Value:
  2248. TRUE success, FALSE an error occurred.
  2249. Last Error:
  2250. ERROR_INVALID_PARAMETER if any of the required parameters are invalid.
  2251. --*/
  2252. BOOL
  2253. AllocResetDevMode(
  2254. IN PINIPRINTER pIniPrinter,
  2255. IN DWORD TypeofHandle,
  2256. IN PDEVMODE pDevMode, OPTIONAL
  2257. OUT PDEVMODE *ppDevMode
  2258. )
  2259. {
  2260. BOOL bRetval = FALSE;
  2261. //
  2262. // Validate the input parameters.
  2263. //
  2264. if (pIniPrinter && ppDevMode)
  2265. {
  2266. //
  2267. // Initalize the out parameter
  2268. //
  2269. *ppDevMode = NULL;
  2270. //
  2271. // If pDevMode == -1 then we want to return the printers default devmode.
  2272. // The -1 token is for internal use, and currently only used by the server
  2273. // service, which does not run in the context of the user, hence we must
  2274. // not use a per user devmode.
  2275. //
  2276. if (pDevMode == (PDEVMODE)-1)
  2277. {
  2278. //
  2279. // If the handle is a 3.x we must convert the devmode.
  2280. //
  2281. if (TypeofHandle & PRINTER_HANDLE_3XCLIENT)
  2282. {
  2283. *ppDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  2284. pDevMode,
  2285. NULL,
  2286. NULL,
  2287. NT3X_VERSION);
  2288. bRetval = !!*ppDevMode;
  2289. }
  2290. else
  2291. {
  2292. //
  2293. // Get the printer's default devmode.
  2294. //
  2295. pDevMode = pIniPrinter->pDevMode;
  2296. }
  2297. }
  2298. //
  2299. // At this point the pDevMode may be either the passed in devmode
  2300. // or the default devmode on the printer. If the devmode on the printer
  2301. // is null then this function will succeed but will not return a devmode.
  2302. //
  2303. if (pDevMode && pDevMode != (PDEVMODE)-1)
  2304. {
  2305. //
  2306. // Make a copy of the passed in devmode, this is less efficient
  2307. // however it simplfies the callers clean up code, less chance for
  2308. // a mistake.
  2309. //
  2310. UINT cbSize = pDevMode->dmSize + pDevMode->dmDriverExtra;
  2311. *ppDevMode = AllocSplMem(cbSize);
  2312. bRetval = !!*ppDevMode;
  2313. if (bRetval)
  2314. {
  2315. //
  2316. // This is OK, YResetPrinter validates that the devmode is of the
  2317. // correct size.
  2318. //
  2319. memcpy(*ppDevMode, pDevMode, cbSize);
  2320. }
  2321. }
  2322. else
  2323. {
  2324. DBGMSG(DBG_TRACE,("LocalResetPrinter: Not resetting the pDevMode field\n"));
  2325. bRetval = TRUE;
  2326. }
  2327. }
  2328. else
  2329. {
  2330. //
  2331. // The function returns a bool, we must set the last error.
  2332. //
  2333. SetLastError(ERROR_INVALID_PARAMETER);
  2334. }
  2335. return bRetval;
  2336. }
  2337. /*++
  2338. Routine Name:
  2339. AllocResetDataType
  2340. Routine Description:
  2341. This routine allocates a new datatype that will be associated with
  2342. a printer handle in ResetPrinter.
  2343. Arguments:
  2344. pIniPrinter - pointer to ini printer structure for the specified printer
  2345. pDatatype - the new data type to validate and allocate
  2346. ppDatatype - where to return the new datatype
  2347. ppIniPrintProc - pointer where to return the associated print processor
  2348. Return Value:
  2349. TRUE function succeeded, FALSE an error occurred, use GetLastError() for
  2350. extended error information.
  2351. Last Error:
  2352. ERROR_INVALID_PARAMETER if a required parameter is invalid.
  2353. ERROR_INVALID_DATATYPE if the specified datatype is invalid.
  2354. --*/
  2355. BOOL
  2356. AllocResetDataType(
  2357. IN PINIPRINTER pIniPrinter,
  2358. IN PCWSTR pDatatype,
  2359. OUT PCWSTR *ppDatatype,
  2360. OUT PINIPRINTPROC *ppIniPrintProc
  2361. )
  2362. {
  2363. BOOL bRetval = FALSE;
  2364. //
  2365. // Validate the input parameters.
  2366. //
  2367. if (pIniPrinter && ppDatatype && ppIniPrintProc)
  2368. {
  2369. //
  2370. // Initalize the out parameters
  2371. //
  2372. *ppDatatype = NULL;
  2373. *ppIniPrintProc = NULL;
  2374. if (pDatatype)
  2375. {
  2376. //
  2377. // If the datatype is -1 we are being requested to
  2378. // return the default datatype for this printer.
  2379. //
  2380. if (pDatatype == (LPWSTR)-1 && pIniPrinter->pDatatype)
  2381. {
  2382. *ppIniPrintProc = FindDatatype(pIniPrinter->pIniPrintProc, pIniPrinter->pDatatype);
  2383. }
  2384. else
  2385. {
  2386. *ppIniPrintProc = FindDatatype(pIniPrinter->pIniPrintProc, (PWSTR)pDatatype);
  2387. }
  2388. //
  2389. // If the print process was found, the datatype is valid,
  2390. // allocate the new datatype.
  2391. //
  2392. if (*ppIniPrintProc)
  2393. {
  2394. *ppDatatype = AllocSplStr(pIniPrinter->pDatatype);
  2395. bRetval = !!*ppDatatype;
  2396. }
  2397. else
  2398. {
  2399. SetLastError(ERROR_INVALID_DATATYPE);
  2400. }
  2401. }
  2402. else
  2403. {
  2404. DBGMSG(DBG_TRACE,("LocalResetPrinter: Not resetting the pDatatype field\n"));
  2405. bRetval = TRUE;
  2406. }
  2407. }
  2408. else
  2409. {
  2410. //
  2411. // The function returns a bool, we must set the last error.
  2412. //
  2413. SetLastError(ERROR_INVALID_PARAMETER);
  2414. }
  2415. return bRetval;
  2416. }
  2417. /*++
  2418. Routine Name:
  2419. SplResetPrinter
  2420. Routine Description:
  2421. The ResetPrinter function lets an application specify the data type
  2422. and device mode values that are used for printing documents submitted
  2423. by the StartDocPrinter function. These values can be overridden by using
  2424. the SetJob function once document printing has started.
  2425. This routine basically has two jobs. To reset the devmode of the
  2426. printer handle and to reset the datatype of the printer handle. Each
  2427. or both operation could be ignored, if the devmode null the devmode
  2428. will not change if the datatye is null the datatype should not change. If
  2429. both operations are requested and any one fails then both operations
  2430. should fail.
  2431. Arguments:
  2432. hPrinter - Valid printer handle
  2433. pDefault - Pointer to a printer defaults structure that has a devmode
  2434. and data type.
  2435. Return Value:
  2436. TRUE function succeeded, FALSE an error occurred, use GetLastError() for
  2437. extended error information.
  2438. Last Error:
  2439. ERROR_INVALID_PARAMETER if the pDefault is NULL,
  2440. ERROR_INVALID_DATATYPE if the new datatype specified is unknown or invalid
  2441. --*/
  2442. BOOL
  2443. SplResetPrinter(
  2444. IN HANDLE hPrinter,
  2445. IN LPPRINTER_DEFAULTS pDefaults
  2446. )
  2447. {
  2448. PSPOOL pSpool = (PSPOOL)hPrinter;
  2449. BOOL bRetval = FALSE;
  2450. PINIPRINTPROC pNewPrintProc = NULL;
  2451. LPWSTR pNewDatatype = NULL;
  2452. PDEVMODE pNewDevMode = NULL;
  2453. DBGMSG(DBG_TRACE, ("ResetPrinter( %08x )\n", hPrinter));
  2454. //
  2455. // Validate the printer handle.
  2456. //
  2457. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER))
  2458. {
  2459. //
  2460. // Validate the pDefaults
  2461. //
  2462. if (pDefaults)
  2463. {
  2464. //
  2465. // Enter the spooler semaphore.
  2466. //
  2467. EnterSplSem();
  2468. //
  2469. // Get the new devmode, a null input devmode indicatest the caller
  2470. // was not interesting in changing the devmode.
  2471. //
  2472. bRetval = AllocResetDevMode(pSpool->pIniPrinter,
  2473. pSpool->TypeofHandle,
  2474. pDefaults->pDevMode,
  2475. &pNewDevMode);
  2476. if (bRetval)
  2477. {
  2478. //
  2479. // Get the new datatype and printprocessor, a null input datatype
  2480. // indicates the caller was not interested in changing the datatype.
  2481. //
  2482. bRetval = AllocResetDataType(pSpool->pIniPrinter,
  2483. pDefaults->pDatatype,
  2484. &pNewDatatype,
  2485. &pNewPrintProc);
  2486. }
  2487. if (bRetval)
  2488. {
  2489. //
  2490. // Release the previous devmode provided we have a new devmode to set
  2491. // a new devmode may not be available in the case the caller did not
  2492. // request a devmode change.
  2493. //
  2494. if (pNewDevMode)
  2495. {
  2496. FreeSplMem(pSpool->pDevMode);
  2497. pSpool->pDevMode = pNewDevMode;
  2498. pNewDevMode = NULL;
  2499. }
  2500. //
  2501. // Release the previous datatype provided we have a new datatype to set
  2502. // a new datatype may not be available in the case the caller did not
  2503. // request a devmode change.
  2504. //
  2505. if (pNewDatatype && pNewPrintProc)
  2506. {
  2507. FreeSplStr(pSpool->pDatatype);
  2508. pSpool->pDatatype = pNewDatatype;
  2509. pNewDatatype = NULL;
  2510. //
  2511. // Release the previous print processor, and assign the new one.
  2512. //
  2513. pSpool->pIniPrintProc->cRef--;
  2514. pSpool->pIniPrintProc = pNewPrintProc;
  2515. pSpool->pIniPrintProc->cRef++;
  2516. pNewPrintProc = NULL;
  2517. }
  2518. }
  2519. //
  2520. // Exit the spooler semaphore.
  2521. //
  2522. LeaveSplSem();
  2523. //
  2524. // Always release any resources, the mem free routines will handle null pointers.
  2525. //
  2526. FreeSplMem(pNewDevMode);
  2527. FreeSplMem(pNewDatatype);
  2528. }
  2529. else
  2530. {
  2531. SetLastError(ERROR_INVALID_PARAMETER);
  2532. }
  2533. }
  2534. return bRetval;
  2535. }
  2536. BOOL
  2537. CopyPrinterIni(
  2538. PINIPRINTER pIniPrinter,
  2539. LPWSTR pNewName
  2540. )
  2541. {
  2542. HKEY hPrinterKey=NULL;
  2543. DWORD Status;
  2544. PWSTR pSourceKeyName = NULL;
  2545. PWSTR pDestKeyName = NULL;
  2546. HANDLE hToken;
  2547. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  2548. BOOL bReturnValue = TRUE;
  2549. SPLASSERT( pIniSpooler != NULL);
  2550. SPLASSERT( pIniSpooler->signature == ISP_SIGNATURE );
  2551. hToken = RevertToPrinterSelf();
  2552. if (!hToken) {
  2553. bReturnValue = FALSE;
  2554. goto error;
  2555. }
  2556. if (!(pSourceKeyName = SubChar(pIniPrinter->pName, L'\\', L','))) {
  2557. bReturnValue = FALSE;
  2558. goto error;
  2559. }
  2560. if (!(pDestKeyName = SubChar(pNewName, L'\\', L','))) {
  2561. bReturnValue = FALSE;
  2562. goto error;
  2563. }
  2564. if( !CopyRegistryKeys( pIniSpooler->hckPrinters,
  2565. pSourceKeyName,
  2566. pIniSpooler->hckPrinters,
  2567. pDestKeyName,
  2568. pIniSpooler )) {
  2569. bReturnValue = FALSE;
  2570. goto error;
  2571. }
  2572. error:
  2573. FreeSplStr(pSourceKeyName);
  2574. FreeSplStr(pDestKeyName);
  2575. if (hToken) {
  2576. if (!ImpersonatePrinterClient(hToken) && bReturnValue)
  2577. {
  2578. bReturnValue = FALSE;
  2579. }
  2580. }
  2581. return bReturnValue;
  2582. }
  2583. VOID
  2584. FixDevModeDeviceName(
  2585. LPWSTR pPrinterName,
  2586. PDEVMODE pDevMode,
  2587. DWORD cbDevMode)
  2588. /*++
  2589. Routine Description:
  2590. Fixes up the dmDeviceName field of the DevMode to be the same
  2591. as the printer name.
  2592. Arguments:
  2593. pPrinterName - Name of the printer (qualified with server for remote)
  2594. pDevMode - DevMode to fix up
  2595. cbDevMode - byte count of devmode.
  2596. Return Value:
  2597. --*/
  2598. {
  2599. DWORD cbDeviceMax;
  2600. DWORD cchDeviceStrLenMax;
  2601. //
  2602. // Compute the maximum length of the device name string
  2603. // this is the min of the structure and allocated space.
  2604. //
  2605. SPLASSERT(cbDevMode && pDevMode);
  2606. if(cbDevMode && pDevMode) {
  2607. cbDeviceMax = ( cbDevMode < sizeof(pDevMode->dmDeviceName)) ?
  2608. cbDevMode :
  2609. sizeof(pDevMode->dmDeviceName);
  2610. SPLASSERT(cbDeviceMax);
  2611. cchDeviceStrLenMax = (cbDeviceMax / sizeof(pDevMode->dmDeviceName[0]));
  2612. StringCchCopy(pDevMode->dmDeviceName, cchDeviceStrLenMax, pPrinterName);
  2613. }
  2614. }
  2615. BOOL
  2616. CopyPrinterDevModeToIniPrinter(
  2617. PINIPRINTER pIniPrinter,
  2618. PDEVMODE pDevMode)
  2619. {
  2620. BOOL bReturn = TRUE;
  2621. DWORD dwInSize = 0;
  2622. DWORD dwCurSize = 0;
  2623. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  2624. WCHAR PrinterName[ MAX_UNC_PRINTER_NAME ];
  2625. if (pDevMode) {
  2626. dwInSize = pDevMode->dmSize + pDevMode->dmDriverExtra;
  2627. if (pIniPrinter->pDevMode) {
  2628. //
  2629. // Detect if the devmodes are identical
  2630. // if they are, no need to copy or send devmode.
  2631. // (Skip the device name though!)
  2632. //
  2633. dwCurSize = pIniPrinter->pDevMode->dmSize
  2634. + pIniPrinter->pDevMode->dmDriverExtra;
  2635. if (dwInSize == dwCurSize) {
  2636. if (dwInSize > sizeof(pDevMode->dmDeviceName)) {
  2637. if (!memcmp(&pDevMode->dmSpecVersion,
  2638. &pIniPrinter->pDevMode->dmSpecVersion,
  2639. dwCurSize - sizeof(pDevMode->dmDeviceName))) {
  2640. //
  2641. // No need to copy this devmode because its identical
  2642. // to what we already have.
  2643. //
  2644. DBGMSG(DBG_TRACE,("Identical DevModes, no update\n"));
  2645. bReturn = FALSE;
  2646. goto FixupName;
  2647. }
  2648. }
  2649. }
  2650. //
  2651. // Free the devmode which we already have.
  2652. //
  2653. FreeSplMem(pIniPrinter->pDevMode);
  2654. }
  2655. pIniPrinter->cbDevMode = pDevMode->dmSize +
  2656. pDevMode->dmDriverExtra;
  2657. SPLASSERT(pIniPrinter->cbDevMode);
  2658. if (pIniPrinter->pDevMode = AllocSplMem(pIniPrinter->cbDevMode)) {
  2659. //
  2660. // OK. This assumes the pIniPrinter's devmode has already been validated.
  2661. //
  2662. memcpy(pIniPrinter->pDevMode, pDevMode, pIniPrinter->cbDevMode);
  2663. //
  2664. // Prepend the machine name if this is not localspl
  2665. //
  2666. if ( pIniSpooler != pLocalIniSpooler ) {
  2667. // For Non Local Printers prepend the Machine Name
  2668. StringCchPrintf(PrinterName, COUNTOF(PrinterName), L"%ws\\%ws", pIniSpooler->pMachineName, pIniPrinter->pName);
  2669. } else {
  2670. StringCchPrintf(PrinterName, COUNTOF(PrinterName), L"%ws", pIniPrinter->pName);
  2671. }
  2672. BroadcastChange(pIniSpooler, WM_DEVMODECHANGE, 0, (LPARAM)PrinterName);
  2673. }
  2674. } else {
  2675. //
  2676. // No old, no new, so no change.
  2677. //
  2678. if (!pIniPrinter->pDevMode)
  2679. return FALSE;
  2680. }
  2681. FixupName:
  2682. if (pIniPrinter->pDevMode) {
  2683. //
  2684. // Fix up the DEVMODE.dmDeviceName field.
  2685. //
  2686. FixDevModeDeviceName(pIniPrinter->pName,
  2687. pIniPrinter->pDevMode,
  2688. pIniPrinter->cbDevMode);
  2689. }
  2690. return bReturn;
  2691. }
  2692. BOOL
  2693. NameAndSecurityCheck(
  2694. LPCWSTR pServer
  2695. )
  2696. {
  2697. PINISPOOLER pIniSpooler;
  2698. BOOL bReturn = TRUE;
  2699. pIniSpooler = FindSpoolerByNameIncRef( (LPWSTR)pServer, NULL );
  2700. if( !pIniSpooler ){
  2701. return ROUTER_UNKNOWN;
  2702. }
  2703. // Check if the call is for the local machine.
  2704. if ( pServer && *pServer ) {
  2705. if ( !MyName((LPWSTR) pServer, pIniSpooler )) {
  2706. bReturn = FALSE;
  2707. goto CleanUp;
  2708. }
  2709. }
  2710. // Check for admin priviledges.
  2711. if ( !ValidateObjectAccess( SPOOLER_OBJECT_SERVER,
  2712. SERVER_ACCESS_ADMINISTER,
  2713. NULL, NULL, pIniSpooler )) {
  2714. bReturn = FALSE;
  2715. }
  2716. CleanUp:
  2717. // The Local case is handled in the router.
  2718. FindSpoolerByNameDecRef( pIniSpooler );
  2719. return bReturn;
  2720. }
  2721. BOOL
  2722. LocalAddPerMachineConnection(
  2723. LPCWSTR pServer,
  2724. LPCWSTR pPrinterName,
  2725. LPCWSTR pPrintServer,
  2726. LPCWSTR pProvider
  2727. )
  2728. {
  2729. return NameAndSecurityCheck(pServer);
  2730. }
  2731. BOOL
  2732. LocalDeletePerMachineConnection(
  2733. LPCWSTR pServer,
  2734. LPCWSTR pPrinterName
  2735. )
  2736. {
  2737. return NameAndSecurityCheck(pServer);
  2738. }
  2739. BOOL
  2740. LocalEnumPerMachineConnections(
  2741. LPCWSTR pServer,
  2742. LPBYTE pPrinterEnum,
  2743. DWORD cbBuf,
  2744. LPDWORD pcbNeeded,
  2745. LPDWORD pcReturned
  2746. )
  2747. {
  2748. SetLastError(ERROR_INVALID_NAME);
  2749. return FALSE;
  2750. }
  2751. BOOL
  2752. UpdatePrinterNetworkName(
  2753. PINIPRINTER pIniPrinter,
  2754. LPWSTR pszPorts
  2755. )
  2756. {
  2757. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  2758. DWORD dwLastError = ERROR_SUCCESS;
  2759. LPWSTR pKeyName = NULL;
  2760. HANDLE hToken;
  2761. BOOL bReturnValue;
  2762. HANDLE hPrinterKey = NULL;
  2763. HANDLE hPrinterHttpDataKey = NULL;
  2764. SplInSem();
  2765. hToken = RevertToPrinterSelf();
  2766. if ( hToken == FALSE ) {
  2767. DBGMSG( DBG_TRACE, ("UpdatePrinterIni failed RevertToPrinterSelf %x\n", GetLastError() ));
  2768. }
  2769. if (!(pKeyName = SubChar(pIniPrinter->pName, L'\\', L','))) {
  2770. dwLastError = GetLastError();
  2771. goto Cleanup;
  2772. }
  2773. if ( !PrinterCreateKey( pIniSpooler->hckPrinters,
  2774. pKeyName,
  2775. &hPrinterKey,
  2776. &dwLastError,
  2777. pIniSpooler )) {
  2778. goto Cleanup;
  2779. }
  2780. if ( !PrinterCreateKey( hPrinterKey,
  2781. L"HttpData",
  2782. &hPrinterHttpDataKey,
  2783. &dwLastError,
  2784. pIniSpooler )) {
  2785. goto Cleanup;
  2786. }
  2787. RegSetString( hPrinterHttpDataKey, L"UIRealNetworkName", pszPorts, &dwLastError, pIniSpooler );
  2788. Cleanup:
  2789. FreeSplStr(pKeyName);
  2790. if ( hPrinterHttpDataKey )
  2791. SplRegCloseKey( hPrinterHttpDataKey, pIniSpooler);
  2792. if ( hPrinterKey )
  2793. SplRegCloseKey( hPrinterKey, pIniSpooler);
  2794. if ( hToken )
  2795. ImpersonatePrinterClient( hToken );
  2796. if ( dwLastError != ERROR_SUCCESS ) {
  2797. SetLastError( dwLastError );
  2798. bReturnValue = FALSE;
  2799. } else {
  2800. bReturnValue = TRUE;
  2801. }
  2802. return bReturnValue;
  2803. }
  2804. DWORD
  2805. KMPrintersAreBlocked(
  2806. )
  2807. {
  2808. return GetSpoolerNumericPolicy(szKMPrintersAreBlocked,
  2809. DefaultKMPrintersAreBlocked);
  2810. }
  2811. PINIPRINTER
  2812. FindPrinterAnywhere(
  2813. LPTSTR pName,
  2814. DWORD SpoolerType
  2815. )
  2816. /*++
  2817. Routine Description:
  2818. Search for a printer name in all pIniSpoolers.
  2819. Arguments:
  2820. pName - Name of printer to search for.
  2821. SpoolerType - Type of spooler the printer should reside in.
  2822. Return Value:
  2823. PINIPRINTER - Found pIniPrinter
  2824. NULL - Not found.
  2825. --*/
  2826. {
  2827. LPCTSTR pszLocalName;
  2828. PINIPRINTER pIniPrinter;
  2829. PINISPOOLER pIniSpooler = FindSpoolerByName( pName,
  2830. &pszLocalName );
  2831. SplInSem();
  2832. if( pIniSpooler &&
  2833. (( pIniPrinter = FindPrinter( pszLocalName, pIniSpooler )) ||
  2834. ( pIniPrinter = FindPrinterShare( pszLocalName, pIniSpooler )))){
  2835. if( pIniPrinter->pIniSpooler->SpoolerFlags & SpoolerType ){
  2836. return pIniPrinter;
  2837. }
  2838. }
  2839. return NULL;
  2840. }
  2841. BOOL
  2842. LocalAddPrinterConnection(
  2843. LPWSTR pName
  2844. )
  2845. {
  2846. //
  2847. // Allow us to make clustered connections to local printers
  2848. // (they appear to be remote).
  2849. //
  2850. BOOL bReturn = FALSE;
  2851. EnterSplSem();
  2852. if( FindPrinterAnywhere( pName, SPL_TYPE_CLUSTER )){
  2853. bReturn = TRUE;
  2854. }
  2855. LeaveSplSem();
  2856. SetLastError(ERROR_INVALID_NAME);
  2857. return bReturn;
  2858. }
  2859. BOOL
  2860. LocalDeletePrinterConnection(
  2861. LPWSTR pName
  2862. )
  2863. {
  2864. //
  2865. // Allow us to remove clustered connections to local printers
  2866. // (they appear to be remote).
  2867. //
  2868. BOOL bReturn = FALSE;
  2869. EnterSplSem();
  2870. if( FindPrinterAnywhere( pName, SPL_TYPE_CLUSTER )){
  2871. bReturn = TRUE;
  2872. }
  2873. LeaveSplSem();
  2874. SetLastError(ERROR_INVALID_NAME);
  2875. return bReturn;
  2876. }