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.

716 lines
24 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1996 - 1999
  6. //
  7. // File: printsi.cpp
  8. //
  9. // This file contains the implementation of the CPrintSecurity object.
  10. //
  11. //--------------------------------------------------------------------------
  12. #include "rshx32.h"
  13. // The following array defines the permission names for NT printers.
  14. SI_ACCESS siPrintAccesses[] =
  15. {
  16. { &GUID_NULL, PRINTER_EXECUTE, MAKEINTRESOURCE(IDS_PRINT_PRINT), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC },
  17. { &GUID_NULL, PRINTER_ALL_ACCESS, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC },
  18. { &GUID_NULL, JOB_ALL_ACCESS, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER_JOBS), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE },
  19. // { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_PRINT_DELETE), SI_ACCESS_SPECIFIC },
  20. { &GUID_NULL, STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_PRINT_READ), SI_ACCESS_SPECIFIC },
  21. { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_PRINT_CHANGE_PERM), SI_ACCESS_SPECIFIC },
  22. { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_PRINT_CHANGE_OWNER), SI_ACCESS_SPECIFIC },
  23. { &GUID_NULL, PRINTER_ALL_ACCESS|JOB_ALL_ACCESS, MAKEINTRESOURCE(IDS_PRINT_JOB_ALL), 0 },
  24. { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NONE), 0 },
  25. };
  26. #define iPrintDefAccess 0 // PRINTER_EXECUTE (i.e. "Print" access)
  27. #define PRINTER_ALL_AUDIT (PRINTER_ALL_ACCESS | ACCESS_SYSTEM_SECURITY)
  28. #define JOB_ALL_AUDIT (JOB_ALL_ACCESS | ACCESS_SYSTEM_SECURITY)
  29. #define PRINTER_JOB_ALL_AUDIT (PRINTER_ALL_ACCESS | JOB_ALL_ACCESS | ACCESS_SYSTEM_SECURITY)
  30. // The following array defines the auditting names for NT printers.
  31. SI_ACCESS siPrintAudits[] =
  32. {
  33. { &GUID_NULL, PRINTER_EXECUTE, MAKEINTRESOURCE(IDS_PRINT_PRINT), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC },
  34. { &GUID_NULL, PRINTER_ALL_AUDIT, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC },
  35. { &GUID_NULL, JOB_ALL_AUDIT, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER_JOBS), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE },
  36. // { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_PRINT_DELETE), SI_ACCESS_SPECIFIC },
  37. { &GUID_NULL, STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_PRINT_READ), SI_ACCESS_SPECIFIC },
  38. { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_PRINT_CHANGE_PERM), SI_ACCESS_SPECIFIC },
  39. { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_PRINT_CHANGE_OWNER), SI_ACCESS_SPECIFIC },
  40. { &GUID_NULL, PRINTER_ALL_AUDIT|JOB_ALL_AUDIT, MAKEINTRESOURCE(IDS_PRINT_JOB_ALL), 0 },
  41. { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NONE), 0 },
  42. };
  43. #define iPrintDefAudit 0 // PRINTER_EXECUTE (i.e. "Print" access)
  44. // The following array defines the inheritance types for NT printers.
  45. SI_INHERIT_TYPE siPrintInheritTypes[] =
  46. {
  47. &GUID_NULL, 0, MAKEINTRESOURCE(IDS_PRINT_PRINTER),
  48. &GUID_NULL, INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_PRINT_DOCUMENT_ONLY),
  49. &GUID_NULL, OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_PRINT_PRINTER_DOCUMENT),
  50. };
  51. BOOL
  52. GetPrinterAlloc(HANDLE hPrinter, DWORD dwLevel, LPBYTE *ppBuffer)
  53. {
  54. BOOL bResult;
  55. DWORD dwLength = 0;
  56. LPBYTE pBuffer = NULL;
  57. bResult = GetPrinter(hPrinter, dwLevel, NULL, 0, &dwLength);
  58. if (dwLength)
  59. {
  60. bResult = FALSE;
  61. pBuffer = (LPBYTE)LocalAlloc(LPTR, dwLength);
  62. if (pBuffer)
  63. {
  64. bResult = GetPrinter(hPrinter, dwLevel, pBuffer, dwLength, &dwLength);
  65. if (!bResult)
  66. {
  67. LocalFree(pBuffer);
  68. pBuffer = NULL;
  69. }
  70. }
  71. }
  72. *ppBuffer = pBuffer;
  73. return bResult;
  74. }
  75. STDMETHODIMP
  76. CheckPrinterAccess(LPCTSTR pszObjectName,
  77. LPDWORD pdwAccessGranted,
  78. LPTSTR pszServer,
  79. ULONG cchServer)
  80. {
  81. HRESULT hr = S_OK;
  82. UINT i;
  83. PRINTER_DEFAULTS PrinterDefaults;
  84. DWORD dwAccessDesired[] = { ALL_SECURITY_ACCESS,
  85. READ_CONTROL,
  86. WRITE_DAC,
  87. WRITE_OWNER,
  88. ACCESS_SYSTEM_SECURITY };
  89. HANDLE hPrinter = NULL;
  90. PrinterDefaults.pDatatype = NULL;
  91. PrinterDefaults.pDevMode = NULL;
  92. TraceEnter(TRACE_PRINTSI, "CheckPrinterAccess");
  93. TraceAssert(pdwAccessGranted != NULL);
  94. __try
  95. {
  96. *pdwAccessGranted = 0;
  97. for (i = 0; i < ARRAYSIZE(dwAccessDesired); i++)
  98. {
  99. if ((dwAccessDesired[i] & *pdwAccessGranted) == dwAccessDesired[i])
  100. continue; // already have this access
  101. PrinterDefaults.DesiredAccess = dwAccessDesired[i];
  102. if (OpenPrinter((LPTSTR)pszObjectName, &hPrinter, &PrinterDefaults))
  103. {
  104. *pdwAccessGranted |= dwAccessDesired[i];
  105. ClosePrinter(hPrinter);
  106. }
  107. else
  108. {
  109. DWORD dwErr = GetLastError();
  110. if (dwErr != ERROR_ACCESS_DENIED &&
  111. dwErr != ERROR_PRIVILEGE_NOT_HELD)
  112. {
  113. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "OpenPrinter failed");
  114. }
  115. }
  116. }
  117. if (pszServer)
  118. {
  119. PrinterDefaults.DesiredAccess = PRINTER_READ;
  120. if (OpenPrinter((LPTSTR)pszObjectName, &hPrinter, &PrinterDefaults))
  121. {
  122. PPRINTER_INFO_2 ppi = NULL;
  123. if (GetPrinterAlloc(hPrinter, 2, (LPBYTE*)&ppi))
  124. {
  125. if (ppi && ppi->pServerName)
  126. lstrcpyn(pszServer, ppi->pServerName, cchServer);
  127. else
  128. *pszServer = TEXT('\0');
  129. LocalFree(ppi);
  130. }
  131. ClosePrinter(hPrinter);
  132. }
  133. }
  134. }
  135. __except(EXCEPTION_EXECUTE_HANDLER)
  136. {
  137. hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND);
  138. }
  139. exit_gracefully:
  140. Trace((TEXT("Access = 0x%08x"), *pdwAccessGranted));
  141. TraceLeaveResult(hr);
  142. }
  143. STDMETHODIMP
  144. CPrintSecurity::Initialize(HDPA hItemList,
  145. DWORD dwFlags,
  146. LPTSTR pszServer,
  147. LPTSTR pszObject)
  148. {
  149. return CSecurityInformation::Initialize(hItemList,
  150. dwFlags | SI_NO_TREE_APPLY | SI_NO_ACL_PROTECT,
  151. pszServer,
  152. pszObject);
  153. }
  154. //
  155. // NT6 REVIEW
  156. //
  157. // GetAceSid, FindManagePrinterACE, MungeAclForPrinter and
  158. // CPrintSecurity::SetSecurity only exist here because
  159. // 1) The spooler removes JOB_ACCESS_ADMINISTER from an ACE unless the
  160. // ACE has INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE.
  161. // 2) The NT4 ACL editor (ACLEDIT) needs extra bogus ACEs to recognize
  162. // "Manage Documents" access. (Must support downlevel clients.)
  163. //
  164. // The first case should be rare, since you have to perform certain
  165. // steps in the NT5 ACL editor (ACLUI) to cause this situation. The
  166. // second situation is common, since CREATER_OWNER and Administrators
  167. // usually have "Manage Documents" access.
  168. //
  169. // If the spooler guys decide to not support NT4 clients for NT6, and they
  170. // stop stripping JOB_ACCESS_ADMINISTER from ACEs, then MungeAclForPrinter
  171. // and CPrintSecurity::SetSecurity can be removed entirely. ENCOURAGE THEM
  172. // TO MAKE THAT CHANGE. (They can also remove similar hacks from their own
  173. // code that add bogus ACEs for the old ACL editor.)
  174. //
  175. PSID
  176. GetAceSid(PACE_HEADER pAce)
  177. {
  178. switch (pAce->AceType)
  179. {
  180. case ACCESS_ALLOWED_ACE_TYPE:
  181. case ACCESS_DENIED_ACE_TYPE:
  182. case SYSTEM_AUDIT_ACE_TYPE:
  183. case SYSTEM_ALARM_ACE_TYPE:
  184. return (PSID)&((PKNOWN_ACE)pAce)->SidStart;
  185. case ACCESS_ALLOWED_COMPOUND_ACE_TYPE:
  186. return (PSID)&((PCOMPOUND_ACCESS_ALLOWED_ACE)pAce)->SidStart;
  187. case ACCESS_ALLOWED_OBJECT_ACE_TYPE:
  188. case ACCESS_DENIED_OBJECT_ACE_TYPE:
  189. case SYSTEM_AUDIT_OBJECT_ACE_TYPE:
  190. case SYSTEM_ALARM_OBJECT_ACE_TYPE:
  191. return RtlObjectAceSid(pAce);
  192. }
  193. return NULL;
  194. }
  195. PACE_HEADER
  196. FindManagePrinterACE(PACL pAcl, PSID pSid)
  197. {
  198. UINT i;
  199. PACE_HEADER pAce;
  200. if (!pAcl || !pSid)
  201. return NULL;
  202. for (i = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
  203. i < pAcl->AceCount;
  204. i++, pAce = (PACE_HEADER)NextAce(pAce))
  205. {
  206. if (pAce->AceType == ACCESS_ALLOWED_ACE_TYPE
  207. && (((PKNOWN_ACE)pAce)->Mask & PRINTER_ALL_ACCESS) == PRINTER_ALL_ACCESS
  208. && !(pAce->AceFlags & INHERIT_ONLY_ACE)
  209. && EqualSid(pSid, GetAceSid(pAce)))
  210. {
  211. return pAce;
  212. }
  213. }
  214. return NULL;
  215. }
  216. BOOL
  217. MungeAclForPrinter(PACL pAcl, PACL *ppAclOut)
  218. {
  219. USHORT i;
  220. PACE_HEADER pAce;
  221. PACE_HEADER pAceCopy = NULL;
  222. if (ppAclOut == NULL)
  223. return FALSE;
  224. *ppAclOut = NULL;
  225. if (pAcl == NULL)
  226. return TRUE;
  227. TraceEnter(TRACE_PRINTSI, "MungeAclForPrinter");
  228. for (i = 0, pAce = (PACE_HEADER)FirstAce(pAcl);
  229. i < pAcl->AceCount;
  230. i++, pAce = (PACE_HEADER)NextAce(pAce))
  231. {
  232. //
  233. // If this ACE has the JOB_ACCESS_ADMINISTER bit and the inherit
  234. // flags indicate that it applies to both printers and documents,
  235. // then we need to treat it specially, since the spooler won't save
  236. // JOB_ACCESS_ADMINISTER on a printer ACE (INHERIT_ONLY_ACE not set).
  237. //
  238. if ((((PKNOWN_ACE)pAce)->Mask & JOB_ACCESS_ADMINISTER) &&
  239. (pAce->AceFlags & (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)) == OBJECT_INHERIT_ACE)
  240. {
  241. //
  242. // Split into 2 aces: one with no inheritance, and one with
  243. // INHERIT_ONLY_ACE turned on. Let the spooler do whatever
  244. // it wants with the mask.
  245. //
  246. // This requires allocating a larger ACL and copying all
  247. // previous aces over.
  248. //
  249. TraceMsg("Splitting JOB_ACCESS_ADMINISTER ACE into 2");
  250. if (*ppAclOut == NULL)
  251. {
  252. //
  253. // Allocate new ACL and copy previous aces. The length is enough
  254. // for 1 copy of all previous aces, and 3 copies (max) of all
  255. // remaining aces.
  256. //
  257. ULONG nPrevLength = (ULONG)((ULONG_PTR)pAce - (ULONG_PTR)pAcl);
  258. *ppAclOut = (PACL)LocalAlloc(LPTR, nPrevLength + (pAcl->AclSize - nPrevLength) * 3);
  259. if (!*ppAclOut)
  260. TraceLeaveValue(FALSE);
  261. CopyMemory(*ppAclOut, pAcl, nPrevLength);
  262. (*ppAclOut)->AclSize = (USHORT)LocalSize(*ppAclOut);
  263. (*ppAclOut)->AceCount = i;
  264. pAceCopy = (PACE_HEADER)ByteOffset(*ppAclOut, nPrevLength);
  265. }
  266. // Turn off inheritance and copy this ace
  267. pAce->AceFlags &= ~OBJECT_INHERIT_ACE;
  268. CopyMemory(pAceCopy, pAce, pAce->AceSize);
  269. pAceCopy = (PACE_HEADER)NextAce(pAceCopy);
  270. (*ppAclOut)->AceCount++;
  271. // Now turn on inheritance (with INHERIT_ONLY_ACE) and copy it
  272. // again (it gets copied way down below). Note that this may
  273. // causes the next IF clause to add a bogus ACE also.
  274. pAce->AceFlags |= OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE;
  275. }
  276. //
  277. // If this ACE has JOB_ALL_ACCESS and INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE,
  278. // and there isn't also a "Manage Printers" ACE for the same SID, add a
  279. // bogus ACE with READ_CONTROL and CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE.
  280. // The old ACL editor on downlevel clients needs this to recognize
  281. // "Manage Documents" access.
  282. //
  283. if (pAce->AceType == ACCESS_ALLOWED_ACE_TYPE
  284. && (((PKNOWN_ACE)pAce)->Mask & JOB_ALL_ACCESS) == JOB_ALL_ACCESS
  285. && (pAce->AceFlags & (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)) == (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)
  286. && !FindManagePrinterACE(pAcl, GetAceSid(pAce)))
  287. {
  288. TraceMsg("Adding bogus ACE for downlevel support");
  289. if (*ppAclOut == NULL)
  290. {
  291. //
  292. // Allocate new ACL and copy previous aces. The length is enough
  293. // for 1 copy of all previous aces, and 3 copies (max) of all
  294. // remaining aces.
  295. //
  296. ULONG nPrevLength = (ULONG)((ULONG_PTR)pAce - (ULONG_PTR)pAcl);
  297. *ppAclOut = (PACL)LocalAlloc(LPTR, nPrevLength + (pAcl->AclSize - nPrevLength) * 3);
  298. if (!*ppAclOut)
  299. TraceLeaveValue(FALSE);
  300. CopyMemory(*ppAclOut, pAcl, nPrevLength);
  301. (*ppAclOut)->AclSize = (USHORT)LocalSize(*ppAclOut);
  302. (*ppAclOut)->AceCount = i;
  303. pAceCopy = (PACE_HEADER)ByteOffset(*ppAclOut, nPrevLength);
  304. }
  305. // Copy this ace, turn on CONTAINER_INHERIT_ACE, and set
  306. // the mask to STANDARD_RIGHTS_READ.
  307. CopyMemory(pAceCopy, pAce, pAce->AceSize);
  308. pAceCopy->AceFlags &= ~OBJECT_INHERIT_ACE;
  309. pAceCopy->AceFlags |= INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE;
  310. ((PKNOWN_ACE)pAceCopy)->Mask = STANDARD_RIGHTS_READ;
  311. pAceCopy = (PACE_HEADER)NextAce(pAceCopy);
  312. (*ppAclOut)->AceCount++;
  313. }
  314. if (*ppAclOut != NULL)
  315. {
  316. // Copy current ace
  317. CopyMemory(pAceCopy, pAce, pAce->AceSize);
  318. pAceCopy = (PACE_HEADER)NextAce(pAceCopy);
  319. (*ppAclOut)->AceCount++;
  320. }
  321. }
  322. if (*ppAclOut != NULL)
  323. {
  324. TraceAssert((ULONG_PTR)pAceCopy > (ULONG_PTR)*ppAclOut &&
  325. (ULONG_PTR)pAceCopy <= (ULONG_PTR)*ppAclOut + (*ppAclOut)->AclSize);
  326. // Set the ACL size to the correct value
  327. (*ppAclOut)->AclSize = (WORD)((ULONG_PTR)pAceCopy - (ULONG_PTR)*ppAclOut);
  328. }
  329. TraceLeaveValue(TRUE);
  330. }
  331. ///////////////////////////////////////////////////////////
  332. //
  333. // ISecurityInformation methods
  334. //
  335. ///////////////////////////////////////////////////////////
  336. STDMETHODIMP
  337. CPrintSecurity::SetSecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD)
  338. {
  339. PACL pDacl = NULL;
  340. PACL pSacl = NULL;
  341. PACL pDaclCopy = NULL;
  342. PACL pSaclCopy = NULL;
  343. BOOL bPresent;
  344. BOOL bDefaulted;
  345. SECURITY_DESCRIPTOR sd;
  346. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::SetSecurity");
  347. if ((si & DACL_SECURITY_INFORMATION)
  348. && GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted)
  349. && bPresent)
  350. {
  351. if (MungeAclForPrinter(pDacl, &pDaclCopy) && pDaclCopy)
  352. pDacl = pDaclCopy;
  353. }
  354. if ((si & SACL_SECURITY_INFORMATION)
  355. && GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted)
  356. && bPresent)
  357. {
  358. if (MungeAclForPrinter(pSacl, &pSaclCopy) && pSaclCopy)
  359. pSacl = pSaclCopy;
  360. }
  361. if (pDaclCopy || pSaclCopy)
  362. {
  363. // Build a new SECURITY_DESCRIPTOR
  364. PSID psid;
  365. DWORD dwRevision;
  366. SECURITY_DESCRIPTOR_CONTROL sdControl = 0;
  367. GetSecurityDescriptorControl(pSD, &sdControl, &dwRevision);
  368. InitializeSecurityDescriptor(&sd, dwRevision);
  369. sd.Control = (SECURITY_DESCRIPTOR_CONTROL)(sdControl & ~SE_SELF_RELATIVE);
  370. if ((si & OWNER_SECURITY_INFORMATION)
  371. && GetSecurityDescriptorOwner(pSD, &psid, &bDefaulted))
  372. {
  373. SetSecurityDescriptorOwner(&sd, psid, bDefaulted);
  374. }
  375. if ((si & GROUP_SECURITY_INFORMATION)
  376. && GetSecurityDescriptorGroup(pSD, &psid, &bDefaulted))
  377. {
  378. SetSecurityDescriptorGroup(&sd, psid, bDefaulted);
  379. }
  380. if (si & SACL_SECURITY_INFORMATION)
  381. {
  382. SetSecurityDescriptorSacl(&sd,
  383. sdControl & SE_SACL_PRESENT,
  384. pSacl,
  385. sdControl & SE_SACL_DEFAULTED);
  386. }
  387. if (si & DACL_SECURITY_INFORMATION)
  388. {
  389. SetSecurityDescriptorDacl(&sd,
  390. sdControl & SE_DACL_PRESENT,
  391. pDacl,
  392. sdControl & SE_DACL_DEFAULTED);
  393. }
  394. // Switch to the new security descriptor
  395. pSD = &sd;
  396. }
  397. // The base class does the rest of the work
  398. HRESULT hr = CSecurityInformation::SetSecurity(si, pSD);
  399. if (pDaclCopy)
  400. LocalFree(pDaclCopy);
  401. if (pSaclCopy)
  402. LocalFree(pSaclCopy);
  403. TraceLeaveResult(hr);
  404. }
  405. STDMETHODIMP
  406. CPrintSecurity::GetAccessRights(const GUID* /*pguidObjectType*/,
  407. DWORD dwFlags,
  408. PSI_ACCESS *ppAccesses,
  409. ULONG *pcAccesses,
  410. ULONG *piDefaultAccess)
  411. {
  412. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::GetAccessRights");
  413. TraceAssert(ppAccesses != NULL);
  414. TraceAssert(pcAccesses != NULL);
  415. TraceAssert(piDefaultAccess != NULL);
  416. if (dwFlags & SI_EDIT_AUDITS)
  417. {
  418. *ppAccesses = siPrintAudits;
  419. *pcAccesses = ARRAYSIZE(siPrintAudits);
  420. *piDefaultAccess = iPrintDefAudit;
  421. }
  422. else
  423. {
  424. *ppAccesses = siPrintAccesses;
  425. *pcAccesses = ARRAYSIZE(siPrintAccesses);
  426. *piDefaultAccess = iPrintDefAccess;
  427. }
  428. TraceLeaveResult(S_OK);
  429. }
  430. GENERIC_MAPPING JobMap =
  431. {
  432. JOB_READ,
  433. JOB_WRITE,
  434. JOB_EXECUTE,
  435. JOB_ALL_ACCESS
  436. };
  437. GENERIC_MAPPING PrinterMap =
  438. {
  439. PRINTER_READ,
  440. PRINTER_WRITE,
  441. PRINTER_EXECUTE,
  442. PRINTER_ALL_ACCESS
  443. };
  444. GENERIC_MAPPING FullPrinterMap =
  445. {
  446. PRINTER_READ | JOB_READ,
  447. PRINTER_WRITE | JOB_WRITE,
  448. PRINTER_EXECUTE | JOB_EXECUTE,
  449. PRINTER_ALL_ACCESS | JOB_ALL_ACCESS
  450. };
  451. STDMETHODIMP
  452. CPrintSecurity::MapGeneric(const GUID* /*pguidObjectType*/,
  453. UCHAR *pAceFlags,
  454. ACCESS_MASK *pmask)
  455. {
  456. PGENERIC_MAPPING pMap;
  457. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::MapGeneric");
  458. TraceAssert(pAceFlags != NULL);
  459. TraceAssert(pmask != NULL);
  460. // This flag has no meaning for printers, but it's often turned on
  461. // in legacy ACLs. Turn it off here
  462. *pAceFlags &= ~CONTAINER_INHERIT_ACE;
  463. // Choose the correct generic mapping according to the inherit
  464. // scope of this ACE.
  465. if (*pAceFlags & OBJECT_INHERIT_ACE)
  466. {
  467. if (*pAceFlags & INHERIT_ONLY_ACE)
  468. pMap = &JobMap; // documents only
  469. else
  470. pMap = &FullPrinterMap; // printers & documents
  471. }
  472. else
  473. pMap = &PrinterMap; // printers only
  474. // Note that the case where INHERIT_ONLY_ACE is ON but OBJECT_INHERIT_ACE
  475. // is OFF falls under the "printers only" case above. However, this
  476. // case makes no sense (inherit-only, but not onto documents) and it
  477. // doesn't matter how we do the mapping.
  478. // Map any generic bits to standard & specific bits.
  479. // When using the NT5 ACL APIs, ntmarta.dll maps generic bits, so this
  480. // isn't always necessary, but we'll do it anyway to be sure.
  481. MapGenericMask(pmask, pMap);
  482. // Turn off any extra bits that ntmarta.dll may have turned on
  483. // (ntmarta uses a different mapping). But leave ACCESS_SYSTEM_SECURITY
  484. // alone in case we're editing a SACL.
  485. *pmask &= (pMap->GenericAll | ACCESS_SYSTEM_SECURITY);
  486. TraceLeaveResult(S_OK);
  487. }
  488. STDMETHODIMP
  489. CPrintSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  490. ULONG *pcInheritTypes)
  491. {
  492. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::GetInheritTypes");
  493. TraceAssert(ppInheritTypes != NULL);
  494. TraceAssert(pcInheritTypes != NULL);
  495. *ppInheritTypes = siPrintInheritTypes;
  496. *pcInheritTypes = ARRAYSIZE(siPrintInheritTypes);
  497. TraceLeaveResult(S_OK);
  498. }
  499. //
  500. // The base class versions of ReadObjectSecurity and WriteObjectSecurity
  501. // use Get/SetNamedSecurityInfo, et al. These API's are generic,
  502. // involve lots of conversions, and are problematic. Since there is no
  503. // inheritance propagation required for printers, override them here
  504. // and use GetPrinter/SetPrinter.
  505. //
  506. STDMETHODIMP
  507. CPrintSecurity::ReadObjectSecurity(LPCTSTR pszObject,
  508. SECURITY_INFORMATION si,
  509. PSECURITY_DESCRIPTOR *ppSD)
  510. {
  511. HRESULT hr;
  512. DWORD dwErr = NOERROR;
  513. HANDLE hPrinter;
  514. PRINTER_DEFAULTS pd = {0};
  515. DWORD dwLength = 0;
  516. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::ReadObjectSecurity");
  517. TraceAssert(pszObject != NULL);
  518. TraceAssert(si != 0);
  519. TraceAssert(ppSD != NULL);
  520. //
  521. // Assume that required privileges have already been
  522. // enabled, if appropriate.
  523. //
  524. if (si & (DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
  525. pd.DesiredAccess |= READ_CONTROL;
  526. if (si & SACL_SECURITY_INFORMATION)
  527. pd.DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  528. __try
  529. {
  530. *ppSD = NULL;
  531. if (OpenPrinter((LPTSTR)pszObject, &hPrinter, &pd))
  532. {
  533. PPRINTER_INFO_3 ppi = NULL;
  534. if (GetPrinterAlloc(hPrinter, 3, (LPBYTE*)&ppi))
  535. {
  536. //
  537. // Rather than allocating a new buffer and copying the
  538. // security descriptor, we can re-use the existing buffer
  539. // by simply moving the security descriptor to the top.
  540. //
  541. dwLength = GetSecurityDescriptorLength(ppi->pSecurityDescriptor);
  542. *ppSD = ppi;
  543. // This is an overlapped copy, so use MoveMemory.
  544. MoveMemory(*ppSD,
  545. ppi->pSecurityDescriptor,
  546. dwLength);
  547. }
  548. else
  549. dwErr = GetLastError();
  550. ClosePrinter(hPrinter);
  551. }
  552. else
  553. dwErr = GetLastError();
  554. }
  555. __except(EXCEPTION_EXECUTE_HANDLER)
  556. {
  557. dwErr = ERROR_PROC_NOT_FOUND;
  558. }
  559. hr = HRESULT_FROM_WIN32(dwErr);
  560. TraceLeaveResult(hr);
  561. }
  562. STDMETHODIMP
  563. CPrintSecurity::WriteObjectSecurity(LPCTSTR pszObject,
  564. SECURITY_INFORMATION si,
  565. PSECURITY_DESCRIPTOR pSD)
  566. {
  567. HRESULT hr;
  568. DWORD dwErr = NOERROR;
  569. HANDLE hPrinter;
  570. PRINTER_DEFAULTS pd = {0};
  571. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::WriteObjectSecurity");
  572. TraceAssert(pszObject != NULL);
  573. TraceAssert(si != 0);
  574. TraceAssert(pSD != NULL);
  575. //
  576. // Assume that required privileges have already been
  577. // enabled, if appropriate.
  578. //
  579. if (si & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
  580. pd.DesiredAccess |= WRITE_OWNER;
  581. if (si & SACL_SECURITY_INFORMATION)
  582. pd.DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  583. if (si & DACL_SECURITY_INFORMATION)
  584. pd.DesiredAccess |= WRITE_DAC;
  585. __try
  586. {
  587. if (OpenPrinter((LPTSTR)pszObject, &hPrinter, &pd))
  588. {
  589. PRINTER_INFO_3 pi = { pSD };
  590. if (!SetPrinter(hPrinter, 3, (LPBYTE)&pi, 0))
  591. dwErr = GetLastError();
  592. ClosePrinter(hPrinter);
  593. }
  594. else
  595. dwErr = GetLastError();
  596. }
  597. __except(EXCEPTION_EXECUTE_HANDLER)
  598. {
  599. dwErr = ERROR_PROC_NOT_FOUND;
  600. }
  601. hr = HRESULT_FROM_WIN32(dwErr);
  602. TraceLeaveResult(hr);
  603. }
  604. STDMETHODIMP
  605. CPrintSecurity::GetInheritSource(SECURITY_INFORMATION si,
  606. PACL pACL,
  607. PINHERITED_FROM *ppInheritArray)
  608. {
  609. return E_NOTIMPL;
  610. }