// Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1995. // File: acl.cxx // Contents: Implementation for the Shares Acl Editor in the "Sharing" // property page. It is just a front end for the Generic // ACL Editor that is specific to Shares. // History: 5-Apr-95 BruceFo Stole from net\ui\shellui\share\shareacl.cxx #include "headers.hxx" #pragma hdrstop #include extern "C" { #include } #include "resource.h" #include "helpids.h" #include "acl.hxx" #include "util.hxx" typedef DWORD (*SedDiscretionaryAclEditorType)( HWND Owner, HANDLE Instance, LPWSTR Server, PSED_OBJECT_TYPE_DESCRIPTOR ObjectType, PSED_APPLICATION_ACCESSES ApplicationAccesses, LPWSTR ObjectName, PSED_FUNC_APPLY_SEC_CALLBACK ApplySecurityCallbackRoutine, ULONG CallbackContext, PSECURITY_DESCRIPTOR SecurityDescriptor, BOOLEAN CouldntReadDacl, BOOLEAN CantWriteDacl, LPDWORD SEDStatusReturn, DWORD Flags ); // NOTE: the SedDiscretionaryAclEditor string is used in GetProcAddress to // get the correct entrypoint. Since GetProcAddress is not UNICODE, this string // must be ANSI. #define ACLEDIT_DLL_STRING TEXT("acledit.dll") #define SEDDISCRETIONARYACLEDITOR_STRING ("SedDiscretionaryAclEditor") // Declare the callback routine based on typedef in sedapi.h. DWORD SedCallback( HWND hwndParent, HANDLE hInstance, ULONG ulCallbackContext, PSECURITY_DESCRIPTOR pSecDesc, PSECURITY_DESCRIPTOR pSecDescNewObjects, BOOLEAN fApplyToSubContainers, BOOLEAN fApplyToSubObjects, LPDWORD StatusReturn ); // Structure for callback function's usage. A pointer to this is passed as // ulCallbackContext. The callback functions sets bSecDescModified to TRUE // and makes a copy of the security descriptor. The caller of EditShareAcl // is responsible for deleting the memory in pSecDesc if bSecDescModified is // TRUE. This flag will be FALSE if the user hit CANCEL in the ACL editor. struct SHARE_CALLBACK_INFO { BOOL bSecDescModified; PSECURITY_DESCRIPTOR pSecDesc; }; // Local function prototypes VOID InitializeShareGenericMapping( IN OUT PGENERIC_MAPPING pSHAREGenericMapping ); LONG CreateDefaultSecDesc( OUT PSECURITY_DESCRIPTOR* ppSecDesc ); VOID DeleteDefaultSecDesc( IN PSECURITY_DESCRIPTOR pSecDesc ); // The following two arrays define the permission names for NT Files. Note // that each index in one array corresponds to the index in the other array. // The second array will be modifed to contain a string pointer pointing to // a loaded string corresponding to the IDS_* in the first array. DWORD g_dwSharePermNames[] = { IDS_ACLEDIT_PERM_GEN_NO_ACCESS, IDS_ACLEDIT_PERM_GEN_READ, IDS_ACLEDIT_PERM_GEN_MODIFY, IDS_ACLEDIT_PERM_GEN_ALL }; SED_APPLICATION_ACCESS g_SedAppAccessSharePerms[] = { { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_NO_ACCESS, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_READ, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_MODIFY, 0, NULL }, { SED_DESC_TYPE_RESOURCE, FILE_PERM_GEN_ALL, 0, NULL } }; // Function: EditShareAcl // Synopsis: Invokes the generic ACL editor, specifically for NT shares // Arguments: [hwndParent] - Parent window handle // [pszShareName] - Fully qualified name of resource we will // edit, basically a share name. // [pSecDesc] - The initial security descriptor. If NULL, we will // create a default that is "World all" access. // [pbSecDescModified] - Set to TRUE if the security descriptor // was modified (i.e., the user hit "OK"), or FALSE if not // (i.e., the user hit "Cancel") // [ppSecDesc] - *ppSecDesc points to a new security descriptor // if *pbSecDescModified is TRUE. This memory must be freed // by the caller. // History: // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code. // Yi-HsinS 09-Oct-1992 Added ulHelpContextBase // BruceFo 4-Apr-95 Stole and used in ntshrui.dll LONG EditShareAcl( IN HWND hwndParent, IN LPWSTR pszServerName, IN TCHAR * pszShareName, IN PSECURITY_DESCRIPTOR pSecDesc, OUT BOOL* pbSecDescModified, OUT PSECURITY_DESCRIPTOR* ppSecDesc ) { appAssert(NULL != pszShareName); appDebugOut((DEB_TRACE, "EditShareAcl, share %ws\n", pszShareName)); appAssert(NULL == pSecDesc || IsValidSecurityDescriptor(pSecDesc)); appAssert(pbSecDescModified); appAssert(ppSecDesc); *pbSecDescModified = FALSE; LONG err ; PWSTR pszPermName; BOOL bCreatedDefaultSecDesc = FALSE; do // error breakout { /* * if pSecDesc is NULL, this is new share or a share with no * security descriptor. * we go and create a new (default) security descriptor. */ if (NULL == pSecDesc) { LONG err = CreateDefaultSecDesc(&pSecDesc); if (err != NERR_Success) { appDebugOut((DEB_ERROR, "CreateDefaultSecDesc failed, 0x%08lx\n", err)); break ; } appDebugOut((DEB_TRACE, "CreateDefaultSecDesc descriptor = 0x%08lx\n", pSecDesc)); bCreatedDefaultSecDesc = TRUE; } appAssert(IsValidSecurityDescriptor(pSecDesc)); /* Retrieve the resource strings appropriate for the type of object we * are looking at */ WCHAR szTypeName[50]; LoadString(g_hInstance, IDS_ACLEDIT_TITLE, szTypeName, ARRAYLEN(szTypeName)); WCHAR szDefaultPermName[50]; LoadString(g_hInstance, IDS_ACLEDIT_PERM_GEN_READ, szDefaultPermName, ARRAYLEN(szDefaultPermName)); /* * other misc stuff we need pass to security editor */ SED_OBJECT_TYPE_DESCRIPTOR sedObjDesc ; SED_HELP_INFO sedHelpInfo ; GENERIC_MAPPING SHAREGenericMapping ; // setup mappings InitializeShareGenericMapping( &SHAREGenericMapping ) ; // setup help: BUGBUG WCHAR szHelpFile[50]; LoadString(g_hInstance, IDS_HELPFILENAME, szHelpFile, ARRAYLEN(szHelpFile)); sedHelpInfo.pszHelpFileName = szHelpFile; sedHelpInfo.aulHelpContext[HC_MAIN_DLG] = ACL_HC_MAIN_DLG; sedHelpInfo.aulHelpContext[HC_ADD_USER_DLG] = ACL_HC_ADD_USER_DLG; sedHelpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_LG_DLG] = ACL_HC_ADD_USER_MEMBERS_LG_DLG; sedHelpInfo.aulHelpContext[HC_ADD_USER_MEMBERS_GG_DLG] = ACL_HC_ADD_USER_MEMBERS_GG_DLG; sedHelpInfo.aulHelpContext[HC_ADD_USER_SEARCH_DLG] = ACL_HC_ADD_USER_SEARCH_DLG; // These are not used, set to zero sedHelpInfo.aulHelpContext[HC_SPECIAL_ACCESS_DLG] = 0 ; sedHelpInfo.aulHelpContext[HC_NEW_ITEM_SPECIAL_ACCESS_DLG] = 0 ; // setup the object description sedObjDesc.Revision = SED_REVISION1 ; sedObjDesc.IsContainer = FALSE ; sedObjDesc.AllowNewObjectPerms = FALSE ; sedObjDesc.MapSpecificPermsToGeneric = TRUE ; sedObjDesc.GenericMapping = &SHAREGenericMapping ; sedObjDesc.GenericMappingNewObjects = &SHAREGenericMapping ; sedObjDesc.HelpInfo = &sedHelpInfo ; sedObjDesc.ObjectTypeName = szTypeName ; sedObjDesc.SpecialObjectAccessTitle = NULL ; /* Now we need to load the global arrays with the permission names * from the resource file. */ UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms); PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ; /* Loop through each permission title retrieving the text from the * resource file and setting the pointer in the array. */ for ( UINT i = 0 ; i < cArrayItems ; i++ ) { pszPermName = GetResourceString(g_dwSharePermNames[i]) ; if (NULL == pszPermName) { appDebugOut((DEB_ERROR, "GetResourceString failed\n")); break ; } aSedAppAccess[i].PermissionTitle = pszPermName; } if (i < cArrayItems) { appDebugOut((DEB_ERROR, "failed to get all share permission names\n")); break ; } SED_APPLICATION_ACCESSES sedAppAccesses ; sedAppAccesses.Count = cArrayItems ; sedAppAccesses.AccessGroup = aSedAppAccess ; sedAppAccesses.DefaultPermName = szDefaultPermName; /* * pass this along so when the call back function is called, * we can set it. */ SHARE_CALLBACK_INFO callbackinfo ; callbackinfo.pSecDesc = NULL; callbackinfo.bSecDescModified = FALSE; // Now, load up the ACL editor and invoke it. We don't keep it around // because our DLL is loaded whenever the system is, so we don't want // the netui*.dll's hanging around as well... HINSTANCE hInstanceAclEditor = NULL; SedDiscretionaryAclEditorType pSedDiscretionaryAclEditor = NULL; hInstanceAclEditor = LoadLibrary(ACLEDIT_DLL_STRING); if (NULL == hInstanceAclEditor) { err = GetLastError(); appDebugOut((DEB_ERROR, "LoadLibrary of acledit.dll failed, 0x%08lx\n", err)); break; } pSedDiscretionaryAclEditor = (SedDiscretionaryAclEditorType) GetProcAddress(hInstanceAclEditor,SEDDISCRETIONARYACLEDITOR_STRING); if ( pSedDiscretionaryAclEditor == NULL ) { err = GetLastError(); appDebugOut((DEB_ERROR, "GetProcAddress of SedDiscretionaryAclEditor failed, 0x%08lx\n", err)); break; } DWORD dwSedReturnStatus ; appAssert(pSedDiscretionaryAclEditor != NULL); err = (*pSedDiscretionaryAclEditor)( hwndParent, g_hInstance, pszServerName, &sedObjDesc, &sedAppAccesses, pszShareName, SedCallback, (ULONG) &callbackinfo, pSecDesc, FALSE, // always can read FALSE, // If we can read, we can write &dwSedReturnStatus, 0 ) ; if (!FreeLibrary(hInstanceAclEditor)) { LONG err2 = GetLastError(); appDebugOut((DEB_ERROR, "FreeLibrary of acledit.dll failed, 0x%08lx\n", err2)); // not fatal: continue... } if (0 != err) { appDebugOut((DEB_ERROR, "SedDiscretionaryAclEditor failed, 0x%08lx\n", err)); break ; } *pbSecDescModified = callbackinfo.bSecDescModified ; if (*pbSecDescModified) { *ppSecDesc = callbackinfo.pSecDesc; appDebugOut((DEB_TRACE, "After calling acl editor, *ppSecDesc = 0x%08lx\n", *ppSecDesc)); appAssert(IsValidSecurityDescriptor(*ppSecDesc)); } } while (FALSE) ; // Free memory... UINT cArrayItems = ARRAYLEN(g_SedAppAccessSharePerms); PSED_APPLICATION_ACCESS aSedAppAccess = g_SedAppAccessSharePerms ; for ( UINT i = 0 ; i < cArrayItems ; i++ ) { pszPermName = aSedAppAccess[i].PermissionTitle; if (NULL == pszPermName) { // if we hit a NULL, that's it! break ; } delete[] pszPermName; } if (bCreatedDefaultSecDesc) { DeleteDefaultSecDesc(pSecDesc); } appAssert(!*pbSecDescModified || IsValidSecurityDescriptor(*ppSecDesc)); if (0 != err) { MyErrorDialog(hwndParent, IERR_NOACLEDITOR); } return err; } // Function: SedCallback // Synopsis: Security Editor callback for the SHARE ACL Editor // Arguments: See sedapi.h // History: // ChuckC 10-Aug-1992 Created // BruceFo 4-Apr-95 Stole and used in ntshrui.dll DWORD SedCallback( HWND hwndParent, HANDLE hInstance, ULONG ulCallbackContext, PSECURITY_DESCRIPTOR pSecDesc, PSECURITY_DESCRIPTOR pSecDescNewObjects, BOOLEAN fApplyToSubContainers, BOOLEAN fApplyToSubObjects, LPDWORD StatusReturn ) { appDebugOut((DEB_TRACE, "SedCallback, got pSecDesc = 0x%08lx\n", pSecDesc)); appAssert(IsValidSecurityDescriptor(pSecDesc)); SHARE_CALLBACK_INFO* pCallbackInfo = (SHARE_CALLBACK_INFO *)ulCallbackContext; appAssert(NULL != pCallbackInfo); delete[] (BYTE*)pCallbackInfo->pSecDesc; pCallbackInfo->pSecDesc = CopySecurityDescriptor(pSecDesc); pCallbackInfo->bSecDescModified = TRUE; appAssert(IsValidSecurityDescriptor(pCallbackInfo->pSecDesc)); appDebugOut((DEB_TRACE, "SedCallback, return pSecDesc = 0x%08lx\n", pCallbackInfo->pSecDesc)); return NOERROR; } // Function: InitializeShareGenericMapping // Synopsis: Initializes the passed generic mapping structure for shares. // Arguments: [pSHAREGenericMapping] - Pointer to GENERIC_MAPPING to be init. // History: // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll VOID InitializeShareGenericMapping( IN OUT PGENERIC_MAPPING pSHAREGenericMapping ) { appDebugOut((DEB_ITRACE, "InitializeShareGenericMapping\n")); pSHAREGenericMapping->GenericRead = FILE_GENERIC_READ ; pSHAREGenericMapping->GenericWrite = FILE_GENERIC_WRITE ; pSHAREGenericMapping->GenericExecute = FILE_GENERIC_EXECUTE ; pSHAREGenericMapping->GenericAll = FILE_ALL_ACCESS ; } // Function: CreateDefaultSecDesc // Synopsis: Create a default ACL for either a new share or for // a share that dont exist. // Arguments: [ppSecDesc] - *ppSecDesc points to a "world all" access // security descriptor on exit. Caller is responsible for // freeing it. // Returns: NERR_Success if OK, api error otherwise. // History: // ChuckC 10-Aug-1992 Created. Culled from NTFS ACL code. // BruceFo 4-Apr-95 Stole and used in ntshrui.dll LONG CreateDefaultSecDesc( OUT PSECURITY_DESCRIPTOR* ppSecDesc ) { appDebugOut((DEB_ITRACE, "CreateDefaultSecDesc\n")); appAssert(NULL != ppSecDesc) ; appAssert(NULL == *ppSecDesc) ; LONG err = NERR_Success; PSECURITY_DESCRIPTOR pSecDesc = NULL; PACL pAcl = NULL; DWORD cbAcl; PSID pSid = NULL; *ppSecDesc = NULL; do // error breakout { // First, create a world SID. Next, create an access allowed // ACE with "Generic All" access with the world SID. Put the ACE in // the ACL and the ACL in the security descriptor. SID_IDENTIFIER_AUTHORITY IDAuthorityWorld = SECURITY_WORLD_SID_AUTHORITY; if (!AllocateAndInitializeSid( &IDAuthorityWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pSid)) { err = GetLastError(); appDebugOut((DEB_ERROR, "AllocateAndInitializeSid failed, 0x%08lx\n", err)); break; } appAssert(IsValidSid(pSid)); cbAcl = sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD)) + GetLengthSid(pSid) ; pAcl = (PACL) new BYTE[cbAcl]; if (NULL == pAcl) { err = ERROR_OUTOFMEMORY; appDebugOut((DEB_ERROR, "new ACL failed\n")); break; } if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION2)) { err = GetLastError(); appDebugOut((DEB_ERROR, "InitializeAcl failed, 0x%08lx\n", err)); break; } if (!AddAccessAllowedAce( pAcl, ACL_REVISION2, GENERIC_ALL, pSid)) { err = GetLastError(); appDebugOut((DEB_ERROR, "AddAccessAllowedAce failed, 0x%08lx\n", err)); break; } appAssert(IsValidAcl(pAcl)); pSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[SECURITY_DESCRIPTOR_MIN_LENGTH]; if (NULL == pSecDesc) { err = ERROR_OUTOFMEMORY; appDebugOut((DEB_ERROR, "new SECURITY_DESCRIPTOR failed\n")); break; } if (!InitializeSecurityDescriptor( pSecDesc, SECURITY_DESCRIPTOR_REVISION1)) { err = GetLastError(); appDebugOut((DEB_ERROR, "InitializeSecurityDescriptor failed, 0x%08lx\n", err)); break; } if (!SetSecurityDescriptorDacl( pSecDesc, TRUE, pAcl, FALSE)) { err = GetLastError(); appDebugOut((DEB_ERROR, "SetSecurityDescriptorDacl failed, 0x%08lx\n", err)); break; } appAssert(IsValidSecurityDescriptor(pSecDesc)); // Make the security descriptor self-relative DWORD dwLen = GetSecurityDescriptorLength(pSecDesc); appDebugOut((DEB_ITRACE, "SECURITY_DESCRIPTOR length = %d\n", dwLen)); PSECURITY_DESCRIPTOR pSelfSecDesc = (PSECURITY_DESCRIPTOR) new BYTE[dwLen]; if (NULL == pSelfSecDesc) { err = ERROR_OUTOFMEMORY; appDebugOut((DEB_ERROR, "new SECURITY_DESCRIPTOR (2) failed\n")); break; } DWORD cbSelfSecDesc = dwLen; if (!MakeSelfRelativeSD(pSecDesc, pSelfSecDesc, &cbSelfSecDesc)) { err = GetLastError(); appDebugOut((DEB_ERROR, "MakeSelfRelativeSD failed, 0x%08lx\n", err)); break; } appAssert(IsValidSecurityDescriptor(pSelfSecDesc)); // all done: set the security descriptor *ppSecDesc = pSelfSecDesc; } while (FALSE) ; if (NULL != pSid) { FreeSid(pSid); } delete[] (BYTE*)pAcl; delete[] (BYTE*)pSecDesc; appAssert(IsValidSecurityDescriptor(*ppSecDesc)); return err; } // Function: DeleteDefaultSecDesc // Synopsis: Delete a security descriptor that was created by // CreateDefaultSecDesc // Arguments: [pSecDesc] - security descriptor to delete // Returns: nothing // History: // BruceFo 4-Apr-95 Created VOID DeleteDefaultSecDesc( IN PSECURITY_DESCRIPTOR pSecDesc ) { appDebugOut((DEB_ITRACE, "DeleteDefaultSecDesc\n")); delete[] (BYTE*)pSecDesc; }