advapi32/tests: Remove some workarounds for older versions.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
fc4aa8046d
commit
10646ddb91
|
@ -80,17 +80,11 @@ static VOID (WINAPI *pBuildTrusteeWithObjectsAndSidA)( PTRUSTEEA pTrustee,
|
|||
GUID* pInheritedObjectGuid,
|
||||
PSID pSid );
|
||||
static LPSTR (WINAPI *pGetTrusteeNameA)( PTRUSTEEA pTrustee );
|
||||
static BOOL (WINAPI *pMakeSelfRelativeSD)( PSECURITY_DESCRIPTOR, PSECURITY_DESCRIPTOR, LPDWORD );
|
||||
static BOOL (WINAPI *pConvertStringSidToSidA)( LPCSTR str, PSID pSid );
|
||||
static BOOL (WINAPI *pCheckTokenMembership)(HANDLE, PSID, PBOOL);
|
||||
static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorA)(LPCSTR, DWORD,
|
||||
PSECURITY_DESCRIPTOR*, PULONG );
|
||||
static BOOL (WINAPI *pConvertStringSecurityDescriptorToSecurityDescriptorW)(LPCWSTR, DWORD,
|
||||
PSECURITY_DESCRIPTOR*, PULONG );
|
||||
static BOOL (WINAPI *pConvertSecurityDescriptorToStringSecurityDescriptorA)(PSECURITY_DESCRIPTOR, DWORD,
|
||||
SECURITY_INFORMATION, LPSTR *, PULONG );
|
||||
static BOOL (WINAPI *pGetFileSecurityA)(LPCSTR, SECURITY_INFORMATION,
|
||||
PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
|
||||
static BOOL (WINAPI *pSetFileSecurityA)(LPCSTR, SECURITY_INFORMATION,
|
||||
PSECURITY_DESCRIPTOR);
|
||||
static DWORD (WINAPI *pGetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION,
|
||||
|
@ -98,33 +92,21 @@ static DWORD (WINAPI *pGetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_IN
|
|||
PSECURITY_DESCRIPTOR*);
|
||||
static DWORD (WINAPI *pSetNamedSecurityInfoA)(LPSTR, SE_OBJECT_TYPE, SECURITY_INFORMATION,
|
||||
PSID, PSID, PACL, PACL);
|
||||
static PDWORD (WINAPI *pGetSidSubAuthority)(PSID, DWORD);
|
||||
static PUCHAR (WINAPI *pGetSidSubAuthorityCount)(PSID);
|
||||
static BOOL (WINAPI *pIsValidSid)(PSID);
|
||||
static DWORD (WINAPI *pRtlAdjustPrivilege)(ULONG,BOOLEAN,BOOLEAN,PBOOLEAN);
|
||||
static BOOL (WINAPI *pCreateWellKnownSid)(WELL_KNOWN_SID_TYPE,PSID,PSID,DWORD*);
|
||||
static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
|
||||
SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
|
||||
|
||||
static NTSTATUS (WINAPI *pLsaQueryInformationPolicy)(LSA_HANDLE,POLICY_INFORMATION_CLASS,PVOID*);
|
||||
static NTSTATUS (WINAPI *pLsaClose)(LSA_HANDLE);
|
||||
static NTSTATUS (WINAPI *pLsaFreeMemory)(PVOID);
|
||||
static NTSTATUS (WINAPI *pLsaOpenPolicy)(PLSA_UNICODE_STRING,PLSA_OBJECT_ATTRIBUTES,ACCESS_MASK,PLSA_HANDLE);
|
||||
static NTSTATUS (WINAPI *pNtQueryObject)(HANDLE,OBJECT_INFORMATION_CLASS,PVOID,ULONG,PULONG);
|
||||
static DWORD (WINAPI *pSetEntriesInAclW)(ULONG, PEXPLICIT_ACCESSW, PACL, PACL*);
|
||||
static DWORD (WINAPI *pSetEntriesInAclA)(ULONG, PEXPLICIT_ACCESSA, PACL, PACL*);
|
||||
static BOOL (WINAPI *pSetSecurityDescriptorControl)(PSECURITY_DESCRIPTOR, SECURITY_DESCRIPTOR_CONTROL,
|
||||
SECURITY_DESCRIPTOR_CONTROL);
|
||||
static DWORD (WINAPI *pGetSecurityInfo)(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION,
|
||||
PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*);
|
||||
static DWORD (WINAPI *pSetSecurityInfo)(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION,
|
||||
PSID, PSID, PACL, PACL);
|
||||
static NTSTATUS (WINAPI *pNtAccessCheck)(PSECURITY_DESCRIPTOR, HANDLE, ACCESS_MASK, PGENERIC_MAPPING,
|
||||
PPRIVILEGE_SET, PULONG, PULONG, NTSTATUS*);
|
||||
static BOOL (WINAPI *pCreateRestrictedToken)(HANDLE, DWORD, DWORD, PSID_AND_ATTRIBUTES, DWORD,
|
||||
PLUID_AND_ATTRIBUTES, DWORD, PSID_AND_ATTRIBUTES, PHANDLE);
|
||||
static BOOL (WINAPI *pGetAclInformation)(PACL,LPVOID,DWORD,ACL_INFORMATION_CLASS);
|
||||
static BOOL (WINAPI *pGetAce)(PACL,DWORD,LPVOID*);
|
||||
static NTSTATUS (WINAPI *pNtSetSecurityObject)(HANDLE,SECURITY_INFORMATION,PSECURITY_DESCRIPTOR);
|
||||
static NTSTATUS (WINAPI *pNtCreateFile)(PHANDLE,ACCESS_MASK,POBJECT_ATTRIBUTES,PIO_STATUS_BLOCK,PLARGE_INTEGER,ULONG,ULONG,ULONG,ULONG,PVOID,ULONG);
|
||||
static BOOL (WINAPI *pRtlDosPathNameToNtPathName_U)(LPCWSTR,PUNICODE_STRING,PWSTR*,CURDIR*);
|
||||
|
@ -184,30 +166,18 @@ static void init(void)
|
|||
pAddAuditAccessAceEx = (void *)GetProcAddress(hmod, "AddAuditAccessAceEx");
|
||||
pAddMandatoryAce = (void *)GetProcAddress(hmod, "AddMandatoryAce");
|
||||
pCheckTokenMembership = (void *)GetProcAddress(hmod, "CheckTokenMembership");
|
||||
pConvertStringSecurityDescriptorToSecurityDescriptorA =
|
||||
(void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorA" );
|
||||
pConvertStringSecurityDescriptorToSecurityDescriptorW =
|
||||
(void *)GetProcAddress(hmod, "ConvertStringSecurityDescriptorToSecurityDescriptorW" );
|
||||
pConvertSecurityDescriptorToStringSecurityDescriptorA =
|
||||
(void *)GetProcAddress(hmod, "ConvertSecurityDescriptorToStringSecurityDescriptorA" );
|
||||
pGetFileSecurityA = (void *)GetProcAddress(hmod, "GetFileSecurityA" );
|
||||
pSetFileSecurityA = (void *)GetProcAddress(hmod, "SetFileSecurityA" );
|
||||
pCreateWellKnownSid = (void *)GetProcAddress( hmod, "CreateWellKnownSid" );
|
||||
pGetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "GetNamedSecurityInfoA");
|
||||
pSetNamedSecurityInfoA = (void *)GetProcAddress(hmod, "SetNamedSecurityInfoA");
|
||||
pGetSidSubAuthority = (void *)GetProcAddress(hmod, "GetSidSubAuthority");
|
||||
pGetSidSubAuthorityCount = (void *)GetProcAddress(hmod, "GetSidSubAuthorityCount");
|
||||
pIsValidSid = (void *)GetProcAddress(hmod, "IsValidSid");
|
||||
pMakeSelfRelativeSD = (void *)GetProcAddress(hmod, "MakeSelfRelativeSD");
|
||||
pSetEntriesInAclW = (void *)GetProcAddress(hmod, "SetEntriesInAclW");
|
||||
pSetEntriesInAclA = (void *)GetProcAddress(hmod, "SetEntriesInAclA");
|
||||
pSetSecurityDescriptorControl = (void *)GetProcAddress(hmod, "SetSecurityDescriptorControl");
|
||||
pGetSecurityInfo = (void *)GetProcAddress(hmod, "GetSecurityInfo");
|
||||
pSetSecurityInfo = (void *)GetProcAddress(hmod, "SetSecurityInfo");
|
||||
pCreateRestrictedToken = (void *)GetProcAddress(hmod, "CreateRestrictedToken");
|
||||
pConvertStringSidToSidA = (void *)GetProcAddress(hmod, "ConvertStringSidToSidA");
|
||||
pGetAclInformation = (void *)GetProcAddress(hmod, "GetAclInformation");
|
||||
pGetAce = (void *)GetProcAddress(hmod, "GetAce");
|
||||
pGetWindowsAccountDomainSid = (void *)GetProcAddress(hmod, "GetWindowsAccountDomainSid");
|
||||
pEqualDomainSid = (void *)GetProcAddress(hmod, "EqualDomainSid");
|
||||
pGetSidIdentifierAuthority = (void *)GetProcAddress(hmod, "GetSidIdentifierAuthority");
|
||||
|
@ -348,13 +318,7 @@ static void test_sid(void)
|
|||
BOOL r, ret;
|
||||
LPSTR str = NULL;
|
||||
|
||||
if( !pConvertStringSidToSidA )
|
||||
{
|
||||
win_skip("ConvertSidToStringSidA or ConvertStringSidToSidA not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
r = pConvertStringSidToSidA( NULL, NULL );
|
||||
r = ConvertStringSidToSidA( NULL, NULL );
|
||||
ok( !r, "expected failure with NULL parameters\n" );
|
||||
if( GetLastError() == ERROR_CALL_NOT_IMPLEMENTED )
|
||||
return;
|
||||
|
@ -362,24 +326,24 @@ static void test_sid(void)
|
|||
"expected GetLastError() is ERROR_INVALID_PARAMETER, got %d\n",
|
||||
GetLastError() );
|
||||
|
||||
r = pConvertStringSidToSidA( refs[0].refStr, NULL );
|
||||
r = ConvertStringSidToSidA( refs[0].refStr, NULL );
|
||||
ok( !r && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"expected GetLastError() is ERROR_INVALID_PARAMETER, got %d\n",
|
||||
GetLastError() );
|
||||
|
||||
r = pConvertStringSidToSidA( NULL, &str );
|
||||
r = ConvertStringSidToSidA( NULL, &psid );
|
||||
ok( !r && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"expected GetLastError() is ERROR_INVALID_PARAMETER, got %d\n",
|
||||
GetLastError() );
|
||||
|
||||
r = pConvertStringSidToSidA( noSubAuthStr, &psid );
|
||||
r = ConvertStringSidToSidA( noSubAuthStr, &psid );
|
||||
ok( !r,
|
||||
"expected failure with no sub authorities\n" );
|
||||
ok( GetLastError() == ERROR_INVALID_SID,
|
||||
"expected GetLastError() is ERROR_INVALID_SID, got %d\n",
|
||||
GetLastError() );
|
||||
|
||||
ok(pConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid), "ConvertStringSidToSidA failed\n");
|
||||
ok(ConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid), "ConvertStringSidToSidA failed\n");
|
||||
pisid = psid;
|
||||
ok(pisid->SubAuthorityCount == 4, "Invalid sub authority count - expected 4, got %d\n", pisid->SubAuthorityCount);
|
||||
ok(pisid->SubAuthority[0] == 21, "Invalid subauthority 0 - expected 21, got %d\n", pisid->SubAuthority[0]);
|
||||
|
@ -403,7 +367,7 @@ static void test_sid(void)
|
|||
if( psid )
|
||||
FreeSid( psid );
|
||||
|
||||
r = pConvertStringSidToSidA( refs[i].refStr, &psid );
|
||||
r = ConvertStringSidToSidA( refs[i].refStr, &psid );
|
||||
ok( r, "failed to parse sid string\n" );
|
||||
pisid = psid;
|
||||
ok( pisid &&
|
||||
|
@ -832,11 +796,6 @@ static void test_FileSecurity(void)
|
|||
| GROUP_SECURITY_INFORMATION
|
||||
| DACL_SECURITY_INFORMATION;
|
||||
|
||||
if (!pGetFileSecurityA) {
|
||||
win_skip ("GetFileSecurity is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!pSetFileSecurityA) {
|
||||
win_skip ("SetFileSecurity is not available\n");
|
||||
return;
|
||||
|
@ -866,7 +825,7 @@ static void test_FileSecurity(void)
|
|||
/* Get size needed */
|
||||
retSize = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
rc = pGetFileSecurityA (file, request, NULL, 0, &retSize);
|
||||
rc = GetFileSecurityA (file, request, NULL, 0, &retSize);
|
||||
if (!rc && (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)) {
|
||||
win_skip("GetFileSecurityA is not implemented\n");
|
||||
goto cleanup;
|
||||
|
@ -883,7 +842,7 @@ static void test_FileSecurity(void)
|
|||
/* Get security descriptor for real */
|
||||
retSize = -1;
|
||||
SetLastError(0xdeadbeef);
|
||||
rc = pGetFileSecurityA (file, request, sd, sdSize, &retSize);
|
||||
rc = GetFileSecurityA (file, request, sd, sdSize, &retSize);
|
||||
ok (rc, "GetFileSecurityA "
|
||||
"was not expected to fail '%s': %d\n", file, GetLastError());
|
||||
ok (retSize == sdSize ||
|
||||
|
@ -903,7 +862,7 @@ static void test_FileSecurity(void)
|
|||
/* Get size needed */
|
||||
retSize = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
rc = pGetFileSecurityA (path, request, NULL, 0, &retSize);
|
||||
rc = GetFileSecurityA (path, request, NULL, 0, &retSize);
|
||||
ok (!rc, "GetFileSecurityA "
|
||||
"was expected to fail for '%s'\n", path);
|
||||
ok (GetLastError() == ERROR_INSUFFICIENT_BUFFER, "GetFileSecurityA "
|
||||
|
@ -916,7 +875,7 @@ static void test_FileSecurity(void)
|
|||
/* Get security descriptor for real */
|
||||
retSize = -1;
|
||||
SetLastError(0xdeadbeef);
|
||||
rc = pGetFileSecurityA (path, request, sd, sdSize, &retSize);
|
||||
rc = GetFileSecurityA (path, request, sd, sdSize, &retSize);
|
||||
ok (rc, "GetFileSecurityA "
|
||||
"was not expected to fail '%s': %d\n", path, GetLastError());
|
||||
ok (retSize == sdSize ||
|
||||
|
@ -933,7 +892,7 @@ static void test_FileSecurity(void)
|
|||
/* Old test */
|
||||
strcpy (wintmpdir, "\\Should not exist");
|
||||
SetLastError(0xdeadbeef);
|
||||
rc = pGetFileSecurityA (wintmpdir, OWNER_SECURITY_INFORMATION, NULL, 0, &sdSize);
|
||||
rc = GetFileSecurityA (wintmpdir, OWNER_SECURITY_INFORMATION, NULL, 0, &sdSize);
|
||||
ok (!rc, "GetFileSecurityA should fail for not existing directories/files\n");
|
||||
ok (GetLastError() == ERROR_FILE_NOT_FOUND,
|
||||
"last error ERROR_FILE_NOT_FOUND expected, got %d\n", GetLastError());
|
||||
|
@ -2191,6 +2150,7 @@ static void test_LookupAccountSid(void)
|
|||
DWORD acc_sizeA, dom_sizeA, user_sizeA;
|
||||
DWORD real_acc_sizeA, real_dom_sizeA;
|
||||
WCHAR accountW[MAX_PATH], domainW[MAX_PATH];
|
||||
LSA_OBJECT_ATTRIBUTES object_attributes;
|
||||
DWORD acc_sizeW, dom_sizeW;
|
||||
DWORD real_acc_sizeW, real_dom_sizeW;
|
||||
PSID pUsersSid = NULL;
|
||||
|
@ -2202,6 +2162,8 @@ static void test_LookupAccountSid(void)
|
|||
int i;
|
||||
HANDLE hToken;
|
||||
PTOKEN_USER ptiUser = NULL;
|
||||
LSA_HANDLE handle;
|
||||
NTSTATUS status;
|
||||
|
||||
/* native windows crashes if account size, domain size, or name use is NULL */
|
||||
|
||||
|
@ -2415,35 +2377,24 @@ static void test_LookupAccountSid(void)
|
|||
}
|
||||
}
|
||||
|
||||
pLsaQueryInformationPolicy = (void *)GetProcAddress( hmod, "LsaQueryInformationPolicy");
|
||||
pLsaOpenPolicy = (void *)GetProcAddress( hmod, "LsaOpenPolicy");
|
||||
pLsaFreeMemory = (void *)GetProcAddress( hmod, "LsaFreeMemory");
|
||||
pLsaClose = (void *)GetProcAddress( hmod, "LsaClose");
|
||||
|
||||
if (pLsaQueryInformationPolicy && pLsaOpenPolicy && pLsaFreeMemory && pLsaClose)
|
||||
{
|
||||
NTSTATUS status;
|
||||
LSA_HANDLE handle;
|
||||
LSA_OBJECT_ATTRIBUTES object_attributes;
|
||||
|
||||
ZeroMemory(&object_attributes, sizeof(object_attributes));
|
||||
object_attributes.Length = sizeof(object_attributes);
|
||||
|
||||
status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_ALL_ACCESS, &handle);
|
||||
status = LsaOpenPolicy( NULL, &object_attributes, POLICY_ALL_ACCESS, &handle);
|
||||
ok(status == STATUS_SUCCESS || status == STATUS_ACCESS_DENIED,
|
||||
"LsaOpenPolicy(POLICY_ALL_ACCESS) returned 0x%08x\n", status);
|
||||
|
||||
/* try a more restricted access mask if necessary */
|
||||
if (status == STATUS_ACCESS_DENIED) {
|
||||
trace("LsaOpenPolicy(POLICY_ALL_ACCESS) failed, trying POLICY_VIEW_LOCAL_INFORMATION\n");
|
||||
status = pLsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION, &handle);
|
||||
status = LsaOpenPolicy( NULL, &object_attributes, POLICY_VIEW_LOCAL_INFORMATION, &handle);
|
||||
ok(status == STATUS_SUCCESS, "LsaOpenPolicy(POLICY_VIEW_LOCAL_INFORMATION) returned 0x%08x\n", status);
|
||||
}
|
||||
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
PPOLICY_ACCOUNT_DOMAIN_INFO info;
|
||||
status = pLsaQueryInformationPolicy(handle, PolicyAccountDomainInformation, (PVOID*)&info);
|
||||
status = LsaQueryInformationPolicy(handle, PolicyAccountDomainInformation, (PVOID*)&info);
|
||||
ok(status == STATUS_SUCCESS, "LsaQueryInformationPolicy() failed, returned 0x%08x\n", status);
|
||||
if (status == STATUS_SUCCESS)
|
||||
{
|
||||
|
@ -2482,14 +2433,13 @@ static void test_LookupAccountSid(void)
|
|||
test_sid_str((PSID)&max_sid.sid);
|
||||
}
|
||||
|
||||
pLsaFreeMemory((LPVOID)info);
|
||||
LsaFreeMemory(info);
|
||||
}
|
||||
|
||||
status = pLsaClose(handle);
|
||||
status = LsaClose(handle);
|
||||
ok(status == STATUS_SUCCESS, "LsaClose() failed, returned 0x%08x\n", status);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL get_sid_info(PSID psid, LPSTR *user, LPSTR *dom)
|
||||
|
@ -2847,7 +2797,7 @@ static void test_security_descriptor(void)
|
|||
expect_eq(isDefault, FALSE, BOOL, "%d");
|
||||
}
|
||||
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"O:SYG:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)"
|
||||
"(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)S:(AU;OICINPIOIDSAFA;CCDCLCSWRPRC;;;SU)"
|
||||
"(AU;NPSA;0x12019f;;;SU)", SDDL_REVISION_1, (void **)&sd_rel, NULL);
|
||||
|
@ -3449,14 +3399,8 @@ static void test_SetEntriesInAclA(void)
|
|||
static const CHAR szEveryone[] = {'E','v','e','r','y','o','n','e',0};
|
||||
static const CHAR szCurrentUser[] = { 'C','U','R','R','E','N','T','_','U','S','E','R','\0'};
|
||||
|
||||
if (!pSetEntriesInAclA)
|
||||
{
|
||||
win_skip("SetEntriesInAclA is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
NewAcl = (PACL)0xdeadbeef;
|
||||
res = pSetEntriesInAclA(0, NULL, NULL, &NewAcl);
|
||||
res = SetEntriesInAclA(0, NULL, NULL, &NewAcl);
|
||||
if(res == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
{
|
||||
win_skip("SetEntriesInAclA is not implemented\n");
|
||||
|
@ -3496,7 +3440,7 @@ static void test_SetEntriesInAclA(void)
|
|||
ExplicitAccess.Trustee.ptstrName = EveryoneSid;
|
||||
ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
||||
ExplicitAccess.Trustee.pMultipleTrustee = NULL;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_SUCCESS, "SetEntriesInAclA failed: %u\n", res);
|
||||
ok(NewAcl != NULL, "returned acl was NULL\n");
|
||||
LocalFree(NewAcl);
|
||||
|
@ -3504,7 +3448,7 @@ static void test_SetEntriesInAclA(void)
|
|||
ExplicitAccess.Trustee.TrusteeType = TRUSTEE_IS_UNKNOWN;
|
||||
ExplicitAccess.Trustee.pMultipleTrustee = NULL;
|
||||
ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_SUCCESS, "SetEntriesInAclA failed: %u\n", res);
|
||||
ok(NewAcl != NULL, "returned acl was NULL\n");
|
||||
LocalFree(NewAcl);
|
||||
|
@ -3517,13 +3461,13 @@ static void test_SetEntriesInAclA(void)
|
|||
{
|
||||
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
|
||||
ExplicitAccess.Trustee.ptstrName = (LPSTR)szEveryone;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_SUCCESS, "SetEntriesInAclA failed: %u\n", res);
|
||||
ok(NewAcl != NULL, "returned acl was NULL\n");
|
||||
LocalFree(NewAcl);
|
||||
|
||||
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_BAD_FORM;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_INVALID_PARAMETER ||
|
||||
broken(res == ERROR_NOT_SUPPORTED), /* NT4 */
|
||||
"SetEntriesInAclA failed: %u\n", res);
|
||||
|
@ -3533,7 +3477,7 @@ static void test_SetEntriesInAclA(void)
|
|||
|
||||
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
|
||||
ExplicitAccess.Trustee.MultipleTrusteeOperation = TRUSTEE_IS_IMPERSONATE;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_INVALID_PARAMETER ||
|
||||
broken(res == ERROR_NOT_SUPPORTED), /* NT4 */
|
||||
"SetEntriesInAclA failed: %u\n", res);
|
||||
|
@ -3543,7 +3487,7 @@ static void test_SetEntriesInAclA(void)
|
|||
|
||||
ExplicitAccess.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;
|
||||
ExplicitAccess.grfAccessMode = SET_ACCESS;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_SUCCESS, "SetEntriesInAclA failed: %u\n", res);
|
||||
ok(NewAcl != NULL, "returned acl was NULL\n");
|
||||
LocalFree(NewAcl);
|
||||
|
@ -3551,7 +3495,7 @@ static void test_SetEntriesInAclA(void)
|
|||
|
||||
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_NAME;
|
||||
ExplicitAccess.Trustee.ptstrName = (LPSTR)szCurrentUser;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_SUCCESS, "SetEntriesInAclA failed: %u\n", res);
|
||||
ok(NewAcl != NULL, "returned acl was NULL\n");
|
||||
LocalFree(NewAcl);
|
||||
|
@ -3559,7 +3503,7 @@ static void test_SetEntriesInAclA(void)
|
|||
ExplicitAccess.grfAccessMode = REVOKE_ACCESS;
|
||||
ExplicitAccess.Trustee.TrusteeForm = TRUSTEE_IS_SID;
|
||||
ExplicitAccess.Trustee.ptstrName = UsersSid;
|
||||
res = pSetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
res = SetEntriesInAclA(1, &ExplicitAccess, OldAcl, &NewAcl);
|
||||
ok(res == ERROR_SUCCESS, "SetEntriesInAclA failed: %u\n", res);
|
||||
ok(NewAcl != NULL, "returned acl was NULL\n");
|
||||
LocalFree(NewAcl);
|
||||
|
@ -3595,7 +3539,7 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD
|
|||
ACCESS_ALLOWED_ACE *ace;
|
||||
BOOL bret;
|
||||
|
||||
bret = pGetAclInformation(dacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(dacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok_(__FILE__, line)(bret, "GetAclInformation failed\n");
|
||||
|
||||
todo_wine_if (todo_count)
|
||||
|
@ -3605,7 +3549,7 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD
|
|||
|
||||
if (acl_size.AceCount > 0)
|
||||
{
|
||||
bret = pGetAce(dacl, 0, (VOID **)&ace);
|
||||
bret = GetAce(dacl, 0, (VOID **)&ace);
|
||||
ok_(__FILE__, line)(bret, "Failed to get Current User ACE\n");
|
||||
|
||||
bret = EqualSid(&ace->SidStart, user_sid);
|
||||
|
@ -3623,7 +3567,7 @@ static void test_inherited_dacl(PACL dacl, PSID admin_sid, PSID user_sid, DWORD
|
|||
}
|
||||
if (acl_size.AceCount > 1)
|
||||
{
|
||||
bret = pGetAce(dacl, 1, (VOID **)&ace);
|
||||
bret = GetAce(dacl, 1, (VOID **)&ace);
|
||||
ok_(__FILE__, line)(bret, "Failed to get Administators Group ACE\n");
|
||||
|
||||
bret = EqualSid(&ace->SidStart, admin_sid);
|
||||
|
@ -3662,7 +3606,7 @@ static void test_CreateDirectoryA(void)
|
|||
DWORD error;
|
||||
PACL pDacl;
|
||||
|
||||
if (!pGetSecurityInfo || !pGetNamedSecurityInfoA || !pCreateWellKnownSid)
|
||||
if (!pGetNamedSecurityInfoA || !pCreateWellKnownSid)
|
||||
{
|
||||
win_skip("Required functions are not available\n");
|
||||
return;
|
||||
|
@ -3762,11 +3706,10 @@ static void test_CreateDirectoryA(void)
|
|||
ok(hTemp != INVALID_HANDLE_VALUE, "CreateFile error %u\n", GetLastError());
|
||||
HeapFree(GetProcessHeap(), 0, pDacl);
|
||||
|
||||
error = pGetSecurityInfo(hTemp, SE_FILE_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
error = GetSecurityInfo(hTemp, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
(PSID *)&owner, NULL, &pDacl, NULL, &pSD);
|
||||
ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error);
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
todo_wine
|
||||
ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n",
|
||||
|
@ -3780,7 +3723,7 @@ static void test_CreateDirectoryA(void)
|
|||
ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error);
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
todo_wine
|
||||
ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n",
|
||||
|
@ -3842,11 +3785,10 @@ static void test_CreateDirectoryA(void)
|
|||
pRtlFreeUnicodeString(&tmpfileW);
|
||||
HeapFree(GetProcessHeap(), 0, pDacl);
|
||||
|
||||
error = pGetSecurityInfo(hTemp, SE_FILE_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
error = GetSecurityInfo(hTemp, SE_FILE_OBJECT, OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
(PSID *)&owner, NULL, &pDacl, NULL, &pSD);
|
||||
ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error);
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
todo_wine
|
||||
ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n",
|
||||
|
@ -3860,7 +3802,7 @@ static void test_CreateDirectoryA(void)
|
|||
ok(error == ERROR_SUCCESS, "GetNamedSecurityInfo failed with error %d\n", error);
|
||||
if (error == ERROR_SUCCESS)
|
||||
{
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
todo_wine
|
||||
ok(acl_size.AceCount == 0, "GetAclInformation returned unexpected entry count (%d != 0).\n",
|
||||
|
@ -4035,11 +3977,11 @@ static void test_GetNamedSecurityInfoA(void)
|
|||
}
|
||||
ok(!error, "GetNamedSecurityInfo failed with error %d\n", error);
|
||||
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
if (acl_size.AceCount > 0)
|
||||
{
|
||||
bret = pGetAce(pDacl, 0, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, 0, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Current User ACE.\n");
|
||||
bret = EqualSid(&ace->SidStart, user_sid);
|
||||
todo_wine ok(bret, "Current User ACE (%s) != Current User SID (%s).\n",
|
||||
|
@ -4051,7 +3993,7 @@ static void test_GetNamedSecurityInfoA(void)
|
|||
}
|
||||
if (acl_size.AceCount > 1)
|
||||
{
|
||||
bret = pGetAce(pDacl, 1, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, 1, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Administators Group ACE.\n");
|
||||
bret = EqualSid(&ace->SidStart, admin_sid);
|
||||
todo_wine ok(bret || broken(!bret) /* win2k */,
|
||||
|
@ -4077,11 +4019,11 @@ static void test_GetNamedSecurityInfoA(void)
|
|||
NULL, NULL, &pDacl, NULL, &pSD);
|
||||
ok(!error, "GetNamedSecurityInfo failed with error %d\n", error);
|
||||
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
if (acl_size.AceCount > 0)
|
||||
{
|
||||
bret = pGetAce(pDacl, 0, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, 0, (VOID **)&ace);
|
||||
ok(bret, "Failed to get ACE.\n");
|
||||
todo_wine ok(((ACE_HEADER *)ace)->AceFlags & INHERITED_ACE,
|
||||
"ACE has unexpected flags: 0x%x\n", ((ACE_HEADER *)ace)->AceFlags);
|
||||
|
@ -4217,12 +4159,12 @@ static void test_GetNamedSecurityInfoA(void)
|
|||
ok(bret, "GetSecurityDescriptorDacl failed with error %d\n", GetLastError());
|
||||
ok(dacl_present, "DACL should be present\n");
|
||||
ok(pDacl && IsValidAcl(pDacl), "GetSecurityDescriptorDacl returned invalid DACL.\n");
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
ok(acl_size.AceCount != 0, "GetAclInformation returned no ACLs\n");
|
||||
for (i=0; i<acl_size.AceCount; i++)
|
||||
{
|
||||
bret = pGetAce(pDacl, i, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, i, (VOID **)&ace);
|
||||
ok(bret, "Failed to get ACE %d.\n", i);
|
||||
bret = EqualSid(&ace->SidStart, users_sid);
|
||||
if (bret) users_ace_id = i;
|
||||
|
@ -4233,7 +4175,7 @@ static void test_GetNamedSecurityInfoA(void)
|
|||
"Builtin Users ACE not found.\n");
|
||||
if (users_ace_id != -1)
|
||||
{
|
||||
bret = pGetAce(pDacl, users_ace_id, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, users_ace_id, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Builtin Users ACE.\n");
|
||||
flags = ((ACE_HEADER *)ace)->AceFlags;
|
||||
ok(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE)
|
||||
|
@ -4250,7 +4192,7 @@ static void test_GetNamedSecurityInfoA(void)
|
|||
ok(admins_ace_id != -1, "Builtin Admins ACE not found.\n");
|
||||
if (admins_ace_id != -1)
|
||||
{
|
||||
bret = pGetAce(pDacl, admins_ace_id, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, admins_ace_id, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Builtin Admins ACE.\n");
|
||||
flags = ((ACE_HEADER *)ace)->AceFlags;
|
||||
ok(flags == 0x0
|
||||
|
@ -4320,18 +4262,12 @@ static void test_ConvertStringSecurityDescriptor(void)
|
|||
{ "D:(D;;GA;;;Nonexistent account)", SDDL_REVISION_1, FALSE, ERROR_INVALID_ACL, ERROR_INVALID_SID } /* W2K */
|
||||
};
|
||||
|
||||
if (!pConvertStringSecurityDescriptorToSecurityDescriptorA)
|
||||
{
|
||||
win_skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(cssd); i++)
|
||||
{
|
||||
DWORD GLE;
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
cssd[i].sidstring, cssd[i].revision, &pSD, NULL);
|
||||
GLE = GetLastError();
|
||||
ok(ret == cssd[i].ret, "(%02u) Expected %s (%d)\n", i, cssd[i].ret ? "success" : "failure", GLE);
|
||||
|
@ -4345,7 +4281,7 @@ static void test_ConvertStringSecurityDescriptor(void)
|
|||
|
||||
/* test behaviour with NULL parameters */
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
NULL, 0xdeadbeef, &pSD, NULL);
|
||||
todo_wine
|
||||
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
|
@ -4360,14 +4296,14 @@ static void test_ConvertStringSecurityDescriptor(void)
|
|||
GetLastError());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"D:(A;;ROB;;;WD)", 0xdeadbeef, NULL, NULL);
|
||||
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
|
||||
GetLastError());
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"D:(A;;ROB;;;WD)", SDDL_REVISION_1, NULL, NULL);
|
||||
ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
|
||||
"ConvertStringSecurityDescriptorToSecurityDescriptor should have failed with ERROR_INVALID_PARAMETER instead of %d\n",
|
||||
|
@ -4381,7 +4317,7 @@ static void test_ConvertStringSecurityDescriptor(void)
|
|||
LocalFree(pSD);
|
||||
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"D:P(A;;GRGW;;;BA)(A;;GRGW;;;S-1-5-21-0-0-0-1000)S:(ML;;NWNR;;;S-1-16-12288)", SDDL_REVISION_1, &pSD, NULL);
|
||||
ok(ret || broken(!ret && GetLastError() == ERROR_INVALID_DATATYPE) /* win2k */,
|
||||
"ConvertStringSecurityDescriptorToSecurityDescriptor failed with error %u\n", GetLastError());
|
||||
|
@ -4390,7 +4326,7 @@ static void test_ConvertStringSecurityDescriptor(void)
|
|||
/* empty DACL */
|
||||
size = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA("D:", SDDL_REVISION_1, &pSD, &size);
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA("D:", SDDL_REVISION_1, &pSD, &size);
|
||||
ok(ret, "unexpected error %u\n", GetLastError());
|
||||
ok(size == sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sizeof(ACL), "got %u\n", size);
|
||||
acl = (ACL *)((char *)pSD + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
||||
|
@ -4404,7 +4340,7 @@ static void test_ConvertStringSecurityDescriptor(void)
|
|||
/* empty SACL */
|
||||
size = 0;
|
||||
SetLastError(0xdeadbeef);
|
||||
ret = pConvertStringSecurityDescriptorToSecurityDescriptorA("S:", SDDL_REVISION_1, &pSD, &size);
|
||||
ret = ConvertStringSecurityDescriptorToSecurityDescriptorA("S:", SDDL_REVISION_1, &pSD, &size);
|
||||
ok(ret, "unexpected error %u\n", GetLastError());
|
||||
ok(size == sizeof(SECURITY_DESCRIPTOR_RELATIVE) + sizeof(ACL), "got %u\n", size);
|
||||
acl = (ACL *)((char *)pSD + sizeof(SECURITY_DESCRIPTOR_RELATIVE));
|
||||
|
@ -4470,7 +4406,7 @@ static void test_ConvertSecurityDescriptorToString(void)
|
|||
ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
|
||||
CHECK_RESULT_AND_FREE("O:SY");
|
||||
|
||||
pConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid);
|
||||
ConvertStringSidToSidA("S-1-5-21-93476-23408-4576", &psid);
|
||||
SetSecurityDescriptorGroup(&desc, psid, TRUE);
|
||||
ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
|
||||
CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576");
|
||||
|
@ -4488,7 +4424,7 @@ static void test_ConvertSecurityDescriptorToString(void)
|
|||
ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
|
||||
CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:");
|
||||
|
||||
pConvertStringSidToSidA("S-1-5-6", &psid2);
|
||||
ConvertStringSidToSidA("S-1-5-6", &psid2);
|
||||
pAddAccessAllowedAceEx(pacl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, 0xf0000000, psid2);
|
||||
ok(pConvertSecurityDescriptorToStringSecurityDescriptorA(&desc, SDDL_REVISION_1, sec_info, &string, &len), "Conversion failed\n");
|
||||
CHECK_RESULT_AND_FREE("O:SYG:S-1-5-21-93476-23408-4576D:(A;NP;GAGXGWGR;;;SU)");
|
||||
|
@ -4630,13 +4566,7 @@ static void test_PrivateObjectSecurity(void)
|
|||
PSECURITY_DESCRIPTOR buf;
|
||||
BOOL ret;
|
||||
|
||||
if (!pConvertStringSecurityDescriptorToSecurityDescriptorA)
|
||||
{
|
||||
win_skip("ConvertStringSecurityDescriptorToSecurityDescriptor is not available\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ok(ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"O:SY"
|
||||
"G:S-1-5-21-93476-23408-4576"
|
||||
"D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)"
|
||||
|
@ -4648,7 +4578,7 @@ static void test_PrivateObjectSecurity(void)
|
|||
|
||||
LocalFree(sec);
|
||||
|
||||
ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ok(ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"O:SY"
|
||||
"G:S-1-5-21-93476-23408-4576",
|
||||
SDDL_REVISION_1, &sec, &dwDescSize), "Creating descriptor failed\n");
|
||||
|
@ -4657,7 +4587,7 @@ static void test_PrivateObjectSecurity(void)
|
|||
|
||||
LocalFree(sec);
|
||||
|
||||
ok(pConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
ok(ConvertStringSecurityDescriptorToSecurityDescriptorA(
|
||||
"O:SY"
|
||||
"G:S-1-5-21-93476-23408-4576"
|
||||
"D:(A;NP;GAGXGWGR;;;SU)(A;IOID;CCDC;;;SU)(D;OICI;0xffffffff;;;S-1-5-21-93476-23408-4576)"
|
||||
|
@ -4786,7 +4716,7 @@ static void test_GetSecurityInfo(void)
|
|||
BYTE flags;
|
||||
DWORD ret;
|
||||
|
||||
if (!pGetSecurityInfo || !pSetSecurityInfo)
|
||||
if (!pSetSecurityInfo)
|
||||
{
|
||||
win_skip("[Get|Set]SecurityInfo is not available\n");
|
||||
return;
|
||||
|
@ -4816,7 +4746,7 @@ static void test_GetSecurityInfo(void)
|
|||
return;
|
||||
}
|
||||
|
||||
ret = pGetSecurityInfo(obj, SE_FILE_OBJECT,
|
||||
ret = GetSecurityInfo(obj, SE_FILE_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
&owner, &group, &pDacl, NULL, &pSD);
|
||||
if (ret == ERROR_CALL_NOT_IMPLEMENTED)
|
||||
|
@ -4845,7 +4775,7 @@ static void test_GetSecurityInfo(void)
|
|||
|
||||
/* If we don't ask for the security descriptor, Windows will still give us
|
||||
the other stuff, leaving us no way to free it. */
|
||||
ret = pGetSecurityInfo(obj, SE_FILE_OBJECT,
|
||||
ret = GetSecurityInfo(obj, SE_FILE_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
|
||||
&owner, &group, &pDacl, NULL, NULL);
|
||||
ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret);
|
||||
|
@ -4872,15 +4802,15 @@ static void test_GetSecurityInfo(void)
|
|||
ret = pSetSecurityInfo(obj, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
|
||||
NULL, NULL, pDacl, NULL);
|
||||
ok(ret == ERROR_SUCCESS, "SetSecurityInfo returned %d\n", ret);
|
||||
ret = pGetSecurityInfo(obj, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
|
||||
ret = GetSecurityInfo(obj, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
|
||||
NULL, NULL, &pDacl, NULL, &pSD);
|
||||
ok(ret == ERROR_SUCCESS, "GetSecurityInfo returned %d\n", ret);
|
||||
ok(pDacl && IsValidAcl(pDacl), "GetSecurityInfo returned invalid DACL.\n");
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
if (acl_size.AceCount > 0)
|
||||
{
|
||||
bret = pGetAce(pDacl, 0, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, 0, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Current User ACE.\n");
|
||||
bret = EqualSid(&ace->SidStart, user_sid);
|
||||
todo_wine ok(bret, "Current User ACE (%s) != Current User SID (%s).\n",
|
||||
|
@ -4892,7 +4822,7 @@ static void test_GetSecurityInfo(void)
|
|||
}
|
||||
if (acl_size.AceCount > 1)
|
||||
{
|
||||
bret = pGetAce(pDacl, 1, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, 1, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Administators Group ACE.\n");
|
||||
bret = EqualSid(&ace->SidStart, admin_sid);
|
||||
todo_wine ok(bret, "Administators Group ACE (%s) != Administators Group SID (%s).\n", debugstr_sid(&ace->SidStart), debugstr_sid(admin_sid));
|
||||
|
@ -4918,7 +4848,7 @@ static void test_GetSecurityInfo(void)
|
|||
FreeSid(domain_sid);
|
||||
|
||||
/* Test querying the ownership of a process */
|
||||
ret = pGetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT,
|
||||
ret = GetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION,
|
||||
NULL, NULL, NULL, NULL, &pSD);
|
||||
ok(!ret, "GetNamedSecurityInfo failed with error %d\n", ret);
|
||||
|
@ -4936,7 +4866,7 @@ static void test_GetSecurityInfo(void)
|
|||
LocalFree(pSD);
|
||||
|
||||
/* Test querying the DACL of a process */
|
||||
ret = pGetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
|
||||
ret = GetSecurityInfo(GetCurrentProcess(), SE_KERNEL_OBJECT, DACL_SECURITY_INFORMATION,
|
||||
NULL, NULL, NULL, NULL, &pSD);
|
||||
ok(!ret, "GetSecurityInfo failed with error %d\n", ret);
|
||||
|
||||
|
@ -4944,12 +4874,12 @@ static void test_GetSecurityInfo(void)
|
|||
ok(bret, "GetSecurityDescriptorDacl failed with error %d\n", GetLastError());
|
||||
ok(dacl_present, "DACL should be present\n");
|
||||
ok(pDacl && IsValidAcl(pDacl), "GetSecurityDescriptorDacl returned invalid DACL.\n");
|
||||
bret = pGetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
bret = GetAclInformation(pDacl, &acl_size, sizeof(acl_size), AclSizeInformation);
|
||||
ok(bret, "GetAclInformation failed\n");
|
||||
ok(acl_size.AceCount != 0, "GetAclInformation returned no ACLs\n");
|
||||
for (i=0; i<acl_size.AceCount; i++)
|
||||
{
|
||||
bret = pGetAce(pDacl, i, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, i, (VOID **)&ace);
|
||||
ok(bret, "Failed to get ACE %d.\n", i);
|
||||
bret = EqualSid(&ace->SidStart, domain_users_sid);
|
||||
if (bret) domain_users_ace_id = i;
|
||||
|
@ -4960,7 +4890,7 @@ static void test_GetSecurityInfo(void)
|
|||
"Domain Users ACE not found.\n");
|
||||
if (domain_users_ace_id != -1)
|
||||
{
|
||||
bret = pGetAce(pDacl, domain_users_ace_id, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, domain_users_ace_id, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Domain Users ACE.\n");
|
||||
flags = ((ACE_HEADER *)ace)->AceFlags;
|
||||
ok(flags == (INHERIT_ONLY_ACE|CONTAINER_INHERIT_ACE),
|
||||
|
@ -4973,7 +4903,7 @@ static void test_GetSecurityInfo(void)
|
|||
"Builtin Admins ACE not found.\n");
|
||||
if (admins_ace_id != -1)
|
||||
{
|
||||
bret = pGetAce(pDacl, admins_ace_id, (VOID **)&ace);
|
||||
bret = GetAce(pDacl, admins_ace_id, (VOID **)&ace);
|
||||
ok(bret, "Failed to get Builtin Admins ACE.\n");
|
||||
flags = ((ACE_HEADER *)ace)->AceFlags;
|
||||
ok(flags == 0x0, "Builtin Admins ACE has unexpected flags (0x%x != 0x0)\n", flags);
|
||||
|
@ -4987,26 +4917,21 @@ static void test_GetSidSubAuthority(void)
|
|||
{
|
||||
PSID psid = NULL;
|
||||
|
||||
if (!pGetSidSubAuthority || !pConvertStringSidToSidA || !pIsValidSid || !pGetSidSubAuthorityCount)
|
||||
{
|
||||
win_skip("Some functions not available\n");
|
||||
return;
|
||||
}
|
||||
/* Note: on windows passing in an invalid index like -1, lets GetSidSubAuthority return 0x05000000 but
|
||||
still GetLastError returns ERROR_SUCCESS then. We don't test these unlikely cornercases here for now */
|
||||
ok(pConvertStringSidToSidA("S-1-5-21-93476-23408-4576",&psid),"ConvertStringSidToSidA failed\n");
|
||||
ok(pIsValidSid(psid),"Sid is not valid\n");
|
||||
ok(ConvertStringSidToSidA("S-1-5-21-93476-23408-4576",&psid),"ConvertStringSidToSidA failed\n");
|
||||
ok(IsValidSid(psid),"Sid is not valid\n");
|
||||
SetLastError(0xbebecaca);
|
||||
ok(*pGetSidSubAuthorityCount(psid) == 4,"GetSidSubAuthorityCount gave %d expected 4\n",*pGetSidSubAuthorityCount(psid));
|
||||
ok(*GetSidSubAuthorityCount(psid) == 4,"GetSidSubAuthorityCount gave %d expected 4\n", *GetSidSubAuthorityCount(psid));
|
||||
ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError());
|
||||
SetLastError(0xbebecaca);
|
||||
ok(*pGetSidSubAuthority(psid,0) == 21,"GetSidSubAuthority gave %d expected 21\n",*pGetSidSubAuthority(psid,0));
|
||||
ok(*GetSidSubAuthority(psid,0) == 21,"GetSidSubAuthority gave %d expected 21\n", *GetSidSubAuthority(psid,0));
|
||||
ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError());
|
||||
SetLastError(0xbebecaca);
|
||||
ok(*pGetSidSubAuthority(psid,1) == 93476,"GetSidSubAuthority gave %d expected 93476\n",*pGetSidSubAuthority(psid,1));
|
||||
ok(*GetSidSubAuthority(psid,1) == 93476,"GetSidSubAuthority gave %d expected 93476\n", *GetSidSubAuthority(psid,1));
|
||||
ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError());
|
||||
SetLastError(0xbebecaca);
|
||||
ok(pGetSidSubAuthority(psid,4) != NULL,"Expected out of bounds GetSidSubAuthority to return a non-NULL pointer\n");
|
||||
ok(GetSidSubAuthority(psid,4) != NULL,"Expected out of bounds GetSidSubAuthority to return a non-NULL pointer\n");
|
||||
ok(GetLastError() == 0,"GetLastError returned %d instead of 0\n",GetLastError());
|
||||
LocalFree(psid);
|
||||
}
|
||||
|
@ -6372,7 +6297,7 @@ static void test_default_dacl_owner_sid(void)
|
|||
|
||||
index = 0;
|
||||
found = FALSE;
|
||||
while (pGetAce( dacl, index++, (void **)&ace ))
|
||||
while (GetAce( dacl, index++, (void **)&ace ))
|
||||
{
|
||||
if (EqualSid( &ace->SidStart, owner )) found = TRUE;
|
||||
}
|
||||
|
@ -6533,7 +6458,7 @@ static void test_AddMandatoryAce(void)
|
|||
|
||||
index = 0;
|
||||
found = FALSE;
|
||||
while (pGetAce(acl, index++, (void **)&ace))
|
||||
while (GetAce(acl, index++, (void **)&ace))
|
||||
{
|
||||
if (ace->Header.AceType != SYSTEM_MANDATORY_LABEL_ACE_TYPE) continue;
|
||||
ok(ace->Header.AceFlags == 0, "Expected flags 0, got %x\n", ace->Header.AceFlags);
|
||||
|
@ -6566,11 +6491,11 @@ static void test_AddMandatoryAce(void)
|
|||
ok(present, "SACL not present\n");
|
||||
ok(sacl != (void *)0xdeadbeef, "SACL not set\n");
|
||||
ok(!defaulted, "SACL defaulted\n");
|
||||
ret = pGetAclInformation(sacl, &acl_size_info, sizeof(acl_size_info), AclSizeInformation);
|
||||
ret = GetAclInformation(sacl, &acl_size_info, sizeof(acl_size_info), AclSizeInformation);
|
||||
ok(ret, "GetAclInformation failed with error %u\n", GetLastError());
|
||||
ok(acl_size_info.AceCount == 1, "SACL contains an unexpected ACE count %u\n", acl_size_info.AceCount);
|
||||
|
||||
ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
ret = GetAce(sacl, 0, (void **)&ace);
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
ok (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE, "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
ok(!ace->Header.AceFlags, "Unexpected ACE flags %#x\n", ace->Header.AceFlags);
|
||||
|
@ -6605,7 +6530,7 @@ static void test_AddMandatoryAce(void)
|
|||
|
||||
index = 0;
|
||||
found = found2 = FALSE;
|
||||
while (pGetAce(sacl, index++, (void **)&ace))
|
||||
while (GetAce(sacl, index++, (void **)&ace))
|
||||
{
|
||||
if (ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE)
|
||||
{
|
||||
|
@ -7082,7 +7007,7 @@ static void test_token_label(void)
|
|||
ok(!defaulted, "SACL defaulted\n");
|
||||
ok(sacl->AceCount == 1, "SACL contains an unexpected ACE count %u\n", sacl->AceCount);
|
||||
|
||||
ret = pGetAce(sacl, 0, (void **)&ace);
|
||||
ret = GetAce(sacl, 0, (void **)&ace);
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
|
||||
ok(ace->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
|
@ -7123,8 +7048,7 @@ static void test_token_security_descriptor(void)
|
|||
STARTUPINFOA startup;
|
||||
PSID psid;
|
||||
|
||||
if (!pDuplicateTokenEx || !pConvertStringSidToSidA || !pAddAccessAllowedAceEx || !pGetAce
|
||||
|| !pSetEntriesInAclW)
|
||||
if (!pDuplicateTokenEx || !pAddAccessAllowedAceEx || !pSetEntriesInAclW)
|
||||
{
|
||||
win_skip("Some functions not available\n");
|
||||
return;
|
||||
|
@ -7141,7 +7065,7 @@ static void test_token_security_descriptor(void)
|
|||
ret = InitializeAcl(acl, 256, ACL_REVISION);
|
||||
ok(ret, "InitializeAcl failed with error %u\n", GetLastError());
|
||||
|
||||
ret = pConvertStringSidToSidA("S-1-5-6", &psid);
|
||||
ret = ConvertStringSidToSidA("S-1-5-6", &psid);
|
||||
ok(ret, "ConvertStringSidToSidA failed with error %u\n", GetLastError());
|
||||
|
||||
ret = pAddAccessAllowedAceEx(acl, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, GENERIC_ALL, psid);
|
||||
|
@ -7175,7 +7099,7 @@ static void test_token_security_descriptor(void)
|
|||
ok(acl2->AceCount == 1, "Expected 1 ACE, got %d\n", acl2->AceCount);
|
||||
ok(!defaulted, "acl2 defaulted\n");
|
||||
|
||||
ret = pGetAce(acl2, 0, (void **)&ace);
|
||||
ret = GetAce(acl2, 0, (void **)&ace);
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
ok(ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE, "Unexpected ACE type %#x\n", ace->Header.AceType);
|
||||
ok(EqualSid(&ace->SidStart, psid), "Expected access allowed ACE\n");
|
||||
|
@ -7212,7 +7136,7 @@ static void test_token_security_descriptor(void)
|
|||
|
||||
index = 0;
|
||||
found = FALSE;
|
||||
while (pGetAce(acl2, index++, (void **)&ace))
|
||||
while (GetAce(acl2, index++, (void **)&ace))
|
||||
{
|
||||
if (ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE && EqualSid(&ace->SidStart, psid))
|
||||
found = TRUE;
|
||||
|
@ -7320,7 +7244,7 @@ static void test_child_token_sd(void)
|
|||
PSID psid;
|
||||
ACL *acl;
|
||||
|
||||
ret = pConvertStringSidToSidA("S-1-5-6", &psid);
|
||||
ret = ConvertStringSidToSidA("S-1-5-6", &psid);
|
||||
ok(ret, "ConvertStringSidToSidA failed with error %u\n", GetLastError());
|
||||
|
||||
ret = OpenProcessToken(GetCurrentProcess(), MAXIMUM_ALLOWED, &token);
|
||||
|
@ -7346,7 +7270,7 @@ static void test_child_token_sd(void)
|
|||
ok(acl->AceCount, "Expected at least one ACE\n");
|
||||
for (i = 0; i < acl->AceCount; i++)
|
||||
{
|
||||
ret = pGetAce(acl, i, (void **)&acc_ace);
|
||||
ret = GetAce(acl, i, (void **)&acc_ace);
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
ok(acc_ace->Header.AceType != ACCESS_ALLOWED_ACE_TYPE || !EqualSid(&acc_ace->SidStart, psid),
|
||||
"ACE inherited from the parent\n");
|
||||
|
@ -7378,7 +7302,7 @@ static void test_child_token_sd(void)
|
|||
ok(acl && acl != (void *)0xdeadbeef, "Got invalid SACL\n");
|
||||
ok(!defaulted, "SACL defaulted\n");
|
||||
ok(acl->AceCount == 1, "Expected exactly one ACE\n");
|
||||
ret = pGetAce(acl, 0, (void **)&ace_label);
|
||||
ret = GetAce(acl, 0, (void **)&ace_label);
|
||||
ok(ret, "GetAce failed with error %u\n", GetLastError());
|
||||
ok(ace_label->Header.AceType == SYSTEM_MANDATORY_LABEL_ACE_TYPE,
|
||||
"Unexpected ACE type %#x\n", ace_label->Header.AceType);
|
||||
|
|
|
@ -45,8 +45,6 @@ static BOOL (WINAPI *pEnumServicesStatusExA)(SC_HANDLE, SC_ENUM_TYPE, DWORD,
|
|||
static BOOL (WINAPI *pEnumServicesStatusExW)(SC_HANDLE, SC_ENUM_TYPE, DWORD,
|
||||
DWORD, LPBYTE, DWORD, LPDWORD,
|
||||
LPDWORD, LPDWORD, LPCWSTR);
|
||||
static DWORD (WINAPI *pGetSecurityInfo)(HANDLE, SE_OBJECT_TYPE, SECURITY_INFORMATION,
|
||||
PSID*, PSID*, PACL*, PACL*, PSECURITY_DESCRIPTOR*);
|
||||
static BOOL (WINAPI *pQueryServiceConfig2A)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
|
||||
static BOOL (WINAPI *pQueryServiceConfig2W)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
|
||||
static BOOL (WINAPI *pQueryServiceStatusEx)(SC_HANDLE, SC_STATUS_TYPE, LPBYTE,
|
||||
|
@ -63,7 +61,6 @@ static void init_function_pointers(void)
|
|||
pChangeServiceConfig2W = (void*)GetProcAddress(hadvapi32, "ChangeServiceConfig2W");
|
||||
pEnumServicesStatusExA= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExA");
|
||||
pEnumServicesStatusExW= (void*)GetProcAddress(hadvapi32, "EnumServicesStatusExW");
|
||||
pGetSecurityInfo = (void *)GetProcAddress(hadvapi32, "GetSecurityInfo");
|
||||
pQueryServiceConfig2A= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2A");
|
||||
pQueryServiceConfig2W= (void*)GetProcAddress(hadvapi32, "QueryServiceConfig2W");
|
||||
pQueryServiceStatusEx= (void*)GetProcAddress(hadvapi32, "QueryServiceStatusEx");
|
||||
|
@ -1910,7 +1907,7 @@ static void test_sequence(void)
|
|||
else
|
||||
{
|
||||
ok(svc_handle != NULL, "Could not create the service : %d\n", GetLastError());
|
||||
if ((svc_handle != NULL) && (pGetSecurityInfo != NULL))
|
||||
if (svc_handle != NULL)
|
||||
{
|
||||
PSID sidOwner, sidGroup;
|
||||
PACL dacl, sacl;
|
||||
|
@ -1920,22 +1917,22 @@ static void test_sequence(void)
|
|||
BOOL bret;
|
||||
|
||||
/* Test using GetSecurityInfo to obtain security information */
|
||||
retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, &sidOwner,
|
||||
retval = GetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, &sidOwner,
|
||||
&sidGroup, &dacl, &sacl, &pSD);
|
||||
LocalFree(pSD);
|
||||
ok(retval == ERROR_SUCCESS, "Expected GetSecurityInfo to succeed: result %d\n", retval);
|
||||
retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL,
|
||||
retval = GetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL,
|
||||
NULL, NULL, NULL, &pSD);
|
||||
LocalFree(pSD);
|
||||
ok(retval == ERROR_SUCCESS, "Expected GetSecurityInfo to succeed: result %d\n", retval);
|
||||
if (!is_nt4)
|
||||
{
|
||||
retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL,
|
||||
retval = GetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL,
|
||||
NULL, &dacl, NULL, &pSD);
|
||||
ok(retval == ERROR_SUCCESS, "Expected GetSecurityInfo to succeed: result %d\n", retval);
|
||||
LocalFree(pSD);
|
||||
SetLastError(0xdeadbeef);
|
||||
retval = pGetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL,
|
||||
retval = GetSecurityInfo(svc_handle, SE_SERVICE, DACL_SECURITY_INFORMATION, NULL,
|
||||
NULL, NULL, NULL, NULL);
|
||||
error = GetLastError();
|
||||
ok(retval == ERROR_INVALID_PARAMETER, "Expected GetSecurityInfo to fail: result %d\n", retval);
|
||||
|
|
Loading…
Reference in New Issue