MSDN示例中SetEntriesInAcl错误87的原因

我不知道很多关于Windows的安全描述符。 为了学习,我正密切关注他们在这里发布的例子。 我的代码在调用SetEntriesInAcl时保持相同的错误(87-无效的参数)。 我无法弄清楚,所以我复制并粘贴了样本中的确切代码并运行。 我结束了同样的错误; 有这方面经验的人有什么想法是怎么回事? 这里是与例子相同的代码:

#pragma comment(lib, "advapi32.lib") #include <windows.h> #include <stdio.h> #include <aclapi.h> #include <tchar.h> void main() { DWORD dwRes, dwDisposition; PSID pEveryoneSID = NULL, pAdminSID = NULL; PACL pACL = NULL; PSECURITY_DESCRIPTOR pSD = NULL; EXPLICIT_ACCESS ea[2]; SID_IDENTIFIER_AUTHORITY SIDAuthWorld = SECURITY_WORLD_SID_AUTHORITY; SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY; SECURITY_ATTRIBUTES sa; LONG lRes; HKEY hkSub = NULL; // Create a well-known SID for the Everyone group. if (!AllocateAndInitializeSid(&SIDAuthWorld, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pEveryoneSID)) { _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError()); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow Everyone read access to the key. ZeroMemory(&ea, 2 * sizeof(EXPLICIT_ACCESS)); ea[0].grfAccessPermissions = KEY_READ; ea[0].grfAccessMode = SET_ACCESS; ea[0].grfInheritance = NO_INHERITANCE; ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[0].Trustee.TrusteeType = TRUSTEE_IS_WELL_KNOWN_GROUP; ea[0].Trustee.ptstrName = (LPTSTR)pEveryoneSID; // Create a SID for the BUILTIN\Administrators group. if (!AllocateAndInitializeSid(&SIDAuthNT, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, &pAdminSID)) { _tprintf(_T("AllocateAndInitializeSid Error %u\n"), GetLastError()); goto Cleanup; } // Initialize an EXPLICIT_ACCESS structure for an ACE. // The ACE will allow the Administrators group full access to // the key. ea[1].grfAccessPermissions = KEY_ALL_ACCESS; ea[1].grfAccessMode = SET_ACCESS; ea[1].grfInheritance = NO_INHERITANCE; ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID; ea[1].Trustee.TrusteeType = TRUSTEE_IS_GROUP; ea[1].Trustee.ptstrName = (LPTSTR)pAdminSID; // Create a new ACL that contains the new ACEs. dwRes = SetEntriesInAcl(2, ea, NULL, &pACL); if (ERROR_SUCCESS != dwRes) { _tprintf(_T("SetEntriesInAcl Error %u\n"), GetLastError()); goto Cleanup; } // Initialize a security descriptor. pSD = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH); if (NULL == pSD) { _tprintf(_T("LocalAlloc Error %u\n"), GetLastError()); goto Cleanup; } if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { _tprintf(_T("InitializeSecurityDescriptor Error %u\n"), GetLastError()); goto Cleanup; } // Add the ACL to the security descriptor. if (!SetSecurityDescriptorDacl(pSD, TRUE, // bDaclPresent flag pACL, FALSE)) // not a default DACL { _tprintf(_T("SetSecurityDescriptorDacl Error %u\n"), GetLastError()); goto Cleanup; } // Initialize a security attributes structure. sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = pSD; sa.bInheritHandle = FALSE; // Use the security attributes to set the security descriptor // when you create a key. lRes = RegCreateKeyEx(HKEY_CURRENT_USER, _T("mykey"), 0, _T(""), 0, KEY_READ | KEY_WRITE, &sa, &hkSub, &dwDisposition); _tprintf(_T("RegCreateKeyEx result %u\n"), lRes); Cleanup: if (pEveryoneSID) FreeSid(pEveryoneSID); if (pAdminSID) FreeSid(pAdminSID); if (pACL) LocalFree(pACL); if (pSD) LocalFree(pSD); if (hkSub) RegCloseKey(hkSub); return; } 

函数SetEntriesInAcl保持失败,错误代码87 – 无效参数的原因是因为编译器选项(/ Zp1)已设置。 Zp1将默认的结构成员对齐设置为一个字节。 当编译器选项设置为默认时,该函数正常工作。 Zp1将EXPLICIT_ACCESS_W结构的大小从48更改为40,导致发生无效参数错误。

在这个经验之后,我会建议不要设置全局结构包装(/ Zp),而是使用#pragma pack(n)来包装你需要的结构; 然后在定义之后使用#pragma pack()重置为默认值。 我很确定Zp选项会影响其他结构,比如SECURITY_DESCRIPTOR及其一些成员。 当使用内存映射文件使用安全属性时,我注意到了一个类似的问题,当删除Zp#时已经解决了这个问题。