title: Selecting the AD ntSecurityDescriptor Attribute as a Non-Admin
body: <p>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. </p>
  
  <p>However, when I try to query the <code>ntSecurityDescriptor</code> 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:</p>
  
  <p><a href="https://msdn.microsoft.com/en-us/library/cc223323.aspx" rel="nofollow noreferrer">https://msdn.microsoft.com/en-us/library/cc223323.aspx</a></p>
  
  <blockquote>
    <p>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.</p>
    
    <p>When sending this control to the DC, the controlValue field is set to
    the BER encoding of the following ASN.1 structure.</p>
  
  <pre><code> SDFlagsRequestValue ::= SEQUENCE {
       Flags    INTEGER
   }
  </code></pre>
    
    <p>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.</p>
    
    <p>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.</p>
  </blockquote>
  
  <p>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.</p>
  
  <p>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:</p>
  
  <pre><code>$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" =&gt; "1.2.840.113556.1.4.801",
      "iscritical" =&gt; true,
      // How should this value be set???
      "value" =&gt; 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);
  </code></pre>
  
  <p>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:</p>
  
  <p><a href="https://github.com/Tirasa/ADSDDL/blob/master/src/main/java/net/tirasa/adsddl/ntsd/controls/SDFlagsControl.java" rel="nofollow noreferrer">https://github.com/Tirasa/ADSDDL/blob/master/src/main/java/net/tirasa/adsddl/ntsd/controls/SDFlagsControl.java</a></p>
  
  <p>But I have been unable to translate what's going on there to PHP. Any ideas?</p>