views:

165

answers:

2

What does ERROR_BAD_INHERITANCE_ACL returned from SetNamedSecurityInfo imply? In this case I'm adding a user to a directory's ACL. I've looked at the directory in question and its rights seem reasonable before the call. But the calls fails.

Any thoughts?

Here is the code snippet doing the work (and as I paste it here, I'm wondering about the NO_MULTIPLE_TRUSTEE value):

pAAP is a pointer to a structure with the following members:
CString objName;          // name of object
SE_OBJECT_TYPE ObjectType;  // type of object
CString trustee;      // trustee for new ACE (explicit user name)
CString targetComputer;
bool bNeedWrite;

 DWORD dwRes = 0;
 PACL pOldDACL = NULL, pNewDACL = NULL;
 PSECURITY_DESCRIPTOR pSD = NULL;
 EXPLICIT_ACCESS ea = {0};
 CSID trusteeSID;

 bool bGotSID = false;
 if(0 == wcsncmp(pAAP->trustee, L"SID:", 4)) //4 = len of SID: //GLOK
  bGotSID = CSID::FromString((LPWSTR)((LPCWSTR)pAAP->trustee + 4), trusteeSID);
 else
  bGotSID = CSID::FromAccount(pAAP->targetComputer, pAAP->trustee, trusteeSID);

 if(false == bGotSID)
 {
  Log(logDEBUG, L"CSID::FromAccount failed for [%s] on [%s].  GLE=%s", pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(GetLastError()));
  _ASSERT(0);
  goto Cleanup;
 }

 // Get a pointer to the existing DACL.
 dwRes = GetNamedSecurityInfo(pAAP->objName.LockBuffer(), pAAP->ObjectType, DACL_SECURITY_INFORMATION,
        NULL, NULL, &pOldDACL, NULL, &pSD);
 pAAP->objName.UnlockBuffer();
 if (ERROR_SUCCESS != dwRes)
 {
  Log(logDEBUG, L"GetNamedSecurityInfo failed on [%s] for [%s] on [%s].  GLE=%s", pAAP->objName, pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(dwRes));
  //_ASSERT(ERROR_FILE_NOT_FOUND == dwRes);
  goto Cleanup; 
 }  

 // Initialize an EXPLICIT_ACCESS structure for the new ACE. 
 ea.grfAccessPermissions = pAAP->bNeedWrite ? GENERIC_ALL : GENERIC_READ;
 ea.grfAccessMode = GRANT_ACCESS;
 ea.grfInheritance= CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;
 ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
 ea.Trustee.TrusteeType = TRUSTEE_IS_USER;
 ea.Trustee.ptstrName = (LPWSTR)(PSID)trusteeSID;
 ea.Trustee.MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE;

 // Create a new ACL that merges the new ACE into the existing DACL.
 dwRes = SetEntriesInAcl(1, &ea, pOldDACL, &pNewDACL);
 if (ERROR_SUCCESS != dwRes)  
 {
  Log(logDEBUG, L"SetEntriesInAcl failed on [%s] for [%s] on [%s].  GLE=%s", pAAP->objName, pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(dwRes));
  //_ASSERT(0);
  goto Cleanup; 
 }  

 // Attach the new ACL as the object's DACL.
 dwRes = SetNamedSecurityInfo(pAAP->objName.LockBuffer(), pAAP->ObjectType, DACL_SECURITY_INFORMATION,
        NULL, NULL, pNewDACL, NULL);
 if (ERROR_SUCCESS != dwRes)  
 {
  Log(logDEBUG, L"SetNamedSecurityInfo failed on [%s] for [%s] on [%s].  GLE=%s", pAAP->objName, pAAP->trustee, pAAP->targetComputer, GetSystemErrorMessage(dwRes));
  //_ASSERT(dwRes == ERROR_BAD_INHERITANCE_ACL);
  goto Cleanup; 
 }  

Cleanup:
 if(pSD != NULL) 
  LocalFree((HLOCAL) pSD); 
 if(pNewDACL != NULL) 
  LocalFree((HLOCAL) pNewDACL);
A: 

If the directory has any subdirectories, I'd check their security settings out too.

Tim Stewart
Why? AFAIK none of the security APIs actually recursively apply security settings. They setup the ACLs so that newly created objects will inherit the inheritable ACLs of their parent. But, when you click "apply these settings recursively" on the security properties dialog, its the shell dialog, not the security API, that does the recursion.
Chris Becke
Tim Stewart
A: 

a code sample would definitely help. it's easy to get the logic to build and set the ACL subtly wrong.

i don't have the code in front of me, but the basic logic is:

  1. acquire the process token with a sufficient access mask
  2. GetNamedSecurityInfo
  3. allocate a new ACL big enough for the new ACE, copy from the old to the new, and call AddAccessAllowedAceEx to add the user's SID
  4. SetNamedSecurityInfo

~jewels

Jewel S