4.1.5.2 Server Behavior of the IDL_DRSDomainControllerInfo Method

Informative summary of behavior: The IDL_DRSDomainControllerInfo method supports four information levels. For levels 1, 2, and 3, the server returns information for the DCs in the domain of the server. For level 0xffffffff, the server returns information about the LDAP connections on the server that are currently open.

Regular read access checks apply to the information that is returned to the caller. Therefore, if the caller does not have read permission on data that needs to be returned, this data is not included in the response. See [MS-ADTS] section 3.1.1.4.3 for more information about access check behavior in read operations.

For information about the Windows versions in which information levels were introduced and supported, see the following behavior note.<14>

Note The server behavior of the IDL_DRSDomainControllerInfo method uses the CrackNames procedure defined in section 4.1.4.2.9.

 ULONG
 IDL_DRSDomainControllerInfo(
   [in, ref] DRS_HANDLE hDrs,
   [in] DWORD dwInVersion,
   [in, ref, switch_is(dwInVersion)] DRS_MSG_DCINFOREQ *pmsgIn,
   [out, ref] DWORD *pdwOutVersion,
   [out, ref, switch_is(*pdwOutVersion)] DRS_MSG_DCINFOREPLY *pmsgOut)
  
 msgIn: DRS_MSG_DCINFOREQ_V1
 infoLevel, i: integer
 domainName: unicodestring
 dcSet: set of DSName
 serversContainer, crObj, dcObj, dsaObj, svrObj, siteObj, obj, v: DSName
 lc: DS_DOMAIN_CONTROLLER_INFO_FFFFFFFFW
 rI1: ADDRESS OF DS_DOMAIN_CONTROLLER_INFO_1W
 rI2: ADDRESS OF DS_DOMAIN_CONTROLLER_INFO_2W
 rI3: ADDRESS OF DS_DOMAIN_CONTROLLER_INFO_3W
 found: boolean
 crackMsgIn: DRS_MSG_CRACKREQ_V1
 crackOut: DS_NAME_RESULTW
 outV: DWORD
 userAccountControl: set of integer
  
 ValidateDRSInput(hDrs, 16)
  
 msgIn := pmsgIn^.V1
 infoLevel := msgIn.InfoLevel
 domainName := msgIn.Domain
  
 pdwOutVersion^ := infoLevel
  
 if infoLevel = 1 then
   pmsgOut^.V1.cItems := 0
   pmsgOut^.V1.rItems := null
 else if infoLevel = 2 then
   pmsgOut^.V2.cItems := 0
   pmsgOut^.V2.rItems := null
 else if infoLevel = 3 then
   pmsgOut^.V3.cItems := 0
   pmsgOut^.V3.rItems := null
 else if infoLevel = 0xFFFFFFFF then
   pmsgOut^.VFFFFFFFF.cItems := 0
   pmsgOut^.VFFFFFFFF.rItems := null
 endif
  
 if dwInVersion ≠ 1 then
   return ERROR_INVALID_PARAMETER
 endif
  
 if not (infoLevel in {1,2,3,0xFFFFFFFF}) then
   return ERROR_INVALID_PARAMETER
 endif
  
  
 if infoLevel = 0xFFFFFFFF then
   /* Enumerate the LDAP connections. */
   if not IsMemberOfBuiltinAdminGroup() then
     return ERROR_ACCESS_DENIED
   endif
  
   pmsgOut^.VFFFFFFFF.cItems := number(dc.ldapConnections)
  
   i := 0
   foreach lc in dc.ldapConnections
     pmsgOut^.VFFFFFFFF.rItems[i].IPAddress := lc.iPAddress
     pmsgOut^.VFFFFFFFF.rItems[i].NotificationCount := 
         lc.notificationCount
     pmsgOut^.VFFFFFFFF.rItems[i].secTimeConnected := 
         lc.secTimeConnected
     pmsgOut^.VFFFFFFFF.rItems[i].Flags := lc.flags
     pmsgOut^.VFFFFFFFF.rItems[i].TotalRequests := lc.totalRequests
     pmsgOut^.VFFFFFFFF.rItems[i].UserName := lc.userName
     pmsgOut^.VFFFFFFFF.rItems[i].Reserved1 := 0
  
     i := i + 1
   endfor
  
   return 0
 endif
  
 /* Verify that the given domain name matches the default domain NC.
  * First check if it is the nETBiosName or dNSHostName of the default
  * domain NC by searching for the crossRef object. If this doesn't 
  * find a match, call IDL_DRSCrackNames to check if the given 
  * domain name is a name for the default domain NC. */
  
 crObj := select one v from children
     DescendantObject(ConfigNC(), "CN=Partitions,")
     where
       (v!dnsRoot = domainName or v!nETBiosName = domainName)
       and 
       v!nCName = DefaultNC()
  
 found := (crObj ≠ null)
  
 if not found then
   /* Not found; use IDL_DRSCrackNames to resolve the name. */
   crackMsgIn.dwFlags := 0
   crackMsgIn.formatOffered := DS_UNKNOWN_NAME
   crackMsgIn.formatDesired := DS_FQDN_1779_NAME
   crackMsgIn.cNames := 3
   crackMsgIn.rpNames[0] := domainName
   crackMsgIn.rpNames[1] := domainName + "\"
   crackMsgIn.rpNames[2] := domainName + "/"
  
   /* Call IDL_DRSCrackNames as a local procedure. */
   CrackNames(crackMsgIn, ADR(crackOut))
   
   i := 0
   while i < 3 and not found
     if crackOut.rItems[i].status = DS_NAME_NO_ERROR 
         then 
       if crackOut.rItems[i].pName = DefaultNC().dn 
           then
         found := true
       else 
         return ERROR_INVALID_PARAMETER
       endif
     endif
     i := i + 1
   endwhile
 endif
  
 if not found then 
   return ERROR_DS_OBJ_NOT_FOUND
 endif
  
 /* Enumerate the DCs in the domain. */
 if infoLevel = 3 then
   /* client requests to return RODCs too */
   userAccountControl :=
       {ADS_UF_SERVER_TRUST_ACCOUNT, ADS_UF_PARTIAL_SECRETS_ACCOUNT}
 else
   userAccountControl := {ADS_UF_SERVER_TRUST_ACCOUNT}
 endif
  
 dcSet := select all v from subtree DefaultNC() where 
      v!objectCategory = GetDefaultObjectCategory(computer) 
        and (userAccountControl ∩ v!userAccountControl ≠ null)
  
 if infoLevel = 1 then
   pmsgOut^.V1.cItems := number(dcSet)
  
   i := 0
   foreach dcObj in dcSet
     rI1 := ADR(pmsgOut^.V1.rItems[i])
  
     rI1^.DnsHostName := dcObj!dNSHostName
     rI1^.ComputerObjectName := dcObj.dn
     /* sAMAccountName excluding the "$" at the end. */
     rI1^.NetbiosName := SubString(dcObj!sAMAccountName, 0,
         dcObj!samAccountName.length-1) 
     rI1^.fDsEnabled := true
  
     /* select a server object from the serverReferenceBL, it is 
        preferred that the server object has a child object with
        CN "NTDS Settings" */    
     svrObj := 
         select one v from all where v.dn in dcObj!serverReferenceBL 
               and DescendantObject(v, "CN=NTDS Settings") ≠ null
     if svrObj = null then
         svrObj := 
             select one v from all where v.dn in dcObj!serverReferenceBL
     endif
     if svrObj ≠ null then
       rI1^.ServerObjectName := svrObj.dn
       serversContainer :=
           select one o from all where o!objectGUID = svrObj!parent
       siteObj := serversContainer!parent
       rI1^.SiteObjectName := siteObj.dn
       dsaObj := DescendantObject(v, "CN=NTDS Settings,")
       rI1^.fIsPdc := (dsaObj = GetFSMORoleOwner(FSMO_PDC))
     endif
     i := i + 1
   endfor 
 else
   if infoLevel = 2 then
     pmsgOut^.V2.cItems := number(dcSet)
  
     i := 0
     foreach dcObj in dcSet
       rI2 := ADR(pmsgOut^.V2.rItems[i])
  
       rI2^.DnsHostName := dcObj!dNSHostName
       rI2^.ComputerObjectName := dcObj.dn
       /* sAMAccountName excluding the "$" at the end. */
       rI2^.NetbiosName := SubString(dcObj!samAccountName, 0,
         dcObj!samAccountName.length-1) 
       rI2^.ComputerObjectGUID := dcObj.guid
       rI2^.fDsEnabled := true
  
       /* select a server object from the serverReferenceBL, it is 
          preferred that the server object has a child object with
          CN "NTDS Settings" */    
       svrObj := 
           select one v from all where v.dn in dcObj!serverReferenceBL 
                 and DescendantObject(v, "CN=NTDS Settings") ≠ null
       if svrObj = null then
           svrObj := 
               select one v from all where v.dn in dcObj!serverReferenceBL
       endif
       if svrObj ≠ null then
         rI2^.ServerObjectName := svrObj.dn
         rI2^.ServerObjectGuid := svrObj.guid
  
       serversContainer :=
           select one o from all where o!objectGUID = svrObj!parent
       siteObj := serversContainer!parent
  
         rI2^.SiteObjectName := siteObj.dn
         rI2^.SiteObjectGUID := siteObj.guid
         dsaObj := DescendantObject(v, "CN=NTDS Settings,")
         rI2^.NtdsDsaObjectGUID := dsaObj.guid
         rI2^.fIsGc := (NTDSDSA_OPT_IS_GC in dsaObj!options)
         rI2^.fIsPdc := (dsaObj = GetFSMORoleOwner(FSMO_PDC))
       endif
       i := i + 1
     endfor
  
 else
   /* infoLevel = 3 */
     pmsgOut^.V3.cItems := number(dcSet)
  
     i := 0
     foreach dcObj in dcSet
       rI3 := ADR(pmsgOut^.V3.rItems[i])
  
       rI3^.DnsHostName := dcObj!dNSHostName
       rI3^.ComputerObjectName := dcObj.dn
       /* sAMAccountName excluding the "$" at the end. */
       rI3^.NetbiosName := SubString(dcObj!samAccountName, 0,
           dcObj!samAccountName.length-1) 
       rI3^.ComputerObjectGUID := dcObj.guid
       rI3^.fDsEnabled := true
  
       /* select a server object from the serverReferenceBL, it is 
          preferred that the server object has a child object with
          CN "NTDS Settings" */    
       svrObj := 
           select one v from all where v.dn in dcObj!serverReferenceBL 
                 and DescendantObject(v, "CN=NTDS Settings") ≠ null
       if svrObj = null then
           svrObj := 
               select one v from all where v.dn in dcObj!serverReferenceBL
       endif
       if svrObj ≠ null then
         rI3^.ServerObjectName := svrObj.dn
         rI3^.ServerObjectGuid := svrObj.guid
  
       serversContainer :=
           select one o from all where o!objectGUID = svrObj!parent
       siteObj := serversContainer!parent
  
         rI3^.SiteObjectName := siteObj.dn
         rI3^.SiteObjectGUID := siteObj.guid
         dsaObj := DescendantObject(v, "CN=NTDS Settings,")
         rI3^.NtdsDsaObjectGUID := dsaObj.guid
         rI3^.fIsGC := (NTDSDSA_OPT_IS_GC in dsaObj!options)
         rI3^.fIsPDC := (dsaObj = GetFSMORoleOwner(FSMO_PDC))
         rI3^.fIsRodc := ((ADS_UF_PARTIAL_SECRETS_ACCOUNT ∩
             dcObj!userAccountControl) ≠ null)
       endif
       i := i + 1
     endfor
   endif
 endif
  
 return 0