Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

750 lines
25 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. HRESULT hr = S_OK;
  348. if ((si & DACL_SECURITY_INFORMATION)
  349. && GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted)
  350. && bPresent)
  351. {
  352. if (MungeAclForPrinter(pDacl, &pDaclCopy) && pDaclCopy)
  353. pDacl = pDaclCopy;
  354. }
  355. if ((si & SACL_SECURITY_INFORMATION)
  356. && GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted)
  357. && bPresent)
  358. {
  359. if (MungeAclForPrinter(pSacl, &pSaclCopy) && pSaclCopy)
  360. pSacl = pSaclCopy;
  361. }
  362. if (pDaclCopy || pSaclCopy)
  363. {
  364. // Build a new SECURITY_DESCRIPTOR
  365. PSID psid;
  366. DWORD dwRevision;
  367. SECURITY_DESCRIPTOR_CONTROL sdControl = 0;
  368. if(!GetSecurityDescriptorControl(pSD, &sdControl, &dwRevision))
  369. {
  370. DWORD dwErr = GetLastError();
  371. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"GetSecurityDescriptorControl failed");
  372. }
  373. if(!InitializeSecurityDescriptor(&sd, dwRevision))
  374. {
  375. DWORD dwErr = GetLastError();
  376. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"InitializeSecurityDescriptor failed");
  377. }
  378. sd.Control = (SECURITY_DESCRIPTOR_CONTROL)(sdControl & ~SE_SELF_RELATIVE);
  379. if ((si & OWNER_SECURITY_INFORMATION)
  380. && GetSecurityDescriptorOwner(pSD, &psid, &bDefaulted))
  381. {
  382. if(!SetSecurityDescriptorOwner(&sd, psid, bDefaulted))
  383. {
  384. DWORD dwErr = GetLastError();
  385. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorOwner failed");
  386. }
  387. }
  388. if ((si & GROUP_SECURITY_INFORMATION)
  389. && GetSecurityDescriptorGroup(pSD, &psid, &bDefaulted))
  390. {
  391. if(!SetSecurityDescriptorGroup(&sd, psid, bDefaulted))
  392. {
  393. DWORD dwErr = GetLastError();
  394. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorGroup failed");
  395. }
  396. }
  397. if (si & SACL_SECURITY_INFORMATION)
  398. {
  399. if(!SetSecurityDescriptorSacl(&sd,
  400. sdControl & SE_SACL_PRESENT,
  401. pSacl,
  402. sdControl & SE_SACL_DEFAULTED))
  403. {
  404. DWORD dwErr = GetLastError();
  405. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorSacl failed");
  406. }
  407. }
  408. if (si & DACL_SECURITY_INFORMATION)
  409. {
  410. if(!SetSecurityDescriptorDacl(&sd,
  411. sdControl & SE_DACL_PRESENT,
  412. pDacl,
  413. sdControl & SE_DACL_DEFAULTED))
  414. {
  415. DWORD dwErr = GetLastError();
  416. ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr),"SetSecurityDescriptorDacl failed");
  417. }
  418. }
  419. // Switch to the new security descriptor
  420. pSD = &sd;
  421. }
  422. // The base class does the rest of the work
  423. hr = CSecurityInformation::SetSecurity(si, pSD);
  424. exit_gracefully:
  425. if (pDaclCopy)
  426. LocalFree(pDaclCopy);
  427. if (pSaclCopy)
  428. LocalFree(pSaclCopy);
  429. TraceLeaveResult(hr);
  430. }
  431. STDMETHODIMP
  432. CPrintSecurity::GetAccessRights(const GUID* /*pguidObjectType*/,
  433. DWORD dwFlags,
  434. PSI_ACCESS *ppAccesses,
  435. ULONG *pcAccesses,
  436. ULONG *piDefaultAccess)
  437. {
  438. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::GetAccessRights");
  439. TraceAssert(ppAccesses != NULL);
  440. TraceAssert(pcAccesses != NULL);
  441. TraceAssert(piDefaultAccess != NULL);
  442. if (dwFlags & SI_EDIT_AUDITS)
  443. {
  444. *ppAccesses = siPrintAudits;
  445. *pcAccesses = ARRAYSIZE(siPrintAudits);
  446. *piDefaultAccess = iPrintDefAudit;
  447. }
  448. else
  449. {
  450. *ppAccesses = siPrintAccesses;
  451. *pcAccesses = ARRAYSIZE(siPrintAccesses);
  452. *piDefaultAccess = iPrintDefAccess;
  453. }
  454. TraceLeaveResult(S_OK);
  455. }
  456. GENERIC_MAPPING JobMap =
  457. {
  458. JOB_READ,
  459. JOB_WRITE,
  460. JOB_EXECUTE,
  461. JOB_ALL_ACCESS
  462. };
  463. GENERIC_MAPPING PrinterMap =
  464. {
  465. PRINTER_READ,
  466. PRINTER_WRITE,
  467. PRINTER_EXECUTE,
  468. PRINTER_ALL_ACCESS
  469. };
  470. GENERIC_MAPPING FullPrinterMap =
  471. {
  472. PRINTER_READ | JOB_READ,
  473. PRINTER_WRITE | JOB_WRITE,
  474. PRINTER_EXECUTE | JOB_EXECUTE,
  475. PRINTER_ALL_ACCESS | JOB_ALL_ACCESS
  476. };
  477. STDMETHODIMP
  478. CPrintSecurity::MapGeneric(const GUID* /*pguidObjectType*/,
  479. UCHAR *pAceFlags,
  480. ACCESS_MASK *pmask)
  481. {
  482. PGENERIC_MAPPING pMap;
  483. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::MapGeneric");
  484. TraceAssert(pAceFlags != NULL);
  485. TraceAssert(pmask != NULL);
  486. // This flag has no meaning for printers, but it's often turned on
  487. // in legacy ACLs. Turn it off here
  488. *pAceFlags &= ~CONTAINER_INHERIT_ACE;
  489. // Choose the correct generic mapping according to the inherit
  490. // scope of this ACE.
  491. if (*pAceFlags & OBJECT_INHERIT_ACE)
  492. {
  493. if (*pAceFlags & INHERIT_ONLY_ACE)
  494. pMap = &JobMap; // documents only
  495. else
  496. pMap = &FullPrinterMap; // printers & documents
  497. }
  498. else
  499. pMap = &PrinterMap; // printers only
  500. // Note that the case where INHERIT_ONLY_ACE is ON but OBJECT_INHERIT_ACE
  501. // is OFF falls under the "printers only" case above. However, this
  502. // case makes no sense (inherit-only, but not onto documents) and it
  503. // doesn't matter how we do the mapping.
  504. // Map any generic bits to standard & specific bits.
  505. // When using the NT5 ACL APIs, ntmarta.dll maps generic bits, so this
  506. // isn't always necessary, but we'll do it anyway to be sure.
  507. MapGenericMask(pmask, pMap);
  508. // Turn off any extra bits that ntmarta.dll may have turned on
  509. // (ntmarta uses a different mapping). But leave ACCESS_SYSTEM_SECURITY
  510. // alone in case we're editing a SACL.
  511. *pmask &= (pMap->GenericAll | ACCESS_SYSTEM_SECURITY);
  512. TraceLeaveResult(S_OK);
  513. }
  514. STDMETHODIMP
  515. CPrintSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes,
  516. ULONG *pcInheritTypes)
  517. {
  518. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::GetInheritTypes");
  519. TraceAssert(ppInheritTypes != NULL);
  520. TraceAssert(pcInheritTypes != NULL);
  521. *ppInheritTypes = siPrintInheritTypes;
  522. *pcInheritTypes = ARRAYSIZE(siPrintInheritTypes);
  523. TraceLeaveResult(S_OK);
  524. }
  525. //
  526. // The base class versions of ReadObjectSecurity and WriteObjectSecurity
  527. // use Get/SetNamedSecurityInfo, et al. These API's are generic,
  528. // involve lots of conversions, and are problematic. Since there is no
  529. // inheritance propagation required for printers, override them here
  530. // and use GetPrinter/SetPrinter.
  531. //
  532. STDMETHODIMP
  533. CPrintSecurity::ReadObjectSecurity(LPCTSTR pszObject,
  534. SECURITY_INFORMATION si,
  535. PSECURITY_DESCRIPTOR *ppSD)
  536. {
  537. HRESULT hr;
  538. DWORD dwErr = NOERROR;
  539. HANDLE hPrinter;
  540. PRINTER_DEFAULTS pd = {0};
  541. DWORD dwLength = 0;
  542. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::ReadObjectSecurity");
  543. TraceAssert(pszObject != NULL);
  544. TraceAssert(si != 0);
  545. TraceAssert(ppSD != NULL);
  546. //
  547. // Assume that required privileges have already been
  548. // enabled, if appropriate.
  549. //
  550. if (si & (DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
  551. pd.DesiredAccess |= READ_CONTROL;
  552. if (si & SACL_SECURITY_INFORMATION)
  553. pd.DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  554. __try
  555. {
  556. *ppSD = NULL;
  557. if (OpenPrinter((LPTSTR)pszObject, &hPrinter, &pd))
  558. {
  559. PPRINTER_INFO_3 ppi = NULL;
  560. if (GetPrinterAlloc(hPrinter, 3, (LPBYTE*)&ppi))
  561. {
  562. //
  563. // Rather than allocating a new buffer and copying the
  564. // security descriptor, we can re-use the existing buffer
  565. // by simply moving the security descriptor to the top.
  566. //
  567. dwLength = GetSecurityDescriptorLength(ppi->pSecurityDescriptor);
  568. *ppSD = ppi;
  569. // This is an overlapped copy, so use MoveMemory.
  570. MoveMemory(*ppSD,
  571. ppi->pSecurityDescriptor,
  572. dwLength);
  573. }
  574. else
  575. dwErr = GetLastError();
  576. ClosePrinter(hPrinter);
  577. }
  578. else
  579. dwErr = GetLastError();
  580. }
  581. __except(EXCEPTION_EXECUTE_HANDLER)
  582. {
  583. dwErr = ERROR_PROC_NOT_FOUND;
  584. }
  585. hr = HRESULT_FROM_WIN32(dwErr);
  586. TraceLeaveResult(hr);
  587. }
  588. STDMETHODIMP
  589. CPrintSecurity::WriteObjectSecurity(LPCTSTR pszObject,
  590. SECURITY_INFORMATION si,
  591. PSECURITY_DESCRIPTOR pSD)
  592. {
  593. HRESULT hr;
  594. DWORD dwErr = NOERROR;
  595. HANDLE hPrinter;
  596. PRINTER_DEFAULTS pd = {0};
  597. TraceEnter(TRACE_PRINTSI, "CPrintSecurity::WriteObjectSecurity");
  598. TraceAssert(pszObject != NULL);
  599. TraceAssert(si != 0);
  600. TraceAssert(pSD != NULL);
  601. //
  602. // Assume that required privileges have already been
  603. // enabled, if appropriate.
  604. //
  605. if (si & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
  606. pd.DesiredAccess |= WRITE_OWNER;
  607. if (si & SACL_SECURITY_INFORMATION)
  608. pd.DesiredAccess |= ACCESS_SYSTEM_SECURITY;
  609. if (si & DACL_SECURITY_INFORMATION)
  610. pd.DesiredAccess |= WRITE_DAC;
  611. __try
  612. {
  613. if (OpenPrinter((LPTSTR)pszObject, &hPrinter, &pd))
  614. {
  615. PRINTER_INFO_3 pi = { pSD };
  616. if (!SetPrinter(hPrinter, 3, (LPBYTE)&pi, 0))
  617. dwErr = GetLastError();
  618. ClosePrinter(hPrinter);
  619. }
  620. else
  621. dwErr = GetLastError();
  622. }
  623. __except(EXCEPTION_EXECUTE_HANDLER)
  624. {
  625. dwErr = ERROR_PROC_NOT_FOUND;
  626. }
  627. hr = HRESULT_FROM_WIN32(dwErr);
  628. TraceLeaveResult(hr);
  629. }
  630. STDMETHODIMP
  631. CPrintSecurity::GetInheritSource(SECURITY_INFORMATION si,
  632. PACL pACL,
  633. PINHERITED_FROM *ppInheritArray)
  634. {
  635. return E_NOTIMPL;
  636. }