diff --git a/dlls/shlwapi/ordinal.c b/dlls/shlwapi/ordinal.c index 90025b4cf2e..de867d6ea8a 100644 --- a/dlls/shlwapi/ordinal.c +++ b/dlls/shlwapi/ordinal.c @@ -4453,3 +4453,151 @@ void WINAPI SHChangeNotify(LONG wEventId, UINT uFlags, LPCVOID dwItem1, LPCVOID } fn(wEventId, uFlags, dwItem1, dwItem2); } + +typedef struct SHELL_USER_SID { /* according to MSDN this should be in shlobj.h... */ + SID_IDENTIFIER_AUTHORITY sidAuthority; + DWORD dwUserGroupID; + DWORD dwUserID; +} SHELL_USER_SID, *PSHELL_USER_SID; + +typedef struct SHELL_USER_PERMISSION { /* ...and this should be in shlwapi.h */ + SHELL_USER_SID susID; + DWORD dwAccessType; + BOOL fInherit; + DWORD dwAccessMask; + DWORD dwInheritMask; + DWORD dwInheritAccessMask; +} SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION; + +/*********************************************************************** + * GetShellSecurityDescriptor [SHLWAPI.475] + * + * prepares SECURITY_DESCRIPTOR from a set of ACEs + * + * PARAMS + * apUserPerm [I] array of pointers to SHELL_USER_PERMISSION structures, + * each of which describes permissions to apply + * cUserPerm [I] number of entries in apUserPerm array + * + * RETURNS + * success: pointer to SECURITY_DESCRIPTOR + * failure: NULL + * + * NOTES + * Call should free returned descriptor with LocalFree + */ +SECURITY_DESCRIPTOR * WINAPI GetShellSecurityDescriptor(PSHELL_USER_PERMISSION *apUserPerm, int cUserPerm) +{ + PSID *sidlist; + PSID cur_user = NULL; + BYTE tuUser[2000]; + DWORD acl_size; + int sid_count, i; + PSECURITY_DESCRIPTOR psd = NULL; + + TRACE("%p %d\n", apUserPerm, cUserPerm); + + if (apUserPerm == NULL || cUserPerm <= 0) + return NULL; + + sidlist = HeapAlloc(GetProcessHeap(), 0, cUserPerm * sizeof(PSID)); + if (!sidlist) + return NULL; + + acl_size = sizeof(ACL); + + for(sid_count = 0; sid_count < cUserPerm; sid_count++) + { + static SHELL_USER_SID null_sid = {{SECURITY_NULL_SID_AUTHORITY}, 0, 0}; + PSHELL_USER_PERMISSION perm = apUserPerm[sid_count]; + PSHELL_USER_SID sid = &perm->susID; + PSID pSid; + BOOL ret = TRUE; + + if (!memcmp((void*)sid, (void*)&null_sid, sizeof(SHELL_USER_SID))) + { /* current user's SID */ + if (!cur_user) + { + HANDLE Token; + DWORD bufsize = sizeof(tuUser); + + ret = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &Token); + if (ret) + { + ret = GetTokenInformation(Token, TokenUser, (void*)tuUser, bufsize, &bufsize ); + if (ret) + cur_user = ((PTOKEN_USER)&tuUser)->User.Sid; + CloseHandle(Token); + } + } + pSid = cur_user; + } else if (sid->dwUserID==0) /* one sub-authority */ + ret = AllocateAndInitializeSid(&sid->sidAuthority, 1, sid->dwUserGroupID, 0, + 0, 0, 0, 0, 0, 0, &pSid); + else + ret = AllocateAndInitializeSid(&sid->sidAuthority, 2, sid->dwUserGroupID, sid->dwUserID, + 0, 0, 0, 0, 0, 0, &pSid); + if (!ret) + goto free_sids; + + sidlist[sid_count] = pSid; + /* increment acl_size (1 ACE for non-inheritable and 2 ACEs for inheritable records */ + acl_size += (sizeof(ACCESS_ALLOWED_ACE)-sizeof(DWORD) + GetLengthSid(pSid)) * (perm->fInherit ? 2 : 1); + } + + psd = LocalAlloc(0, sizeof(SECURITY_DESCRIPTOR) + acl_size); + + if (psd != NULL) + { + PACL pAcl = (PACL)(((BYTE*)psd)+sizeof(SECURITY_DESCRIPTOR)); + + if (!InitializeSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION)) + goto error; + + if (!InitializeAcl(pAcl, acl_size, ACL_REVISION)) + goto error; + + for(i = 0; i < sid_count; i++) + { + PSHELL_USER_PERMISSION sup = apUserPerm[i]; + PSID sid = sidlist[i]; + + switch(sup->dwAccessType) + { + case ACCESS_ALLOWED_ACE_TYPE: + if (!AddAccessAllowedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid)) + goto error; + if (sup->fInherit && !AddAccessAllowedAceEx(pAcl, ACL_REVISION, + (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid)) + goto error; + break; + case ACCESS_DENIED_ACE_TYPE: + if (!AddAccessDeniedAce(pAcl, ACL_REVISION, sup->dwAccessMask, sid)) + goto error; + if (sup->fInherit && !AddAccessDeniedAceEx(pAcl, ACL_REVISION, + (BYTE)sup->dwInheritMask, sup->dwInheritAccessMask, sid)) + goto error; + break; + default: + goto error; + } + } + + if (!SetSecurityDescriptorDacl(psd, TRUE, pAcl, FALSE)) + goto error; + } + goto free_sids; + +error: + LocalFree(psd); + psd = NULL; +free_sids: + for(i = 0; i < sid_count; i++) + { + if (!cur_user || sidlist[i] != cur_user) + FreeSid(sidlist[i]); + } + HeapFree(GetProcessHeap(), 0, sidlist); + + return psd; +} diff --git a/dlls/shlwapi/shlwapi.spec b/dlls/shlwapi/shlwapi.spec index 0843ad975e0..369e24262c2 100644 --- a/dlls/shlwapi/shlwapi.spec +++ b/dlls/shlwapi/shlwapi.spec @@ -472,7 +472,7 @@ 472 stub -noname SHCreatePropertyBagOnProfileSelections 473 stub -noname SHGetIniStringUTF7W 474 stub -noname SHSetIniStringUTF7W -475 stub -noname GetShellSecurityDescriptor +475 stdcall -noname GetShellSecurityDescriptor(ptr long) 476 stub -noname SHGetObjectCompatFlags 477 stub -noname SHCreatePropertyBagOnMemory 478 stdcall -noname IUnknown_TranslateAcceleratorIO(ptr ptr) diff --git a/dlls/shlwapi/tests/ordinal.c b/dlls/shlwapi/tests/ordinal.c index ff650bdcc09..ef2151a1ff9 100644 --- a/dlls/shlwapi/tests/ordinal.c +++ b/dlls/shlwapi/tests/ordinal.c @@ -327,6 +327,110 @@ static void test_fdsa(void) HeapFree(GetProcessHeap(), 0, mem); } + +typedef struct SHELL_USER_SID { + SID_IDENTIFIER_AUTHORITY sidAuthority; + DWORD dwUserGroupID; + DWORD dwUserID; +} SHELL_USER_SID, *PSHELL_USER_SID; +typedef struct SHELL_USER_PERMISSION { + SHELL_USER_SID susID; + DWORD dwAccessType; + BOOL fInherit; + DWORD dwAccessMask; + DWORD dwInheritMask; + DWORD dwInheritAccessMask; +} SHELL_USER_PERMISSION, *PSHELL_USER_PERMISSION; +static void test_GetShellSecurityDescriptor(void) +{ + SHELL_USER_PERMISSION supCurrentUserFull = { + { {SECURITY_NULL_SID_AUTHORITY}, 0, 0 }, + ACCESS_ALLOWED_ACE_TYPE, FALSE, + GENERIC_ALL, 0, 0 }; +#define MY_INHERITANCE 0xBE /* invalid value to proof behavior */ + SHELL_USER_PERMISSION supEveryoneDenied = { + { {SECURITY_WORLD_SID_AUTHORITY}, SECURITY_WORLD_RID, 0 }, + ACCESS_DENIED_ACE_TYPE, TRUE, + GENERIC_WRITE, MY_INHERITANCE | 0xDEADBA00, GENERIC_READ }; + PSHELL_USER_PERMISSION rgsup[2] = { + &supCurrentUserFull, &supEveryoneDenied, + }; + SECURITY_DESCRIPTOR* psd; + SECURITY_DESCRIPTOR* (WINAPI*pGetShellSecurityDescriptor)(PSHELL_USER_PERMISSION*,int); + + pGetShellSecurityDescriptor=(void*)GetProcAddress(hShlwapi,(char*)475); + + psd = pGetShellSecurityDescriptor(NULL, 2); + ok(psd==NULL, "GetShellSecurityDescriptor should fail\n"); + psd = pGetShellSecurityDescriptor(rgsup, 0); + ok(psd==NULL, "GetShellSecurityDescriptor should fail\n"); + + psd = pGetShellSecurityDescriptor(rgsup, 2); + ok(psd!=NULL, "GetShellSecurityDescriptor failed\n"); + if (psd!=NULL) + { + BOOL bHasDacl = FALSE, bDefaulted; + PACL pAcl; + DWORD dwRev; + SECURITY_DESCRIPTOR_CONTROL control; + + ok(IsValidSecurityDescriptor(psd), "returned value is not valid SD\n"); + + ok(GetSecurityDescriptorControl(psd, &control, &dwRev), + "GetSecurityDescriptorControl failed with error %d\n", GetLastError()); + ok(0 == (control & SE_SELF_RELATIVE), "SD should be absolute\n"); + + ok(GetSecurityDescriptorDacl(psd, &bHasDacl, &pAcl, &bDefaulted), + "GetSecurityDescriptorDacl failed with error %d\n", GetLastError()); + + ok(bHasDacl, "SD has no DACL\n"); + if (bHasDacl) + { + ok(!bDefaulted, "DACL should not be defaulted\n"); + + ok(pAcl != NULL, "NULL DACL!\n"); + if (pAcl != NULL) + { + ACL_SIZE_INFORMATION asiSize; + + ok(IsValidAcl(pAcl), "DACL is not valid\n"); + + ok(GetAclInformation(pAcl, &asiSize, sizeof(asiSize), AclSizeInformation), + "GetAclInformation failed with error %d\n", GetLastError()); + + ok(asiSize.AceCount == 3, "Incorrect number of ACEs: %d entries\n", asiSize.AceCount); + if (asiSize.AceCount == 3) + { + ACCESS_ALLOWED_ACE *paaa; /* will use for DENIED too */ + + ok(GetAce(pAcl, 0, (LPVOID*)&paaa), "GetAce failed with error %d\n", GetLastError()); + ok(paaa->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, + "Invalid ACE type %d\n", paaa->Header.AceType); + ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags); + ok(paaa->Mask == GENERIC_ALL, "Invalid ACE mask %x\n", paaa->Mask); + + ok(GetAce(pAcl, 1, (LPVOID*)&paaa), "GetAce failed with error %d\n", GetLastError()); + ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, + "Invalid ACE type %d\n", paaa->Header.AceType); + /* first one of two ACEs generated from inheritable entry - without inheritance */ + ok(paaa->Header.AceFlags == 0, "Invalid ACE flags %x\n", paaa->Header.AceFlags); + ok(paaa->Mask == GENERIC_WRITE, "Invalid ACE mask %x\n", paaa->Mask); + + ok(GetAce(pAcl, 2, (LPVOID*)&paaa), "GetAce failed with error %d\n", GetLastError()); + ok(paaa->Header.AceType == ACCESS_DENIED_ACE_TYPE, + "Invalid ACE type %d\n", paaa->Header.AceType); + /* second ACE - with inheritance */ + ok(paaa->Header.AceFlags == MY_INHERITANCE, + "Invalid ACE flags %x\n", paaa->Header.AceFlags); + ok(paaa->Mask == GENERIC_READ, "Invalid ACE mask %x\n", paaa->Mask); + } + } + } + + LocalFree(psd); + } +} + START_TEST(ordinal) { hShlwapi = LoadLibraryA("shlwapi.dll"); @@ -345,6 +449,7 @@ START_TEST(ordinal) test_SHSearchMapInt(); test_alloc_shared(); test_fdsa(); + test_GetShellSecurityDescriptor(); FreeLibrary(hShlwapi); }