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.

2263 lines
64 KiB

  1. /*++
  2. Copyright (c) 1990 - 1995 Microsoft Corporation
  3. Module Name:
  4. setprn.c
  5. Abstract:
  6. This module provides all the public exported APIs relating to Printer
  7. management for the Local Print Providor
  8. SplSetPrinter
  9. Author:
  10. Dave Snipp (DaveSn) 15-Mar-1991
  11. Revision History:
  12. Muhunthan Sivapragasam (MuhuntS) 25-Aug-95
  13. -- support for level 4, and PRINTER_CONTROL_SET_STATUS.
  14. -- eliminate duplicate code
  15. Muhunthan Sivapragasam (MuhuntS) 18-Jun-1995 -- PeinterInfo5 changes
  16. Krishna Ganugapati (KrishnaG) 1-Jun-1994 -- rewrote these functions.
  17. SWilson - Added SetPrinter Level 7
  18. --*/
  19. #define NOMINMAX
  20. #include <precomp.h>
  21. #pragma hdrstop
  22. #include "clusspl.h"
  23. #define PRINTER_NO_CONTROL 0x00
  24. typedef enum {
  25. SECURITY_SUCCESS = 0,
  26. SECURITY_NOCHANGE = 1,
  27. SECURITY_FAIL = 2
  28. } PRINTER_SECURITY_STATUS;
  29. PRINTER_SECURITY_STATUS
  30. SetPrinterSecurity(
  31. SECURITY_INFORMATION SecurityInformation,
  32. PINIPRINTER pIniPrinter,
  33. PSECURITY_DESCRIPTOR pSecurityDescriptor
  34. );
  35. VOID
  36. RegClearKey(
  37. HKEY hKey,
  38. PINISPOOLER pIniSpooler
  39. );
  40. DWORD
  41. ValidatePrinterAttributes(
  42. DWORD SourceAttributes,
  43. DWORD OriginalAttributes,
  44. LPWSTR pDatatype,
  45. LPBOOL pbValid,
  46. BOOL bSettableOnly
  47. );
  48. BOOL
  49. ChangePrinterAttributes(
  50. DWORD dNewAttributes,
  51. DWORD dOldAttributes,
  52. PINIPRINTER pIniPrinter,
  53. PINISPOOLER pIniSpooler,
  54. LPWSTR pszNewShareName,
  55. BOOL bShareRecreate,
  56. BOOL bShareUpdate
  57. );
  58. BOOL
  59. NewPort(
  60. PKEYDATA pKeyData,
  61. PINIPRINTER pIniPrinter
  62. );
  63. BOOL
  64. SplSetPrinterExtraEx(
  65. HANDLE hPrinter,
  66. DWORD dwPrivateFlag
  67. )
  68. {
  69. BOOL ReturnValue = FALSE;
  70. PSPOOL pSpool = (PSPOOL)hPrinter;
  71. EnterSplSem();
  72. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  73. pSpool->pIniPrinter->dwPrivateFlag = dwPrivateFlag;
  74. ReturnValue = TRUE;
  75. }
  76. LeaveSplSem();
  77. return ReturnValue;
  78. }
  79. BOOL
  80. SplGetPrinterExtraEx(
  81. HANDLE hPrinter,
  82. LPDWORD pdwPrivateFlag
  83. )
  84. {
  85. BOOL ReturnValue = FALSE;
  86. PSPOOL pSpool = (PSPOOL)hPrinter;
  87. EnterSplSem();
  88. if ((pSpool != NULL) &&
  89. (pSpool != INVALID_HANDLE_VALUE) &&
  90. ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER) &&
  91. pdwPrivateFlag) {
  92. *pdwPrivateFlag = pSpool->pIniPrinter->dwPrivateFlag;
  93. ReturnValue = TRUE;
  94. }
  95. LeaveSplSem();
  96. return ReturnValue;
  97. }
  98. BOOL
  99. SplSetPrinterExtra(
  100. HANDLE hPrinter,
  101. LPBYTE pExtraData
  102. )
  103. {
  104. BOOL ReturnValue;
  105. PSPOOL pSpool = (PSPOOL)hPrinter;
  106. EnterSplSem();
  107. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  108. pSpool->pIniPrinter->pExtraData = pExtraData;
  109. UpdatePrinterIni( pSpool->pIniPrinter , UPDATE_CHANGEID );
  110. ReturnValue = TRUE;
  111. } else {
  112. ReturnValue = FALSE;
  113. }
  114. LeaveSplSem();
  115. return ReturnValue;
  116. }
  117. BOOL
  118. SplGetPrinterExtra(
  119. HANDLE hPrinter,
  120. PBYTE *ppExtraData
  121. )
  122. {
  123. PSPOOL pSpool = (PSPOOL)hPrinter;
  124. BOOL ReturnValue;
  125. if (ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER)) {
  126. *ppExtraData = pSpool->pIniPrinter->pExtraData;
  127. ReturnValue = TRUE;
  128. } else {
  129. ReturnValue = FALSE;
  130. }
  131. return ReturnValue;
  132. }
  133. BOOL
  134. ValidateLevelAndSecurityAccesses(
  135. PSPOOL pSpool,
  136. DWORD Level,
  137. LPBYTE pPrinterInfo,
  138. DWORD Command,
  139. PDWORD pdwAccessRequired,
  140. PDWORD pSecurityInformation
  141. )
  142. {
  143. DWORD AccessRequired = 0;
  144. DWORD SecurityInformation= 0;
  145. PSECURITY_DESCRIPTOR pSecurityDescriptor;
  146. //
  147. // Set pdwAccessRequired = 0 and
  148. // Set pSecurityInformation = 0;
  149. *pdwAccessRequired = 0;
  150. *pSecurityInformation = 0;
  151. switch (Level) {
  152. case 0:
  153. case 4:
  154. case 5:
  155. case 6:
  156. case 7:
  157. AccessRequired = PRINTER_ACCESS_ADMINISTER;
  158. break;
  159. case 2:
  160. pSecurityDescriptor =
  161. ((PPRINTER_INFO_2)pPrinterInfo)->pSecurityDescriptor;
  162. AccessRequired = PRINTER_ACCESS_ADMINISTER;
  163. if (GetSecurityInformation(pSecurityDescriptor,
  164. &SecurityInformation)) {
  165. AccessRequired |= GetPrivilegeRequired( SecurityInformation );
  166. } else {
  167. //
  168. // Bug 54918 - We should be returning the false on GetSecurityInformation
  169. // failing. The reason we're not doing it is because this will break
  170. // Printman. Printman should pass in Valid security descriptors for Level 2
  171. // Fix in Printman KrishnaG 6/17
  172. //
  173. // LastError = GetLastError();
  174. // return FALSE;
  175. }
  176. break;
  177. case 3:
  178. pSecurityDescriptor =
  179. ((PPRINTER_INFO_3)pPrinterInfo)->pSecurityDescriptor;
  180. if (!pSecurityDescriptor) {
  181. SetLastError( ERROR_INVALID_PARAMETER );
  182. return FALSE;
  183. }
  184. if (GetSecurityInformation(pSecurityDescriptor,
  185. &SecurityInformation)) {
  186. AccessRequired |= GetPrivilegeRequired( SecurityInformation );
  187. } else {
  188. // LastError = GetLastError();
  189. return FALSE;
  190. }
  191. break;
  192. default:
  193. SetLastError(ERROR_INVALID_LEVEL);
  194. return FALSE;
  195. }
  196. if (!AccessGranted(SPOOLER_OBJECT_PRINTER,
  197. AccessRequired,
  198. pSpool) ) {
  199. SetLastError(ERROR_ACCESS_DENIED);
  200. return FALSE;
  201. }
  202. *pdwAccessRequired = AccessRequired;
  203. *pSecurityInformation = SecurityInformation;
  204. return TRUE;
  205. }
  206. PKEYDATA
  207. CreateAndValidatePortTokenList(
  208. LPWSTR pPortName,
  209. PINISPOOLER pIniSpooler
  210. )
  211. {
  212. PKEYDATA pKeyData = CreateTokenList(pPortName);
  213. if ( pKeyData ) {
  214. if ( !ValidatePortTokenList(pKeyData, pIniSpooler, FALSE, NULL) ) {
  215. FreePortTokenList(pKeyData);
  216. SetLastError(ERROR_UNKNOWN_PORT);
  217. pKeyData = NULL;
  218. }
  219. }
  220. return pKeyData;
  221. }
  222. BOOL
  223. NewPort(
  224. PKEYDATA pKeyData,
  225. PINIPRINTER pIniPrinter
  226. )
  227. {
  228. DWORD i, j;
  229. BOOL rc=TRUE;
  230. if (!pKeyData) {
  231. SetLastError(ERROR_UNKNOWN_PORT);
  232. return FALSE;
  233. }
  234. // Check if # of requested vs. existing ports differs
  235. if (pIniPrinter->cPorts != pKeyData->cTokens)
  236. return TRUE;
  237. // for each requested port see if printer already has it
  238. for (i = 0 ; i < pKeyData->cTokens ; ++i) {
  239. // see if requested port is already assigned to printer
  240. for (j = 0 ; j < pIniPrinter->cPorts &&
  241. wcscmp(pIniPrinter->ppIniPorts[j]->pName, ((PINIPORT)pKeyData->pTokens[i])->pName)
  242. ; ++j) {
  243. DBGMSG(DBG_TRACE,("NewPort (Existing vs. Requested): \"%ws\" ?= \"%ws\"\n",
  244. pIniPrinter->ppIniPorts[j]->pName, ((PINIPORT)pKeyData->pTokens[i])->pName));
  245. }
  246. if (j == pIniPrinter->cPorts) { // found new port, so return
  247. DBGMSG(DBG_TRACE,("NewPort FOUND: \"%ws\"\n", ((PINIPORT)pKeyData->pTokens[i])->pName));
  248. return TRUE;
  249. }
  250. }
  251. return FALSE;
  252. }
  253. VOID
  254. ChangePrinterName(
  255. LPWSTR pszNewName,
  256. PINIPRINTER pIniPrinter,
  257. PINISPOOLER pIniSpooler,
  258. LPDWORD pdwPrinterVector
  259. )
  260. /*++
  261. Routine Description:
  262. Changes printer name
  263. Arguments:
  264. pszNewName - New printer name allocated using AllocSplStr
  265. pIniPrinter - for the printer we changing name
  266. pIniSpooler - Spooler that owns printer
  267. pdwPrinterVector - pointer to notification vector
  268. Return Value:
  269. nothing
  270. History:
  271. MuhuntS (Muhunthan Sivapragasam) July 95
  272. --*/
  273. {
  274. LPWSTR pNewName, pOldName;
  275. //
  276. // Before deleting the printer entry make sure you copy
  277. // all information with respect to the printer to the registry
  278. // There could be several levels of keys.
  279. //
  280. CopyPrinterIni(pIniPrinter, pszNewName);
  281. DeletePrinterIni(pIniPrinter);
  282. pOldName = pIniPrinter->pName;
  283. pIniPrinter->pName = pszNewName;
  284. *pdwPrinterVector |= BIT(I_PRINTER_PRINTER_NAME);
  285. //
  286. // Delete the old entries in WIN.INI:
  287. //
  288. CheckAndUpdatePrinterRegAll(pIniSpooler,
  289. pOldName,
  290. NULL,
  291. UPDATE_REG_DELETE );
  292. FreeSplStr(pOldName);
  293. //
  294. // If printer is offline we need to write that info back with new name
  295. //
  296. if ( pIniPrinter->Attributes & PRINTER_ATTRIBUTE_WORK_OFFLINE )
  297. WritePrinterOnlineStatusInCurrentConfig(pIniPrinter);
  298. }
  299. BOOL
  300. SetLocalPrinterSTRESS(
  301. PINIPRINTER pIniPrinter,
  302. PPRINTER_INFO_STRESS pPrinterSTRESS
  303. )
  304. {
  305. if ( !pPrinterSTRESS ) {
  306. SetLastError(ERROR_INVALID_PARAMETER);
  307. return FALSE;
  308. }
  309. //
  310. // Allow the caller to update the counters.
  311. //
  312. pIniPrinter->cTotalJobs = pPrinterSTRESS->cTotalJobs;
  313. pIniPrinter->cTotalBytes.LowPart = pPrinterSTRESS->cTotalBytes;
  314. pIniPrinter->cTotalBytes.HighPart = pPrinterSTRESS->dwHighPartTotalBytes;
  315. pIniPrinter->MaxcRef = pPrinterSTRESS->MaxcRef;
  316. pIniPrinter->cTotalPagesPrinted = pPrinterSTRESS->cTotalPagesPrinted;
  317. pIniPrinter->cMaxSpooling = pPrinterSTRESS->cMaxSpooling;
  318. pIniPrinter->cErrorOutOfPaper = pPrinterSTRESS->cErrorOutOfPaper;
  319. pIniPrinter->cErrorNotReady = pPrinterSTRESS->cErrorNotReady;
  320. pIniPrinter->cJobError = pPrinterSTRESS->cJobError;
  321. pIniPrinter->dwLastError = pPrinterSTRESS->dwLastError;
  322. pIniPrinter->stUpTime = pPrinterSTRESS->stUpTime;
  323. pIniPrinter->pIniSpooler->cEnumerateNetworkPrinters =
  324. pPrinterSTRESS->cEnumerateNetworkPrinters;
  325. pIniPrinter->pIniSpooler->cAddNetPrinters =
  326. pPrinterSTRESS->cAddNetPrinters;
  327. UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
  328. return TRUE;
  329. }
  330. BOOL
  331. SetPrinterStatus(
  332. PINIPRINTER pIniPrinter,
  333. DWORD Status
  334. )
  335. {
  336. DWORD OldStatus = pIniPrinter->Status;
  337. pIniPrinter->Status &= PRINTER_STATUS_PRIVATE;
  338. pIniPrinter->Status |= MapPrinterStatus(MAP_SETTABLE, Status);
  339. if ( PrinterStatusBad(OldStatus) &&
  340. !PrinterStatusBad(pIniPrinter->Status) ) {
  341. CHECK_SCHEDULER();
  342. }
  343. SetPrinterChange(pIniPrinter,
  344. NULL,
  345. NVPrinterStatus,
  346. PRINTER_CHANGE_SET_PRINTER,
  347. pIniPrinter->pIniSpooler);
  348. return TRUE;
  349. }
  350. BOOL
  351. SetLocalPrinter0(
  352. PINIPRINTER pIniPrinter,
  353. DWORD Command
  354. )
  355. {
  356. DWORD Change = PRINTER_CHANGE_SET_PRINTER;
  357. BOOL bReturn = TRUE;
  358. INCPRINTERREF( pIniPrinter );
  359. switch (Command) {
  360. case PRINTER_CONTROL_PURGE:
  361. //
  362. // PurgePrinter always returns TRUE now, still ..
  363. //
  364. if ( PurgePrinter(pIniPrinter) ) {
  365. SplLogEvent(pIniPrinter->pIniSpooler,
  366. LOG_WARNING,
  367. MSG_PRINTER_PURGED,
  368. TRUE,
  369. pIniPrinter->pName,
  370. NULL );
  371. Change |= PRINTER_CHANGE_DELETE_JOB;
  372. } else {
  373. bReturn = FALSE;
  374. }
  375. break;
  376. case PRINTER_CONTROL_RESUME:
  377. pIniPrinter->Status &= ~PRINTER_PAUSED;
  378. CHECK_SCHEDULER();
  379. UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
  380. SplLogEvent(pIniPrinter->pIniSpooler,
  381. LOG_WARNING,
  382. MSG_PRINTER_UNPAUSED,
  383. TRUE,
  384. pIniPrinter->pName,
  385. NULL );
  386. //
  387. // WMI Trace Events.
  388. //
  389. {
  390. // Wmi only knows about jobs, so each job needs to be resumed
  391. // separately.
  392. PINIJOB pIniJob = pIniPrinter->pIniFirstJob;
  393. while (pIniJob)
  394. {
  395. if ( !((pIniJob->Status & JOB_DESPOOLING) ||
  396. (pIniJob->Status & JOB_PRINTING) ||
  397. (pIniJob->Status & JOB_PRINTED) ||
  398. (pIniJob->Status & JOB_ABANDON)) )
  399. {
  400. LogWmiTraceEvent(pIniJob->JobId,
  401. EVENT_TRACE_TYPE_SPL_RESUME, NULL);
  402. }
  403. pIniJob = pIniJob->pIniNextJob;
  404. }
  405. }
  406. break;
  407. case PRINTER_CONTROL_PAUSE:
  408. pIniPrinter->Status |= PRINTER_PAUSED;
  409. UpdatePrinterIni( pIniPrinter, KEEP_CHANGEID );
  410. SplLogEvent(pIniPrinter->pIniSpooler,
  411. LOG_WARNING,
  412. MSG_PRINTER_PAUSED,
  413. TRUE,
  414. pIniPrinter->pName,
  415. NULL);
  416. //
  417. // WMI Trace Events
  418. //
  419. {
  420. //
  421. // Wmi only knows about jobs, so each job needs to be paused
  422. // separately.
  423. //
  424. PINIJOB pIniJob = pIniPrinter->pIniFirstJob;
  425. while (pIniJob)
  426. {
  427. //
  428. // HANDLE PRINTING DIRECT ???
  429. // I don't believe pausing a printer can stop a job already
  430. // being sent to the printer.
  431. //
  432. if ( !((pIniJob->Status & JOB_DESPOOLING) ||
  433. (pIniJob->Status & JOB_PRINTING) ||
  434. (pIniJob->Status & JOB_PRINTED) ||
  435. (pIniJob->Status & JOB_ABANDON)) )
  436. {
  437. LogWmiTraceEvent(pIniJob->JobId,
  438. EVENT_TRACE_TYPE_SPL_PAUSE,
  439. NULL);
  440. }
  441. pIniJob = pIniJob->pIniNextJob;
  442. }
  443. }
  444. break;
  445. default:
  446. SetLastError(ERROR_INVALID_PRINTER_COMMAND);
  447. bReturn = FALSE;
  448. break;
  449. }
  450. DECPRINTERREF( pIniPrinter );
  451. if (bReturn) {
  452. SetPrinterChange(pIniPrinter,
  453. NULL,
  454. (Command == PRINTER_CONTROL_PURGE) ? NVPurge
  455. : NVPrinterStatus,
  456. Change,
  457. pIniPrinter->pIniSpooler);
  458. }
  459. return bReturn;
  460. }
  461. BOOL
  462. ValidateSetPrinter2(
  463. PINIPRINTER pIniPrinter,
  464. PINIPRINTER pTempIniPrinter,
  465. PPRINTER_INFO_2 pPrinterInfo2
  466. )
  467. /*++
  468. Routine Description:
  469. Validates and builds request info about a SetPrinter info call for
  470. Printer information that could be changed only for level2.
  471. Arguments:
  472. pIniPrinter - PINIPRINTER of the printer handle passed in
  473. pTempIniPrinter - this structure is used to gather info about all
  474. parameters being changed
  475. pPrinterInfo2 - the PrinterInfo2 structure being passed in
  476. Return Value:
  477. TRUE: If all the validation is succesful
  478. FALSE: If validation of one or more request fails
  479. On succesful return fields which need to be changed will be set in
  480. pTempIniPrinter. Cleanup of this structure will be done later.
  481. History:
  482. MuhuntS (Muhunthan Sivapragasam) Aug 95
  483. --*/
  484. {
  485. BOOL bFail = FALSE;
  486. DWORD LastError = ERROR_SUCCESS;
  487. PINIVERSION pIniVersion = NULL;
  488. PINIENVIRONMENT pIniEnvironment = NULL;
  489. BOOL bSuccess = FALSE;
  490. // Servername can't change
  491. // Printername handled for level 2, 4, 5
  492. // Sharenname length validation
  493. if ( pPrinterInfo2->pShareName && wcslen(pPrinterInfo2->pShareName) > PATHLEN-1 ){
  494. bFail = TRUE;
  495. LastError = ERROR_INVALID_PARAMETER;
  496. }
  497. // Share Name (validation later if required)
  498. AllocOrUpdateString(&pTempIniPrinter->pShareName,
  499. pPrinterInfo2->pShareName,
  500. pIniPrinter->pShareName,
  501. TRUE,
  502. &bFail);
  503. if ( bFail )
  504. goto Cleanup;
  505. // Port Name for level 2, 5
  506. // DriverName
  507. bSuccess = FindLocalDriverAndVersion(pIniPrinter->pIniSpooler,
  508. pPrinterInfo2->pDriverName,
  509. &pTempIniPrinter->pIniDriver,
  510. &pIniVersion);
  511. if ( !bSuccess ) {
  512. LastError = ERROR_UNKNOWN_PRINTER_DRIVER;
  513. goto Cleanup;
  514. }
  515. pIniEnvironment = GetLocalArchEnv(pIniPrinter->pIniSpooler);
  516. //
  517. // If we have a queue with a KMPD, then we need to let the user manage it,
  518. // even if the policy for blocking KMPD is enabled. However, if the caller
  519. // wants to change the printer driver to a KMPD, then we do not allow that
  520. //
  521. if (pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver)
  522. {
  523. INCDRIVERREF(pTempIniPrinter->pIniDriver);
  524. if (KMPrintersAreBlocked() &&
  525. IniDriverIsKMPD(pIniPrinter->pIniSpooler,
  526. pIniEnvironment,
  527. pIniVersion,
  528. pTempIniPrinter->pIniDriver)) {
  529. SplLogEvent( pIniPrinter->pIniSpooler,
  530. LOG_ERROR,
  531. MSG_KM_PRINTERS_BLOCKED,
  532. TRUE,
  533. pIniPrinter->pName,
  534. NULL );
  535. LastError = ERROR_KM_DRIVER_BLOCKED;
  536. goto Cleanup;
  537. }
  538. }
  539. // Comment length validation
  540. if ( pPrinterInfo2->pComment && wcslen(pPrinterInfo2->pComment) > PATHLEN-1 ){
  541. bFail = TRUE;
  542. LastError = ERROR_INVALID_PARAMETER;
  543. }
  544. // Comment
  545. AllocOrUpdateString(&pTempIniPrinter->pComment,
  546. pPrinterInfo2->pComment,
  547. pIniPrinter->pComment,
  548. TRUE,
  549. &bFail);
  550. // Location length validation
  551. if ( pPrinterInfo2->pLocation && wcslen(pPrinterInfo2->pLocation) > MAX_PATH-1 ){
  552. bFail = TRUE;
  553. LastError = ERROR_INVALID_PARAMETER;
  554. }
  555. // Location
  556. AllocOrUpdateString(&pTempIniPrinter->pLocation,
  557. pPrinterInfo2->pLocation,
  558. pIniPrinter->pLocation,
  559. TRUE,
  560. &bFail);
  561. // DevMode at the end
  562. // SepFile length validation
  563. if( !CheckSepFile( pPrinterInfo2->pSepFile )) {
  564. bFail = TRUE;
  565. LastError = ERROR_INVALID_SEPARATOR_FILE;
  566. }
  567. // SepFile
  568. AllocOrUpdateString(&pTempIniPrinter->pSepFile,
  569. pPrinterInfo2->pSepFile,
  570. pIniPrinter->pSepFile,
  571. TRUE,
  572. &bFail);
  573. if ( bFail )
  574. goto Cleanup;
  575. if ( pIniPrinter->pSepFile != pTempIniPrinter->pSepFile &&
  576. !CheckSepFile(pPrinterInfo2->pSepFile) ) {
  577. LastError = ERROR_INVALID_SEPARATOR_FILE;
  578. goto Cleanup;
  579. }
  580. // Print Processor
  581. pTempIniPrinter->pIniPrintProc = FindPrintProc(
  582. pPrinterInfo2->pPrintProcessor,
  583. pIniEnvironment );
  584. if ( !pTempIniPrinter->pIniPrintProc ) {
  585. LastError = ERROR_UNKNOWN_PRINTPROCESSOR;
  586. goto Cleanup;
  587. }
  588. if ( pTempIniPrinter->pIniPrintProc != pIniPrinter->pIniPrintProc )
  589. pTempIniPrinter->pIniPrintProc->cRef++;
  590. // Datatype
  591. if ( !pPrinterInfo2->pDatatype || wcslen(pPrinterInfo2->pDatatype) > MAX_PATH-1) {
  592. LastError = ERROR_INVALID_DATATYPE;
  593. goto Cleanup; // Ok to fail ???
  594. } else {
  595. AllocOrUpdateString(&pTempIniPrinter->pDatatype,
  596. pPrinterInfo2->pDatatype,
  597. pIniPrinter->pDatatype,
  598. TRUE,
  599. &bFail);
  600. }
  601. // Parameters length validation
  602. if (pPrinterInfo2->pParameters && wcslen(pPrinterInfo2->pParameters) > MAX_PATH-1){
  603. bFail = TRUE;
  604. LastError = ERROR_INVALID_PARAMETER;
  605. }
  606. // Parameters
  607. AllocOrUpdateString(&pTempIniPrinter->pParameters,
  608. pPrinterInfo2->pParameters,
  609. pIniPrinter->pParameters,
  610. TRUE,
  611. &bFail);
  612. if ( bFail )
  613. goto Cleanup;
  614. // SecurityDescriptor for level 2, 3
  615. // Attributes for level 2, 4, 5
  616. // Priority
  617. pTempIniPrinter->Priority = pPrinterInfo2->Priority;
  618. if ( pTempIniPrinter->Priority != pIniPrinter->Priority &&
  619. pTempIniPrinter->Priority != NO_PRIORITY &&
  620. ( pTempIniPrinter->Priority > MAX_PRIORITY ||
  621. pTempIniPrinter->Priority < MIN_PRIORITY ) ) {
  622. LastError = ERROR_INVALID_PRIORITY;
  623. goto Cleanup;
  624. }
  625. // Default Priority
  626. pTempIniPrinter->DefaultPriority = pPrinterInfo2->DefaultPriority;
  627. if ( pTempIniPrinter->DefaultPriority != pIniPrinter->DefaultPriority &&
  628. pTempIniPrinter->DefaultPriority != NO_PRIORITY &&
  629. ( pTempIniPrinter->DefaultPriority > MAX_PRIORITY ||
  630. pTempIniPrinter->DefaultPriority < MIN_PRIORITY ) ) {
  631. LastError = ERROR_INVALID_PRIORITY;
  632. goto Cleanup;
  633. }
  634. // Start time
  635. pTempIniPrinter->StartTime = pPrinterInfo2->StartTime;
  636. if ( pTempIniPrinter->StartTime != pIniPrinter->StartTime &&
  637. pTempIniPrinter->StartTime >= ONEDAY ) {
  638. LastError = ERROR_INVALID_TIME;
  639. goto Cleanup;
  640. }
  641. // Until time
  642. pTempIniPrinter->UntilTime = pPrinterInfo2->UntilTime;
  643. if ( pTempIniPrinter->UntilTime != pIniPrinter->UntilTime &&
  644. pTempIniPrinter->StartTime >= ONEDAY ) {
  645. LastError = ERROR_INVALID_TIME;
  646. goto Cleanup;
  647. }
  648. // Status for level 0, 2
  649. // Status can't chg
  650. // AveragePPM can't chg
  651. Cleanup:
  652. if ( LastError ) {
  653. SetLastError(LastError);
  654. return FALSE;
  655. }
  656. if ( bFail )
  657. return FALSE;
  658. return TRUE;
  659. }
  660. VOID
  661. ProcessSetPrinter2(
  662. PINIPRINTER pIniPrinter,
  663. PINIPRINTER pTempIniPrinter,
  664. PPRINTER_INFO_2 pPrinterInfo2,
  665. LPDWORD pdwPrinterVector,
  666. PDEVMODE pDevMode
  667. )
  668. /*++
  669. Routine Description:
  670. Process SetPrinter for level 2. Only fields which can be changed ONLY
  671. by level 2 will be processed here. That is: All the fields built by
  672. ValidateSetPrinter2.
  673. Arguments:
  674. pIniPrinter - PINIPRINTER of the printer handle passed in
  675. pTempIniPrinter - this structure is has all the fields which needs to
  676. be set. Other fields will be the same as the previous
  677. pPrinterInfo2 - the PrinterInfo2 structure being passed in
  678. pdwPrinterVector - Notification Info
  679. pDevMode - New dev mode to be set
  680. Return Value:
  681. nothing
  682. History:
  683. MuhuntS (Muhunthan Sivapragasam) Aug 95
  684. --*/
  685. {
  686. HANDLE hToken;
  687. PINISPOOLER pIniSpooler = pIniPrinter->pIniSpooler;
  688. HKEY hKey = NULL;
  689. DWORD dwResult;
  690. // Sharename
  691. if ( pTempIniPrinter->pShareName != pIniPrinter->pShareName ) {
  692. FreeSplStr(pIniPrinter->pShareName);
  693. pIniPrinter->pShareName = pTempIniPrinter->pShareName;
  694. *pdwPrinterVector |= BIT(I_PRINTER_SHARE_NAME);
  695. }
  696. // Driver
  697. if ( pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver ) {
  698. DECDRIVERREF(pIniPrinter->pIniDriver);
  699. if (pIniPrinter->pIniSpooler->SpoolerFlags & SPL_PRINTER_DRIVER_EVENT)
  700. {
  701. hToken = RevertToPrinterSelf();
  702. dwResult = OpenPrinterKey(pIniPrinter, KEY_READ | KEY_WRITE, &hKey, szPrinterData, TRUE);
  703. if (dwResult == ERROR_SUCCESS) {
  704. DeleteSubkeys( hKey, pIniSpooler );
  705. RegClearKey( hKey, pIniSpooler );
  706. SplRegCloseKey(hKey, pIniPrinter->pIniSpooler);
  707. }
  708. if (hToken)
  709. ImpersonatePrinterClient(hToken);
  710. }
  711. pIniPrinter->pIniDriver = pTempIniPrinter->pIniDriver;
  712. *pdwPrinterVector |= BIT(I_PRINTER_DRIVER_NAME);
  713. }
  714. // Comment
  715. if ( pTempIniPrinter->pComment != pIniPrinter->pComment ) {
  716. FreeSplStr(pIniPrinter->pComment);
  717. pIniPrinter->pComment = pTempIniPrinter->pComment;
  718. *pdwPrinterVector |= BIT(I_PRINTER_COMMENT);
  719. }
  720. // Location
  721. if ( pTempIniPrinter->pLocation != pIniPrinter->pLocation ) {
  722. FreeSplStr(pIniPrinter->pLocation);
  723. pIniPrinter->pLocation = pTempIniPrinter->pLocation;
  724. *pdwPrinterVector |= BIT(I_PRINTER_LOCATION);
  725. }
  726. // DevMode at the end
  727. if ( CopyPrinterDevModeToIniPrinter(pIniPrinter,
  728. pDevMode) ) {
  729. *pdwPrinterVector |= BIT(I_PRINTER_DEVMODE);
  730. }
  731. // SepFile
  732. if ( pTempIniPrinter->pSepFile != pIniPrinter->pSepFile ) {
  733. FreeSplStr(pIniPrinter->pSepFile);
  734. pIniPrinter->pSepFile = pTempIniPrinter->pSepFile;
  735. *pdwPrinterVector |= BIT(I_PRINTER_SEPFILE);
  736. }
  737. // PrintProcessor
  738. if ( pIniPrinter->pIniPrintProc != pTempIniPrinter->pIniPrintProc) {
  739. pIniPrinter->pIniPrintProc->cRef--;
  740. pIniPrinter->pIniPrintProc = pTempIniPrinter->pIniPrintProc;
  741. *pdwPrinterVector |= BIT(I_PRINTER_PRINT_PROCESSOR);
  742. }
  743. // Datatype
  744. if ( pIniPrinter->pDatatype != pTempIniPrinter->pDatatype ) {
  745. FreeSplStr(pIniPrinter->pDatatype);
  746. pIniPrinter->pDatatype = pTempIniPrinter->pDatatype;
  747. *pdwPrinterVector |= BIT(I_PRINTER_DATATYPE);
  748. }
  749. // Parameters
  750. if ( pIniPrinter->pParameters != pTempIniPrinter->pParameters ) {
  751. FreeSplStr(pIniPrinter->pParameters);
  752. pIniPrinter->pParameters = pTempIniPrinter->pParameters;
  753. *pdwPrinterVector |= BIT(I_PRINTER_PARAMETERS);
  754. }
  755. // Priority
  756. if ( pTempIniPrinter->Priority != pIniPrinter->Priority ) {
  757. pIniPrinter->Priority = pTempIniPrinter->Priority;
  758. *pdwPrinterVector |= BIT(I_PRINTER_PRIORITY);
  759. }
  760. // Default Priority
  761. if ( pTempIniPrinter->DefaultPriority != pIniPrinter->DefaultPriority ) {
  762. pIniPrinter->DefaultPriority = pTempIniPrinter->DefaultPriority;
  763. *pdwPrinterVector |= BIT(I_PRINTER_DEFAULT_PRIORITY);
  764. }
  765. // Start time
  766. if ( pTempIniPrinter->StartTime != pIniPrinter->StartTime ) {
  767. pIniPrinter->StartTime = pTempIniPrinter->StartTime;
  768. *pdwPrinterVector |= BIT(I_PRINTER_START_TIME);
  769. }
  770. // Until time
  771. if ( pTempIniPrinter->UntilTime != pIniPrinter->UntilTime ) {
  772. pIniPrinter->UntilTime = pTempIniPrinter->UntilTime;
  773. *pdwPrinterVector |= BIT(I_PRINTER_UNTIL_TIME);
  774. }
  775. }
  776. VOID
  777. CleanupSetPrinter(
  778. PINIPRINTER pIniPrinter,
  779. PINIPRINTER pTempIniPrinter,
  780. PKEYDATA pKeyData,
  781. DWORD Level,
  782. BOOL bReturnValue
  783. )
  784. /*++
  785. Routine Description:
  786. This routine is called at the end of SplSetPrinter call to free up all
  787. the allocations done to process it which are not needed.
  788. At the beginning of a SetPrinter we make an identical copy of the
  789. pIniPrinter in pTempIniPrinter and collect all arguments in there.
  790. Now if the call is failing each of the arguments collected in there
  791. need to be freed.
  792. Arguments:
  793. pIniPrinter - PINIPRINTER of the printer handle passed in
  794. pTempIniPrinter - this structure is has all the fields which needs to
  795. be freed. Any field different than pIniPrinter was
  796. built part of processing the call and needs to be freed.
  797. pPrinterInfo2 - built for port info
  798. bReturnValue - return value of SetPrinter
  799. Return Value:
  800. nothing
  801. History:
  802. MuhuntS (Muhunthan Sivapragasam) Aug 95
  803. --*/
  804. {
  805. //
  806. // We adjust INIPORT, INIDRIVER refcounts. So should be inside the spl sem
  807. //
  808. SplInSem();
  809. FreePortTokenList(pKeyData);
  810. if ( pTempIniPrinter ) {
  811. if ( !bReturnValue && Level == 2 ) {
  812. if ( pTempIniPrinter->pShareName != pIniPrinter->pShareName )
  813. FreeSplStr(pTempIniPrinter->pShareName);
  814. if ( pTempIniPrinter->pComment != pIniPrinter->pComment )
  815. FreeSplStr(pTempIniPrinter->pComment);
  816. if ( pTempIniPrinter->pLocation != pIniPrinter->pLocation )
  817. FreeSplStr(pTempIniPrinter->pLocation);
  818. if ( pTempIniPrinter->pSepFile != pIniPrinter->pSepFile )
  819. FreeSplStr(pTempIniPrinter->pSepFile);
  820. if ( pTempIniPrinter->pDatatype != pIniPrinter->pDatatype )
  821. FreeSplStr(pTempIniPrinter->pDatatype);
  822. if ( pTempIniPrinter->pParameters != pIniPrinter->pParameters )
  823. FreeSplStr(pTempIniPrinter->pParameters);
  824. if ( ( pTempIniPrinter->pIniDriver != NULL ) &&
  825. ( pTempIniPrinter->pIniDriver != pIniPrinter->pIniDriver )) {
  826. DECDRIVERREF(pTempIniPrinter->pIniDriver);
  827. }
  828. if ( ( pTempIniPrinter->pIniPrintProc != NULL ) &&
  829. ( pTempIniPrinter->pIniPrintProc != pIniPrinter->pIniPrintProc )) {
  830. pTempIniPrinter->pIniPrintProc->cRef--;
  831. }
  832. }
  833. FreeSplMem(pTempIniPrinter);
  834. }
  835. }
  836. BOOL
  837. ValidateAndBuildSetPrinterRequest(
  838. PINIPRINTER pIniPrinter,
  839. PINIPRINTER pTempIniPrinter,
  840. LPBYTE pPrinterInfo,
  841. DWORD Level,
  842. SECURITY_INFORMATION SecurityInformation,
  843. LPBOOL pbSecurityChg,
  844. LPBOOL pbNameChg,
  845. LPBOOL pbAttributeChg,
  846. LPWSTR *ppszNewPrinterName,
  847. PKEYDATA *ppKeyData
  848. )
  849. /*++
  850. Routine Description:
  851. This routine is called to validate a SetPrinter request. We try to as
  852. much vaidation as possible at the beginning to see the changes are
  853. possible. The routine will collect all changes requested in the
  854. pTempIniPrinter structure.
  855. Arguments:
  856. pIniPrinter - PINIPRINTER of the printer handle passed in
  857. pTempIniPrinter - this structure will be used to collect all the
  858. changes requested
  859. pPrinterInfo - PrinterInfo_N structure passed in
  860. Level - Level of PrinterInfo_N
  861. SecurityInformation - security information
  862. pbSecurityChg - this will be set if a security change is requested
  863. pbNameChg - this will be set if a name change is requested
  864. pbAttributeChg - this will be set if a attribute change is requested
  865. ppszNewPrinterName - *ppszNewPrinterName will give the new printer name
  866. to be set on a name change
  867. ppKeyData - *ppKeyData will give the Port token info for a level 2 or 5
  868. call
  869. Return Value:
  870. TRUE - if all the validations succeed
  871. FALSE - a validation fails
  872. History:
  873. MuhuntS (Muhunthan Sivapragasam) Aug 95
  874. --*/
  875. {
  876. PPRINTER_INFO_2 pPrinterInfo2 = (PPRINTER_INFO_2)pPrinterInfo;
  877. PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)pPrinterInfo;
  878. PPRINTER_INFO_4 pPrinterInfo4 = (PPRINTER_INFO_4)pPrinterInfo;
  879. PPRINTER_INFO_5 pPrinterInfo5 = (PPRINTER_INFO_5)pPrinterInfo;
  880. LPWSTR pPortName;
  881. DWORD dwLastError;
  882. BOOL bValid = TRUE;
  883. switch (Level) {
  884. case 2:
  885. pTempIniPrinter->pSecurityDescriptor =
  886. pPrinterInfo2->pSecurityDescriptor;
  887. if ( !ValidateSetPrinter2(pIniPrinter, pTempIniPrinter, pPrinterInfo2) )
  888. return FALSE;
  889. pTempIniPrinter->pName = pPrinterInfo2->pPrinterName;
  890. pPortName = pPrinterInfo2->pPortName;
  891. if ( !pTempIniPrinter->pIniDriver->pIniLangMonitor )
  892. pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
  893. if ( pIniPrinter->pIniDriver != pTempIniPrinter->pIniDriver ) {
  894. pPrinterInfo2->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
  895. if ( pTempIniPrinter->pIniDriver->pIniLangMonitor )
  896. pPrinterInfo2->Attributes |= PRINTER_ATTRIBUTE_ENABLE_BIDI;
  897. }
  898. pTempIniPrinter->Attributes =
  899. ValidatePrinterAttributes(pPrinterInfo2->Attributes,
  900. pIniPrinter->Attributes,
  901. pPrinterInfo2->pDatatype,
  902. &bValid,
  903. TRUE);
  904. if (!bValid) {
  905. return FALSE;
  906. }
  907. *pbAttributeChg = pTempIniPrinter->Attributes != pIniPrinter->Attributes;
  908. break;
  909. case 3:
  910. pTempIniPrinter->pSecurityDescriptor = pPrinterInfo3->pSecurityDescriptor;
  911. if ( !SecurityInformation || !pTempIniPrinter->pSecurityDescriptor ) {
  912. SetLastError(ERROR_INVALID_PARAMETER);
  913. return FALSE;
  914. }
  915. break;
  916. case 4:
  917. pTempIniPrinter->pName = pPrinterInfo4->pPrinterName;
  918. if ( !pIniPrinter->pIniDriver->pIniLangMonitor )
  919. pPrinterInfo4->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
  920. pTempIniPrinter->Attributes =
  921. ValidatePrinterAttributes(pPrinterInfo4->Attributes,
  922. pIniPrinter->Attributes,
  923. pIniPrinter->pDatatype,
  924. &bValid,
  925. TRUE);
  926. if (!bValid) {
  927. return FALSE;
  928. }
  929. *pbAttributeChg = pTempIniPrinter->Attributes != pIniPrinter->Attributes;
  930. break;
  931. case 5:
  932. pTempIniPrinter->pName = pPrinterInfo5->pPrinterName;
  933. pPortName = pPrinterInfo5->pPortName;
  934. if ( !pIniPrinter->pIniDriver->pIniLangMonitor )
  935. pPrinterInfo5->Attributes &= ~PRINTER_ATTRIBUTE_ENABLE_BIDI;
  936. pTempIniPrinter->Attributes =
  937. ValidatePrinterAttributes(pPrinterInfo5->Attributes,
  938. pIniPrinter->Attributes,
  939. pIniPrinter->pDatatype,
  940. &bValid,
  941. TRUE);
  942. if (!bValid) {
  943. return FALSE;
  944. }
  945. *pbAttributeChg = pTempIniPrinter->Attributes != pIniPrinter->Attributes;
  946. //
  947. // Validate timeout?
  948. //
  949. pTempIniPrinter->dnsTimeout = pPrinterInfo5->DeviceNotSelectedTimeout;
  950. pTempIniPrinter->txTimeout = pPrinterInfo5->TransmissionRetryTimeout;
  951. break;
  952. default:
  953. SetLastError(ERROR_INVALID_LEVEL);
  954. return FALSE;
  955. }
  956. //
  957. // Validate share name if the shared bit is getting set or share name
  958. // is being changed
  959. //
  960. if ( (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) &&
  961. ( !(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) ||
  962. pTempIniPrinter->pShareName != pIniPrinter->pShareName) ) {
  963. dwLastError = ValidatePrinterShareName(pTempIniPrinter->pShareName,
  964. pIniPrinter->pIniSpooler,
  965. pIniPrinter);
  966. if ( dwLastError != ERROR_SUCCESS ) {
  967. SetLastError(dwLastError);
  968. return FALSE;
  969. }
  970. }
  971. //
  972. // Is there a security change?
  973. //
  974. if ( SecurityInformation && (Level == 2 || Level == 3) ) {
  975. DWORD dwSize;
  976. dwSize = GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
  977. if ( dwSize !=
  978. GetSecurityDescriptorLength(pTempIniPrinter->pSecurityDescriptor) ||
  979. memcmp(pTempIniPrinter->pSecurityDescriptor,
  980. pIniPrinter->pSecurityDescriptor,
  981. dwSize) ) {
  982. *pbSecurityChg = TRUE;
  983. }
  984. }
  985. //
  986. // Is there a name change?
  987. //
  988. if ( Level == 2 || Level == 4 || Level == 5 ) {
  989. DWORD LastError;
  990. if ( !pTempIniPrinter->pName || !*pTempIniPrinter->pName ) {
  991. SetLastError(ERROR_INVALID_PARAMETER);
  992. return FALSE;
  993. }
  994. //
  995. // Validate name if a change is requested
  996. //
  997. if ( lstrcmpi(pTempIniPrinter->pName, pIniPrinter->pName) ) {
  998. LastError = ValidatePrinterName(pTempIniPrinter->pName,
  999. pIniPrinter->pIniSpooler,
  1000. pIniPrinter,
  1001. ppszNewPrinterName);
  1002. if ( LastError != ERROR_SUCCESS ) {
  1003. *ppszNewPrinterName = NULL;
  1004. SetLastError(LastError);
  1005. return FALSE;
  1006. }
  1007. //
  1008. // Check if printer name really changed for remote calls
  1009. //
  1010. if ( lstrcmpi(*ppszNewPrinterName, pIniPrinter->pName) ) {
  1011. *ppszNewPrinterName = AllocSplStr(*ppszNewPrinterName);
  1012. if ( !*ppszNewPrinterName )
  1013. return FALSE;
  1014. *pbNameChg = TRUE;
  1015. } else {
  1016. *ppszNewPrinterName = NULL;
  1017. }
  1018. }
  1019. //
  1020. // Validate attributes if a change is requested
  1021. // Don't allow a change from queued to direct or vice versa
  1022. // if there are already jobs on the printer.
  1023. //
  1024. if ( pIniPrinter->cJobs > 0 ) {
  1025. if ( (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) !=
  1026. (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) ) {
  1027. SetLastError(ERROR_PRINTER_HAS_JOBS_QUEUED);
  1028. return FALSE;
  1029. }
  1030. }
  1031. }
  1032. if ( Level == 2 || Level == 5 ) {
  1033. if ( !pPortName || !*pPortName ) {
  1034. SetLastError(ERROR_UNKNOWN_PORT);
  1035. return FALSE;
  1036. }
  1037. *ppKeyData = CreateAndValidatePortTokenList(pPortName,
  1038. pIniPrinter->pIniSpooler);
  1039. if ( !*ppKeyData )
  1040. return FALSE;
  1041. }
  1042. return TRUE;
  1043. }
  1044. BOOL
  1045. SplSetPrinter(
  1046. HANDLE hPrinter,
  1047. DWORD Level,
  1048. LPBYTE pPrinterInfo,
  1049. DWORD Command
  1050. )
  1051. {
  1052. PSPOOL pSpool = (PSPOOL)hPrinter;
  1053. DWORD i, LastError = ERROR_SUCCESS;
  1054. DWORD AccessRequired = 0;
  1055. PINIPRINTER pIniPrinter = pSpool->pIniPrinter, pTempIniPrinter = NULL;
  1056. PINISPOOLER pIniSpooler;
  1057. BOOL bReturn = TRUE;
  1058. DWORD dwResult;
  1059. BOOL bShareUpdate;
  1060. BOOL bShareRecreate;
  1061. DWORD dwPrinterVector = 0;
  1062. NOTIFYVECTOR NotifyVector;
  1063. BOOL bUpdateDsSpoolerKey = FALSE;
  1064. BOOL bNewPort;
  1065. BOOL bDataChanged = FALSE;
  1066. DWORD OldAttributes = 0;
  1067. PPRINTER_INFO_2 pPrinterInfo2 = (PPRINTER_INFO_2)pPrinterInfo;
  1068. PPRINTER_INFO_3 pPrinterInfo3 = (PPRINTER_INFO_3)pPrinterInfo;
  1069. PPRINTER_INFO_4 pPrinterInfo4 = (PPRINTER_INFO_4)pPrinterInfo;
  1070. PPRINTER_INFO_5 pPrinterInfo5 = (PPRINTER_INFO_5)pPrinterInfo;
  1071. PPRINTER_INFO_7 pPrinterInfo7 = (PPRINTER_INFO_7)pPrinterInfo;
  1072. PRINTER_INFO_7 PrinterInfo7;
  1073. BOOL bSecurityChg, bNameChg, bAttributeChg;
  1074. LPWSTR pszNewPrinterName = NULL, pszOldPrinterName = NULL;
  1075. PINIJOB pIniJob;
  1076. PKEYDATA pKeyData = NULL;
  1077. PDEVMODE pDevMode = NULL;
  1078. PINIDRIVER pIniDriver;
  1079. PINIPRINTPROC pIniPrintProc;
  1080. SECURITY_INFORMATION SecurityInformation;
  1081. ZERONV(NotifyVector);
  1082. bSecurityChg = bNameChg = bAttributeChg = FALSE;
  1083. bShareUpdate = bShareRecreate = FALSE;
  1084. //
  1085. // If level != 0 info struct should be non-null, and command 0
  1086. //
  1087. if ( Level && Command ) {
  1088. SetLastError(ERROR_INVALID_PRINTER_COMMAND);
  1089. return FALSE;
  1090. }
  1091. if ( Level && !pPrinterInfo ) {
  1092. SetLastError(ERROR_INVALID_PARAMETER);
  1093. return FALSE;
  1094. }
  1095. EnterSplSem();
  1096. if (!ValidateSpoolHandle(pSpool, PRINTER_HANDLE_SERVER )) {
  1097. bReturn = FALSE;
  1098. goto Cleanup;
  1099. }
  1100. //
  1101. // If it is a remote call get default devmode from driver and then update it
  1102. //
  1103. if ( Level == 2 ) {
  1104. pDevMode = pPrinterInfo2->pDevMode;
  1105. if ( pDevMode && (pSpool->TypeofHandle & PRINTER_HANDLE_REMOTE_DATA) ) {
  1106. //
  1107. // If the driver can't convert devmode user's can't set devmode from remote m/c
  1108. //
  1109. pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  1110. pDevMode,
  1111. NULL,
  1112. NULL,
  1113. CURRENT_VERSION);
  1114. }
  1115. }
  1116. SplInSem();
  1117. pIniSpooler = pIniPrinter->pIniSpooler;
  1118. SPLASSERT(pIniPrinter->signature == IP_SIGNATURE );
  1119. SPLASSERT(pIniSpooler->signature == ISP_SIGNATURE );
  1120. if (pSpool->pIniPrinter->Status & PRINTER_ZOMBIE_OBJECT) {
  1121. LastError = ERROR_PRINTER_DELETED;
  1122. goto Cleanup;
  1123. }
  1124. if ( !ValidateLevelAndSecurityAccesses(pSpool,
  1125. Level,
  1126. pPrinterInfo,
  1127. Command,
  1128. &AccessRequired,
  1129. &SecurityInformation) ){
  1130. bReturn = FALSE;
  1131. goto Cleanup;
  1132. }
  1133. //
  1134. // Level 7 & publishing levels
  1135. //
  1136. if (Level == 7) {
  1137. if ( !(pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE)) {
  1138. if (pPrinterInfo7->dwAction != DSPRINT_PUBLISH &&
  1139. pPrinterInfo7->dwAction != DSPRINT_UNPUBLISH &&
  1140. pPrinterInfo7->dwAction != DSPRINT_REPUBLISH &&
  1141. pPrinterInfo7->dwAction != DSPRINT_UPDATE) {
  1142. LastError = ERROR_INVALID_PARAMETER;
  1143. bReturn = FALSE;
  1144. goto Cleanup;
  1145. }
  1146. DBGMSG(DBG_EXEC, ("SplSetPrinter: DS Action %d: %ws %ws",
  1147. pPrinterInfo7->dwAction,
  1148. pIniPrinter->pName,
  1149. pIniPrinter->pszObjectGUID ?
  1150. pIniPrinter->pszObjectGUID : L"<NULL>"));
  1151. bUpdateDsSpoolerKey = TRUE;
  1152. } else {
  1153. //
  1154. // For connections, we rely directly on pPrinterInfo7->dwAction because
  1155. // the we cannot determine a pending publishing state based on attributes and GUID.
  1156. // If the remote printer is in Pending publishing, we need to save this in dwAction.
  1157. //
  1158. if (!pIniPrinter->pszObjectGUID || !pPrinterInfo7->pszObjectGUID) {
  1159. FreeSplStr(pIniPrinter->pszObjectGUID);
  1160. pIniPrinter->pszObjectGUID = NULL;
  1161. dwPrinterVector |= BIT(I_PRINTER_OBJECT_GUID);
  1162. } else if (wcscmp(pIniPrinter->pszObjectGUID, pPrinterInfo7->pszObjectGUID)) {
  1163. FreeSplStr(pIniPrinter->pszObjectGUID);
  1164. }
  1165. if ( pPrinterInfo7->pszObjectGUID ) {
  1166. if (!(pIniPrinter->pszObjectGUID = AllocSplStr(pPrinterInfo7->pszObjectGUID))) {
  1167. bReturn = FALSE;
  1168. goto Cleanup;
  1169. }
  1170. }
  1171. pIniPrinter->dwAction = pPrinterInfo7->dwAction;
  1172. dwPrinterVector |= BIT(I_PRINTER_OBJECT_GUID);
  1173. }
  1174. goto Finish;
  1175. } else if (Level != 3 && Level != 0) {
  1176. bUpdateDsSpoolerKey = TRUE;
  1177. }
  1178. //
  1179. // We need to do this for Level 0, 2, 3, 4, 5
  1180. // (except for level 3 which is security case)
  1181. //
  1182. if ( Level != 3 && pSpool->hPort ) {
  1183. if ( pSpool->hPort == INVALID_PORT_HANDLE ) {
  1184. //
  1185. // If this value is 0, then when we return GetLastError,
  1186. // the client will think we succeeded.
  1187. //
  1188. SPLASSERT( pSpool->OpenPortError );
  1189. LastError = pSpool->OpenPortError;
  1190. goto Cleanup;
  1191. } else {
  1192. bReturn = SetPrinter(pSpool->hPort,
  1193. Level,
  1194. pPrinterInfo,
  1195. Command);
  1196. if ( !Level )
  1197. goto Cleanup;
  1198. }
  1199. }
  1200. if ( Level != 6 && Level != 0 ) {
  1201. pTempIniPrinter = (PINIPRINTER) AllocSplMem(sizeof(INIPRINTER));
  1202. if ( !pTempIniPrinter )
  1203. goto Cleanup;
  1204. CopyMemory(pTempIniPrinter, pIniPrinter, sizeof(INIPRINTER));
  1205. }
  1206. //
  1207. // The actual processing begins here
  1208. //
  1209. if ( !Level && !Command ) {
  1210. bReturn = SetLocalPrinterSTRESS(pIniPrinter,
  1211. (PPRINTER_INFO_STRESS)pPrinterInfo);
  1212. goto Cleanup;
  1213. } else if ( !Level ) {
  1214. bReturn = SetLocalPrinter0(pIniPrinter, Command);
  1215. goto Cleanup;
  1216. } else if ( Level == 6 ) {
  1217. bReturn = SetPrinterStatus(pIniPrinter,
  1218. ((LPPRINTER_INFO_6)pPrinterInfo)->dwStatus);
  1219. goto Cleanup;
  1220. } else {
  1221. if ( !ValidateAndBuildSetPrinterRequest(pIniPrinter,
  1222. pTempIniPrinter,
  1223. pPrinterInfo,
  1224. Level,
  1225. SecurityInformation,
  1226. &bSecurityChg,
  1227. &bNameChg,
  1228. &bAttributeChg,
  1229. &pszNewPrinterName,
  1230. &pKeyData) ) {
  1231. bReturn = FALSE;
  1232. goto Cleanup;
  1233. } // else we follow thru rest of code since all valiations succeded
  1234. // Just a flag stating whether we have a new port
  1235. bNewPort = NewPort(pKeyData, pIniPrinter);
  1236. if (bNewPort) {
  1237. dwPrinterVector |= BIT(I_PRINTER_PORT_NAME);
  1238. }
  1239. }
  1240. //
  1241. // --------------------All validation done---------------------------
  1242. //
  1243. //
  1244. // Now set security information; Remember we have
  1245. // a valid SecurityDescriptor and "SecurityInformation
  1246. // is non-zero at this point. We have validated this
  1247. // information
  1248. //
  1249. if ( bSecurityChg ) {
  1250. if ( SetPrinterSecurityDescriptor(SecurityInformation,
  1251. pTempIniPrinter->pSecurityDescriptor,
  1252. &pIniPrinter->pSecurityDescriptor) ) {
  1253. dwPrinterVector |= BIT(I_PRINTER_SECURITY_DESCRIPTOR);
  1254. bShareUpdate = TRUE;
  1255. } else {
  1256. bReturn = FALSE;
  1257. goto Cleanup;
  1258. }
  1259. }
  1260. // Can we avoid doing this if bNewPort == NULL?
  1261. if ( Level == 2 || Level == 5 ) {
  1262. //
  1263. // bi-dir associate pIniPrinter with ports inside pKeyData.
  1264. //
  1265. bReturn = SetPrinterPorts(pSpool, pIniPrinter, pKeyData);
  1266. if ( !bReturn )
  1267. goto Cleanup;
  1268. }
  1269. if ( bAttributeChg ) {
  1270. if ( !(pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_ENABLE_DEVQ) &&
  1271. pIniPrinter->cJobs) {
  1272. pIniJob = pIniPrinter->pIniFirstJob;
  1273. while (pIniJob) {
  1274. if (pIniJob->Status & JOB_BLOCKED_DEVQ) {
  1275. PNOTIFYVECTOR pNotifyVector = &NVJobStatus;
  1276. pIniJob->Status &= ~JOB_BLOCKED_DEVQ;
  1277. if( pIniJob->pStatus ){
  1278. FreeSplStr(pIniJob->pStatus);
  1279. pIniJob->pStatus = NULL;
  1280. pNotifyVector = &NVJobStatusAndString;
  1281. }
  1282. SetPrinterChange(pIniJob->pIniPrinter,
  1283. pIniJob,
  1284. *pNotifyVector,
  1285. PRINTER_CHANGE_SET_JOB,
  1286. pIniJob->pIniPrinter->pIniSpooler);
  1287. }
  1288. pIniJob = pIniJob->pIniNextJob;
  1289. }
  1290. }
  1291. }
  1292. //
  1293. // The comment must be changed here since ShareThisPrinter
  1294. // will look at pComment when the printer is reshared.
  1295. //
  1296. if ( Level == 2 &&
  1297. pIniPrinter->pComment != pTempIniPrinter->pComment ) {
  1298. FreeSplStr(pIniPrinter->pComment);
  1299. pIniPrinter->pComment = pTempIniPrinter->pComment;
  1300. dwPrinterVector |= BIT(I_PRINTER_COMMENT);
  1301. if (pTempIniPrinter->Attributes & PRINTER_ATTRIBUTE_SHARED) {
  1302. bShareUpdate = TRUE;
  1303. }
  1304. }
  1305. //
  1306. // Change printer name if different
  1307. //
  1308. if ( bNameChg ) {
  1309. pszOldPrinterName = AllocSplStr(pIniPrinter->pName);
  1310. if (!pszOldPrinterName && pIniPrinter->pName) {
  1311. bReturn = FALSE;
  1312. goto Cleanup;
  1313. }
  1314. ChangePrinterName(pszNewPrinterName, pIniPrinter, pIniSpooler,
  1315. &dwPrinterVector);
  1316. pszNewPrinterName = NULL;
  1317. //
  1318. // The print share must be recreated since there's no way
  1319. // to change the path without deleting and creating a new one.
  1320. //
  1321. bShareRecreate = TRUE;
  1322. }
  1323. //
  1324. // If Share name changed force update
  1325. //
  1326. if ( pIniPrinter->pShareName != pTempIniPrinter->pShareName ) {
  1327. bShareRecreate = TRUE;
  1328. }
  1329. if ( bAttributeChg || bShareUpdate || bShareRecreate ) {
  1330. OldAttributes = pIniPrinter->Attributes;
  1331. pIniPrinter->Attributes = pTempIniPrinter->Attributes;
  1332. bReturn = ChangePrinterAttributes(pIniPrinter->Attributes,
  1333. OldAttributes,
  1334. pIniPrinter,
  1335. pIniSpooler,
  1336. pTempIniPrinter->pShareName,
  1337. bShareRecreate,
  1338. bShareUpdate);
  1339. if (!bReturn) {
  1340. LastError = GetLastError();
  1341. }
  1342. if (pIniPrinter->Attributes != OldAttributes) {
  1343. dwPrinterVector |= BIT(I_PRINTER_ATTRIBUTES);
  1344. }
  1345. }
  1346. if ( Level == 2 ) {
  1347. ProcessSetPrinter2(pIniPrinter,
  1348. pTempIniPrinter,
  1349. pPrinterInfo2,
  1350. &dwPrinterVector,
  1351. pDevMode);
  1352. }
  1353. Finish:
  1354. // Sometimes SetPrinter can fail certain calls after it has modified some parameters.
  1355. // For instance, we may have failed to update some sharing fields. If we get to this
  1356. // point (or anywhere after the last goto Cleanup), then we need to update the ds keys.
  1357. // We should really clean up SetPrinter so it undoes everything, but we don't have enough time
  1358. // to fix it properly before NT6.
  1359. bDataChanged = TRUE;
  1360. CHECK_SCHEDULER();
  1361. // Can we avoid doing this if dwPrinterVector == NULL?
  1362. UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID );
  1363. // Can we avoid doing this if dwPrinterVector == NULL?
  1364. UpdateWinIni( pIniPrinter ); // So the port on the device is correct
  1365. //
  1366. // Log event that the SetPrinter was done.
  1367. //
  1368. INCPRINTERREF(pIniPrinter);
  1369. SplLogEvent(pIniSpooler, LOG_INFO, MSG_PRINTER_SET, TRUE, pIniPrinter->pName, NULL);
  1370. DECPRINTERREF(pIniPrinter);
  1371. NotifyVector[PRINTER_NOTIFY_TYPE] |= dwPrinterVector;
  1372. //
  1373. // Indicate that a change has occurred.
  1374. //
  1375. SetPrinterChange(pIniPrinter,
  1376. NULL,
  1377. NotifyVector,
  1378. PRINTER_CHANGE_SET_PRINTER,
  1379. pIniSpooler);
  1380. Cleanup:
  1381. SplInSem();
  1382. if ( LastError != ERROR_SUCCESS ) {
  1383. SetLastError(LastError);
  1384. bReturn = FALSE;
  1385. }
  1386. CleanupSetPrinter(pIniPrinter, pTempIniPrinter, pKeyData,
  1387. Level, bReturn);
  1388. if (bDataChanged) {
  1389. INCPRINTERREF(pIniPrinter);
  1390. LeaveSplSem();
  1391. SplOutSem();
  1392. //
  1393. // If the printer driver changed
  1394. // Call the printer driver to initialize itself
  1395. //
  1396. if (dwPrinterVector & BIT(I_PRINTER_DRIVER_NAME)) {
  1397. PDEVMODE pDevMode = NULL;
  1398. PrinterDriverEvent(pIniPrinter, PRINTER_EVENT_INITIALIZE, (LPARAM)NULL);
  1399. //
  1400. // If the driver name changed then convert the devmode to the new driver's
  1401. // devmode. Note this must be done after the printer event initialize
  1402. // because the driver is not able to handle a convert devmode call before
  1403. // being initialized. Also if the conversion fails we potentially end up
  1404. // having the old devmode in the registry. We could null out the devmode
  1405. // but is it better to have a bad old devmode in the registry rather than a null
  1406. // devmode. A null devmode is more dangerous because an application may
  1407. // get really confused with a null devmode rather than a bad devmode
  1408. // which the driver will eventually fix, because they have to handle foreign
  1409. // devmodes any way.
  1410. //
  1411. EnterSplSem();
  1412. //
  1413. // Now convert the devmode to the driver specific devmode.
  1414. //
  1415. pDevMode = ConvertDevModeToSpecifiedVersion(pIniPrinter,
  1416. pIniPrinter->pDevMode,
  1417. NULL,
  1418. NULL,
  1419. CURRENT_VERSION);
  1420. //
  1421. // If a new devmode was returned then release the current printer's
  1422. // devmode and save the new devmode.
  1423. //
  1424. if (pDevMode) {
  1425. FreeSplMem(pIniPrinter->pDevMode);
  1426. pIniPrinter->pDevMode = pDevMode;
  1427. pIniPrinter->cbDevMode = pDevMode->dmSize + pDevMode->dmDriverExtra;
  1428. }
  1429. //
  1430. // Write the newly converted devmode to the registry again.
  1431. //
  1432. UpdatePrinterIni( pIniPrinter, UPDATE_CHANGEID );
  1433. LeaveSplSem();
  1434. }
  1435. //
  1436. // If the printer attributes changed, call the driver with the two
  1437. // different sets of attributes, this is to allow the fax driver to
  1438. // start up the fax service when a printer gets shared out.
  1439. //
  1440. if (dwPrinterVector & BIT(I_PRINTER_ATTRIBUTES)) {
  1441. PRINTER_EVENT_ATTRIBUTES_INFO AttributesInfo = {
  1442. sizeof(PRINTER_EVENT_ATTRIBUTES_INFO),
  1443. OldAttributes,
  1444. pIniPrinter->Attributes
  1445. };
  1446. PrinterDriverEvent(pIniPrinter, PRINTER_EVENT_ATTRIBUTES_CHANGED, (LPARAM)&AttributesInfo);
  1447. }
  1448. EnterSplSem();
  1449. SplInSem();
  1450. DECPRINTERREF(pIniPrinter);
  1451. }
  1452. // Don't update if this is from cache
  1453. if (!bDataChanged || ((Level == 2 || Level == 5) && !dwPrinterVector) ||
  1454. (pIniPrinter->pIniSpooler->SpoolerFlags & SPL_TYPE_CACHE)) {
  1455. bUpdateDsSpoolerKey = FALSE;
  1456. } else if (bUpdateDsSpoolerKey) {
  1457. if (Level != 7)
  1458. {
  1459. //
  1460. // Update unly values that changed.
  1461. //
  1462. UpdateDsSpoolerKey(hPrinter, dwPrinterVector);
  1463. } else if (pPrinterInfo7->dwAction != DSPRINT_UNPUBLISH)
  1464. {
  1465. //
  1466. // Update the all values in Registry for level 7.
  1467. //
  1468. UpdateDsSpoolerKey(hPrinter, 0xffffffff);
  1469. }
  1470. //
  1471. // Reset Driver DS Properties if driver changed
  1472. //
  1473. if (dwPrinterVector & BIT(I_PRINTER_DRIVER_NAME)) {
  1474. INCPRINTERREF(pIniPrinter);
  1475. LeaveSplSem();
  1476. //
  1477. // This calls SetPrinterDs with DSPRINT_UPDATE anyway.
  1478. //
  1479. RecreateDsKey(hPrinter, SPLDS_DRIVER_KEY);
  1480. EnterSplSem();
  1481. DECPRINTERREF(pIniPrinter);
  1482. } else if (Level != 7 || pPrinterInfo7->dwAction != DSPRINT_UNPUBLISH) {
  1483. //
  1484. // If the driver didn't change, query the driver again for capabilities.
  1485. //
  1486. UpdateDsDriverKey(hPrinter);
  1487. }
  1488. }
  1489. if (bUpdateDsSpoolerKey) {
  1490. if (pIniPrinter->DsKeyUpdateForeground || (Level == 7 && pPrinterInfo7->dwAction == DSPRINT_UNPUBLISH)) {
  1491. if (Level == 7) {
  1492. if ((dwResult = SetPrinterDs(hPrinter, pPrinterInfo7->dwAction, FALSE)) != ERROR_SUCCESS) {
  1493. SetLastError(dwResult);
  1494. bReturn = FALSE;
  1495. }
  1496. } else {
  1497. //
  1498. // Update only, in the background thread.
  1499. //
  1500. SetPrinterDs(hPrinter, DSPRINT_UPDATE, FALSE);
  1501. }
  1502. }
  1503. }
  1504. LeaveSplSem();
  1505. SplOutSem();
  1506. if ( pDevMode && pDevMode != pPrinterInfo2->pDevMode )
  1507. FreeSplMem(pDevMode);
  1508. if ( pszOldPrinterName ) {
  1509. FreeSplStr(pszOldPrinterName);
  1510. }
  1511. FreeSplStr(pszNewPrinterName);
  1512. return bReturn;
  1513. }
  1514. PRINTER_SECURITY_STATUS
  1515. SetPrinterSecurity(
  1516. SECURITY_INFORMATION SecurityInformation,
  1517. PINIPRINTER pIniPrinter,
  1518. PSECURITY_DESCRIPTOR pSecurityDescriptor)
  1519. {
  1520. DWORD dwSize;
  1521. if (!pSecurityDescriptor)
  1522. return SECURITY_FAIL;
  1523. if (pIniPrinter->pSecurityDescriptor) {
  1524. dwSize = GetSecurityDescriptorLength(pIniPrinter->pSecurityDescriptor);
  1525. if (dwSize == GetSecurityDescriptorLength(pSecurityDescriptor)) {
  1526. if (!memcmp(pSecurityDescriptor,
  1527. pIniPrinter->pSecurityDescriptor,
  1528. dwSize)) {
  1529. return SECURITY_NOCHANGE;
  1530. }
  1531. }
  1532. }
  1533. if( !SetPrinterSecurityDescriptor( SecurityInformation,
  1534. pSecurityDescriptor,
  1535. &pIniPrinter->pSecurityDescriptor ) ) {
  1536. DBGMSG(DBG_WARNING, ("SetPrinterSecurityDescriptor failed. Error = %d\n",
  1537. GetLastError()));
  1538. return SECURITY_FAIL;
  1539. }
  1540. UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID);
  1541. return SECURITY_SUCCESS;
  1542. }
  1543. VOID
  1544. RegClearKey(
  1545. HKEY hKey,
  1546. PINISPOOLER pIniSpooler
  1547. )
  1548. {
  1549. DWORD dwError;
  1550. WCHAR szValue[4*MAX_PATH];
  1551. DWORD cchValue;
  1552. while (TRUE) {
  1553. cchValue = COUNTOF(szValue);
  1554. dwError = SplRegEnumValue( hKey,
  1555. 0,
  1556. szValue,
  1557. &cchValue,
  1558. NULL,
  1559. NULL,
  1560. NULL,
  1561. pIniSpooler );
  1562. if( dwError != ERROR_SUCCESS ){
  1563. if( dwError != ERROR_NO_MORE_ITEMS ){
  1564. DBGMSG( DBG_ERROR, ( "RegClearKey: Failed %d\n", dwError ));
  1565. }
  1566. break;
  1567. }
  1568. dwError = SplRegDeleteValue( hKey, szValue, pIniSpooler );
  1569. if( dwError != ERROR_SUCCESS ){
  1570. DBGMSG( DBG_ERROR, ( "RegDeleteValue: %s Failed %d\n",
  1571. szValue, dwError ));
  1572. break;
  1573. }
  1574. }
  1575. }
  1576. BOOL
  1577. ChangePrinterAttributes(
  1578. DWORD dNewAttributes,
  1579. DWORD dOldAttributes,
  1580. PINIPRINTER pIniPrinter,
  1581. PINISPOOLER pIniSpooler,
  1582. LPWSTR pszNewShareName,
  1583. BOOL bShareRecreate,
  1584. BOOL bShareUpdate
  1585. )
  1586. /*++
  1587. Routine Description:
  1588. Changes printer attributes by validating sharing information.
  1589. Already the validated attributes are set, we want to validate
  1590. by changing the share information
  1591. Arguments:
  1592. dNewAttributes - New attributes specified on SetPrinter call
  1593. dOldAttributes - pIniPrinter->Attributes before the call
  1594. pIniPrinter - of the printer we are changing attributes
  1595. pIniSpooler - Spooler that owns printer
  1596. pszNewShareName - the share name that will be set if SetPrinter succeeds
  1597. bShareRecreate - Share must be recreated because the printer or share
  1598. name changed.
  1599. bShareUpdate - Share just needs to be updated, since comment / SD changed.
  1600. Return Value:
  1601. DWORD TRUE on success, FALSE else.
  1602. History:
  1603. MuhuntS (Muhunthan Sivapragasam) July 95
  1604. --*/
  1605. {
  1606. BOOL Shared, bReturn = TRUE;
  1607. //
  1608. // We are going to have to be able to restore the attributes if the share
  1609. // modification fails. We need to set the current attributes now because
  1610. // the NetSharexxx is going to call OpenPrinter, and possibly an AddJob
  1611. // which needs the correct Attributes.
  1612. //
  1613. if (dNewAttributes & PRINTER_ATTRIBUTE_SHARED) {
  1614. if (!(dOldAttributes & PRINTER_ATTRIBUTE_SHARED)) {
  1615. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_SHARED;
  1616. Shared = ShareThisPrinter( pIniPrinter, pszNewShareName, TRUE );
  1617. if ( !Shared ) {
  1618. pIniPrinter->Attributes = dOldAttributes;
  1619. bReturn = FALSE;
  1620. }
  1621. } else {
  1622. //
  1623. // We are shared, and so is the old one. If share name changed
  1624. // we have to remove old share and reshare.
  1625. //
  1626. if ( bShareRecreate ) {
  1627. if (ShareThisPrinter(pIniPrinter,
  1628. pIniPrinter->pShareName,
  1629. FALSE)) {
  1630. #if DBG
  1631. WCHAR pwszError[256];
  1632. wsprintf(pwszError,
  1633. L"Error %d, removing share",
  1634. GetLastError());
  1635. //
  1636. // Error: the printer shouldn't be shared at this
  1637. // point.
  1638. //
  1639. INCPRINTERREF(pIniPrinter);
  1640. SplLogEvent(pIniSpooler,
  1641. LOG_ERROR,
  1642. MSG_SHARE_FAILED,
  1643. TRUE,
  1644. L"SetLocalPrinter ShareThisPrinter FALSE",
  1645. pIniPrinter->pName,
  1646. pIniPrinter->pShareName,
  1647. pwszError,
  1648. NULL);
  1649. DECPRINTERREF(pIniPrinter);
  1650. #endif
  1651. bReturn = FALSE;
  1652. } else if (!ShareThisPrinter(pIniPrinter,
  1653. pszNewShareName,
  1654. TRUE)) {
  1655. #if DBG
  1656. WCHAR pwszError[256];
  1657. wsprintf(pwszError,
  1658. L"Error %d, adding share",
  1659. GetLastError());
  1660. //
  1661. // Error: the printer shouldn't be shared at this
  1662. // point.
  1663. //
  1664. INCPRINTERREF(pIniPrinter);
  1665. SplLogEvent(pIniSpooler,
  1666. LOG_ERROR,
  1667. MSG_SHARE_FAILED,
  1668. TRUE,
  1669. L"SetLocalPrinter ShareThisPrinter TRUE",
  1670. pIniPrinter->pName,
  1671. pIniPrinter->pShareName,
  1672. pwszError,
  1673. NULL);
  1674. DECPRINTERREF(pIniPrinter);
  1675. #endif
  1676. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
  1677. pIniPrinter->Status |= PRINTER_WAS_SHARED;
  1678. bReturn = FALSE;
  1679. }
  1680. } else if ( bShareUpdate ) {
  1681. //
  1682. // If comment/description changed then we just do a NetShareSet
  1683. //
  1684. bReturn = SetPrinterShareInfo(pIniPrinter);
  1685. }
  1686. }
  1687. } else if (dOldAttributes & PRINTER_ATTRIBUTE_SHARED) {
  1688. Shared = ShareThisPrinter(pIniPrinter, pIniPrinter->pShareName, FALSE);
  1689. if (!Shared) {
  1690. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_SHARED;
  1691. pIniPrinter->Status |= PRINTER_WAS_SHARED;
  1692. CreateServerThread();
  1693. } else {
  1694. pIniPrinter->Attributes = dOldAttributes;
  1695. bReturn = FALSE;
  1696. }
  1697. }
  1698. if (((dOldAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) &&
  1699. !(dNewAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) ) ||
  1700. (!(dOldAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) &&
  1701. (dNewAttributes & PRINTER_ATTRIBUTE_WORK_OFFLINE) ) ) {
  1702. WritePrinterOnlineStatusInCurrentConfig(pIniPrinter);
  1703. }
  1704. return bReturn;
  1705. }