Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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