/*++ Copyright (C) Microsoft Corporation, 1995 - 1997 All rights reserved. Module Name: prtsec.cxx Abstract: Print queue administration. Author: Albert Ting (AlbertT) 28-Aug-1995 Environment: Revision History: 28-Aug-1995 AlbertT Munged from prtq32.c. --*/ #include "precomp.hxx" #pragma hdrstop #include "time.hxx" #include "psetup.hxx" #include "drvsetup.hxx" #include "instarch.hxx" #include "portslv.hxx" #include "dsinterf.hxx" #include "prtprop.hxx" #ifdef SECURITY #ifndef UNICODE #error "Acledit entrypoints are Unicode only." #endif LPCTSTR gpszAclEdit = TEXT( "acledit.dll" ); LPCSTR gpszSedDiscretionaryAclEditor = "SedDiscretionaryAclEditor"; LPCSTR gpszSedSystemAclEditor = "SedSystemAclEditor"; LPCSTR gpszSedTakeOwnership = "SedTakeOwnership"; HINSTANCE TPrinterSecurity::ghLibraryAcledit; TPrinterSecurity::PFNSED_DISCRETIONARY_ACL_EDITOR TPrinterSecurity::gpfnSedDiscretionaryAclEditor; TPrinterSecurity::PFNSED_SYSTEM_ACL_EDITOR TPrinterSecurity::gpfnSedSystemAclEditor; TPrinterSecurity::PFNSED_TAKE_OWNERSHIP TPrinterSecurity::gpfnSedTakeOwnership; BOOL TPrinterSecurity::gbStringsLoaded = FALSE; GENERIC_MAPPING TPrinterSecurity::gGenericMappingPrinters = { PRINTER_READ, PRINTER_WRITE, PRINTER_EXECUTE, PRINTER_ALL_ACCESS }; GENERIC_MAPPING TPrinterSecurity::gGenericMappingDocuments = { JOB_READ, JOB_WRITE, JOB_EXECUTE, JOB_ALL_ACCESS }; SED_HELP_INFO TPrinterSecurity::gHelpInfoPermissions = { NULL, { ID_HELP_PERMISSIONS_MAIN_DLG, 0, 0, ID_HELP_PERMISSIONS_ADD_USER_DLG, ID_HELP_PERMISSIONS_LOCAL_GROUP, ID_HELP_PERMISSIONS_GLOBAL_GROUP, ID_HELP_PERMISSIONS_FIND_ACCOUNT } }; SED_HELP_INFO TPrinterSecurity::gHelpInfoAuditing = { NULL, { ID_HELP_AUDITING_MAIN_DLG, 0, 0, ID_HELP_AUDITING_ADD_USER_DLG, ID_HELP_AUDITING_LOCAL_GROUP, ID_HELP_AUDITING_GLOBAL_GROUP, ID_HELP_AUDITING_FIND_ACCOUNT } }; SED_HELP_INFO TPrinterSecurity::gHelpInfoTakeOwnership = { NULL, { ID_HELP_TAKE_OWNERSHIP } }; SED_OBJECT_TYPE_DESCRIPTOR TPrinterSecurity::gObjectTypeDescriptor = { SED_REVISION1, // Revision TRUE, // IsContainer TRUE, // AllowNewObjectPerms TRUE, // MapSpecificPermsToGeneric &TPrinterSecurity::gGenericMappingPrinters, // GenericMapping &TPrinterSecurity::gGenericMappingDocuments, // GenericMappingNewObjects NULL, // ObjectTypeName NULL, // HelpInfo NULL, // ApplyToSubContainerTitle NULL, // ApplyToObjectsTitle NULL, // ApplyToSubContainerConfirmation NULL, // SpecialObjectAccessTitle NULL // SpecialNewObjectAccessTitle }; // // Application accesses passed to the discretionary ACL editor // as well as the Take Ownership dialog. // SED_APPLICATION_ACCESS TPrinterSecurity::gpDiscretionaryAccessGroup[TPrinterSecurity::PERMS_COUNT] = { // // No Access: // { SED_DESC_TYPE_CONT_AND_NEW_OBJECT, // Type 0, // AccessMask1 0, // AccessMask2 NULL // PermissionTitle }, // // Print permission: // { SED_DESC_TYPE_CONT_AND_NEW_OBJECT, GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE, ACCESS_MASK_NEW_OBJ_NOT_SPECIFIED, NULL }, // // Document Administer permission: // { SED_DESC_TYPE_CONT_AND_NEW_OBJECT, STANDARD_RIGHTS_READ, GENERIC_ALL, NULL }, // // Administer permission: // { SED_DESC_TYPE_CONT_AND_NEW_OBJECT, GENERIC_ALL, GENERIC_ALL, NULL } }; // // Application accesses passed to the system ACL editor: // SED_APPLICATION_ACCESS TPrinterSecurity::gpSystemAccessGroup[TPrinterSecurity::PERMS_AUDIT_COUNT] = { // // Print permission: // { SED_DESC_TYPE_AUDIT, PRINTER_ACCESS_USE, ACCESS_MASK_NEW_OBJ_NOT_SPECIFIED, NULL }, { SED_DESC_TYPE_AUDIT, PRINTER_ACCESS_ADMINISTER | ACCESS_SYSTEM_SECURITY, ACCESS_MASK_NEW_OBJ_NOT_SPECIFIED, NULL }, { SED_DESC_TYPE_AUDIT, DELETE, ACCESS_MASK_NEW_OBJ_NOT_SPECIFIED, NULL }, { SED_DESC_TYPE_AUDIT, WRITE_DAC, ACCESS_MASK_NEW_OBJ_NOT_SPECIFIED, NULL }, { SED_DESC_TYPE_AUDIT, WRITE_OWNER, ACCESS_MASK_NEW_OBJ_NOT_SPECIFIED, NULL } }; /******************************************************************** Acquire a single privilege. This routine needs to be rewritten if multiple privleges are required at once. ********************************************************************/ class TAcquirePrivilege { SIGNATURE( 'acpr' ) public: TAcquirePrivilege( LPTSTR pszPrivilegeName ); ~TAcquirePrivilege(); BOOL bValid( VOID ) { return _pPrivilegesOld ? TRUE : FALSE; } private: enum _CONSTANTS { kPrivilegeSizeHint = 256, kPrivCount = 1 }; HANDLE _hToken; PTOKEN_PRIVILEGES _pPrivilegesOld; }; /******************************************************************** TAcquirePrivilege ********************************************************************/ TAcquirePrivilege:: TAcquirePrivilege( LPTSTR pszPrivilegeName ) : _hToken( NULL ), _pPrivilegesOld( NULL ) /*++ Routine Description: This adjusts the token to acquire one privilege. Note: This is efficient only for acquiring a single privilege. For multiple privileges, this routine should be rewritten so that the _hToken is reused. Arguments: pszPrivilegeName - Privilege string to acquire. Return Value: --*/ { if( !OpenThreadToken( GetCurrentThread( ), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, TRUE, &_hToken )){ SPLASSERT( !_hToken ); if( GetLastError() == ERROR_NO_TOKEN ){ // // This means we are not impersonating anybody. // Get the token out of the process. // if( !OpenProcessToken( GetCurrentProcess( ), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &_hToken )){ SPLASSERT( !_hToken ); return; } } else { SPLASSERT( !_hToken ); return; } } // // We have a valid _hToken at this point. // BYTE abyPrivileges[sizeof( TOKEN_PRIVILEGES ) + (( kPrivCount - 1 ) * sizeof( LUID_AND_ATTRIBUTES ))]; PTOKEN_PRIVILEGES pPrivilegesNew; pPrivilegesNew = (PTOKEN_PRIVILEGES)abyPrivileges; ZeroMemory( abyPrivileges, sizeof( abyPrivileges )); if( !LookupPrivilegeValue( NULL, pszPrivilegeName, &pPrivilegesNew->Privileges[0].Luid )){ DBGMSG( DBG_WARN, ( "AcquirePrivilege.ctr: LookupPrivilegeValue failed: %d\n", GetLastError( ))); return; } // // Save previous privileges. // DWORD cbPrivilegesOld = kPrivilegeSizeHint; TStatusB bStatus; Retry: _pPrivilegesOld = (PTOKEN_PRIVILEGES)AllocMem( cbPrivilegesOld ); if( !_pPrivilegesOld ){ return; } // // Set up the privilege set we will need. // pPrivilegesNew->PrivilegeCount = kPrivCount; // // Luid set above. // pPrivilegesNew->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; bStatus DBGCHK = AdjustTokenPrivileges( _hToken, FALSE, pPrivilegesNew, cbPrivilegesOld, _pPrivilegesOld, &cbPrivilegesOld ); if( !bStatus ){ FreeMem( _pPrivilegesOld ); _pPrivilegesOld = NULL; if( GetLastError() == ERROR_INSUFFICIENT_BUFFER ){ goto Retry; } DBGMSG( DBG_WARN, ( "AcquirePrivilege.ctr: AdjustTokenPrivileges failed: Error %d\n", GetLastError( ))); return; } // // _pPrivilegesOld is our valid check. // } TAcquirePrivilege:: ~TAcquirePrivilege( VOID ) /*++ Routine Description: Restore privileges and free buffer. _hToken needs to be close if it is non-NULL. _pPrivilegeOld is our valid check. Arguments: Return Value: --*/ { if( _pPrivilegesOld ){ TStatusB bStatus; bStatus DBGCHK = AdjustTokenPrivileges( _hToken, FALSE, _pPrivilegesOld, 0, NULL, NULL ); FreeMem( _pPrivilegesOld ); } if( _hToken ){ CloseHandle( _hToken ); } } /******************************************************************** Security. ********************************************************************/ BOOL TPrinterSecurity:: bInitStrings( VOID ) { // // Check whether the strings have been loaded. // if( gbStringsLoaded == TRUE ){ return TRUE; } gbStringsLoaded = TRUE; gHelpInfoPermissions.pszHelpFileName = (LPTSTR)gszWindowsHlp; gHelpInfoAuditing.pszHelpFileName = (LPTSTR)gszWindowsHlp; gHelpInfoTakeOwnership.pszHelpFileName = (LPTSTR)gszWindowsHlp; gObjectTypeDescriptor.ObjectTypeName = pszLoadString( ghInst, IDS_PRINTER ); gpDiscretionaryAccessGroup[PERMS_NOACC].PermissionTitle = pszLoadString( ghInst, IDS_SEC_NOACCESS ); gpDiscretionaryAccessGroup[PERMS_PRINT].PermissionTitle = pszLoadString( ghInst, IDS_SEC_PRINT ); gpDiscretionaryAccessGroup[PERMS_DOCAD].PermissionTitle = pszLoadString( ghInst, IDS_SEC_ADMINISTERDOCUMENTS ); gpDiscretionaryAccessGroup[PERMS_ADMIN].PermissionTitle = pszLoadString( ghInst, IDS_SEC_ADMINISTER ); gpSystemAccessGroup[PERMS_AUDIT_PRINT].PermissionTitle = pszLoadString( ghInst, IDS_SEC_AUDIT_PRINT ); gpSystemAccessGroup[PERMS_AUDIT_ADMINISTER].PermissionTitle = pszLoadString( ghInst, IDS_SEC_AUDIT_ADMINISTER ); gpSystemAccessGroup[PERMS_AUDIT_DELETE].PermissionTitle = pszLoadString( ghInst, IDS_SEC_AUDIT_DELETE ); gpSystemAccessGroup[PERMS_AUDIT_CHANGE_PERMISSIONS].PermissionTitle = pszLoadString( ghInst, IDS_SEC_CHANGE_PERMISSIONS ); gpSystemAccessGroup[PERMS_AUDIT_TAKE_OWNERSHIP].PermissionTitle = pszLoadString( ghInst, IDS_SEC_TAKE_OWNERSHIP ); return TRUE; } BOOL TPrinterSecurity:: bHandleMessage( UINT uMsg, WPARAM wParam, LPARAM lParam ) { switch( uMsg ){ case WM_INITDIALOG: if( !bInitStrings( )){ DBGMSG( DBG_ERROR, ( "PrinterSecurity.bHandlMessage: InitStrings failed %d\n", GetLastError( ))); } return TRUE; case WM_HELP: case WM_CONTEXTMENU: return PrintUIHelp( uMsg, _hDlg, wParam, lParam ); case WM_DESTROY: return TRUE; case WM_COMMAND: switch( GET_WM_COMMAND_ID( wParam, lParam )){ case IDC_SEC_PERMS: vCallDiscretionaryAclEditor(); break; case IDC_SEC_AUDIT: vCallSystemAclEditor(); break; case IDC_SEC_OWNER: vCallTakeOwnershipDialog(); break; } } return FALSE; } /******************************************************************** Load the dll. ********************************************************************/ BOOL TPrinterSecurity:: bLoadAcledit( VOID ) /*++ Routine Description: Loads acledit and sets pfns. Note: Not multithread safe, no unloading done. Arguments: Return Value: TRUE = success, FALSE = error. --*/ { if( ghLibraryAcledit ){ return TRUE; } ghLibraryAcledit = LoadLibrary( gpszAclEdit ); if( !ghLibraryAcledit ){ goto Fail; } gpfnSedDiscretionaryAclEditor = (PFNSED_DISCRETIONARY_ACL_EDITOR)GetProcAddress( ghLibraryAcledit, gpszSedDiscretionaryAclEditor ); gpfnSedSystemAclEditor = (PFNSED_SYSTEM_ACL_EDITOR)GetProcAddress( ghLibraryAcledit, gpszSedSystemAclEditor ); gpfnSedTakeOwnership = (PFNSED_TAKE_OWNERSHIP)GetProcAddress( ghLibraryAcledit, gpszSedTakeOwnership ); if( !gpfnSedDiscretionaryAclEditor || !gpfnSedSystemAclEditor || !gpfnSedTakeOwnership ){ FreeLibrary( ghLibraryAcledit ); ghLibraryAcledit = NULL; goto Fail; } return TRUE; Fail: vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE ); return FALSE; } /******************************************************************** Bring up each of the dialogs. ********************************************************************/ VOID TPrinterSecurity:: vCallDiscretionaryAclEditor( VOID ) /*++ Routine Description: Edit access privileges of print queue. Arguments: Return Values: --*/ { HANDLE hPrinterWriteDac = NULL;; DWORD dwAccess = WRITE_DAC; SED_APPLICATION_ACCESSES ApplicationAccesses; DWORD SedStatus; TStatusB bStatus; TStatus Status; Status DBGNOCHK = 0; PPRINTER_INFO_3 pInfo3 = NULL; DWORD cbInfo3 = 0; if( !bLoadAcledit( )){ goto Fail; } // // Get the security descriptor. // if( !_pPrinterData->hPrinter( )){ Status DBGCHK = ERROR_ACCESS_DENIED; goto Fail; } bStatus DBGCHK = VDataRefresh::bGetPrinter( _pPrinterData->hPrinter(), 3, (PVOID*)&pInfo3, &cbInfo3 ); if( !bStatus ){ SPLASSERT( !pInfo3 ); Status DBGCHK = GetLastError(); goto Fail; } SECURITY_CONTEXT SecurityContext; Status DBGCHK = TPrinter::sOpenPrinter( _pPrinterData->strPrinterName(), &dwAccess, &hPrinterWriteDac ); if( Status == ERROR_SUCCESS){ SPLASSERT( hPrinterWriteDac ); SecurityContext.hPrinter = hPrinterWriteDac; } else { SPLASSERT( !hPrinterWriteDac ); SecurityContext.hPrinter = _pPrinterData->hPrinter(); } SecurityContext.SecurityInformation = DACL_SECURITY_INFORMATION; SecurityContext.pPrinterSecurity = this; // // Pass all the permissions to the ACL editor, // and set up the type required: // ApplicationAccesses.Count = PERMS_COUNT; ApplicationAccesses.AccessGroup = gpDiscretionaryAccessGroup; ApplicationAccesses.DefaultPermName = gpDiscretionaryAccessGroup[PERMS_PRINT].PermissionTitle; COUNT i; for( i = 0; i < PERMS_COUNT; ++i ){ ApplicationAccesses.AccessGroup[i].Type = SED_DESC_TYPE_CONT_AND_NEW_OBJECT; } SED_OBJECT_TYPE_DESCRIPTOR Descriptor = gObjectTypeDescriptor; Descriptor.AllowNewObjectPerms = TRUE; Descriptor.HelpInfo = &gHelpInfoPermissions; Status DBGCHK = (*gpfnSedDiscretionaryAclEditor)( _hDlg, ghInst, (LPTSTR)(LPCTSTR)_pPrinterData->strServerName(), &Descriptor, &ApplicationAccesses, (LPTSTR)(LPCTSTR)_pPrinterData->strPrinterName(), SedCallback2, (DWORD)&SecurityContext, pInfo3->pSecurityDescriptor, FALSE, (BOOLEAN)!hPrinterWriteDac, &SedStatus, 0 ); Fail: if( Status ){ SetLastError( Status ); vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE ); } // // Close the printer use to write the Dac. // if( hPrinterWriteDac ){ ClosePrinter( hPrinterWriteDac ); } FreeMem( pInfo3 ); } VOID TPrinterSecurity:: vCallSystemAclEditor( VOID ) /*++ Routine Description: Edit auditing properties of print queue. Arguments: Return Values: --*/ { HANDLE hPrinterSystemAccess = NULL; SED_APPLICATION_ACCESSES ApplicationAccesses; DWORD SedStatus; TStatusB bStatus; TStatus Status; Status DBGNOCHK = 0; if( !bLoadAcledit( )){ return; } { TAcquirePrivilege AcquirePrivilege( SE_SECURITY_NAME ); if( !VALID_OBJ( AcquirePrivilege )){ vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE ); return; } DWORD dwAccess = ACCESS_SYSTEM_SECURITY; Status DBGCHK = TPrinter::sOpenPrinter( _pPrinterData->strPrinterName(), &dwAccess, &hPrinterSystemAccess ); if( Status != ERROR_SUCCESS ){ vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE ); return; } } // // Get the security descriptor. // PPRINTER_INFO_3 pInfo3 = NULL; DWORD cbInfo3 = 0; bStatus DBGCHK = VDataRefresh::bGetPrinter( hPrinterSystemAccess, 3, (PVOID*)&pInfo3, &cbInfo3 ); if( !bStatus ){ Status DBGCHK = GetLastError(); goto Fail; } SECURITY_CONTEXT SecurityContext; SecurityContext.SecurityInformation = SACL_SECURITY_INFORMATION; SecurityContext.pPrinterSecurity = this; SPLASSERT( hPrinterSystemAccess ); SecurityContext.hPrinter = hPrinterSystemAccess; // // Pass only the Print and Administer permissions to the ACL editor, // and set up the type required: // ApplicationAccesses.Count = PERMS_AUDIT_COUNT; ApplicationAccesses.AccessGroup = gpSystemAccessGroup; ApplicationAccesses.DefaultPermName = gpDiscretionaryAccessGroup[PERMS_PRINT].PermissionTitle; SED_OBJECT_TYPE_DESCRIPTOR Descriptor = gObjectTypeDescriptor; Descriptor.AllowNewObjectPerms = FALSE; Descriptor.HelpInfo = &gHelpInfoAuditing; Status DBGCHK = (*gpfnSedSystemAclEditor)( _hDlg, ghInst, (LPTSTR)(LPCTSTR)_pPrinterData->strServerName(), &Descriptor, &ApplicationAccesses, (LPTSTR)(LPCTSTR)_pPrinterData->strPrinterName(), SedCallback2, (DWORD)&SecurityContext, pInfo3->pSecurityDescriptor, FALSE, &SedStatus, 0 ); Fail: if( Status ){ SetLastError( Status ); vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE ); } FreeMem( pInfo3 ); if( hPrinterSystemAccess ){ ClosePrinter( hPrinterSystemAccess ); } } VOID TPrinterSecurity:: vCallTakeOwnershipDialog( VOID ) /*++ Routine Description: Edit ownership of print queue. How does a user get to this dialog if they can't get properties on a printer? Arguments: Return Values: --*/ { SED_APPLICATION_ACCESSES ApplicationAccesses; DWORD SedStatus; TStatusB bStatus; TStatus Status; HANDLE hPrinterWriteOwner = NULL; Status DBGNOCHK = 0; if( !bLoadAcledit( )){ return; } // // Get the security descriptor. // PPRINTER_INFO_3 pInfo3 = NULL; DWORD cbInfo3 = 0; // // Attempt to retrieve the previous owner. // if( _pPrinterData->hPrinter( )){ bStatus DBGCHK = VDataRefresh::bGetPrinter( _pPrinterData->hPrinter(), 3, (PVOID*)&pInfo3, &cbInfo3 ); } { TAcquirePrivilege AcquirePrivilege( SE_TAKE_OWNERSHIP_NAME ); SECURITY_CONTEXT SecurityContext; DWORD dwAccess = WRITE_OWNER; Status DBGCHK = TPrinter::sOpenPrinter( _pPrinterData->strPrinterName(), &dwAccess, &hPrinterWriteOwner ); if( Status == ERROR_SUCCESS){ SPLASSERT( hPrinterWriteOwner ); SecurityContext.hPrinter = hPrinterWriteOwner; } else { SPLASSERT( !hPrinterWriteOwner ); SecurityContext.hPrinter = _pPrinterData->hPrinter(); } SecurityContext.SecurityInformation = OWNER_SECURITY_INFORMATION; SecurityContext.pPrinterSecurity = this; ApplicationAccesses.Count = PERMS_COUNT; ApplicationAccesses.AccessGroup = gpDiscretionaryAccessGroup; ApplicationAccesses.DefaultPermName = gpDiscretionaryAccessGroup[PERMS_PRINT].PermissionTitle; COUNT i; for( i = 0; i < PERMS_COUNT; ++i ){ ApplicationAccesses.AccessGroup[i].Type = SED_DESC_TYPE_AUDIT; } BOOL bCantReadOwner; PSECURITY_DESCRIPTOR pSecurityDescriptor; bCantReadOwner = pInfo3 ? FALSE : TRUE; pSecurityDescriptor = pInfo3 ? pInfo3->pSecurityDescriptor : NULL; TString strPrinter; bStatus DBGCHK = strPrinter.bLoadString( ghInst, IDS_PRINTER ); Status DBGCHK = (*gpfnSedTakeOwnership)( _hDlg, ghInst, (LPTSTR)(LPCTSTR)_pPrinterData->strServerName(), (LPTSTR)(LPCTSTR)strPrinter, (LPTSTR)(LPCTSTR)_pPrinterData->strPrinterName(), 1, SedCallback2, (DWORD)&SecurityContext, pSecurityDescriptor, (BOOLEAN)bCantReadOwner, (BOOLEAN)!hPrinterWriteOwner, &SedStatus, &gHelpInfoTakeOwnership, 0 ); } if( hPrinterWriteOwner ){ ClosePrinter( hPrinterWriteOwner ); } FreeMem( pInfo3 ); } /******************************************************************** Security callback routine. ********************************************************************/ DWORD TPrinterSecurity:: SedCallback2( HWND hwndParent, HANDLE hInstance, DWORD dwCallBackContext, PSECURITY_DESCRIPTOR psdUpdated, PSECURITY_DESCRIPTOR pSecDescNewObjects, BOOLEAN bApplyToSubContainers, BOOLEAN bApplyToSubObjects, LPDWORD pdwStatusReturn ) /*++ Routine Description: Called by acledit to process writes. Arguments: . Return Values: . --*/ { UNREFERENCED_PARAMETER( pdwStatusReturn ); UNREFERENCED_PARAMETER( bApplyToSubObjects ); UNREFERENCED_PARAMETER( bApplyToSubContainers ); UNREFERENCED_PARAMETER( pSecDescNewObjects ); UNREFERENCED_PARAMETER( hInstance ); UNREFERENCED_PARAMETER( hwndParent ); PSECURITY_CONTEXT pSecurityContext; SECURITY_DESCRIPTOR SecurityDescriptorNew; PSECURITY_DESCRIPTOR pSelfRelativeSD = NULL; DWORD cbSelfRelativeSD; TStatusB bStatus; pSecurityContext = (PSECURITY_CONTEXT)dwCallBackContext; SPLASSERT( pSecurityContext->hPrinter ); if( InitializeSecurityDescriptor( &SecurityDescriptorNew, SECURITY_DESCRIPTOR_REVISION1 ) && BuildNewSecurityDescriptor( &SecurityDescriptorNew, pSecurityContext->SecurityInformation, psdUpdated )){ pSelfRelativeSD = AllocCopySecurityDescriptor( &SecurityDescriptorNew, &cbSelfRelativeSD ); } else { DBGMSG( DBG_ERROR, ( "PrinterSecurity.SedCallback2: InitializeSD failedt %d\n", GetLastError( ))); } if( !pSelfRelativeSD ){ DBGMSG( DBG_WARN, ( "PrinterSecurity.SedCallback2: Alloc copy sd failed %d\n", GetLastError( ))); SPLASSERT( GetLastError( )); vShowUnexpectedError( NULL, IDS_ERR_PRINTER_PROP_TITLE ); return GetLastError(); } PRINTER_INFO_3 PrinterInfo3; PrinterInfo3.pSecurityDescriptor = pSelfRelativeSD; bStatus DBGCHK = SetPrinter( pSecurityContext->hPrinter, 3, (PBYTE)&PrinterInfo3, 0 ); // // Free the newly created sd. // FreeMem( pSelfRelativeSD ); if( !bStatus ){ SPLASSERT( GetLastError( )); iMessage( NULL, IDS_ERR_PRINTER_PROP_TITLE, IDS_ERR_SAVE_PRINTER, MB_OK|MB_ICONHAND, kMsgGetLastError, NULL ); return GetLastError(); } // // Refresh the property page set. // pSecurityContext->pPrinterSecurity->vReloadPages(); return ERROR_SUCCESS; } /******************************************************************** Helpers. ********************************************************************/ BOOL TPrinterSecurity:: BuildNewSecurityDescriptor( PSECURITY_DESCRIPTOR psdNew, SECURITY_INFORMATION SecurityInformation, PSECURITY_DESCRIPTOR psdUpdated ) /*++ Routine Description: Builds new security desriptor. Arguments: Return Values: --*/ { BOOL bDefaulted = FALSE; PSID pOwnerSid = NULL; PSID pGroupSid = NULL; BOOL bDaclPresent = FALSE; PACL pDacl = NULL; BOOL bSaclPresent = FALSE; PACL pSacl = NULL; TStatusB bStatus; switch( SecurityInformation ){ case OWNER_SECURITY_INFORMATION: if( GetSecurityDescriptorOwner( psdUpdated, &pOwnerSid, &bDefaulted )){ bStatus DBGCHK = SetSecurityDescriptorOwner( psdNew, pOwnerSid, bDefaulted ); } break; case DACL_SECURITY_INFORMATION: if( GetSecurityDescriptorDacl( psdUpdated, &bDaclPresent, &pDacl, &bDefaulted )) { bStatus DBGCHK = SetSecurityDescriptorDacl( psdNew, bDaclPresent, pDacl, bDefaulted ); } break; case SACL_SECURITY_INFORMATION: if( GetSecurityDescriptorSacl( psdUpdated, &bSaclPresent, &pSacl, &bDefaulted )) { bStatus DBGCHK = SetSecurityDescriptorSacl( psdNew, bSaclPresent, pSacl, bDefaulted ); } break; default: DBGMSG( DBG_ERROR, ( "PrinterSecurity.BuildSD: Unknown type %d\n", SecurityInformation )); return FALSE; } return bStatus; } PSECURITY_DESCRIPTOR TPrinterSecurity:: AllocCopySecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecurityDescriptor, OUT PDWORD pdwLength ) /*++ Routine Description: Alloc copy of security descriptor. Arguments: pSecurityDescriptor - sd to copy. pdwLength - Output length. Return Value: Newly allocated sd. NULL if failed. --*/ { PSECURITY_DESCRIPTOR psdCopy; DWORD dwLength; dwLength = GetSecurityDescriptorLength(pSecurityDescriptor); psdCopy = AllocMem( dwLength ); if( psdCopy ){ MakeSelfRelativeSD( pSecurityDescriptor, psdCopy, &dwLength); *pdwLength = dwLength; } return psdCopy; } #endif // def SECURITY