我正在为 Active Directory ACL/ACE 开发 SDDL/安全描述符解析器。我几乎完成了,当我使用管理帐户连接到 LDAP 时,一切正常。
但是,当我尝试查询ntSecurityDescriptor
作为非管理帐户,它不返回任何值。用户帐户本身有权读取该属性。当我开始调查这个问题时,我遇到了以下 LDAP 服务器控件:
https://msdn.microsoft.com/en-us/library/cc223323.aspx
LDAP_SERVER_SD_FLAGS_OID 控件与 LDAP 搜索一起使用
请求控制 Windows 安全描述符的一部分
取回。 DC 仅返回证券的指定部分
描述符。它还与 LDAP 添加和修改请求一起使用
控制要修改的 Windows 安全描述符的部分。直流电
仅修改安全描述符的指定部分。
当将此控制发送到 DC 时,controlValue 字段设置为
以下 ASN.1 结构的 BER 编码。
SDFlagsRequestValue ::= SEQUENCE {
Flags INTEGER
}
Flags 值具有以下格式,以大端字节表示
命令。 X 表示未使用的位,应由客户端设置为 0,并且
服务器必须忽略它。
指定未设置位或不使用 LDAP_SERVER_SD_FLAGS_OID 控件的 Flags 相当于将 Flags 设置为 (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)。将此控制发送到 DC 不会导致服务器在其响应中包含任何控制。
文档中该声明的最后部分似乎不正确,至少在非管理用户的上下文中不正确。
我的问题:我应该如何使用标准 PHP LDAP 库函数将此控件发送到 LDAP?我知道我必须设置服务器控件,但我不确定如何对值进行编码。我已将范围缩小到最简单的示例:
$user = '[email protected]';
$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);
我知道控件的值需要进行 BER 编码,但我不确定如何实现文档中定义的值。我找到了以下 Java 示例:
https://github.com/Tirasa/ADSDDL/blob/master/src/main/java/net/tirasa/adsddl/ntsd/controls/SDFlagsControl.java
但我一直无法将那里发生的事情翻译成 PHP。有任何想法吗?