// PermPage.cpp : Implementation of data object classes #include "stdafx.h" #include "cookie.h" #include "macros.h" USE_HANDLE_MACROS("FILEMGMT(PermPage.cpp)") #include "DynamLnk.h" // DynamicDLL #include "PermPage.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /* * Share General Permissions -- from shareacl.hxx #define FILE_PERM_GEN_NO_ACCESS (0) #define FILE_PERM_GEN_READ (GENERIC_READ |\ GENERIC_EXECUTE) #define FILE_PERM_GEN_MODIFY (GENERIC_READ |\ GENERIC_EXECUTE |\ GENERIC_WRITE |\ DELETE ) #define FILE_PERM_GEN_ALL (GENERIC_ALL) */ SI_ACCESS siShareAccesses[] = { { &GUID_NULL, FILE_ALL_ACCESS, MAKEINTRESOURCE(IDS_SHAREPERM_ALL), SI_ACCESS_GENERAL }, { &GUID_NULL, FILE_GENERIC_READ | FILE_EXECUTE | FILE_GENERIC_WRITE | DELETE, MAKEINTRESOURCE(IDS_SHAREPERM_MODIFY), SI_ACCESS_GENERAL }, { &GUID_NULL, FILE_GENERIC_READ | FILE_EXECUTE, MAKEINTRESOURCE(IDS_SHAREPERM_READ), SI_ACCESS_GENERAL } }; #define iShareDefAccess 2 // index of value in array siShareAccesses #ifndef ARRAYSIZE #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) #endif STDMETHODIMP CSecurityInformation::GetAccessRights( const GUID * /*pguidObjectType*/, DWORD /*dwFlags*/, PSI_ACCESS *ppAccess, ULONG *pcAccesses, ULONG *piDefaultAccess ) { ASSERT(ppAccess); ASSERT(pcAccesses); ASSERT(piDefaultAccess); *ppAccess = siShareAccesses; *pcAccesses = ARRAYSIZE(siShareAccesses); *piDefaultAccess = iShareDefAccess; return S_OK; } // This is consistent with the NETUI code GENERIC_MAPPING ShareMap = { FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS }; STDMETHODIMP CSecurityInformation::MapGeneric( const GUID * /*pguidObjectType*/, UCHAR * /*pAceFlags*/, ACCESS_MASK *pMask ) { ASSERT(pMask); MapGenericMask(pMask, &ShareMap); return S_OK; } STDMETHODIMP CSecurityInformation::GetInheritTypes ( PSI_INHERIT_TYPE * /*ppInheritTypes*/, ULONG * /*pcInheritTypes*/ ) { return E_NOTIMPL; } STDMETHODIMP CSecurityInformation::PropertySheetPageCallback( HWND /*hwnd*/, UINT /*uMsg*/, SI_PAGE_TYPE /*uPage*/ ) { return S_OK; } /* JeffreyS 1/24/97: If you don't set the SI_RESET flag in ISecurityInformation::GetObjectInformation, then fDefault should never be TRUE so you can ignore it. Returning E_NOTIMPL in this case is OK too. If you want the user to be able to reset the ACL to some default state (defined by you) then turn on SI_RESET and return your default ACL when fDefault is TRUE. This happens if/when the user pushes a button that is only visible when SI_RESET is on. */ STDMETHODIMP CShareSecurityInformation::GetObjectInformation ( PSI_OBJECT_INFO pObjectInfo ) { ASSERT(pObjectInfo != NULL && !IsBadWritePtr(pObjectInfo, sizeof(*pObjectInfo))); pObjectInfo->dwFlags = SI_EDIT_ALL | SI_NO_ACL_PROTECT | SI_PAGE_TITLE; pObjectInfo->hInstance = g_hInstanceSave; pObjectInfo->pszServerName = QueryMachineName(); pObjectInfo->pszObjectName = QueryShareName(); pObjectInfo->pszPageTitle = QueryPageTitle(); return S_OK; } typedef enum _AcluiApiIndex { ACLUI_CREATE_PAGE = 0 }; // not subject to localization static LPCSTR g_apchFunctionNames[] = { "CreateSecurityPage", NULL }; // not subject to localization DynamicDLL g_AcluiDLL( _T("ACLUI.DLL"), g_apchFunctionNames ); /* HPROPSHEETPAGE ACLUIAPI CreateSecurityPage( LPSECURITYINFO psi ); */ typedef HPROPSHEETPAGE (*CREATEPAGE_PROC) (LPSECURITYINFO); HRESULT MyCreateShareSecurityPage( IN LPPROPERTYSHEETCALLBACK pCallBack, IN CShareSecurityInformation *pSecInfo, IN LPCTSTR pszMachineName, IN LPCTSTR pszShareName ) { ASSERT( pCallBack ); ASSERT( pSecInfo ); HRESULT hr = S_OK; if ( !g_AcluiDLL.LoadFunctionPointers() ) return hr; // ignore the load failure pSecInfo->SetMachineName( pszMachineName ); pSecInfo->SetShareName( pszShareName ); CString csPageTitle; csPageTitle.LoadString(IDS_SHARE_SECURITY); pSecInfo->SetPageTitle( csPageTitle ); pSecInfo->AddRef(); HPROPSHEETPAGE hPage = ((CREATEPAGE_PROC)g_AcluiDLL[ACLUI_CREATE_PAGE])(pSecInfo); if (hPage) pCallBack->AddPage(hPage); else hr = HRESULT_FROM_WIN32(GetLastError()); pSecInfo->Release(); return hr; } HRESULT CSecurityInformation::NewDefaultDescriptor( OUT PSECURITY_DESCRIPTOR *ppsd, IN SECURITY_INFORMATION /*RequestedInformation*/ ) { ASSERT(ppsd); *ppsd = NULL; PSID psidWorld = NULL, psidAdmins = NULL; PACL pAcl = NULL; SECURITY_DESCRIPTOR sd; DWORD dwErr = 0; do { // false loop // get World SID for "everyone" SID_IDENTIFIER_AUTHORITY IDAuthorityWorld = SECURITY_WORLD_SID_AUTHORITY; if ( !::AllocateAndInitializeSid( &IDAuthorityWorld, 1, SECURITY_WORLD_RID, 0,0,0,0,0,0,0, &psidWorld ) ) { dwErr = GetLastError(); break; } // get Admins SID SID_IDENTIFIER_AUTHORITY IDAuthorityNT = SECURITY_NT_AUTHORITY; if ( !::AllocateAndInitializeSid( &IDAuthorityNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0,0,0,0,0,0, &psidAdmins ) ) { dwErr = GetLastError(); break; } // build ACL, and add AccessAllowedAce to it DWORD cbAcl = sizeof (ACL) + sizeof (ACCESS_ALLOWED_ACE) + ::GetLengthSid(psidWorld) - sizeof (DWORD); pAcl = reinterpret_cast(LocalAlloc(LPTR, cbAcl)); if ( !pAcl || !::InitializeAcl(pAcl, cbAcl, ACL_REVISION2) || !::AddAccessAllowedAce(pAcl, ACL_REVISION2, GENERIC_ALL, psidWorld) ) { dwErr = GetLastError(); break; } // add ACL to the security descriptor, and set Owner and Group appropriately if ( !::InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION) || !::SetSecurityDescriptorDacl(&sd, TRUE, pAcl, FALSE) || !::SetSecurityDescriptorOwner(&sd, psidAdmins, FALSE) || !::SetSecurityDescriptorGroup(&sd, psidAdmins, FALSE) ) { dwErr = GetLastError(); break; } // convert security descriptor to self-relative format DWORD cbSD = 0; ::MakeSelfRelativeSD(&sd, NULL, &cbSD); // this call should fail and set cbSD to the correct size *ppsd = (PSECURITY_DESCRIPTOR)(LocalAlloc(LPTR, cbSD)); if ( !(*ppsd) || !::MakeSelfRelativeSD(&sd, *ppsd, &cbSD) ) { dwErr = GetLastError(); break; } } while (FALSE); // false loop // clean up if (psidWorld) (void)::FreeSid(psidWorld); if (psidAdmins) (void)::FreeSid(psidAdmins); if (pAcl) LocalFree(pAcl); if (dwErr && *ppsd) { LocalFree(*ppsd); *ppsd = NULL; } return (dwErr ? HRESULT_FROM_WIN32(dwErr) : S_OK); } HRESULT CSecurityInformation::MakeSelfRelativeCopy( IN PSECURITY_DESCRIPTOR psdOriginal, OUT PSECURITY_DESCRIPTOR *ppsdNew ) { ASSERT(psdOriginal); ASSERT(ppsdNew); *ppsdNew = NULL; DWORD dwErr = 0; PSECURITY_DESCRIPTOR psdSelfRelative = NULL; do { // false loop DWORD cbSD = ::GetSecurityDescriptorLength(psdOriginal); psdSelfRelative = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, cbSD); if ( !psdSelfRelative ) { dwErr = ::GetLastError(); break; } // we have to find out whether the original is already self-relative SECURITY_DESCRIPTOR_CONTROL sdc = 0; DWORD dwRevision = 0; if ( !::GetSecurityDescriptorControl(psdOriginal, &sdc, &dwRevision) ) { dwErr = ::GetLastError(); break; } if (sdc & SE_SELF_RELATIVE) { ::memcpy(psdSelfRelative, psdOriginal, cbSD); } else if ( !::MakeSelfRelativeSD(psdOriginal, psdSelfRelative, &cbSD) ) { dwErr = ::GetLastError(); break; } *ppsdNew = psdSelfRelative; } while (FALSE); if (dwErr && psdSelfRelative) LocalFree(psdSelfRelative); return (dwErr ? HRESULT_FROM_WIN32(dwErr) : S_OK); }