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.

2653 lines
81 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Abstract:
  4. This module provides functionality for ADs within spooler
  5. Author:
  6. Steve Wilson (NT) December 1996
  7. Revision History:
  8. --*/
  9. #include <precomp.h>
  10. #pragma hdrstop
  11. #include "ds.hxx"
  12. #define LOG_EVENT_ERROR_BUFFER_SIZE 11
  13. #define PPM_FACTOR 48
  14. #define LOTS_OF_FORMS 300 // This is a little more than twice the number of built-in forms
  15. extern BOOL gbInDomain;
  16. extern BOOL gdwLogDsEvents;
  17. extern "C" HANDLE ghDsUpdateThread;
  18. extern "C" DWORD gdwDsUpdateThreadId;
  19. extern "C" BOOL (*pfnOpenPrinter)(LPTSTR, LPHANDLE, LPPRINTER_DEFAULTS);
  20. extern "C" BOOL (*pfnClosePrinter)(HANDLE);
  21. extern "C" DWORD
  22. SetPrinterDs(
  23. HANDLE hPrinter,
  24. DWORD dwAction,
  25. BOOL bSynchronous
  26. )
  27. {
  28. PSPOOL pSpool = (PSPOOL) hPrinter;
  29. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  30. HRESULT hr;
  31. HANDLE hToken = NULL;
  32. PWSTR pszObjectGUID, pszCN, pszDN;
  33. DWORD DsKeyUpdate, Attributes;
  34. BOOL DoChange = FALSE;
  35. NOTIFYVECTOR NotifyVector;
  36. SplInSem();
  37. if (!gbInDomain)
  38. return ERROR_DS_UNAVAILABLE;
  39. // Don't allow masquerading printer publishing
  40. if (pSpool->pIniPort && !(pSpool->pIniPort->Status & PP_MONITOR))
  41. return ERROR_INVALID_PARAMETER;
  42. hToken = RevertToPrinterSelf(); // All DS accesses are done by LocalSystem account
  43. // If any of these change we'll update the registry entry
  44. DsKeyUpdate = pIniPrinter->DsKeyUpdate;
  45. pszObjectGUID = pIniPrinter->pszObjectGUID;
  46. pszCN = pIniPrinter->pszCN;
  47. pszDN = pIniPrinter->pszDN;
  48. Attributes = pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED;
  49. // Attribute states desired state, not current state
  50. switch (dwAction) {
  51. case DSPRINT_UPDATE:
  52. if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  53. hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_FILE_NOT_FOUND);
  54. } else if (bSynchronous) {
  55. // We are in the background thread.
  56. if (pIniPrinter->DsKeyUpdate) {
  57. INCPRINTERREF(pIniPrinter);
  58. LeaveSplSem();
  59. hr = DsPrinterPublish(hPrinter);
  60. EnterSplSem();
  61. DECPRINTERREF(pIniPrinter);
  62. } else {
  63. hr = ERROR_SUCCESS;
  64. }
  65. } else {
  66. // Here we are in the foreground thread.
  67. if (pIniPrinter->DsKeyUpdateForeground) {
  68. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
  69. pIniPrinter->dwAction = DSPRINT_PUBLISH;
  70. hr = ERROR_IO_PENDING;
  71. } else {
  72. hr = ERROR_SUCCESS;
  73. }
  74. }
  75. break;
  76. case DSPRINT_PUBLISH:
  77. if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) &&
  78. PrinterPublishProhibited()) {
  79. // There is a policy against publishing printers from this machine.
  80. hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_ACCESS_DENIED);
  81. } else {
  82. if (bSynchronous) {
  83. INCPRINTERREF(pIniPrinter);
  84. LeaveSplSem();
  85. hr = DsPrinterPublish(hPrinter);
  86. EnterSplSem();
  87. DECPRINTERREF(pIniPrinter);
  88. } else {
  89. // This is a Pending Unpublish state
  90. if (!(pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED) && pIniPrinter->pszObjectGUID)
  91. pIniPrinter->dwAction = DSPRINT_REPUBLISH;
  92. else
  93. pIniPrinter->dwAction = DSPRINT_PUBLISH;
  94. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
  95. hr = ERROR_IO_PENDING;
  96. }
  97. }
  98. break;
  99. case DSPRINT_REPUBLISH:
  100. if (PrinterPublishProhibited()) {
  101. // There is a policy against publishing printers from this machine.
  102. hr = MAKE_HRESULT( SEVERITY_ERROR, FACILITY_WIN32, ERROR_ACCESS_DENIED);
  103. } else {
  104. // Synchronous mode is from background thread and it should only call Publish/Unpublish
  105. if (bSynchronous) {
  106. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_INVALID_PARAMETER);
  107. SPLASSERT(FALSE);
  108. } else {
  109. pIniPrinter->dwAction = DSPRINT_REPUBLISH;
  110. pIniPrinter->Attributes |= PRINTER_ATTRIBUTE_PUBLISHED;
  111. hr = ERROR_IO_PENDING;
  112. }
  113. }
  114. break;
  115. case DSPRINT_UNPUBLISH:
  116. if (bSynchronous) {
  117. INCPRINTERREF(pIniPrinter);
  118. LeaveSplSem();
  119. hr = DsPrinterUnpublish(hPrinter);
  120. EnterSplSem();
  121. DECPRINTERREF(pIniPrinter);
  122. } else {
  123. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_PUBLISHED;
  124. pIniPrinter->dwAction = DSPRINT_UNPUBLISH;
  125. hr = ERROR_IO_PENDING;
  126. }
  127. break;
  128. default:
  129. hr = ERROR_INVALID_PARAMETER;
  130. break;
  131. }
  132. // Update Registry and set notifications
  133. if (pszCN != pIniPrinter->pszCN ||
  134. pszDN != pIniPrinter->pszDN ||
  135. pszObjectGUID != pIniPrinter->pszObjectGUID ||
  136. DsKeyUpdate != pIniPrinter->DsKeyUpdate ||
  137. Attributes != (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  138. ZERONV(NotifyVector);
  139. if (pszObjectGUID != pIniPrinter->pszObjectGUID) {
  140. NotifyVector[PRINTER_NOTIFY_TYPE] |= BIT(I_PRINTER_OBJECT_GUID);
  141. DoChange = TRUE;
  142. }
  143. if (Attributes != (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_PUBLISHED)) {
  144. NotifyVector[PRINTER_NOTIFY_TYPE] |= BIT(I_PRINTER_ATTRIBUTES);
  145. DoChange = TRUE;
  146. }
  147. if (DoChange) {
  148. UpdatePrinterIni(pIniPrinter, UPDATE_CHANGEID);
  149. SetPrinterChange(pIniPrinter,
  150. NULL,
  151. NotifyVector,
  152. PRINTER_CHANGE_SET_PRINTER,
  153. pIniPrinter->pIniSpooler);
  154. } else if (DsKeyUpdate != pIniPrinter->DsKeyUpdate) {
  155. UpdatePrinterIni(pIniPrinter, UPDATE_DS_ONLY);
  156. }
  157. }
  158. SplInSem();
  159. if (hr == ERROR_IO_PENDING && !bSynchronous)
  160. SpawnDsUpdate(1);
  161. if (hToken)
  162. ImpersonatePrinterClient(hToken);
  163. return (DWORD) hr;
  164. }
  165. HRESULT
  166. DsPrinterPublish(
  167. HANDLE hPrinter
  168. )
  169. {
  170. HRESULT hr;
  171. PSPOOL pSpool = (PSPOOL) hPrinter;
  172. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  173. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  174. BOOL bUpdating = !!pIniPrinter->pszObjectGUID;
  175. DWORD dwDsKeyUpdate;
  176. SplOutSem();
  177. #if DBG
  178. EnterSplSem();
  179. DBGMSG( DBG_EXEC, ("DsPrinterPublish: %ws\n", pIniPrinter->pName));
  180. LeaveSplSem();
  181. #endif
  182. // On first publish update all keys and tell the driver to write its non-devcap properties
  183. if (!bUpdating) {
  184. // We execute this on the background thread and hence donot need any
  185. // to be in the critical section.
  186. pIniPrinter->DsKeyUpdate |= DS_KEY_PUBLISH | DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER;
  187. }
  188. // Update DS properties
  189. dwDsKeyUpdate = pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER);
  190. hr = DsPrinterUpdate(hPrinter);
  191. BAIL_ON_FAILURE(hr);
  192. DBGMSG( DBG_EXEC, ("PublishDsUpdate: Printer Updated\n" ) );
  193. error:
  194. if (SUCCEEDED(hr)) {
  195. // Only write a success event if something changed
  196. if (dwDsKeyUpdate != pIniPrinter->DsKeyUpdate) {
  197. SplLogEvent( pIniPrinter->pIniSpooler,
  198. gdwLogDsEvents & LOG_INFO,
  199. bUpdating ? MSG_PRINTER_UPDATED
  200. : MSG_PRINTER_PUBLISHED,
  201. FALSE,
  202. pIniPrinter->pszCN,
  203. pIniPrinter->pszDN,
  204. NULL );
  205. }
  206. } else if (pIniPrinter->pszCN && pIniPrinter->pszDN) {
  207. wsprintf(ErrorBuffer, L"%x", hr);
  208. SplLogEvent( pIniPrinter->pIniSpooler,
  209. gdwLogDsEvents & LOG_ERROR,
  210. MSG_PRINTER_NOT_PUBLISHED,
  211. FALSE,
  212. pIniPrinter->pszCN,
  213. pIniPrinter->pszDN,
  214. ErrorBuffer,
  215. NULL );
  216. }
  217. if (pIniPrinter->DsKeyUpdate)
  218. hr = ERROR_IO_PENDING;
  219. return hr;
  220. }
  221. HRESULT
  222. DsPrinterUpdate(
  223. HANDLE hPrinter
  224. )
  225. {
  226. PSPOOL pSpool = (PSPOOL) hPrinter;
  227. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  228. HRESULT hr = S_OK;
  229. DWORD dwResult;
  230. BOOL bImpersonating = FALSE;
  231. IADs *pADs = NULL;
  232. SplOutSem();
  233. if(!(pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER))) {
  234. pIniPrinter->DsKeyUpdate = 0;
  235. }
  236. // If we aren't truly published yet, be sure to publish mandatory properties first!
  237. if (!pIniPrinter->pszObjectGUID) {
  238. //
  239. // Fail if we're on a cluster but couldn't get the Cluster GUID
  240. // The Cluster GUID is required later in AddClusterAce
  241. //
  242. if ((pIniPrinter->pIniSpooler->SpoolerFlags & SPL_CLUSTER_REG) &&
  243. !pIniPrinter->pIniSpooler->pszClusterGUID) {
  244. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, ERROR_CLUSTER_NO_SECURITY_CONTEXT);
  245. BAIL_ON_FAILURE(hr);
  246. }
  247. // Get or Create printQueue object
  248. hr = GetPrintQueue(hPrinter, &pADs);
  249. BAIL_ON_FAILURE(hr);
  250. hr = PublishMandatoryProperties(hPrinter, pADs);
  251. BAIL_ON_FAILURE(hr);
  252. } else {
  253. // If we are a Cluster, impersonate the Cluster User
  254. if (pIniPrinter->pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE) {
  255. // Impersonate the client
  256. if (!ImpersonatePrinterClient(pIniPrinter->pIniSpooler->hClusterToken)) {
  257. dwResult = GetLastError();
  258. DBGMSG(DBG_WARNING,("DsPrinterPublish FAILED: %d\n", dwResult));
  259. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  260. BAIL_ON_FAILURE(hr);
  261. }
  262. bImpersonating = TRUE;
  263. }
  264. // Get or Create printQueue object
  265. hr = GetPrintQueue(hPrinter, &pADs);
  266. BAIL_ON_FAILURE(hr);
  267. }
  268. // Update User - updates from Registry
  269. //
  270. // CopyRegistry2Ds for DS_KEY_USER values must
  271. // be called in the first place since there could be duplicate values
  272. // that might overwrite properties contained by either
  273. // DS_KEY_SPOOLER or DS_KEY_DRIVER.
  274. // Ignore the return value since publishing of DS_KEY_USER values
  275. // is not critical
  276. //
  277. if (pIniPrinter->DsKeyUpdate & DS_KEY_USER) {
  278. CopyRegistry2Ds(hPrinter, DS_KEY_USER, pADs);
  279. }
  280. // Update Spooler - updates from Registry
  281. if (pIniPrinter->DsKeyUpdate & DS_KEY_SPOOLER) {
  282. hr = CopyRegistry2Ds(hPrinter, DS_KEY_SPOOLER, pADs);
  283. BAIL_ON_FAILURE(hr);
  284. }
  285. // Update Driver - updates from Registry
  286. if (pIniPrinter->DsKeyUpdate & DS_KEY_DRIVER) {
  287. hr = CopyRegistry2Ds(hPrinter, DS_KEY_DRIVER, pADs);
  288. // Ignore missing key
  289. if (HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND)
  290. hr = S_OK;
  291. BAIL_ON_FAILURE(hr);
  292. }
  293. error:
  294. if (pADs)
  295. pADs->Release();
  296. if (bImpersonating)
  297. pIniPrinter->pIniSpooler->hClusterToken = RevertToPrinterSelf();
  298. return hr;
  299. }
  300. HRESULT
  301. DsDeletePQObject(
  302. HANDLE hPrinter
  303. )
  304. {
  305. PSPOOL pSpool = (PSPOOL) hPrinter;
  306. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  307. IADsContainer *pADsContainer = NULL;
  308. IADs *pADs = NULL;
  309. HRESULT hr = E_FAIL;
  310. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  311. BOOL bImpersonating = FALSE;
  312. DWORD dwError;
  313. //
  314. // This routine is called when AddClusterAce failed. Even if we faild deleteing the object,
  315. // we really want to clean up the pIniPrinter structure so that we prevent the case where
  316. // the object stays forever in pending un/publishing.
  317. // That's because the other cluster node fails to delete/update it
  318. // since the printQueue object doesn't have the cluster user ace added. Pruner also fails to delete it
  319. // since the PrintQueue's GUID matches the pIniPrinter's GUID.
  320. //
  321. SplOutSem();
  322. hr = GetPrintQueueContainer(hPrinter, &pADsContainer, &pADs);
  323. BAIL_ON_FAILURE(hr);
  324. // Delete Printer Object
  325. hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pIniPrinter->pszCN);
  326. DBGMSG(DBG_EXEC,("DsPrinterUnpublish FAILED: %x, %ws\n", hr, pIniPrinter->pszCN));
  327. BAIL_ON_FAILURE(hr);
  328. error:
  329. if (pADs)
  330. pADs->Release();
  331. if (pADsContainer)
  332. pADsContainer->Release();
  333. pIniPrinter->DsKeyUpdate = 0;
  334. FreeSplStr(pIniPrinter->pszObjectGUID);
  335. pIniPrinter->pszObjectGUID = NULL;
  336. FreeSplStr(pIniPrinter->pszCN);
  337. pIniPrinter->pszCN = NULL;
  338. FreeSplStr(pIniPrinter->pszDN);
  339. pIniPrinter->pszDN = NULL;
  340. return hr;
  341. }
  342. HRESULT
  343. DsPrinterUnpublish(
  344. HANDLE hPrinter
  345. )
  346. {
  347. PSPOOL pSpool = (PSPOOL) hPrinter;
  348. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  349. IADsContainer *pADsContainer = NULL;
  350. IADs *pADs = NULL;
  351. HRESULT hr = E_FAIL;
  352. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  353. BOOL bImpersonating = FALSE;
  354. DWORD dwError;
  355. SplOutSem();
  356. // If we are a Cluster, impersonate the Cluster User
  357. if (pIniPrinter->pIniSpooler->hClusterToken != INVALID_HANDLE_VALUE) {
  358. // Impersonate the client
  359. if (!ImpersonatePrinterClient(pIniPrinter->pIniSpooler->hClusterToken)) {
  360. dwError = GetLastError();
  361. DBGMSG(DBG_WARNING,("DsPrinterUnpublish FAILED: %d\n", dwError));
  362. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwError);
  363. goto error;
  364. }
  365. bImpersonating = TRUE;
  366. }
  367. hr = GetPrintQueueContainer(hPrinter, &pADsContainer, &pADs);
  368. BAIL_ON_FAILURE(hr);
  369. // Delete Printer Object
  370. hr = pADsContainer->Delete(SPLDS_PRINTER_CLASS, pIniPrinter->pszCN);
  371. DBGMSG(DBG_EXEC,("DsPrinterUnpublish FAILED: %x, %ws\n", hr, pIniPrinter->pszCN));
  372. BAIL_ON_FAILURE(hr);
  373. error:
  374. if (bImpersonating)
  375. pIniPrinter->pIniSpooler->hClusterToken = RevertToPrinterSelf();
  376. if (hr == HRESULT_FROM_WIN32(ERROR_DS_NO_SUCH_OBJECT) ||
  377. HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND ||
  378. HRESULT_CODE(hr) == ERROR_PATH_NOT_FOUND) {
  379. hr = S_OK;
  380. SplLogEvent( pIniPrinter->pIniSpooler,
  381. gdwLogDsEvents & LOG_INFO,
  382. MSG_MISSING_PRINTER_UNPUBLISHED,
  383. FALSE,
  384. pIniPrinter->pName,
  385. NULL );
  386. } else if (SUCCEEDED(hr)) {
  387. SplLogEvent( pIniPrinter->pIniSpooler,
  388. gdwLogDsEvents & LOG_INFO,
  389. MSG_PRINTER_UNPUBLISHED,
  390. FALSE,
  391. pIniPrinter->pszCN,
  392. pIniPrinter->pszDN,
  393. NULL );
  394. } else if(pIniPrinter->pszCN && pIniPrinter->pszDN) {
  395. wsprintf(ErrorBuffer, L"%x", hr);
  396. SplLogEvent( pIniPrinter->pIniSpooler,
  397. gdwLogDsEvents & LOG_ERROR,
  398. MSG_CANT_DELETE_PRINTQUEUE,
  399. FALSE,
  400. pIniPrinter->pszCN,
  401. pIniPrinter->pszDN,
  402. ErrorBuffer,
  403. NULL );
  404. }
  405. if (SUCCEEDED(hr)) {
  406. pIniPrinter->DsKeyUpdate = 0;
  407. FreeSplStr(pIniPrinter->pszObjectGUID);
  408. pIniPrinter->pszObjectGUID = NULL;
  409. FreeSplStr(pIniPrinter->pszCN);
  410. pIniPrinter->pszCN = NULL;
  411. FreeSplStr(pIniPrinter->pszDN);
  412. pIniPrinter->pszDN = NULL;
  413. } else {
  414. pIniPrinter->DsKeyUpdate = DS_KEY_UNPUBLISH;
  415. }
  416. if (pADs)
  417. pADs->Release();
  418. if (pADsContainer)
  419. pADsContainer->Release();
  420. if (pIniPrinter->DsKeyUpdate)
  421. hr = ERROR_IO_PENDING;
  422. return hr;
  423. }
  424. LPCWSTR
  425. MapDSFlag2DSKey(
  426. DWORD Flag
  427. )
  428. {
  429. DWORD idx;
  430. LPCWSTR pKey = NULL;
  431. struct DSEntry
  432. {
  433. DWORD Flag;
  434. LPCWSTR pKey;
  435. };
  436. static DSEntry DSKeys [] = {
  437. {DS_KEY_SPOOLER , SPLDS_SPOOLER_KEY},
  438. {DS_KEY_DRIVER , SPLDS_DRIVER_KEY},
  439. {DS_KEY_USER , SPLDS_USER_KEY},
  440. {0 , NULL},
  441. };
  442. for (idx = 0; DSKeys[idx].pKey; idx++) {
  443. if(DSKeys[idx].Flag & Flag) {
  444. pKey = DSKeys[idx].pKey;
  445. }
  446. }
  447. return pKey;
  448. }
  449. HRESULT
  450. CopyRegistry2Ds(
  451. HANDLE hPrinter,
  452. DWORD Flag,
  453. IADs *pADs
  454. )
  455. {
  456. HRESULT hr = ERROR_SUCCESS;
  457. DWORD i;
  458. DWORD dwLDAPError;
  459. DWORD cbEnumValues = 0;
  460. PPRINTER_ENUM_VALUES pEnumValues = NULL;
  461. DWORD nEnumValues;
  462. DWORD dwResult;
  463. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  464. BSTR bstrADsPath = NULL;
  465. PINIPRINTER pIniPrinter = ((PSPOOL)hPrinter)->pIniPrinter;
  466. LPCWSTR pKey = MapDSFlag2DSKey(Flag);
  467. #if DBG
  468. EnterSplSem();
  469. DBGMSG(DBG_EXEC, ("Mass Publish %ws", ((PSPOOL)hPrinter)->pIniPrinter->pName));
  470. LeaveSplSem();
  471. #endif
  472. // Enumerate and Publish Key
  473. dwResult = SplEnumPrinterDataEx( hPrinter,
  474. pKey,
  475. (LPBYTE) pEnumValues,
  476. cbEnumValues,
  477. &cbEnumValues,
  478. &nEnumValues
  479. );
  480. if (dwResult != ERROR_MORE_DATA) {
  481. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  482. if( HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND && Flag != DS_KEY_SPOOLER) {
  483. goto IgnoreError;
  484. }
  485. else {
  486. goto error;
  487. }
  488. }
  489. if (!(pEnumValues = (PPRINTER_ENUM_VALUES) AllocSplMem(cbEnumValues))) {
  490. DBGMSG(DBG_EXEC,("CopyRegistry2Ds EnumPrinterDataEx FAILED: %d\n", GetLastError()));
  491. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  492. BAIL_ON_FAILURE(hr);
  493. }
  494. dwResult = SplEnumPrinterDataEx( hPrinter,
  495. pKey,
  496. (LPBYTE) pEnumValues,
  497. cbEnumValues,
  498. &cbEnumValues,
  499. &nEnumValues
  500. );
  501. if (dwResult != ERROR_SUCCESS) {
  502. DBGMSG(DBG_EXEC,("CopyRegistry2Ds 2nd EnumPrinterDataEx FAILED: %d\n", GetLastError()));
  503. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  504. if( HRESULT_CODE(hr) == ERROR_FILE_NOT_FOUND && Flag != DS_KEY_SPOOLER) {
  505. goto IgnoreError;
  506. }
  507. else {
  508. goto error;
  509. }
  510. }
  511. // Mass publish
  512. for (i = 0 ; i < nEnumValues ; ++i) {
  513. hr = PublishDsData( pADs,
  514. pEnumValues[i].pValueName,
  515. pEnumValues[i].dwType,
  516. (PBYTE) pEnumValues[i].pData);
  517. // Don't bail out on failure to put a specific property
  518. if (FAILED(hr)) {
  519. if (pEnumValues[i].pValueName) {
  520. DBGMSG(DBG_EXEC, ("Put property failed: %x, %ws\n", hr, pEnumValues[i].pValueName));
  521. } else {
  522. DBGMSG(DBG_EXEC, ("Put property failed: %x\n", hr));
  523. }
  524. } else {
  525. DBGMSG(DBG_EXEC, ("Put %ws succeeded\n", pEnumValues[i].pValueName));
  526. }
  527. }
  528. hr = pADs->SetInfo();
  529. // Mass publishing failed, now try Setting on every Put
  530. if (SUCCEEDED(hr)) {
  531. DBGMSG( DBG_EXEC, ("Mass Publishing Succeeded for %ws\n", pKey) );
  532. } else {
  533. if (HRESULT_CODE(hr) == ERROR_EXTENDED_ERROR)
  534. ADsGetLastError(&dwLDAPError, NULL, 0, NULL, 0);
  535. else
  536. dwLDAPError = hr;
  537. DBGMSG( DBG_EXEC, ("Mass Publishing FAILED for %ws: %x\n", pKey, dwLDAPError) );
  538. // Now we have to try SetInfo/GetInfo on every Put.
  539. // If the DS lacks a spooler property, then the spooler will never
  540. // be able to publish any properties. Also, we'll fail if duplicate
  541. // strings exist in REG_MULTISZ attributes.
  542. // Maybe it is better to publish what we can,
  543. // but this requires calling SetInfo() for every property, which defeats the cache.
  544. // Alternatively, we could try doing the single SetInfo once and if that fails, resort
  545. // to the SetInfo on every Put.
  546. // Additionally, when SetInfo fails it is necessary to call GetInfo on that property
  547. // in order to clear the cache's update flag for the property. When SetInfo fails
  548. // it does not clear the update flag: the update flag is only cleared when SetInfo
  549. // succeeds. Not calling GetInfo will result in SetInfo() errors on all subsequent
  550. // attempts to publish a property.
  551. // Refresh the cache
  552. hr = pADs->GetInfo();
  553. BAIL_ON_FAILURE(hr);
  554. for (i = 0 ; i < nEnumValues ; ++i) {
  555. hr = PublishDsData( pADs,
  556. pEnumValues[i].pValueName,
  557. pEnumValues[i].dwType,
  558. (PBYTE) pEnumValues[i].pData);
  559. // Don't bail out on failure to put a specific property
  560. if (FAILED(hr)) {
  561. if (pEnumValues[i].pValueName) {
  562. DBGMSG(DBG_EXEC, ("Put property failed: %x, %ws\n", hr, pEnumValues[i].pValueName));
  563. } else {
  564. DBGMSG(DBG_EXEC, ("Put property failed: %x\n", hr));
  565. }
  566. wsprintf(ErrorBuffer, L"%x", hr);
  567. hr = pADs->get_ADsPath(&bstrADsPath);
  568. if (SUCCEEDED(hr)) {
  569. SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler,
  570. gdwLogDsEvents & LOG_WARNING,
  571. MSG_CANT_PUBLISH_PROPERTY,
  572. FALSE,
  573. pEnumValues[i].pValueName ? pEnumValues[i].pValueName : L"NULLName",
  574. bstrADsPath,
  575. ErrorBuffer,
  576. NULL );
  577. SysFreeString(bstrADsPath);
  578. }
  579. } else {
  580. DBGMSG(DBG_EXEC, ("Put2 %ws succeeded\n", pEnumValues[i].pValueName));
  581. }
  582. hr = pADs->SetInfo();
  583. if (FAILED(hr)) {
  584. if (HRESULT_CODE(hr) == ERROR_EXTENDED_ERROR)
  585. ADsGetLastError(&dwLDAPError, NULL, 0, NULL, 0);
  586. if (pEnumValues[i].dwType == REG_SZ)
  587. DBGMSG(DBG_EXEC, ("PUBLISH FAILED: %ws, \"%ws\", %x\n", pEnumValues[i].pValueName,
  588. (LPWSTR) pEnumValues[i].pData,
  589. dwLDAPError));
  590. else
  591. DBGMSG(DBG_EXEC, ("PUBLISH FAILED: %ws, %x\n", pEnumValues[i].pValueName, dwLDAPError));
  592. wsprintf(ErrorBuffer, L"%x", hr);
  593. hr = pADs->get_ADsPath(&bstrADsPath);
  594. if (SUCCEEDED(hr)) {
  595. SplLogEvent( ((PSPOOL) hPrinter)->pIniSpooler,
  596. gdwLogDsEvents & LOG_WARNING,
  597. MSG_CANT_PUBLISH_PROPERTY,
  598. FALSE,
  599. pEnumValues[i].pValueName ? pEnumValues[i].pValueName : L"NULLName",
  600. bstrADsPath,
  601. ErrorBuffer,
  602. NULL );
  603. SysFreeString(bstrADsPath);
  604. }
  605. // reset cache update flag
  606. // If this fails, there's nothing more that can be done except throw our hands up
  607. // in despair. If this fails, no spooler properties will ever be published.
  608. hr = pADs->GetInfo();
  609. BAIL_ON_FAILURE(hr);
  610. }
  611. else {
  612. DBGMSG( DBG_EXEC, ("Published: %ws\n", pEnumValues[i].pValueName) );
  613. }
  614. }
  615. }
  616. IgnoreError:
  617. EnterSplSem();
  618. pIniPrinter->DsKeyUpdate &= ~Flag;
  619. if(!(pIniPrinter->DsKeyUpdate & (DS_KEY_SPOOLER | DS_KEY_DRIVER | DS_KEY_USER))) {
  620. pIniPrinter->DsKeyUpdate = 0;
  621. }
  622. LeaveSplSem();
  623. error:
  624. FreeSplMem(pEnumValues);
  625. return hr;
  626. }
  627. HRESULT
  628. PublishDsData(
  629. IADs *pADs,
  630. LPWSTR pValue,
  631. DWORD dwType,
  632. PBYTE pData
  633. )
  634. {
  635. HRESULT hr;
  636. BOOL bCreated = FALSE;
  637. switch (dwType) {
  638. case REG_SZ:
  639. hr = put_BSTR_Property(pADs, pValue, (LPWSTR) pData);
  640. break;
  641. case REG_MULTI_SZ:
  642. hr = put_MULTISZ_Property(pADs, pValue, (LPWSTR) pData);
  643. break;
  644. case REG_DWORD:
  645. hr = put_DWORD_Property(pADs, pValue, (DWORD *) pData);
  646. break;
  647. case REG_BINARY:
  648. hr = put_BOOL_Property(pADs, pValue, (BOOL *) pData);
  649. break;
  650. }
  651. return hr;
  652. }
  653. HRESULT
  654. PublishMandatoryProperties(
  655. HANDLE hPrinter,
  656. IADs *pADs
  657. )
  658. {
  659. PSPOOL pSpool = (PSPOOL) hPrinter;
  660. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  661. HRESULT hr, hrAce;
  662. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  663. #if DBG
  664. EnterSplSem();
  665. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: %ws\n", pIniPrinter->pName));
  666. LeaveSplSem();
  667. #endif
  668. hr = SetMandatoryProperties(hPrinter, pADs);
  669. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: SMP result %d\n", hr));
  670. BAIL_ON_FAILURE(hr);
  671. // New Schema has correct SD by default, so no need to call PutDSSD
  672. // hr = PutDSSD(pIniPrinter, pADs);
  673. hr = pADs->SetInfo();
  674. if (FAILED(hr)) {
  675. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: SetInfo failed %d\n", hr));
  676. wsprintf(ErrorBuffer, L"%x", hr);
  677. SplLogEvent( pSpool->pIniSpooler,
  678. gdwLogDsEvents & LOG_ERROR,
  679. MSG_CANT_PUBLISH_MANDATORY_PROPERTIES,
  680. FALSE,
  681. pIniPrinter->pszCN,
  682. pIniPrinter->pszDN,
  683. ErrorBuffer,
  684. NULL );
  685. // If SetInfo returns ERROR_BUSY it means the object already exists.
  686. // We should have avoided this conflict when we created the CN because
  687. // we check for conflicts and generate a random name. Nonetheless, an
  688. // object could have appeared between the time we generated the CN and this SetInfo,
  689. // so failing here will let us try again and we'll generate a new name if we clear the
  690. // current one.
  691. if (HRESULT_CODE(hr) == ERROR_BUSY) {
  692. FreeSplMem(pIniPrinter->pszCN);
  693. pIniPrinter->pszCN = NULL;
  694. FreeSplMem(pIniPrinter->pszDN);
  695. pIniPrinter->pszDN = NULL;
  696. }
  697. BAIL_ON_FAILURE(hr);
  698. }
  699. // Get & Set ACE if we're a cluster
  700. hrAce = AddClusterAce(pSpool, pADs);
  701. // Get & store GUID
  702. hr = GetGUID(pADs, &pIniPrinter->pszObjectGUID);
  703. //
  704. // Keep the first failure, if present
  705. //
  706. if (FAILED(hrAce)) {
  707. hr = hrAce;
  708. wsprintf(ErrorBuffer, L"%x", hrAce);
  709. SplLogEvent( pSpool->pIniSpooler,
  710. gdwLogDsEvents & LOG_ERROR,
  711. MSG_CANT_ADD_CLUSTER_ACE,
  712. FALSE,
  713. pIniPrinter->pszCN,
  714. pIniPrinter->pszDN,
  715. ErrorBuffer,
  716. NULL );
  717. DsDeletePQObject(hPrinter);
  718. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: AddClusterAce failed %d\n", hr));
  719. BAIL_ON_FAILURE(hr);
  720. }
  721. //
  722. // Unpublish if we can't add the cluster ace or get the GUID
  723. // If we can't get the GUID, unpublishing will fail, but internal flags
  724. // will be set correctly and pruner will delete the orphan
  725. //
  726. if (FAILED(hr)){
  727. DsPrinterUnpublish(hPrinter);
  728. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: GetGuid failed %d\n", hr));
  729. BAIL_ON_FAILURE(hr);
  730. } else {
  731. DBGMSG(DBG_EXEC, ("PublishMandatoryProperties: GetGuid success %ws\n",
  732. pIniPrinter->pszObjectGUID));
  733. }
  734. error:
  735. if (FAILED(hr)) {
  736. pIniPrinter->Attributes &= ~PRINTER_ATTRIBUTE_PUBLISHED;
  737. }
  738. return hr;
  739. }
  740. HRESULT
  741. SetMandatoryProperties(
  742. HANDLE hPrinter,
  743. IADs *pADs
  744. )
  745. {
  746. PSPOOL pSpool = (PSPOOL) hPrinter;
  747. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  748. WCHAR szBuffer[MAX_UNC_PRINTER_NAME + 1];
  749. DWORD dwResult;
  750. DWORD dwTemp;
  751. HRESULT hr;
  752. PWSTR pszServerName = NULL;
  753. // Get FQDN of this machine
  754. hr = GetDNSMachineName(pIniPrinter->pIniSpooler->pMachineName + 2, &pszServerName);
  755. BAIL_ON_FAILURE(hr);
  756. // UNC Printer Name
  757. // Build the UNC Printer Path
  758. wcscpy(szBuffer, L"\\\\");
  759. wcscat(szBuffer, pszServerName);
  760. wcscat(szBuffer, TEXT("\\"));
  761. wcscat(szBuffer, pIniPrinter->pName);
  762. dwResult = SplSetPrinterDataEx(
  763. hPrinter,
  764. SPLDS_SPOOLER_KEY,
  765. SPLDS_UNC_NAME,
  766. REG_SZ,
  767. (PBYTE) szBuffer,
  768. (wcslen(szBuffer) + 1)*sizeof *szBuffer);
  769. if (dwResult != ERROR_SUCCESS) {
  770. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  771. BAIL_ON_FAILURE(hr);
  772. }
  773. if (pADs) {
  774. hr = PublishDsData( pADs,
  775. SPLDS_UNC_NAME,
  776. REG_SZ,
  777. (PBYTE) szBuffer);
  778. BAIL_ON_FAILURE(hr);
  779. }
  780. // versionNumber
  781. dwTemp = DS_PRINTQUEUE_VERSION_WIN2000;
  782. dwResult = SplSetPrinterDataEx(
  783. hPrinter,
  784. SPLDS_SPOOLER_KEY,
  785. SPLDS_VERSION_NUMBER,
  786. REG_DWORD,
  787. (PBYTE) &dwTemp,
  788. sizeof dwTemp);
  789. if (dwResult != ERROR_SUCCESS) {
  790. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  791. BAIL_ON_FAILURE(hr);
  792. }
  793. if (pADs) {
  794. hr = PublishDsData( pADs,
  795. SPLDS_VERSION_NUMBER,
  796. REG_DWORD,
  797. (PBYTE) &dwTemp);
  798. BAIL_ON_FAILURE(hr);
  799. }
  800. // ServerName (without \\)
  801. dwResult = SplSetPrinterDataEx( hPrinter,
  802. SPLDS_SPOOLER_KEY,
  803. SPLDS_SERVER_NAME,
  804. REG_SZ,
  805. (PBYTE) pszServerName,
  806. (wcslen(pszServerName) + 1)*sizeof(WCHAR));
  807. if (dwResult != ERROR_SUCCESS) {
  808. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  809. BAIL_ON_FAILURE(hr);
  810. }
  811. if (pADs) {
  812. hr = PublishDsData( pADs,
  813. SPLDS_SERVER_NAME,
  814. REG_SZ,
  815. (PBYTE) pszServerName);
  816. BAIL_ON_FAILURE(hr);
  817. }
  818. // ShortServerName (without \\)
  819. dwResult = SplSetPrinterDataEx( hPrinter,
  820. SPLDS_SPOOLER_KEY,
  821. SPLDS_SHORT_SERVER_NAME,
  822. REG_SZ,
  823. (PBYTE) (pIniPrinter->pIniSpooler->pMachineName + 2),
  824. (wcslen(pIniPrinter->pIniSpooler->pMachineName + 2) + 1)*sizeof(WCHAR));
  825. if (dwResult != ERROR_SUCCESS) {
  826. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  827. BAIL_ON_FAILURE(hr);
  828. }
  829. if (pADs) {
  830. hr = PublishDsData( pADs,
  831. SPLDS_SHORT_SERVER_NAME,
  832. REG_SZ,
  833. (PBYTE) pIniPrinter->pIniSpooler->pMachineName + 2);
  834. BAIL_ON_FAILURE(hr);
  835. }
  836. // printerName
  837. dwResult = SplSetPrinterDataEx(
  838. hPrinter,
  839. SPLDS_SPOOLER_KEY,
  840. SPLDS_PRINTER_NAME,
  841. REG_SZ,
  842. (PBYTE) pIniPrinter->pName,
  843. pIniPrinter->pName ?
  844. (wcslen(pIniPrinter->pName) + 1)*sizeof *pIniPrinter->pName : 0);
  845. if (dwResult != ERROR_SUCCESS) {
  846. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  847. BAIL_ON_FAILURE(hr);
  848. }
  849. if (pADs) {
  850. hr = PublishDsData( pADs,
  851. SPLDS_PRINTER_NAME,
  852. REG_SZ,
  853. (PBYTE) pIniPrinter->pName);
  854. BAIL_ON_FAILURE(hr);
  855. }
  856. error:
  857. FreeSplStr(pszServerName);
  858. return hr;
  859. }
  860. // UpdateDsSpoolerKey - writes IniPrinter to registry
  861. VOID
  862. UpdateDsSpoolerKey(
  863. HANDLE hPrinter,
  864. DWORD dwVector
  865. )
  866. {
  867. PSPOOL pSpool = (PSPOOL) hPrinter;
  868. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  869. DWORD i, cbBytes, dwTemp;
  870. LPWSTR pString = NULL, pStr;
  871. DWORD dwResult = ERROR_SUCCESS;
  872. BOOL bSet = FALSE;
  873. BYTE Byte;
  874. PWSTR pszUrl = NULL;
  875. SplInSem();
  876. // *** PRINTER_INFO_2 properties ***
  877. // Description
  878. if (dwVector & BIT(I_PRINTER_COMMENT)) {
  879. dwResult = SplSetPrinterDataEx(
  880. hPrinter,
  881. SPLDS_SPOOLER_KEY,
  882. SPLDS_DESCRIPTION,
  883. REG_SZ,
  884. (PBYTE) pIniPrinter->pComment,
  885. pIniPrinter->pComment ?
  886. (wcslen(pIniPrinter->pComment) + 1)*sizeof *pIniPrinter->pComment : 0);
  887. bSet = TRUE;
  888. #if DBG
  889. if (dwResult != ERROR_SUCCESS)
  890. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Description, %x\n", dwResult) );
  891. #endif
  892. }
  893. // Driver-Name
  894. if (dwVector & BIT(I_PRINTER_DRIVER_NAME)) {
  895. dwResult = SplSetPrinterDataEx(
  896. hPrinter,
  897. SPLDS_SPOOLER_KEY,
  898. SPLDS_DRIVER_NAME,
  899. REG_SZ,
  900. (PBYTE) pIniPrinter->pIniDriver->pName,
  901. pIniPrinter->pIniDriver->pName ?
  902. (wcslen(pIniPrinter->pIniDriver->pName) + 1)*sizeof *pIniPrinter->pIniDriver->pName : 0);
  903. bSet = TRUE;
  904. #if DBG
  905. if (dwResult != ERROR_SUCCESS)
  906. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: DriverName, %x\n", dwResult) );
  907. #endif
  908. }
  909. // Location
  910. if (dwVector & BIT(I_PRINTER_LOCATION)) {
  911. dwResult = SplSetPrinterDataEx(
  912. hPrinter,
  913. SPLDS_SPOOLER_KEY,
  914. SPLDS_LOCATION,
  915. REG_SZ,
  916. (PBYTE) pIniPrinter->pLocation,
  917. pIniPrinter->pLocation ?
  918. (wcslen(pIniPrinter->pLocation) + 1)*sizeof *pIniPrinter->pLocation : 0);
  919. bSet = TRUE;
  920. #if DBG
  921. if (dwResult != ERROR_SUCCESS)
  922. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Location, %x\n", dwResult) );
  923. #endif
  924. }
  925. // portName
  926. if (dwVector & BIT(I_PRINTER_PORT_NAME)) {
  927. for(i = cbBytes = 0 ; i < pIniPrinter->cPorts ; ++i)
  928. cbBytes += (wcslen(pIniPrinter->ppIniPorts[i]->pName) + 1)*sizeof(WCHAR);
  929. cbBytes += sizeof(WCHAR); // final NULL of MULTI_SZ
  930. if (!(pString = (LPWSTR) AllocSplMem(cbBytes))) {
  931. dwResult = GetLastError();
  932. goto error;
  933. }
  934. for(i = 0, pStr = pString ; i < pIniPrinter->cPorts ; ++i, pStr += wcslen(pStr) + 1)
  935. wcscpy(pStr, pIniPrinter->ppIniPorts[i]->pName);
  936. dwResult = SplSetPrinterDataEx(
  937. hPrinter,
  938. SPLDS_SPOOLER_KEY,
  939. SPLDS_PORT_NAME,
  940. REG_MULTI_SZ,
  941. (PBYTE) pString,
  942. cbBytes);
  943. bSet = TRUE;
  944. #if DBG
  945. if (dwResult != ERROR_SUCCESS)
  946. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PortName, %x\n", dwResult) );
  947. #endif
  948. }
  949. // startTime
  950. if (dwVector & BIT(I_PRINTER_START_TIME)) {
  951. dwResult = SplSetPrinterDataEx(
  952. hPrinter,
  953. SPLDS_SPOOLER_KEY,
  954. SPLDS_PRINT_START_TIME,
  955. REG_DWORD,
  956. (PBYTE) &pIniPrinter->StartTime,
  957. sizeof pIniPrinter->StartTime);
  958. bSet = TRUE;
  959. #if DBG
  960. if (dwResult != ERROR_SUCCESS)
  961. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: StartTime, %x\n", dwResult) );
  962. #endif
  963. }
  964. // endTime
  965. if (dwVector & BIT(I_PRINTER_UNTIL_TIME)) {
  966. dwResult = SplSetPrinterDataEx(
  967. hPrinter,
  968. SPLDS_SPOOLER_KEY,
  969. SPLDS_PRINT_END_TIME,
  970. REG_DWORD,
  971. (PBYTE) &pIniPrinter->UntilTime,
  972. sizeof pIniPrinter->UntilTime);
  973. bSet = TRUE;
  974. #if DBG
  975. if (dwResult != ERROR_SUCCESS)
  976. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: EndTime, %x\n", dwResult) );
  977. #endif
  978. }
  979. // printerName
  980. if (dwVector & BIT(I_PRINTER_PRINTER_NAME)) {
  981. dwResult = SplSetPrinterDataEx(
  982. hPrinter,
  983. SPLDS_SPOOLER_KEY,
  984. SPLDS_PRINTER_NAME,
  985. REG_SZ,
  986. (PBYTE) pIniPrinter->pName,
  987. pIniPrinter->pName ?
  988. (wcslen(pIniPrinter->pName) + 1)*sizeof *pIniPrinter->pName : 0);
  989. bSet = TRUE;
  990. #if DBG
  991. if (dwResult != ERROR_SUCCESS)
  992. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PrinterName, %x\n", dwResult) );
  993. #endif
  994. }
  995. // keepPrintedJobs
  996. if (dwVector & BIT(I_PRINTER_ATTRIBUTES)) {
  997. Byte = (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS) ? 1 : 0;
  998. dwResult = SplSetPrinterDataEx(
  999. hPrinter,
  1000. SPLDS_SPOOLER_KEY,
  1001. SPLDS_PRINT_KEEP_PRINTED_JOBS,
  1002. REG_BINARY,
  1003. &Byte,
  1004. sizeof Byte);
  1005. bSet = TRUE;
  1006. #if DBG
  1007. if (dwResult != ERROR_SUCCESS)
  1008. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: KeepPrintedJobs, %x\n", dwResult) );
  1009. #endif
  1010. }
  1011. // printSeparatorFile
  1012. if (dwVector & BIT(I_PRINTER_SEPFILE)) {
  1013. dwResult = SplSetPrinterDataEx(
  1014. hPrinter,
  1015. SPLDS_SPOOLER_KEY,
  1016. SPLDS_PRINT_SEPARATOR_FILE,
  1017. REG_SZ,
  1018. (PBYTE) pIniPrinter->pSepFile,
  1019. pIniPrinter->pSepFile ?
  1020. (wcslen(pIniPrinter->pSepFile) + 1)*sizeof *pIniPrinter->pSepFile : 0);
  1021. bSet = TRUE;
  1022. #if DBG
  1023. if (dwResult != ERROR_SUCCESS)
  1024. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: SeparatorFile, %x\n", dwResult) );
  1025. #endif
  1026. }
  1027. // printShareName
  1028. if (dwVector & BIT(I_PRINTER_SHARE_NAME)) {
  1029. dwResult = SplSetPrinterDataEx(
  1030. hPrinter,
  1031. SPLDS_SPOOLER_KEY,
  1032. SPLDS_PRINT_SHARE_NAME,
  1033. REG_SZ,
  1034. (PBYTE) pIniPrinter->pShareName,
  1035. pIniPrinter->pShareName ?
  1036. (wcslen(pIniPrinter->pShareName) + 1)*sizeof *pIniPrinter->pShareName : 0);
  1037. bSet = TRUE;
  1038. #if DBG
  1039. if (dwResult != ERROR_SUCCESS)
  1040. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: ShareName, %x\n", dwResult) );
  1041. #endif
  1042. }
  1043. // printSpooling
  1044. if (dwVector & BIT(I_PRINTER_ATTRIBUTES)) {
  1045. if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
  1046. pStr = L"PrintDirect";
  1047. } else if (pIniPrinter->Attributes & PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST) {
  1048. pStr = L"PrintAfterSpooled";
  1049. } else {
  1050. pStr = L"PrintWhileSpooling";
  1051. }
  1052. dwResult = SplSetPrinterDataEx(
  1053. hPrinter,
  1054. SPLDS_SPOOLER_KEY,
  1055. SPLDS_PRINT_SPOOLING,
  1056. REG_SZ,
  1057. (PBYTE) pStr,
  1058. (wcslen(pStr) + 1)*sizeof *pStr);
  1059. bSet = TRUE;
  1060. #if DBG
  1061. if (dwResult != ERROR_SUCCESS)
  1062. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: PrintSpooling, %x\n", dwResult) );
  1063. #endif
  1064. }
  1065. // priority
  1066. if (dwVector & BIT(I_PRINTER_PRIORITY)) {
  1067. dwResult = SplSetPrinterDataEx(
  1068. hPrinter,
  1069. SPLDS_SPOOLER_KEY,
  1070. SPLDS_PRIORITY,
  1071. REG_DWORD,
  1072. (PBYTE) &pIniPrinter->Priority,
  1073. sizeof pIniPrinter->Priority);
  1074. bSet = TRUE;
  1075. #if DBG
  1076. if (dwResult != ERROR_SUCCESS)
  1077. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Priority, %x\n", dwResult) );
  1078. #endif
  1079. }
  1080. // Non-Info2 properties
  1081. if (bSet) {
  1082. SetMandatoryProperties(hPrinter, NULL);
  1083. // URL
  1084. if (pszUrl = GetPrinterUrl(pSpool)) {
  1085. dwResult = SplSetPrinterDataEx(
  1086. hPrinter,
  1087. SPLDS_SPOOLER_KEY,
  1088. SPLDS_URL,
  1089. REG_SZ,
  1090. (PBYTE) pszUrl,
  1091. (wcslen(pszUrl) + 1)*sizeof *pszUrl);
  1092. #if DBG
  1093. if (dwResult != ERROR_SUCCESS)
  1094. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: URL, %x\n", dwResult) );
  1095. #endif
  1096. }
  1097. // Immortal
  1098. dwResult = ImmortalPolicy();
  1099. dwResult = SplSetPrinterDataEx(
  1100. hPrinter,
  1101. SPLDS_SPOOLER_KEY,
  1102. SPLDS_FLAGS,
  1103. REG_DWORD,
  1104. (PBYTE) &dwResult,
  1105. sizeof(dwResult));
  1106. #if DBG
  1107. if (dwResult != ERROR_SUCCESS)
  1108. DBGMSG( DBG_WARNING, ("UpdateDsSpoolerKey: Immortal, %x\n", dwResult) );
  1109. #endif
  1110. }
  1111. error:
  1112. FreeSplMem(pszUrl);
  1113. FreeSplMem(pString);
  1114. }
  1115. VOID
  1116. UpdateDsDriverKey(
  1117. HANDLE hPrinter
  1118. )
  1119. {
  1120. PSPOOL pSpool = (PSPOOL) hPrinter;
  1121. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  1122. DWORD i, cbBytes;
  1123. WCHAR szBuffer[33]; // Used by ltow
  1124. LPWSTR pString, pStr;
  1125. BOOL bResult;
  1126. DWORD dwResult;
  1127. BYTE Byte;
  1128. LPWSTR pOutput = NULL, pTemp = NULL, pTemp1 = NULL;
  1129. DWORD cOutputBytes, cTempBytes;
  1130. POINTS point;
  1131. DWORD dwServerMajorVersion, dwServerMinorVersion;
  1132. DWORD cbNeeded;
  1133. HANDLE hModule = FALSE;
  1134. PDEVCAP pDevCap;
  1135. PSPLDEVCAP pSplDevCaps;
  1136. HANDLE hDevCapPrinter = NULL;
  1137. WCHAR pPrinterName[MAX_UNC_PRINTER_NAME];
  1138. WCHAR pBuf[100];
  1139. BOOL bInSplSem = TRUE;
  1140. DWORD dwTemp, dwPrintRate, dwPrintRateUnit, dwPrintPPM;
  1141. // *** DeviceCapability properties ***
  1142. SplInSem();
  1143. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: %ws\n", pIniPrinter->pName));
  1144. pOutput = (LPWSTR) AllocSplMem(cOutputBytes = 200);
  1145. if (!pOutput)
  1146. goto error;
  1147. pTemp = (LPWSTR) AllocSplMem(cTempBytes = 200);
  1148. if (!pTemp)
  1149. goto error;
  1150. // Get & Load Driver
  1151. PINIENVIRONMENT pIniEnvironment;
  1152. pIniEnvironment = FindEnvironment(szEnvironment, pSpool->pIniSpooler);
  1153. if (pIniEnvironment) {
  1154. WCHAR szConfigFile[INTERNET_MAX_HOST_NAME_LENGTH + MAX_PATH + 1];
  1155. PINIVERSION pIniVersion;
  1156. pIniVersion = FindVersionForDriver(pIniEnvironment, pIniPrinter->pIniDriver);
  1157. if (!pIniVersion)
  1158. goto error;
  1159. if( !(i = GetDriverVersionDirectory(szConfigFile,
  1160. (DWORD)(COUNTOF(szConfigFile) - wcslen(pIniPrinter->pIniDriver->pConfigFile) - 1),
  1161. pSpool->pIniSpooler,
  1162. pIniEnvironment,
  1163. pIniVersion,
  1164. pIniPrinter->pIniDriver,
  1165. NULL)) ) {
  1166. goto error;
  1167. }
  1168. szConfigFile[i++] = L'\\';
  1169. wcscpy(szConfigFile + i, pIniPrinter->pIniDriver->pConfigFile);
  1170. if (!(hModule = LoadLibrary(szConfigFile))) {
  1171. goto error;
  1172. }
  1173. if (!(pDevCap = reinterpret_cast<PDEVCAP>(GetProcAddress(hModule, "DrvDeviceCapabilities")))) {
  1174. goto error;
  1175. }
  1176. pSplDevCaps = reinterpret_cast<PSPLDEVCAP>(GetProcAddress(hModule, (LPCSTR) MAKELPARAM(254, 0)));
  1177. } else {
  1178. goto error;
  1179. }
  1180. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: driver found\n"));
  1181. INCPRINTERREF(pIniPrinter);
  1182. // We need to use UNC format so we go to the right pIniSpooler.
  1183. // For instance, we won't find the printer if it's in the cluster pIniSpooler and we don't use
  1184. // the virtual cluster name (\\server\printer).
  1185. wsprintf(pPrinterName, L"%s\\%s", pIniPrinter->pIniSpooler->pMachineName, pIniPrinter->pName);
  1186. LeaveSplSem();
  1187. bInSplSem = FALSE;
  1188. if (!(*pfnOpenPrinter)(pPrinterName, &hDevCapPrinter, NULL)) {
  1189. dwResult = GetLastError();
  1190. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: OpenPrinter failed %d\n",
  1191. dwResult));
  1192. goto error;
  1193. }
  1194. // printBinNames
  1195. if (!DevCapMultiSz( hPrinter,
  1196. hDevCapPrinter,
  1197. pDevCap,
  1198. NULL,
  1199. pPrinterName,
  1200. DC_BINNAMES,
  1201. 24,
  1202. SPLDS_PRINT_BIN_NAMES)) {
  1203. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_BINNAMES failed %d\n", GetLastError()));
  1204. }
  1205. // printCollate (awaiting DC_COLLATE)
  1206. _try {
  1207. dwResult = (*pDevCap)( hDevCapPrinter,
  1208. pPrinterName,
  1209. DC_COLLATE,
  1210. NULL,
  1211. NULL);
  1212. } _except(1) {
  1213. SetLastError(GetExceptionCode());
  1214. dwResult = GDI_ERROR;
  1215. }
  1216. if (dwResult != GDI_ERROR) {
  1217. dwResult = SplSetPrinterDataEx(
  1218. hPrinter,
  1219. SPLDS_DRIVER_KEY,
  1220. SPLDS_PRINT_COLLATE,
  1221. REG_BINARY,
  1222. (PBYTE) &dwResult,
  1223. sizeof(BYTE));
  1224. #if DBG
  1225. if (dwResult != ERROR_SUCCESS)
  1226. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Collate, %x\n", dwResult) );
  1227. #endif
  1228. } else {
  1229. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_COLLATE failed %d\n", GetLastError()));
  1230. }
  1231. // printColor
  1232. _try {
  1233. dwResult = (*pDevCap)( hDevCapPrinter,
  1234. pPrinterName,
  1235. DC_COLORDEVICE,
  1236. NULL,
  1237. NULL);
  1238. } _except(1) {
  1239. SetLastError(GetExceptionCode());
  1240. dwResult = GDI_ERROR;
  1241. }
  1242. if (dwResult == GDI_ERROR) {
  1243. // Try alternative method
  1244. dwResult = ThisIsAColorPrinter(pIniPrinter->pName);
  1245. } else {
  1246. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_COLORDEVICE failed %d\n", GetLastError()));
  1247. }
  1248. dwResult = SplSetPrinterDataEx(
  1249. hPrinter,
  1250. SPLDS_DRIVER_KEY,
  1251. SPLDS_PRINT_COLOR,
  1252. REG_BINARY,
  1253. (PBYTE) &dwResult,
  1254. sizeof(BYTE));
  1255. #if DBG
  1256. if (dwResult != ERROR_SUCCESS)
  1257. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Color, %x\n", dwResult) );
  1258. #endif
  1259. // printDuplexSupported
  1260. _try {
  1261. dwResult = (*pDevCap)( hDevCapPrinter,
  1262. pPrinterName,
  1263. DC_DUPLEX,
  1264. NULL,
  1265. NULL);
  1266. } _except(1) {
  1267. SetLastError(GetExceptionCode());
  1268. dwResult = GDI_ERROR;
  1269. }
  1270. if (dwResult != GDI_ERROR) {
  1271. dwResult = !!dwResult;
  1272. dwResult = SplSetPrinterDataEx(
  1273. hPrinter,
  1274. SPLDS_DRIVER_KEY,
  1275. SPLDS_PRINT_DUPLEX_SUPPORTED,
  1276. REG_BINARY,
  1277. (PBYTE) &dwResult,
  1278. sizeof(BYTE));
  1279. #if DBG
  1280. if (dwResult != ERROR_SUCCESS)
  1281. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Duplex, %x\n", dwResult) );
  1282. #endif
  1283. } else {
  1284. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_DUPLEX failed %d\n", GetLastError()));
  1285. }
  1286. // printStaplingSupported
  1287. _try {
  1288. dwResult = (*pDevCap)( hDevCapPrinter,
  1289. pPrinterName,
  1290. DC_STAPLE,
  1291. NULL,
  1292. NULL);
  1293. } _except(1) {
  1294. SetLastError(GetExceptionCode());
  1295. dwResult = GDI_ERROR;
  1296. }
  1297. if (dwResult != GDI_ERROR) {
  1298. dwResult = SplSetPrinterDataEx(
  1299. hPrinter,
  1300. SPLDS_DRIVER_KEY,
  1301. SPLDS_PRINT_STAPLING_SUPPORTED,
  1302. REG_BINARY,
  1303. (PBYTE) &dwResult,
  1304. sizeof(BYTE));
  1305. #if DBG
  1306. if (dwResult != ERROR_SUCCESS)
  1307. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Duplex, %x\n", dwResult) );
  1308. #endif
  1309. } else {
  1310. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_STAPLE failed %d\n", GetLastError()));
  1311. }
  1312. // printMaxXExtent & printMaxYExtent
  1313. _try {
  1314. dwResult = (*pDevCap)( hDevCapPrinter,
  1315. pPrinterName,
  1316. DC_MAXEXTENT,
  1317. NULL,
  1318. NULL);
  1319. } _except(1) {
  1320. SetLastError(GetExceptionCode());
  1321. dwResult = GDI_ERROR;
  1322. }
  1323. if (dwResult != GDI_ERROR) {
  1324. *((DWORD *) &point) = dwResult;
  1325. dwTemp = (DWORD) point.x;
  1326. dwResult = SplSetPrinterDataEx(
  1327. hPrinter,
  1328. SPLDS_DRIVER_KEY,
  1329. SPLDS_PRINT_MAX_X_EXTENT,
  1330. REG_DWORD,
  1331. (PBYTE) &dwTemp,
  1332. sizeof(DWORD));
  1333. #if DBG
  1334. if (dwResult != ERROR_SUCCESS)
  1335. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MaxXExtent, %x\n", dwResult) );
  1336. #endif
  1337. dwTemp = (DWORD) point.y;
  1338. dwResult = SplSetPrinterDataEx(
  1339. hPrinter,
  1340. SPLDS_DRIVER_KEY,
  1341. SPLDS_PRINT_MAX_Y_EXTENT,
  1342. REG_DWORD,
  1343. (PBYTE) &dwTemp,
  1344. sizeof(DWORD));
  1345. #if DBG
  1346. if (dwResult != ERROR_SUCCESS)
  1347. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MaxYExtent, %x\n", dwResult) );
  1348. #endif
  1349. } else {
  1350. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MAXEXTENT failed %d\n", GetLastError()));
  1351. }
  1352. // printMinXExtent & printMinYExtent
  1353. _try {
  1354. dwResult = (*pDevCap)( hDevCapPrinter,
  1355. pPrinterName,
  1356. DC_MINEXTENT,
  1357. NULL,
  1358. NULL);
  1359. } _except(1) {
  1360. SetLastError(GetExceptionCode());
  1361. dwResult = GDI_ERROR;
  1362. }
  1363. if (dwResult != GDI_ERROR) {
  1364. *((DWORD *) &point) = dwResult;
  1365. dwTemp = (DWORD) point.x;
  1366. dwResult = SplSetPrinterDataEx(
  1367. hPrinter,
  1368. SPLDS_DRIVER_KEY,
  1369. SPLDS_PRINT_MIN_X_EXTENT,
  1370. REG_DWORD,
  1371. (PBYTE) &dwTemp,
  1372. sizeof(DWORD));
  1373. #if DBG
  1374. if (dwResult != ERROR_SUCCESS)
  1375. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MinXExtent, %x\n", dwResult) );
  1376. #endif
  1377. dwTemp = (DWORD) point.y;
  1378. dwResult = SplSetPrinterDataEx(
  1379. hPrinter,
  1380. SPLDS_DRIVER_KEY,
  1381. SPLDS_PRINT_MIN_Y_EXTENT,
  1382. REG_DWORD,
  1383. (PBYTE) &dwTemp,
  1384. sizeof(DWORD));
  1385. #if DBG
  1386. if (dwResult != ERROR_SUCCESS)
  1387. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: MinYExtent, %x\n", dwResult) );
  1388. #endif
  1389. } else {
  1390. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MINEXTENT failed %d\n", GetLastError()));
  1391. }
  1392. // printMediaSupported - Not part of printQueue, but is in Schema
  1393. if (!DevCapMultiSz( hPrinter,
  1394. hDevCapPrinter,
  1395. pDevCap,
  1396. pSplDevCaps,
  1397. pPrinterName,
  1398. DC_PAPERNAMES,
  1399. 64,
  1400. SPLDS_PRINT_MEDIA_SUPPORTED)) {
  1401. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PAPERNAMES failed %d\n", GetLastError()));
  1402. }
  1403. // printMediaReady
  1404. if (!DevCapMultiSz( hPrinter,
  1405. hDevCapPrinter,
  1406. pDevCap,
  1407. pSplDevCaps,
  1408. pPrinterName,
  1409. DC_MEDIAREADY,
  1410. 64,
  1411. SPLDS_PRINT_MEDIA_READY)) {
  1412. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_MEDIAREADY failed %d\n", GetLastError()));
  1413. }
  1414. // printNumberUp
  1415. _try {
  1416. dwResult = (*pDevCap)( hDevCapPrinter,
  1417. pPrinterName,
  1418. DC_NUP,
  1419. NULL,
  1420. NULL);
  1421. } _except(1) {
  1422. SetLastError(GetExceptionCode());
  1423. dwResult = GDI_ERROR;
  1424. }
  1425. if (dwResult != GDI_ERROR) {
  1426. dwResult = SplSetPrinterDataEx(
  1427. hPrinter,
  1428. SPLDS_DRIVER_KEY,
  1429. SPLDS_PRINT_NUMBER_UP,
  1430. REG_DWORD,
  1431. (PBYTE) &dwResult,
  1432. sizeof(DWORD));
  1433. #if DBG
  1434. if (dwResult != ERROR_SUCCESS)
  1435. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: NumberUp, %x\n", dwResult) );
  1436. #endif
  1437. } else {
  1438. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_NUP failed %d\n", GetLastError()));
  1439. }
  1440. // printMemory
  1441. _try {
  1442. dwResult = (*pDevCap)( hDevCapPrinter,
  1443. pPrinterName,
  1444. DC_PRINTERMEM,
  1445. NULL,
  1446. NULL);
  1447. } _except(1) {
  1448. SetLastError(GetExceptionCode());
  1449. dwResult = GDI_ERROR;
  1450. }
  1451. if (dwResult != GDI_ERROR) {
  1452. dwResult = SplSetPrinterDataEx(
  1453. hPrinter,
  1454. SPLDS_DRIVER_KEY,
  1455. SPLDS_PRINT_MEMORY,
  1456. REG_DWORD,
  1457. (PBYTE) &dwResult,
  1458. sizeof(DWORD));
  1459. #if DBG
  1460. if (dwResult != ERROR_SUCCESS)
  1461. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: printMemory, %x\n", dwResult) );
  1462. #endif
  1463. } else {
  1464. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTERMEM failed %d\n", GetLastError()));
  1465. }
  1466. // printOrientationsSupported
  1467. _try {
  1468. dwResult = (*pDevCap)( hDevCapPrinter,
  1469. pPrinterName,
  1470. DC_ORIENTATION,
  1471. NULL,
  1472. NULL);
  1473. } _except(1) {
  1474. SetLastError(GetExceptionCode());
  1475. dwResult = GDI_ERROR;
  1476. }
  1477. if (dwResult != GDI_ERROR) {
  1478. if (dwResult == 90 || dwResult == 270) {
  1479. wcscpy(pBuf, L"PORTRAIT");
  1480. wcscpy(pStr = pBuf + wcslen(pBuf) + 1, L"LANDSCAPE");
  1481. }
  1482. else {
  1483. wcscpy(pStr = pBuf, L"PORTRAIT");
  1484. }
  1485. pStr += wcslen(pStr) + 1;
  1486. *pStr++ = L'\0';
  1487. dwResult = SplSetPrinterDataEx(
  1488. hPrinter,
  1489. SPLDS_DRIVER_KEY,
  1490. SPLDS_PRINT_ORIENTATIONS_SUPPORTED,
  1491. REG_MULTI_SZ,
  1492. (PBYTE) pBuf,
  1493. (DWORD) ((ULONG_PTR) pStr - (ULONG_PTR) pBuf));
  1494. #if DBG
  1495. if (dwResult != ERROR_SUCCESS)
  1496. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Orientations, %x\n", dwResult) );
  1497. #endif
  1498. } else {
  1499. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_ORIENTATION failed %d\n", GetLastError()));
  1500. }
  1501. // printMaxResolutionSupported
  1502. _try {
  1503. dwResult = (*pDevCap)( hDevCapPrinter,
  1504. pPrinterName,
  1505. DC_ENUMRESOLUTIONS,
  1506. NULL,
  1507. NULL);
  1508. } _except(1) {
  1509. SetLastError(GetExceptionCode());
  1510. dwResult = GDI_ERROR;
  1511. }
  1512. if (dwResult != GDI_ERROR) {
  1513. if (cOutputBytes < dwResult*2*sizeof(DWORD)) {
  1514. if(!(pTemp1 = (LPWSTR) ReallocSplMem(pOutput, 0, cOutputBytes = dwResult*2*sizeof(DWORD))))
  1515. goto error;
  1516. pOutput = pTemp1;
  1517. }
  1518. _try {
  1519. dwResult = (*pDevCap)( hDevCapPrinter,
  1520. pPrinterName,
  1521. DC_ENUMRESOLUTIONS,
  1522. pOutput,
  1523. NULL);
  1524. } _except(1) {
  1525. SetLastError(GetExceptionCode());
  1526. dwResult = GDI_ERROR;
  1527. }
  1528. if (dwResult != GDI_ERROR && dwResult > 0) {
  1529. // Find the maximum resolution: we have dwResult*2 resolutions to check
  1530. _try {
  1531. for(i = dwTemp = 0 ; i < dwResult*2 ; ++i) {
  1532. if (((DWORD *) pOutput)[i] > dwTemp)
  1533. dwTemp = ((DWORD *) pOutput)[i];
  1534. }
  1535. dwResult = SplSetPrinterDataEx(
  1536. hPrinter,
  1537. SPLDS_DRIVER_KEY,
  1538. SPLDS_PRINT_MAX_RESOLUTION_SUPPORTED,
  1539. REG_DWORD,
  1540. (PBYTE) &dwTemp,
  1541. sizeof(DWORD));
  1542. } _except(1) {
  1543. SetLastError(dwResult = GetExceptionCode());
  1544. }
  1545. #if DBG
  1546. if (dwResult != ERROR_SUCCESS)
  1547. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Resolution, %x\n", dwResult) );
  1548. #endif
  1549. }
  1550. } else {
  1551. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_ENUMRESOLUTIONS failed %d\n", GetLastError()));
  1552. }
  1553. // printLanguage
  1554. if (!DevCapMultiSz( hPrinter,
  1555. hDevCapPrinter,
  1556. pDevCap,
  1557. NULL,
  1558. pPrinterName,
  1559. DC_PERSONALITY,
  1560. 32,
  1561. SPLDS_PRINT_LANGUAGE)) {
  1562. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PERSONALITY failed %d\n", GetLastError()));
  1563. }
  1564. // printRate
  1565. // NOTE: If PrintRate is 0, no value is published
  1566. _try {
  1567. dwResult = (*pDevCap)( hDevCapPrinter,
  1568. pPrinterName,
  1569. DC_PRINTRATE,
  1570. NULL,
  1571. NULL);
  1572. } _except(1) {
  1573. SetLastError(GetExceptionCode());
  1574. dwResult = GDI_ERROR;
  1575. }
  1576. dwPrintRate = dwResult ? dwResult : GDI_ERROR;
  1577. if (dwPrintRate != GDI_ERROR) {
  1578. dwResult = SplSetPrinterDataEx(
  1579. hPrinter,
  1580. SPLDS_DRIVER_KEY,
  1581. SPLDS_PRINT_RATE,
  1582. REG_DWORD,
  1583. (PBYTE) &dwPrintRate,
  1584. sizeof(DWORD));
  1585. #if DBG
  1586. if (dwResult != ERROR_SUCCESS)
  1587. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: PrintRate, %x\n", dwResult) );
  1588. #endif
  1589. } else {
  1590. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTRATE failed %d\n", GetLastError()));
  1591. }
  1592. // printRateUnit
  1593. _try {
  1594. dwResult = (*pDevCap)( hDevCapPrinter,
  1595. pPrinterName,
  1596. DC_PRINTRATEUNIT,
  1597. NULL,
  1598. NULL);
  1599. } _except(1) {
  1600. SetLastError(GetExceptionCode());
  1601. dwResult = GDI_ERROR;
  1602. }
  1603. dwPrintRateUnit = dwResult;
  1604. //
  1605. // If the capability isn't supported, set printRateUnit to empty string.
  1606. //
  1607. switch (dwPrintRateUnit) {
  1608. case PRINTRATEUNIT_PPM:
  1609. pStr = L"PagesPerMinute";
  1610. break;
  1611. case PRINTRATEUNIT_CPS:
  1612. pStr = L"CharactersPerSecond";
  1613. break;
  1614. case PRINTRATEUNIT_LPM:
  1615. pStr = L"LinesPerMinute";
  1616. break;
  1617. case PRINTRATEUNIT_IPM:
  1618. pStr = L"InchesPerMinute";
  1619. break;
  1620. default:
  1621. pStr = L"";
  1622. break;
  1623. }
  1624. if (pStr) {
  1625. dwResult = SplSetPrinterDataEx(
  1626. hPrinter,
  1627. SPLDS_DRIVER_KEY,
  1628. SPLDS_PRINT_RATE_UNIT,
  1629. REG_SZ,
  1630. (PBYTE) pStr,
  1631. (wcslen(pStr) + 1)*sizeof *pStr);
  1632. #if DBG
  1633. if (dwResult != ERROR_SUCCESS)
  1634. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: PrintRateUnit, %x\n", dwResult) );
  1635. #endif
  1636. } else {
  1637. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_PRINTRATEUNIT no unit %d\n", dwPrintRateUnit ));
  1638. }
  1639. // printPagesPerMinute
  1640. // DevCap returns 0 if there is no entry in GPD
  1641. _try {
  1642. dwResult = (*pDevCap)( hDevCapPrinter,
  1643. pPrinterName,
  1644. DC_PRINTRATEPPM,
  1645. NULL,
  1646. NULL);
  1647. } _except(1) {
  1648. SetLastError(GetExceptionCode());
  1649. dwResult = GDI_ERROR;
  1650. }
  1651. if (dwResult == GDI_ERROR)
  1652. dwResult = 0;
  1653. dwPrintPPM = dwResult;
  1654. // If dwPrintPPM == 0, then calculate PPM from PrintRate
  1655. if (dwPrintPPM == 0) {
  1656. if (dwPrintRate == GDI_ERROR) {
  1657. dwPrintPPM = GDI_ERROR;
  1658. } else {
  1659. switch (dwPrintRateUnit) {
  1660. case PRINTRATEUNIT_PPM:
  1661. dwPrintPPM = dwPrintRate;
  1662. break;
  1663. case PRINTRATEUNIT_CPS:
  1664. case PRINTRATEUNIT_LPM:
  1665. dwPrintPPM = dwPrintRate/PPM_FACTOR;
  1666. if (dwPrintPPM == 0)
  1667. dwPrintPPM = 1; // min PPM is 1
  1668. break;
  1669. default:
  1670. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: PRINTRATEUNIT not found %d\n",
  1671. dwPrintRateUnit));
  1672. dwPrintPPM = GDI_ERROR;
  1673. break;
  1674. }
  1675. }
  1676. }
  1677. if (dwPrintPPM != GDI_ERROR) {
  1678. dwResult = SplSetPrinterDataEx(
  1679. hPrinter,
  1680. SPLDS_DRIVER_KEY,
  1681. SPLDS_PRINT_PAGES_PER_MINUTE,
  1682. REG_DWORD,
  1683. (PBYTE) &dwPrintPPM,
  1684. sizeof(DWORD));
  1685. #if DBG
  1686. if (dwResult != ERROR_SUCCESS)
  1687. DBGMSG(DBG_WARNING, ("UpdateDsDriverKey: PrintPagesPerMinute, %x\n", dwResult));
  1688. #endif
  1689. } else {
  1690. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: PPM failed %d\n", GetLastError()));
  1691. }
  1692. // printDriverVersion
  1693. _try {
  1694. dwResult = (*pDevCap)( hDevCapPrinter,
  1695. pPrinterName,
  1696. DC_VERSION,
  1697. NULL,
  1698. NULL);
  1699. } _except(1) {
  1700. SetLastError(GetExceptionCode());
  1701. dwResult = GDI_ERROR;
  1702. }
  1703. if (dwResult != GDI_ERROR) {
  1704. dwResult = SplSetPrinterDataEx(
  1705. hPrinter,
  1706. SPLDS_DRIVER_KEY,
  1707. SPLDS_DRIVER_VERSION,
  1708. REG_DWORD,
  1709. (PBYTE) &dwResult,
  1710. sizeof(DWORD));
  1711. #if DBG
  1712. if (dwResult != ERROR_SUCCESS)
  1713. DBGMSG( DBG_WARNING, ("UpdateDsDriverKey: Driver Version, %x\n", dwResult) );
  1714. #endif
  1715. } else {
  1716. DBGMSG( DBG_EXEC, ("UpdateDsDriverKey: DC_VERSION failed %d\n", GetLastError()));
  1717. }
  1718. error:
  1719. if (hDevCapPrinter)
  1720. (*pfnClosePrinter)(hDevCapPrinter);
  1721. if (!bInSplSem) {
  1722. EnterSplSem();
  1723. DECPRINTERREF(pIniPrinter);
  1724. }
  1725. if (hModule)
  1726. FreeLibrary(hModule);
  1727. FreeSplMem(pOutput);
  1728. FreeSplMem(pTemp);
  1729. }
  1730. BOOL
  1731. DevCapMultiSz(
  1732. HANDLE hPrinter,
  1733. HANDLE hDevCapPrinter,
  1734. PDEVCAP pDevCap,
  1735. PSPLDEVCAP pSplDevCap,
  1736. PWSTR pszPrinterName,
  1737. WORD fwCapability,
  1738. DWORD dwElementBytes,
  1739. PWSTR pszRegValue
  1740. )
  1741. /*++
  1742. Function Description:
  1743. This function writes a multisz devcap string to the DsDriverKey registry
  1744. Parameters:
  1745. hPrinter - printer handle
  1746. hDevCapPrinter - devcap handle
  1747. pDevCap - devcap function pointer
  1748. pszPrinterName - name of the printer
  1749. fwCapability - devcap capability entry
  1750. dwElementBytes - length of each string element in the array returned by devcaps
  1751. pszRegValue - name of the registry value to which the multisz string will be written
  1752. Return Values:
  1753. BOOL - TRUE if successful, FALSE if not. Call GetLastError to retrieve failure error.
  1754. --*/
  1755. {
  1756. DWORD dwResult, cbBytes;
  1757. PWSTR pszDevCapBuffer = NULL;
  1758. PWSTR pszRegData = NULL;
  1759. _try {
  1760. dwResult = GDI_ERROR;
  1761. if (pSplDevCap) {
  1762. dwResult = (*pSplDevCap)( hDevCapPrinter,
  1763. pszPrinterName,
  1764. fwCapability,
  1765. NULL,
  1766. 0,
  1767. NULL);
  1768. }
  1769. if (dwResult == GDI_ERROR) {
  1770. dwResult = (*pDevCap)( hDevCapPrinter,
  1771. pszPrinterName,
  1772. fwCapability,
  1773. NULL,
  1774. NULL);
  1775. }
  1776. if (dwResult != GDI_ERROR) {
  1777. //
  1778. // DeviceCapabilities doesn't take a buffer size parameter, so if you get
  1779. // printer properties on a hundred or so printers at the same time, you will
  1780. // occasionally hit the case where win32 cache is deleting & adding forms in
  1781. // RefreshFormsCache and DC_PAPERNAMES calls EnumForms and gets different
  1782. // results. The first call may return 3 forms and second returns 20. So we
  1783. // allocate a big buffer here so third party drivers don't AV. For unidrv
  1784. // we have a different interface that accepts a buffer size.
  1785. //
  1786. if ((fwCapability == DC_PAPERNAMES || fwCapability == DC_MEDIAREADY) && dwResult < LOTS_OF_FORMS) {
  1787. cbBytes = LOTS_OF_FORMS*dwElementBytes*sizeof(WCHAR);
  1788. } else {
  1789. cbBytes = dwResult*dwElementBytes*sizeof(WCHAR);
  1790. }
  1791. pszDevCapBuffer = (PWSTR) AllocSplMem(cbBytes);
  1792. if (pszDevCapBuffer) {
  1793. dwResult = GDI_ERROR;
  1794. if (pSplDevCap) {
  1795. dwResult = (*pSplDevCap)( hDevCapPrinter,
  1796. pszPrinterName,
  1797. fwCapability,
  1798. pszDevCapBuffer,
  1799. cbBytes/sizeof(WCHAR),
  1800. NULL);
  1801. }
  1802. if (dwResult == GDI_ERROR) {
  1803. dwResult = (*pDevCap)( hDevCapPrinter,
  1804. pszPrinterName,
  1805. fwCapability,
  1806. pszDevCapBuffer,
  1807. NULL);
  1808. }
  1809. if (dwResult != GDI_ERROR) {
  1810. if (!(pszRegData = DevCapStrings2MultiSz(pszDevCapBuffer, dwResult, dwElementBytes, &cbBytes))) {
  1811. dwResult = GDI_ERROR;
  1812. }
  1813. }
  1814. } else {
  1815. dwResult = GDI_ERROR;
  1816. }
  1817. }
  1818. } _except(1) {
  1819. SetLastError(GetExceptionCode());
  1820. dwResult = GDI_ERROR;
  1821. }
  1822. if (dwResult != GDI_ERROR) {
  1823. dwResult = SplSetPrinterDataEx(
  1824. hPrinter,
  1825. SPLDS_DRIVER_KEY,
  1826. pszRegValue,
  1827. REG_MULTI_SZ,
  1828. (PBYTE) pszRegData,
  1829. cbBytes);
  1830. if (dwResult != ERROR_SUCCESS) {
  1831. SetLastError(dwResult);
  1832. dwResult = GDI_ERROR;
  1833. }
  1834. } else {
  1835. WCHAR szzNull[2];
  1836. szzNull[0] = szzNull[1] = '\0';
  1837. dwResult = SplSetPrinterDataEx(
  1838. hPrinter,
  1839. SPLDS_DRIVER_KEY,
  1840. pszRegValue,
  1841. REG_MULTI_SZ,
  1842. (PBYTE) szzNull,
  1843. 2 * sizeof(WCHAR));
  1844. }
  1845. FreeSplStr(pszDevCapBuffer);
  1846. FreeSplStr(pszRegData);
  1847. return dwResult != GDI_ERROR;
  1848. }
  1849. // RecreateDsKey: Clears existing published properties and recreates & republishes Registry key
  1850. extern "C" DWORD
  1851. RecreateDsKey(
  1852. HANDLE hPrinter,
  1853. PWSTR pszKey
  1854. )
  1855. {
  1856. PSPOOL pSpool = (PSPOOL)hPrinter;
  1857. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  1858. SplOutSem();
  1859. // 1) Clear all published Properties under Key
  1860. ClearDsKey(hPrinter, pszKey);
  1861. // 2) Delete Key
  1862. EnterSplSem();
  1863. SplDeletePrinterKey(hPrinter, pszKey);
  1864. // 3) Recreate Key
  1865. if (!wcscmp(pszKey, SPLDS_DRIVER_KEY)) {
  1866. UpdateDsDriverKey(hPrinter);
  1867. }
  1868. else if (!wcscmp(pszKey, SPLDS_SPOOLER_KEY)) {
  1869. UpdateDsSpoolerKey(hPrinter, 0xffffffff);
  1870. }
  1871. // 4) Republish Key
  1872. SetPrinterDs(hPrinter, DSPRINT_UPDATE, FALSE);
  1873. LeaveSplSem();
  1874. SplOutSem();
  1875. return ERROR_SUCCESS;
  1876. }
  1877. // ClearDsKey: clears all properties in specified key
  1878. HRESULT
  1879. ClearDsKey(
  1880. HANDLE hPrinter,
  1881. PWSTR pszKey
  1882. )
  1883. {
  1884. HRESULT hr = ERROR_SUCCESS;
  1885. DWORD i;
  1886. DWORD cbEnumValues = 0;
  1887. PPRINTER_ENUM_VALUES pEnumValues = NULL;
  1888. DWORD nEnumValues;
  1889. DWORD dwResult;
  1890. PSPOOL pSpool = (PSPOOL)hPrinter;
  1891. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  1892. IADs *pADs = NULL;
  1893. HANDLE hToken = NULL;
  1894. VARIANT var;
  1895. SplOutSem();
  1896. //
  1897. // If we're not published, there's no DS key to clear, so just return success
  1898. //
  1899. if (!pIniPrinter->pszObjectGUID)
  1900. return S_OK;
  1901. hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1902. if (FAILED(hr))
  1903. return hr;
  1904. hToken = RevertToPrinterSelf(); // All DS accesses are done by LocalSystem account
  1905. // 1) Enumerate all the Values under key
  1906. // Enumerate and Publish Key
  1907. dwResult = SplEnumPrinterDataEx( hPrinter,
  1908. pszKey,
  1909. NULL,
  1910. 0,
  1911. &cbEnumValues,
  1912. &nEnumValues
  1913. );
  1914. if (dwResult != ERROR_MORE_DATA) {
  1915. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  1916. goto error;
  1917. }
  1918. if (!(pEnumValues = (PPRINTER_ENUM_VALUES) AllocSplMem(cbEnumValues))) {
  1919. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  1920. BAIL_ON_FAILURE(hr);
  1921. }
  1922. dwResult = SplEnumPrinterDataEx( hPrinter,
  1923. pszKey,
  1924. (LPBYTE) pEnumValues,
  1925. cbEnumValues,
  1926. &cbEnumValues,
  1927. &nEnumValues
  1928. );
  1929. if (dwResult != ERROR_SUCCESS) {
  1930. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwResult);
  1931. goto error;
  1932. }
  1933. // Get or Create printQueue object
  1934. hr = GetPrintQueue(hPrinter, &pADs);
  1935. BAIL_ON_FAILURE(hr);
  1936. // 2) Clear Published Properties
  1937. VariantInit(&var);
  1938. for (i = 0 ; i < nEnumValues ; ++i) {
  1939. hr = pADs->PutEx(
  1940. ADS_PROPERTY_CLEAR,
  1941. pEnumValues[i].pValueName,
  1942. var
  1943. );
  1944. #if DBG
  1945. if (FAILED(hr))
  1946. DBGMSG(DBG_EXEC, ("Failed to clear property: %ws\n", pEnumValues[i].pValueName));
  1947. #endif
  1948. }
  1949. hr = pADs->SetInfo();
  1950. BAIL_ON_FAILURE(hr);
  1951. error:
  1952. FreeSplMem(pEnumValues);
  1953. if (hToken)
  1954. ImpersonatePrinterClient(hToken);
  1955. if (pADs) {
  1956. pADs->Release();
  1957. }
  1958. CoUninitialize();
  1959. return hr;
  1960. }
  1961. HRESULT
  1962. PutDSSD(
  1963. PINIPRINTER pIniPrinter,
  1964. IADs *pADs
  1965. )
  1966. {
  1967. IADsSecurityDescriptor *pSD = NULL;
  1968. IADsAccessControlList *pACL = NULL;
  1969. IDispatch *pSDDispatch = NULL;
  1970. IDispatch *pACLDispatch = NULL;
  1971. HRESULT hr, hr1;
  1972. DWORD cb, cbDomain;
  1973. DOMAIN_CONTROLLER_INFO *pDCI = NULL;
  1974. PWSTR pszTrustee = NULL;
  1975. PDSROLE_PRIMARY_DOMAIN_INFO_BASIC pDsRole = NULL;
  1976. DWORD dwRet;
  1977. WCHAR ErrorBuffer[LOG_EVENT_ERROR_BUFFER_SIZE];
  1978. BSTR bstrADsPath = NULL;
  1979. // Get SecurityDescriptor
  1980. // *** Create ACE
  1981. hr = CoCreateInstance( CLSID_SecurityDescriptor,
  1982. NULL,
  1983. CLSCTX_INPROC_SERVER,
  1984. IID_IADsSecurityDescriptor,
  1985. (void **) &pSD);
  1986. BAIL_ON_FAILURE(hr);
  1987. hr = pSD->QueryInterface(IID_IDispatch, (void **) &pSDDispatch);
  1988. BAIL_ON_FAILURE(hr);
  1989. // Create DACL
  1990. hr = CoCreateInstance( CLSID_AccessControlList,
  1991. NULL,
  1992. CLSCTX_INPROC_SERVER,
  1993. IID_IADsAccessControlList,
  1994. (void **) &pACL);
  1995. BAIL_ON_FAILURE(hr);
  1996. hr = pACL->QueryInterface(IID_IDispatch, (void **) &pACLDispatch);
  1997. BAIL_ON_FAILURE(hr);
  1998. // Get Domain name
  1999. dwRet = DsRoleGetPrimaryDomainInformation(NULL, DsRolePrimaryDomainInfoBasic, (PBYTE *) &pDsRole);
  2000. if (dwRet) {
  2001. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, dwRet);
  2002. BAIL_ON_FAILURE(hr);
  2003. }
  2004. // *** Create ACEs ***
  2005. // NTPRINTING\SWILSONTEST$
  2006. cbDomain = wcslen(pDsRole->DomainNameFlat);
  2007. cb = cbDomain + wcslen(pIniPrinter->pIniSpooler->pMachineName + 2) + 3; // add \, $, NULL
  2008. cb *= sizeof(WCHAR);
  2009. if (!(pszTrustee = (PWSTR) AllocSplMem(cb))) {
  2010. hr = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, GetLastError());
  2011. BAIL_ON_FAILURE(hr);
  2012. }
  2013. wsprintf(pszTrustee, L"%ws\\%ws$", pDsRole->DomainNameFlat, pIniPrinter->pIniSpooler->pMachineName + 2);
  2014. hr = CreateAce(pACL, (BSTR) pszTrustee, GENERIC_ALL);
  2015. BAIL_ON_FAILURE(hr);
  2016. hr = CreateAce(pACL, (BSTR) L"Domain Admins", GENERIC_ALL);
  2017. BAIL_ON_FAILURE(hr);
  2018. hr = CreateAce(pACL, (BSTR) L"Authenticated Users", GENERIC_READ);
  2019. BAIL_ON_FAILURE(hr);
  2020. hr = CreateAce(pACL, (BSTR) L"System", GENERIC_ALL);
  2021. BAIL_ON_FAILURE(hr);
  2022. // Write it out
  2023. hr = pACL->put_AclRevision(ACL_REVISION4);
  2024. BAIL_ON_FAILURE(hr);
  2025. hr = pSD->put_DiscretionaryAcl(pACLDispatch);
  2026. BAIL_ON_FAILURE(hr);
  2027. hr = put_Dispatch_Property(pADs, L"nTSecurityDescriptor", pSDDispatch);
  2028. BAIL_ON_FAILURE(hr);
  2029. // If SetInfo returns ERROR_BUSY it means the object already exists
  2030. // If the object exists, delete it and create a new one
  2031. hr = pADs->SetInfo();
  2032. if (HRESULT_CODE(hr) == ERROR_BUSY)
  2033. pIniPrinter->DsKeyUpdate = DS_KEY_REPUBLISH;
  2034. BAIL_ON_FAILURE(hr);
  2035. DBGMSG(DBG_EXEC, ("PutDSSD: Successfully added ACL\n"));
  2036. error:
  2037. FreeSplMem(pszTrustee);
  2038. if (pSDDispatch)
  2039. pSDDispatch->Release();
  2040. if (pACLDispatch)
  2041. pACLDispatch->Release();
  2042. if (pSD)
  2043. pSD->Release();
  2044. if (pACL)
  2045. pACL->Release();
  2046. if (pDCI)
  2047. NetApiBufferFree(pDCI);
  2048. if (pDsRole)
  2049. DsRoleFreeMemory((PVOID) pDsRole);
  2050. if (FAILED(hr)) {
  2051. DBGMSG(DBG_EXEC, ("PutDSSD: Failed to add ACL: %x\n\n", hr));
  2052. wsprintf(ErrorBuffer, L"%x", hr);
  2053. hr1 = pADs->get_ADsPath(&bstrADsPath);
  2054. if (SUCCEEDED(hr1)) {
  2055. SplLogEvent( pIniPrinter->pIniSpooler,
  2056. gdwLogDsEvents & LOG_ERROR,
  2057. MSG_CANT_WRITE_ACL,
  2058. FALSE,
  2059. bstrADsPath,
  2060. ErrorBuffer,
  2061. NULL );
  2062. SysFreeString(bstrADsPath);
  2063. }
  2064. }
  2065. return hr;
  2066. }
  2067. HRESULT
  2068. CreateAce(
  2069. IADsAccessControlList *pACL,
  2070. BSTR pszTrustee,
  2071. DWORD dwAccessMask
  2072. )
  2073. {
  2074. IADsAccessControlEntry *pACE = NULL;
  2075. IDispatch *pACEDispatch = NULL;
  2076. HRESULT hr;
  2077. // *** Create ACE
  2078. hr = CoCreateInstance( CLSID_AccessControlEntry,
  2079. NULL,
  2080. CLSCTX_INPROC_SERVER,
  2081. IID_IADsAccessControlEntry,
  2082. (void **) &pACE);
  2083. BAIL_ON_FAILURE(hr);
  2084. hr = pACE->put_AccessMask(dwAccessMask);
  2085. BAIL_ON_FAILURE(hr);
  2086. hr = pACE->put_AceType(ACCESS_ALLOWED_ACE_TYPE);
  2087. BAIL_ON_FAILURE(hr);
  2088. hr = pACE->put_AceFlags(0);
  2089. BAIL_ON_FAILURE(hr);
  2090. hr = pACE->put_Trustee(pszTrustee);
  2091. BAIL_ON_FAILURE(hr);
  2092. hr = pACE->QueryInterface(IID_IDispatch, (void **) &pACEDispatch);
  2093. BAIL_ON_FAILURE(hr);
  2094. hr = pACL->AddAce(pACEDispatch);
  2095. BAIL_ON_FAILURE(hr);
  2096. error:
  2097. if (pACEDispatch)
  2098. pACEDispatch->Release();
  2099. if (pACE)
  2100. pACE->Release();
  2101. return hr;
  2102. }
  2103. HRESULT
  2104. AddClusterAce(
  2105. PSPOOL pSpool,
  2106. IADs *pADsPrintQueue
  2107. )
  2108. {
  2109. PINIPRINTER pIniPrinter = pSpool->pIniPrinter;
  2110. IDispatch *pSDPrintQueueDispatch = NULL;
  2111. IADsSecurityDescriptor *pSDPrintQueue = NULL;
  2112. IDispatch *pACLPrintQueueDispatch = NULL;
  2113. IADsAccessControlList *pACLPrintQueue = NULL;
  2114. PWSTR pszClusterDN = NULL;
  2115. PWSTR pszAccount = NULL;
  2116. HRESULT hr;
  2117. // If we don't have a GUID, then we're not a cluster and we don't need to add the ACE
  2118. if (!pIniPrinter->pIniSpooler->pszClusterGUID)
  2119. return S_OK;
  2120. // Get the Cluster Object DN
  2121. hr = GetPublishPointFromGUID(NULL, pIniPrinter->pIniSpooler->pszClusterGUID, &pszClusterDN, NULL, FALSE);
  2122. BAIL_ON_FAILURE(hr);
  2123. // Get the PrintQueue Security Descriptor
  2124. hr = get_Dispatch_Property(pADsPrintQueue, L"nTSecurityDescriptor", &pSDPrintQueueDispatch);
  2125. BAIL_ON_FAILURE(hr);
  2126. hr = pSDPrintQueueDispatch->QueryInterface(IID_IADsSecurityDescriptor, (void **) &pSDPrintQueue);
  2127. BAIL_ON_FAILURE(hr);
  2128. // Get DACL from the Security Descriptor
  2129. hr = pSDPrintQueue->get_DiscretionaryAcl(&pACLPrintQueueDispatch);
  2130. BAIL_ON_FAILURE(hr);
  2131. hr = pACLPrintQueueDispatch->QueryInterface(IID_IADsAccessControlList, (void **) &pACLPrintQueue);
  2132. BAIL_ON_FAILURE(hr);
  2133. // Create the new ACE & Add it to the ACL
  2134. // Cluster account is a user account, so get current user and stick it in this ACE
  2135. hr = FQDN2Whatever(pszClusterDN, &pszAccount, DS_NT4_ACCOUNT_NAME);
  2136. BAIL_ON_FAILURE(hr);
  2137. hr = CreateAce(pACLPrintQueue, (BSTR) pszAccount, GENERIC_ALL);
  2138. BAIL_ON_FAILURE(hr);
  2139. // Write the ACL back to the Security Descriptor
  2140. hr = pSDPrintQueue->put_DiscretionaryAcl(pACLPrintQueueDispatch);
  2141. BAIL_ON_FAILURE(hr);
  2142. // Write the Security Descriptor back to the object
  2143. hr = put_Dispatch_Property(pADsPrintQueue, L"nTSecurityDescriptor", pSDPrintQueueDispatch);
  2144. BAIL_ON_FAILURE(hr);
  2145. hr = pADsPrintQueue->SetInfo();
  2146. BAIL_ON_FAILURE(hr);
  2147. error:
  2148. if (pACLPrintQueueDispatch)
  2149. pACLPrintQueueDispatch->Release();
  2150. if (pACLPrintQueue)
  2151. pACLPrintQueue->Release();
  2152. if (pSDPrintQueueDispatch)
  2153. pSDPrintQueueDispatch->Release();
  2154. if (pSDPrintQueue)
  2155. pSDPrintQueue->Release();
  2156. FreeSplStr(pszClusterDN);
  2157. FreeSplStr(pszAccount);
  2158. return hr;
  2159. }