I'm working on a SDDL/Security Descriptor parser for Active Directory ACLs/ACEs. I'm nearly complete, everything works fine when I connect to LDAP using an administrative account.
However, when I try to query the ntSecurityDescriptor
as a non-administrative account it returns no values. The user account itself has rights to read the attribute. When I started to investigate this I ran across the following LDAP server control:
https://msdn.microsoft.com/en-us/library/cc223323.aspx
The LDAP_SERVER_SD_FLAGS_OID control is used with an LDAP Search request to control the portion of a Windows security descriptor to retrieve. The DC returns only the specified portion of the security descriptors. It is also used with LDAP Add and Modify requests to control the portion of a Windows security descriptor to modify. The DC modifies only the specified portion of the security descriptor.
When sending this control to the DC, the controlValue field is set to the BER encoding of the following ASN.1 structure.
SDFlagsRequestValue ::= SEQUENCE { Flags INTEGER }
The Flags value has the following format presented in big-endian byte order. X denotes unused bits that SHOULD be set to 0 by the client and that MUST be ignored by the server.
Specifying Flags with no bits set, or not using the LDAP_SERVER_SD_FLAGS_OID control, is equivalent to setting Flags to (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION). Sending this control to the DC does not cause the server to include any controls in its response.
The last part of that statement from the docs does not appear to be correct, at least not when under the context of a non-administrative user.
My question: how am I supposed to send this control to LDAP using the standard PHP LDAP library functions? I know I have to set the server controls, but I'm not sure how to encode the value. I have narrowed this down to the simplest possible example:
$user = 'user@example.local';
$pass = 'secret';
$server = 'dc1.example.local';
$ldap = ldap_connect($server);
ldap_set_option($ldap, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ldap, LDAP_OPT_REFERRALS, 0);
ldap_bind($ldap, $user, $pass);
$ctrl1 = array(
"oid" => "1.2.840.113556.1.4.801",
"iscritical" => true,
// How should this value be set???
"value" => sprintf("%c%c%c%c%c", 48, 3, 2, 1, 15)
);
if (!ldap_set_option($ldap, LDAP_OPT_SERVER_CONTROLS, array($ctrl1))) {
echo "Failed to set server controls";
}
$searchUser = "user";
$dn = "dc=example,dc=local";
$filter="(sAMAccountName=$searchUser)";
$attr = array("ntsecuritydescriptor");
$sr = ldap_search($ldap, $dn, $filter, $attr);
$info = ldap_get_entries($ldap, $sr);
// Should contain ntSecurityDescriptor...but it does not.
var_dump($info);
I know the value for the control needs to be BER encoded, but I'm not sure how to achieve that for the value as it is defined in the docs. I was able to find the following Java example:
But I have been unable to translate what's going on there to PHP. Any ideas?