4.1.1.3 Server Behavior of the IDL_DRSAddEntry Method

Informative summary of behavior: A disabled crossRef object cr is one with cr!Enabled = false. Enabling a disabled crossRef object cr means setting cr!nCName and cr!dnsRoot, and removing cr!Enabled.

This method enables, creates, or modifies one or more objects, as requested by the client, in a single transaction. It enables crossRef objects, creates crossRef objects and nTDSDSA objects, and modifies arbitrary objects. The client uses an ENTINF structure to specify the state of each enabled, created, or modified object:

  • Enabling a crossRef object: The dnsRoot attribute of a disabled crossRef object contains a set of one or more DNS host names, expressed as Unicode strings. The request to enable a crossRef object succeeds only if the IP address of the client that is making the request matches the IP address of one of the DNS host names in the dnsRoot attribute. When a disabled crossRef object is enabled through this method, the server is not required to be the Domain Naming Master FSMO role owner.

    The client has to specify the nCName and dnsRoot attributes. The trustParent and rootTrust attributes are optional.

  • Creating a crossRef object: If the request creates a crossRef object, it succeeds only if the server owns the forest's Domain Naming Master FSMO role. The access check is the same as when a crossRef object is created through LDAP.

    The client specifies the same attributes that are required during an LDAP Add of a crossRef object, namely the new object's DN, plus all must-have attributes of the crossRef class. See [MS-ADTS] section 6.1.1.2.1.1 for the specification of crossRef objects.

  • Creating an nTDSDSA object: Creating an nTDSDSA object is not possible with LDAP. To create an nTDSDSA object, the hasMasterNCs attribute in the request has to identify the forest's schema NC and config NC, and the DC's default NC; that is, the domain of the DC corresponding to the new nTDSDSA object. If the default NC exists on the server as the nTDSDSA object is being created by IDL_DRSAddEntry, the client has to have the control access right DS-Replication-Manage-Topology on the default NC. Otherwise, the client has to have the right to enable or create the crossRef object that corresponds to the default NC, and has to enable or create this crossRef object in the same IDL_DRSAddEntry request.

    The client specifies the new object's DN, plus the hasMasterNCs attribute. To create an nTDSDSA object for a functional DC, the request will contain invocationId, dMDLocation, options, msDS-Behavior-Version, and systemFlags. See [MS-ADTS] section 6.1.1.2.2.1.2.1.1 for the specification of nTDSDSA objects.

    If the serverReference attribute is given a value in the request, the computer object to which the serverReference attribute points is updated with a new replication SPN.

  • Modifying an object: To modify an existing object (other than enabling a crossRef object), the client-supplied ENTINF structure includes ENTINF_REMOTE_MODIFY in the ulFlags field and specifies the modified attributes and their values. The client has to have the same rights as those needed to perform the modification via LDAP. The DC enforces the same schema and other constraints on the modification as if performed via LDAP. Performing the modification by using IDL_DRSAddEntry rather than LDAP allows changes to multiple objects to be made in a single transaction.<8>

     ULONG
     IDL_DRSAddEntry(
         [in, ref]  DRS_HANDLE hDrs,
         [in] DWORD dwInVersion,
         [in, ref, switch_is(dwInVersion)]
             DRS_MSG_ADDENTRYREQ *pmsgIn,
         [out, ref] DWORD *pdwOutVersion,
         [out, ref, switch_is(*pdwOutVersion)]
             DRS_MSG_ADDENTRYREPLY *pmsgOut)
      
     ext: DRS_EXTENSIONS_INT
     pEntInfList: ADDRESS OF ENTINFLIST
     pClientCreds: ADDRESS OF DRS_SecBufferDesc
     objCls : ATTRTYP
     ncNameV: DSName
     infoList: ADDENTRY_REPLY_INFO
     cObjects: ULONG
     res: boolean
     prefixTable: PrefixTable
      
     ValidateDRSInput(hDrs, 17)
      
     /* Only attributes and classes in the base schema can be specified.*/
     prefixTable := NewPrefixTable()
      
     /* Set the default response version */
     pdwOutVersion := 2
      
     if dwInVersion = 1 then /* obsolete */
       pmsgOut^.V1.Guid := 0
       pmsgOut^.V1.Sid := 0
       pmsgOut^.V1.errCode := 0
       pmsgOut^.V1.dsid := 0
       pmsgOut^.V1.extendedErr := 0
       pmsgOut^.V1.extendedData := 0
       pmsgOut^.V1.problem := 0
     else if dwInVersion = 2 then
       pmsgOut^.V2.pErrorObject:= null
       pmsgOut^.V2.errCode := 0
       pmsgOut^.V2.dsid := 0
       pmsgOut^.V2.extendedEr := 0
       pmsgOut^.V2.extendedData := 0
       pmsgOut^.V2.problem := 0
       pmsgOut^.V2.cObjectsAdded := 0
       pmsgOut^.V2.infoList := null
     else if dwInVersion = 3 then
       pmsgOut^.V3.pdsErrObject := null
       pmsgOut^.V3.dwErrVer := 0
       pmsgOut^.V3. pErrData := null
       pmsgOut^.V3.ULONG cObjectsAdded := 0
       pmsgOut^.V3.infoList := null
     endif
      
      
     /* Validate parameters. */
     if not (dwInVersion in {2,3}) then
       SetErrorData(SV_PROBLEM_UNAVAILABLE, 0, ERROR_DS_UNAVAILABLE,
            pmsgOut, 2)
       return 0
     endif
      
     /* If the client supports the version 3 response, use version 3. */
     ext := ClientExtensions(hDrs)
     if DRS_EXT_ADDENTRYREPLY_V3 in ext.dwFlags then
       pdwOutVersion^ := 3
     else
       pdwOutVersion^ := 2
     endif
      
     cObjects := 0
      
     if dwInVersion = 2 then
       pEntInfList := pmsgIn^.V2.EntInfList
       pClientCreds := null
     else
       pEntInfList := pmsgIn^.V3.EntInfList
       pClientCreds := pmsgIn^.V3.pClientCreds
     endif
      
     /* If explicit credentials are given, use them for access checks. */
     if pClientCreds ≠ null then
       err := UseCredsForAccessCheck(pClientCreds^)
       if err ≠ 0 then
         return err
       endif
     endif
      
     /* Walk through each item in the EntInfList and perform the requested
      * operation. */
     e := pEntInfList
     while e ≠ null
       if ENTINF_REMOTE_MODIFY in e^.ulFlags then
         if DSAObj()!msDS-Behavior-Version ≥ DS_BEHAVIOR_WIN2008 then
           res := PerformModifyEntInf(
               hDrs, e^.Entinf, ADR(infoList[cObjects]))
           if not res then
             return 0
           endif
         else
           /* Not supported (Win2k3 or older DC). */
           SetErrorData(SV_PROBLEM_UNAVAILABLE,
                        0,
                        ERROR_DS_UNAVAILABLE,
                        pmsgOut,
                        pdwOutVersion^)
           return 0
         endif
       else
         objCls := ENTINF_GetValue(e^.Entinf, objectClass, prefixTable)
         if objCls = crossRef then
           /* Create or enable a crossRef object. */
           res := CreateCrossRef(hDrs, e^.Entinf, psmgOut, pdwOutVersion^,
               ADR(infoList[cObjects]))
           if not res then
             return 0
           endif
         else if objCls = nTDSDSA then
           /* Create an nTDSDSA object. */
           res :=  CreateNtdsDsa(hDrs, e^.Entinf, pEntInfList, pmsgOut,
               pdwOutVersion^, ADR(infoList[cObjects]))
           if not res then
             return 0
           endif
         else
           /* Not supported. */
           SetErrorData(SV_PROBLEM_BUSY, 0, ERROR_DS_DRA_INVALID_PARAMETER,
               pmsgOut, pdwOutVersion^)
           return 0
         endif
       endif
      
       e := e^.pNextEntInf
       cObjects := cObjects + 1
     endwhile
      
     if pdwOutVersion^ = 2 then
       pmsgOut^.V2.cObjectsAdded := cObjects
       pmsgOut^.V2.infoList := infoList
     else
       pmsgOut^.V3.cObjectsAdded := cObjects
       pmsgOut^.V3.infoList := infoList
     endif
      
     return 0