//+------------------------------------------------------------------------- // // Microsoft Windows // // Copyright (C) Microsoft Corporation, 1996 - 1999 // // File: printsi.cpp // // This file contains the implementation of the CPrintSecurity object. // //-------------------------------------------------------------------------- #include "rshx32.h" // The following array defines the permission names for NT printers. SI_ACCESS siPrintAccesses[] = { { &GUID_NULL, PRINTER_EXECUTE, MAKEINTRESOURCE(IDS_PRINT_PRINT), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC }, { &GUID_NULL, PRINTER_ALL_ACCESS, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC }, { &GUID_NULL, JOB_ALL_ACCESS, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER_JOBS), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE }, // { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_PRINT_DELETE), SI_ACCESS_SPECIFIC }, { &GUID_NULL, STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_PRINT_READ), SI_ACCESS_SPECIFIC }, { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_PRINT_CHANGE_PERM), SI_ACCESS_SPECIFIC }, { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_PRINT_CHANGE_OWNER), SI_ACCESS_SPECIFIC }, { &GUID_NULL, PRINTER_ALL_ACCESS|JOB_ALL_ACCESS, MAKEINTRESOURCE(IDS_PRINT_JOB_ALL), 0 }, { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NONE), 0 }, }; #define iPrintDefAccess 0 // PRINTER_EXECUTE (i.e. "Print" access) #define PRINTER_ALL_AUDIT (PRINTER_ALL_ACCESS | ACCESS_SYSTEM_SECURITY) #define JOB_ALL_AUDIT (JOB_ALL_ACCESS | ACCESS_SYSTEM_SECURITY) #define PRINTER_JOB_ALL_AUDIT (PRINTER_ALL_ACCESS | JOB_ALL_ACCESS | ACCESS_SYSTEM_SECURITY) // The following array defines the auditting names for NT printers. SI_ACCESS siPrintAudits[] = { { &GUID_NULL, PRINTER_EXECUTE, MAKEINTRESOURCE(IDS_PRINT_PRINT), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC }, { &GUID_NULL, PRINTER_ALL_AUDIT, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC }, { &GUID_NULL, JOB_ALL_AUDIT, MAKEINTRESOURCE(IDS_PRINT_ADMINISTER_JOBS), SI_ACCESS_GENERAL | SI_ACCESS_SPECIFIC | OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE }, // { &GUID_NULL, DELETE, MAKEINTRESOURCE(IDS_PRINT_DELETE), SI_ACCESS_SPECIFIC }, { &GUID_NULL, STANDARD_RIGHTS_READ, MAKEINTRESOURCE(IDS_PRINT_READ), SI_ACCESS_SPECIFIC }, { &GUID_NULL, WRITE_DAC, MAKEINTRESOURCE(IDS_PRINT_CHANGE_PERM), SI_ACCESS_SPECIFIC }, { &GUID_NULL, WRITE_OWNER, MAKEINTRESOURCE(IDS_PRINT_CHANGE_OWNER), SI_ACCESS_SPECIFIC }, { &GUID_NULL, PRINTER_ALL_AUDIT|JOB_ALL_AUDIT, MAKEINTRESOURCE(IDS_PRINT_JOB_ALL), 0 }, { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_NONE), 0 }, }; #define iPrintDefAudit 0 // PRINTER_EXECUTE (i.e. "Print" access) // The following array defines the inheritance types for NT printers. SI_INHERIT_TYPE siPrintInheritTypes[] = { &GUID_NULL, 0, MAKEINTRESOURCE(IDS_PRINT_PRINTER), &GUID_NULL, INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_PRINT_DOCUMENT_ONLY), &GUID_NULL, OBJECT_INHERIT_ACE, MAKEINTRESOURCE(IDS_PRINT_PRINTER_DOCUMENT), }; BOOL GetPrinterAlloc(HANDLE hPrinter, DWORD dwLevel, LPBYTE *ppBuffer) { BOOL bResult; DWORD dwLength = 0; LPBYTE pBuffer = NULL; bResult = GetPrinter(hPrinter, dwLevel, NULL, 0, &dwLength); if (dwLength) { bResult = FALSE; pBuffer = (LPBYTE)LocalAlloc(LPTR, dwLength); if (pBuffer) { bResult = GetPrinter(hPrinter, dwLevel, pBuffer, dwLength, &dwLength); if (!bResult) { LocalFree(pBuffer); pBuffer = NULL; } } } *ppBuffer = pBuffer; return bResult; } STDMETHODIMP CheckPrinterAccess(LPCTSTR pszObjectName, LPDWORD pdwAccessGranted, LPTSTR pszServer, ULONG cchServer) { HRESULT hr = S_OK; UINT i; PRINTER_DEFAULTS PrinterDefaults; DWORD dwAccessDesired[] = { ALL_SECURITY_ACCESS, READ_CONTROL, WRITE_DAC, WRITE_OWNER, ACCESS_SYSTEM_SECURITY }; HANDLE hPrinter = NULL; PrinterDefaults.pDatatype = NULL; PrinterDefaults.pDevMode = NULL; TraceEnter(TRACE_PRINTSI, "CheckPrinterAccess"); TraceAssert(pdwAccessGranted != NULL); __try { *pdwAccessGranted = 0; for (i = 0; i < ARRAYSIZE(dwAccessDesired); i++) { if ((dwAccessDesired[i] & *pdwAccessGranted) == dwAccessDesired[i]) continue; // already have this access PrinterDefaults.DesiredAccess = dwAccessDesired[i]; if (OpenPrinter((LPTSTR)pszObjectName, &hPrinter, &PrinterDefaults)) { *pdwAccessGranted |= dwAccessDesired[i]; ClosePrinter(hPrinter); } else { DWORD dwErr = GetLastError(); if (dwErr != ERROR_ACCESS_DENIED && dwErr != ERROR_PRIVILEGE_NOT_HELD) { ExitGracefully(hr, HRESULT_FROM_WIN32(dwErr), "OpenPrinter failed"); } } } if (pszServer) { PrinterDefaults.DesiredAccess = PRINTER_READ; if (OpenPrinter((LPTSTR)pszObjectName, &hPrinter, &PrinterDefaults)) { PPRINTER_INFO_2 ppi = NULL; if (GetPrinterAlloc(hPrinter, 2, (LPBYTE*)&ppi)) { if (ppi && ppi->pServerName) lstrcpyn(pszServer, ppi->pServerName, cchServer); else *pszServer = TEXT('\0'); LocalFree(ppi); } ClosePrinter(hPrinter); } } } __except(EXCEPTION_EXECUTE_HANDLER) { hr = HRESULT_FROM_WIN32(ERROR_PROC_NOT_FOUND); } exit_gracefully: Trace((TEXT("Access = 0x%08x"), *pdwAccessGranted)); TraceLeaveResult(hr); } STDMETHODIMP CPrintSecurity::Initialize(HDPA hItemList, DWORD dwFlags, LPTSTR pszServer, LPTSTR pszObject) { return CSecurityInformation::Initialize(hItemList, dwFlags | SI_NO_TREE_APPLY | SI_NO_ACL_PROTECT, pszServer, pszObject); } // // NT6 REVIEW // // GetAceSid, FindManagePrinterACE, MungeAclForPrinter and // CPrintSecurity::SetSecurity only exist here because // 1) The spooler removes JOB_ACCESS_ADMINISTER from an ACE unless the // ACE has INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE. // 2) The NT4 ACL editor (ACLEDIT) needs extra bogus ACEs to recognize // "Manage Documents" access. (Must support downlevel clients.) // // The first case should be rare, since you have to perform certain // steps in the NT5 ACL editor (ACLUI) to cause this situation. The // second situation is common, since CREATER_OWNER and Administrators // usually have "Manage Documents" access. // // If the spooler guys decide to not support NT4 clients for NT6, and they // stop stripping JOB_ACCESS_ADMINISTER from ACEs, then MungeAclForPrinter // and CPrintSecurity::SetSecurity can be removed entirely. ENCOURAGE THEM // TO MAKE THAT CHANGE. (They can also remove similar hacks from their own // code that add bogus ACEs for the old ACL editor.) // PSID GetAceSid(PACE_HEADER pAce) { switch (pAce->AceType) { case ACCESS_ALLOWED_ACE_TYPE: case ACCESS_DENIED_ACE_TYPE: case SYSTEM_AUDIT_ACE_TYPE: case SYSTEM_ALARM_ACE_TYPE: return (PSID)&((PKNOWN_ACE)pAce)->SidStart; case ACCESS_ALLOWED_COMPOUND_ACE_TYPE: return (PSID)&((PCOMPOUND_ACCESS_ALLOWED_ACE)pAce)->SidStart; case ACCESS_ALLOWED_OBJECT_ACE_TYPE: case ACCESS_DENIED_OBJECT_ACE_TYPE: case SYSTEM_AUDIT_OBJECT_ACE_TYPE: case SYSTEM_ALARM_OBJECT_ACE_TYPE: return RtlObjectAceSid(pAce); } return NULL; } PACE_HEADER FindManagePrinterACE(PACL pAcl, PSID pSid) { UINT i; PACE_HEADER pAce; if (!pAcl || !pSid) return NULL; for (i = 0, pAce = (PACE_HEADER)FirstAce(pAcl); i < pAcl->AceCount; i++, pAce = (PACE_HEADER)NextAce(pAce)) { if (pAce->AceType == ACCESS_ALLOWED_ACE_TYPE && (((PKNOWN_ACE)pAce)->Mask & PRINTER_ALL_ACCESS) == PRINTER_ALL_ACCESS && !(pAce->AceFlags & INHERIT_ONLY_ACE) && EqualSid(pSid, GetAceSid(pAce))) { return pAce; } } return NULL; } BOOL MungeAclForPrinter(PACL pAcl, PACL *ppAclOut) { USHORT i; PACE_HEADER pAce; PACE_HEADER pAceCopy = NULL; if (ppAclOut == NULL) return FALSE; *ppAclOut = NULL; if (pAcl == NULL) return TRUE; TraceEnter(TRACE_PRINTSI, "MungeAclForPrinter"); for (i = 0, pAce = (PACE_HEADER)FirstAce(pAcl); i < pAcl->AceCount; i++, pAce = (PACE_HEADER)NextAce(pAce)) { // // If this ACE has the JOB_ACCESS_ADMINISTER bit and the inherit // flags indicate that it applies to both printers and documents, // then we need to treat it specially, since the spooler won't save // JOB_ACCESS_ADMINISTER on a printer ACE (INHERIT_ONLY_ACE not set). // if ((((PKNOWN_ACE)pAce)->Mask & JOB_ACCESS_ADMINISTER) && (pAce->AceFlags & (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)) == OBJECT_INHERIT_ACE) { // // Split into 2 aces: one with no inheritance, and one with // INHERIT_ONLY_ACE turned on. Let the spooler do whatever // it wants with the mask. // // This requires allocating a larger ACL and copying all // previous aces over. // TraceMsg("Splitting JOB_ACCESS_ADMINISTER ACE into 2"); if (*ppAclOut == NULL) { // // Allocate new ACL and copy previous aces. The length is enough // for 1 copy of all previous aces, and 3 copies (max) of all // remaining aces. // ULONG nPrevLength = (ULONG)((ULONG_PTR)pAce - (ULONG_PTR)pAcl); *ppAclOut = (PACL)LocalAlloc(LPTR, nPrevLength + (pAcl->AclSize - nPrevLength) * 3); if (!*ppAclOut) TraceLeaveValue(FALSE); CopyMemory(*ppAclOut, pAcl, nPrevLength); (*ppAclOut)->AclSize = (USHORT)LocalSize(*ppAclOut); (*ppAclOut)->AceCount = i; pAceCopy = (PACE_HEADER)ByteOffset(*ppAclOut, nPrevLength); } // Turn off inheritance and copy this ace pAce->AceFlags &= ~OBJECT_INHERIT_ACE; CopyMemory(pAceCopy, pAce, pAce->AceSize); pAceCopy = (PACE_HEADER)NextAce(pAceCopy); (*ppAclOut)->AceCount++; // Now turn on inheritance (with INHERIT_ONLY_ACE) and copy it // again (it gets copied way down below). Note that this may // causes the next IF clause to add a bogus ACE also. pAce->AceFlags |= OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE; } // // If this ACE has JOB_ALL_ACCESS and INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, // and there isn't also a "Manage Printers" ACE for the same SID, add a // bogus ACE with READ_CONTROL and CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE. // The old ACL editor on downlevel clients needs this to recognize // "Manage Documents" access. // if (pAce->AceType == ACCESS_ALLOWED_ACE_TYPE && (((PKNOWN_ACE)pAce)->Mask & JOB_ALL_ACCESS) == JOB_ALL_ACCESS && (pAce->AceFlags & (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE)) == (INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE) && !FindManagePrinterACE(pAcl, GetAceSid(pAce))) { TraceMsg("Adding bogus ACE for downlevel support"); if (*ppAclOut == NULL) { // // Allocate new ACL and copy previous aces. The length is enough // for 1 copy of all previous aces, and 3 copies (max) of all // remaining aces. // ULONG nPrevLength = (ULONG)((ULONG_PTR)pAce - (ULONG_PTR)pAcl); *ppAclOut = (PACL)LocalAlloc(LPTR, nPrevLength + (pAcl->AclSize - nPrevLength) * 3); if (!*ppAclOut) TraceLeaveValue(FALSE); CopyMemory(*ppAclOut, pAcl, nPrevLength); (*ppAclOut)->AclSize = (USHORT)LocalSize(*ppAclOut); (*ppAclOut)->AceCount = i; pAceCopy = (PACE_HEADER)ByteOffset(*ppAclOut, nPrevLength); } // Copy this ace, turn on CONTAINER_INHERIT_ACE, and set // the mask to STANDARD_RIGHTS_READ. CopyMemory(pAceCopy, pAce, pAce->AceSize); pAceCopy->AceFlags &= ~OBJECT_INHERIT_ACE; pAceCopy->AceFlags |= INHERIT_ONLY_ACE | CONTAINER_INHERIT_ACE; ((PKNOWN_ACE)pAceCopy)->Mask = STANDARD_RIGHTS_READ; pAceCopy = (PACE_HEADER)NextAce(pAceCopy); (*ppAclOut)->AceCount++; } if (*ppAclOut != NULL) { // Copy current ace CopyMemory(pAceCopy, pAce, pAce->AceSize); pAceCopy = (PACE_HEADER)NextAce(pAceCopy); (*ppAclOut)->AceCount++; } } if (*ppAclOut != NULL) { TraceAssert((ULONG_PTR)pAceCopy > (ULONG_PTR)*ppAclOut && (ULONG_PTR)pAceCopy <= (ULONG_PTR)*ppAclOut + (*ppAclOut)->AclSize); // Set the ACL size to the correct value (*ppAclOut)->AclSize = (WORD)((ULONG_PTR)pAceCopy - (ULONG_PTR)*ppAclOut); } TraceLeaveValue(TRUE); } /////////////////////////////////////////////////////////// // // ISecurityInformation methods // /////////////////////////////////////////////////////////// STDMETHODIMP CPrintSecurity::SetSecurity(SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD) { PACL pDacl = NULL; PACL pSacl = NULL; PACL pDaclCopy = NULL; PACL pSaclCopy = NULL; BOOL bPresent; BOOL bDefaulted; SECURITY_DESCRIPTOR sd; TraceEnter(TRACE_PRINTSI, "CPrintSecurity::SetSecurity"); if ((si & DACL_SECURITY_INFORMATION) && GetSecurityDescriptorDacl(pSD, &bPresent, &pDacl, &bDefaulted) && bPresent) { if (MungeAclForPrinter(pDacl, &pDaclCopy) && pDaclCopy) pDacl = pDaclCopy; } if ((si & SACL_SECURITY_INFORMATION) && GetSecurityDescriptorSacl(pSD, &bPresent, &pSacl, &bDefaulted) && bPresent) { if (MungeAclForPrinter(pSacl, &pSaclCopy) && pSaclCopy) pSacl = pSaclCopy; } if (pDaclCopy || pSaclCopy) { // Build a new SECURITY_DESCRIPTOR PSID psid; DWORD dwRevision; SECURITY_DESCRIPTOR_CONTROL sdControl = 0; GetSecurityDescriptorControl(pSD, &sdControl, &dwRevision); InitializeSecurityDescriptor(&sd, dwRevision); sd.Control = (SECURITY_DESCRIPTOR_CONTROL)(sdControl & ~SE_SELF_RELATIVE); if ((si & OWNER_SECURITY_INFORMATION) && GetSecurityDescriptorOwner(pSD, &psid, &bDefaulted)) { SetSecurityDescriptorOwner(&sd, psid, bDefaulted); } if ((si & GROUP_SECURITY_INFORMATION) && GetSecurityDescriptorGroup(pSD, &psid, &bDefaulted)) { SetSecurityDescriptorGroup(&sd, psid, bDefaulted); } if (si & SACL_SECURITY_INFORMATION) { SetSecurityDescriptorSacl(&sd, sdControl & SE_SACL_PRESENT, pSacl, sdControl & SE_SACL_DEFAULTED); } if (si & DACL_SECURITY_INFORMATION) { SetSecurityDescriptorDacl(&sd, sdControl & SE_DACL_PRESENT, pDacl, sdControl & SE_DACL_DEFAULTED); } // Switch to the new security descriptor pSD = &sd; } // The base class does the rest of the work HRESULT hr = CSecurityInformation::SetSecurity(si, pSD); if (pDaclCopy) LocalFree(pDaclCopy); if (pSaclCopy) LocalFree(pSaclCopy); TraceLeaveResult(hr); } STDMETHODIMP CPrintSecurity::GetAccessRights(const GUID* /*pguidObjectType*/, DWORD dwFlags, PSI_ACCESS *ppAccesses, ULONG *pcAccesses, ULONG *piDefaultAccess) { TraceEnter(TRACE_PRINTSI, "CPrintSecurity::GetAccessRights"); TraceAssert(ppAccesses != NULL); TraceAssert(pcAccesses != NULL); TraceAssert(piDefaultAccess != NULL); if (dwFlags & SI_EDIT_AUDITS) { *ppAccesses = siPrintAudits; *pcAccesses = ARRAYSIZE(siPrintAudits); *piDefaultAccess = iPrintDefAudit; } else { *ppAccesses = siPrintAccesses; *pcAccesses = ARRAYSIZE(siPrintAccesses); *piDefaultAccess = iPrintDefAccess; } TraceLeaveResult(S_OK); } GENERIC_MAPPING JobMap = { JOB_READ, JOB_WRITE, JOB_EXECUTE, JOB_ALL_ACCESS }; GENERIC_MAPPING PrinterMap = { PRINTER_READ, PRINTER_WRITE, PRINTER_EXECUTE, PRINTER_ALL_ACCESS }; GENERIC_MAPPING FullPrinterMap = { PRINTER_READ | JOB_READ, PRINTER_WRITE | JOB_WRITE, PRINTER_EXECUTE | JOB_EXECUTE, PRINTER_ALL_ACCESS | JOB_ALL_ACCESS }; STDMETHODIMP CPrintSecurity::MapGeneric(const GUID* /*pguidObjectType*/, UCHAR *pAceFlags, ACCESS_MASK *pmask) { PGENERIC_MAPPING pMap; TraceEnter(TRACE_PRINTSI, "CPrintSecurity::MapGeneric"); TraceAssert(pAceFlags != NULL); TraceAssert(pmask != NULL); // This flag has no meaning for printers, but it's often turned on // in legacy ACLs. Turn it off here *pAceFlags &= ~CONTAINER_INHERIT_ACE; // Choose the correct generic mapping according to the inherit // scope of this ACE. if (*pAceFlags & OBJECT_INHERIT_ACE) { if (*pAceFlags & INHERIT_ONLY_ACE) pMap = &JobMap; // documents only else pMap = &FullPrinterMap; // printers & documents } else pMap = &PrinterMap; // printers only // Note that the case where INHERIT_ONLY_ACE is ON but OBJECT_INHERIT_ACE // is OFF falls under the "printers only" case above. However, this // case makes no sense (inherit-only, but not onto documents) and it // doesn't matter how we do the mapping. // Map any generic bits to standard & specific bits. // When using the NT5 ACL APIs, ntmarta.dll maps generic bits, so this // isn't always necessary, but we'll do it anyway to be sure. MapGenericMask(pmask, pMap); // Turn off any extra bits that ntmarta.dll may have turned on // (ntmarta uses a different mapping). But leave ACCESS_SYSTEM_SECURITY // alone in case we're editing a SACL. *pmask &= (pMap->GenericAll | ACCESS_SYSTEM_SECURITY); TraceLeaveResult(S_OK); } STDMETHODIMP CPrintSecurity::GetInheritTypes(PSI_INHERIT_TYPE *ppInheritTypes, ULONG *pcInheritTypes) { TraceEnter(TRACE_PRINTSI, "CPrintSecurity::GetInheritTypes"); TraceAssert(ppInheritTypes != NULL); TraceAssert(pcInheritTypes != NULL); *ppInheritTypes = siPrintInheritTypes; *pcInheritTypes = ARRAYSIZE(siPrintInheritTypes); TraceLeaveResult(S_OK); } // // The base class versions of ReadObjectSecurity and WriteObjectSecurity // use Get/SetNamedSecurityInfo, et al. These API's are generic, // involve lots of conversions, and are problematic. Since there is no // inheritance propagation required for printers, override them here // and use GetPrinter/SetPrinter. // STDMETHODIMP CPrintSecurity::ReadObjectSecurity(LPCTSTR pszObject, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR *ppSD) { HRESULT hr; DWORD dwErr = NOERROR; HANDLE hPrinter; PRINTER_DEFAULTS pd = {0}; DWORD dwLength = 0; TraceEnter(TRACE_PRINTSI, "CPrintSecurity::ReadObjectSecurity"); TraceAssert(pszObject != NULL); TraceAssert(si != 0); TraceAssert(ppSD != NULL); // // Assume that required privileges have already been // enabled, if appropriate. // if (si & (DACL_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) pd.DesiredAccess |= READ_CONTROL; if (si & SACL_SECURITY_INFORMATION) pd.DesiredAccess |= ACCESS_SYSTEM_SECURITY; __try { *ppSD = NULL; if (OpenPrinter((LPTSTR)pszObject, &hPrinter, &pd)) { PPRINTER_INFO_3 ppi = NULL; if (GetPrinterAlloc(hPrinter, 3, (LPBYTE*)&ppi)) { // // Rather than allocating a new buffer and copying the // security descriptor, we can re-use the existing buffer // by simply moving the security descriptor to the top. // dwLength = GetSecurityDescriptorLength(ppi->pSecurityDescriptor); *ppSD = ppi; // This is an overlapped copy, so use MoveMemory. MoveMemory(*ppSD, ppi->pSecurityDescriptor, dwLength); } else dwErr = GetLastError(); ClosePrinter(hPrinter); } else dwErr = GetLastError(); } __except(EXCEPTION_EXECUTE_HANDLER) { dwErr = ERROR_PROC_NOT_FOUND; } hr = HRESULT_FROM_WIN32(dwErr); TraceLeaveResult(hr); } STDMETHODIMP CPrintSecurity::WriteObjectSecurity(LPCTSTR pszObject, SECURITY_INFORMATION si, PSECURITY_DESCRIPTOR pSD) { HRESULT hr; DWORD dwErr = NOERROR; HANDLE hPrinter; PRINTER_DEFAULTS pd = {0}; TraceEnter(TRACE_PRINTSI, "CPrintSecurity::WriteObjectSecurity"); TraceAssert(pszObject != NULL); TraceAssert(si != 0); TraceAssert(pSD != NULL); // // Assume that required privileges have already been // enabled, if appropriate. // if (si & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) pd.DesiredAccess |= WRITE_OWNER; if (si & SACL_SECURITY_INFORMATION) pd.DesiredAccess |= ACCESS_SYSTEM_SECURITY; if (si & DACL_SECURITY_INFORMATION) pd.DesiredAccess |= WRITE_DAC; __try { if (OpenPrinter((LPTSTR)pszObject, &hPrinter, &pd)) { PRINTER_INFO_3 pi = { pSD }; if (!SetPrinter(hPrinter, 3, (LPBYTE)&pi, 0)) dwErr = GetLastError(); ClosePrinter(hPrinter); } else dwErr = GetLastError(); } __except(EXCEPTION_EXECUTE_HANDLER) { dwErr = ERROR_PROC_NOT_FOUND; } hr = HRESULT_FROM_WIN32(dwErr); TraceLeaveResult(hr); } STDMETHODIMP CPrintSecurity::GetInheritSource(SECURITY_INFORMATION si, PACL pACL, PINHERITED_FROM *ppInheritArray) { return E_NOTIMPL; }