Export (0) Print
Expand All

4.1.29.3 Server Behavior of the IDL_DRSAddCloneDC Method

Informative summary of behavior: The IDL_DRSAddCloneDC method is used to create a new domain controller (DC) by duplicating the states of the original DC. The states of a DC are composed of computer, server, NTDS settings, FRS, DFSR, and connection objects that are maintained for each DC. When duplicating an object, this RPC method replaces all references to the original DC with corresponding objects of the new DC. The caller must have the control access right DS-Clone-Domain-Controller on the default NC. When called, this RPC method:

  1. Validates that the caller has permission to perform the operation.

  2. Creates new account and other objects for the new domain controller account by copying information from the existing domain controller.

  3. Returns the name, site, and password for the new domain controller to the client.

ULONG
IDL_DRSAddCloneDC(
    [in, ref] DRS_HANDLE hDrs,
    [in] DWORD dwInVersion,
    [in, ref, switch_is(dwInVersion)] 
        DRS_MSG_ADDCLONEDCREQ *pmsgIn,
    [out, ref] DWORD *pdwOutVersion,
    [out, ref, switch_is(*pdwOutVersion)] 
        DRS_MSG_ADDCLONEDCREPLY *pmsgOut)

msgIn: DRS_MSG_ADDCLONEDCREQ_V1
clientCreds: ClientAuthorizationInfo
tlInfo: TranslationInfo
callerSid: SID
isRodc: boolean

computerObj: DSName
originalDCSrvObj: DSName
originalDCSiteObj: DSName
originalDCServersObj: DSName
originalDSAObj: DSName

newDCComputerObj: DSName
newDCSiteObj: DSName
newDCServersObj: DSName
newDCServerObj: DSName
newDSAObj: DSName


ValidateDRSInput(hDrs, 28)

pdwOutVersion^ := 1
pmsgOut^.V1.pwszCloneDCName := null
pmsgOut^.V1.pwszSite := null
pmsgOut^.V1.cPasswordLength := 0
pmsgOut^.V1.pwsNewDCAccountPassword := null
if dwInVersion ≠ 1 then
  return ERROR_DS_DRA_INVALID_PARAMETER
endif
msgIn := pmsgIn^.V1

if GetKeyLength(hDrs) < 128 then
    return ERROR_DS_STRONG_AUTH_REQUIRED
endif

if not AccessCheckCAR(DefaultNC(), DS-Clone-Domain-Controller) then
  return ERROR_DS_DRA_ACCESS_DENIED
endif

/* Check that the caller (the "source" DC) is actually a DC by
 * checking Enterprise Domain Controllers or Enterprise Read-Only Domain 
 * Controllers SID in its token. */
clientCreds := GetCallerAuthorizationInfo()
if not CheckGroupMembership(clientCreds, SidFromStringSid("S-1-5-9")) then
    if not CheckGroupMembership(clientCreds, SidFromStringSid("S-1-5-498"))
      then
        return ERROR_DS_DRA_ACCESS_DENIED
    else
        isRodc := true
    endif
endif

/* The DC must own the PDC role */
if GetFSMORoleOwner(FSMO_PDC) ≠ DSAObj() then
  return ERROR_INVALID_DOMAIN_ROLE
endif

callerSid := GetPrincipalSid(clientCreds)

/* get the original DC computer object */
computerObj := select one obj from all where
             (obj!objectSid = callerSid)

tlInfo.OriginalDC.Name := computerObj!sAMAccountName.Remove('$')

/* generate cloned DC name if not specified */
if (msgIn.pwszCloneDCName = null)
    found : boolean 
    newDCName : string

    /* Generate new name by appendling '–CL' and 4 digits to the original
     * DC name */
    found := false
    For suffix = 0000 to 9999 do
       newDCName := tlInfo.OriginalDC.Name[0 .. 8] + '-CL' + suffix 

       if not exists(
           select o from all where o!sAMAccountName = (newDCName + '$')
       ) then
           found := true
           break
        endif
    endfor
    if not found then 
        return ERROR_DS_UNWILLING_TO_PERFORM
    endif
    tlInfo.newDC.Name := newDCName
else
    tlInfo.newDC.Name := msgIn.pwszCloneDCName
endIf

tlInfo.OriginalDC.Sid := computerObj!objectSid
tlInfo.OriginalDC.dnsHostName := computerObj!dNSHostName

if isRodc then
    newKrbTgtAcct : DSName
    newKrbTgtAcct := GenerateNewKrbTgtAcct()
    tlInfo.objMap[computerObj!msDS-KrbTgtLink] := newKrbTgtAcct
endif

/* Duplicate original DC computer object */
newDCComputerObj := DuplicateObject(computerObj, computerObj!parent,
                        "cn=" + tlInfo.newDC.Name, tlInfo)
tlInfo.objMap[compuerObj!distinguishedName] :=
  newDCComputerObj!distinguishedName
tlInfo.NewDC.Sid := newDCComputerObj!objectSid
tlInfo.NewDC.dnsHostName := newDCComputerObj!dNSHostName

/* Get the original DC server object */
originalDCSrvObj := select one v from ConfigNC()
  where v.dn in computerObj!serverReferenceBL
originalDCServersObj := originalDCSrvObj!parent
originalDCSiteObj := originalDCSrvObj!parent

/* use the specified site for the new DC.
 * use the original DC site if the site is not specified */
if (msgIn.pwszSite ≠ null) then
    siteContainer: DSName 
    siteContainer := DescendantObject(ConfigNC(), "CN=Sites,")
    newDCSiteObj := select one v from siteContainer!children
        where v!name = msgIn.pwszSite
    if newDCSiteObj = null
        return ERROR_NO_SUCH_SITE
    endIf
else
    newDCSiteObj := originalDCSiteObj
endIf
newDCServersObj := DescendantObject(newDCSiteObj, "CN=Servers")

/* Duplicate the original DC servers object if the servers object is not 
 * present in the new DC site */
if not exists newDCServersObj then
    newDCServersObj := DuplicateObject(originalDCServersObj, 
               newDCSiteObj, "CN=Servers", tlInfo)
endIf
tlInfo.objMap[originalDCServersObj!distinguishedName] :=
    newDCServersObj!distinguishedName

/* Duplicate the server object */
newDCServerObj := DescendantObject(newDCServersObj,
    "CN=" + tlInfo.newDC.Name)

if not exists newDCServerObj then
    newDCServerObj := DuplicateObject(originalDCSrvObj, newDCServersObj,
            "CN=" + tlInfo.newDC.Name, tlInfo)
endIf
tlInfo.objMap[originalDCSrvObj!distinguishedName] :=
    newDCServerObj!distinguishedName

/* Duplicate the NTDS settings object */
originalDSAObj := DescendantObject(originalDCSrvObj,
    "CN=NTDS Settings")
newDSAObj := DuplicateObject(originalDSAObj, newDCServerObj,
    "CN=NTDS Settings", tlInfo)
tlInfo.objMap[originalDSAObj!distinguishedName] :=
    newDSAObj!distinguishedName

if isRodc then
    newConnObj: DSName
    topologyObj: DSName
    originalDFSRObj: DSName
    newDFSRObj: DSName
    frsSysvolObj: DSName
    originalFRSObj: DSName
    newfrsObj : DSName

    foreach obj in originalDSAObj!children where
      obj!objectClass = "ntdsConnection"
        newConnObj := DuplicateObject(obj, newDSAObj,
            "CN=" + tlInfo.newDC.Name, tlInfo)
        objMap[obj!distinguishedName] := newConnObj!distinguishedName
    endfor

    /* Duplicate DFSR topology object */
    topologyObj := DescendantObject(DefaultNC(),
      "CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System")
    originalDFSRObj := DescendantObject(topologyObj,
        "CN=" + tlInfo.OriginalDC.Name)

    if originalDFSRObj ≠ null then 
        newDFSRObj = DuplicateObject(originalDFSRObj, topologyObj,
            "CN="+ tlInfo.newDC.Name, tlInfo)
    endIf

    /* Duplicate FRS object */
    frsSysvolObj = DescendantObject(DefaultNC(),
      "CN=Domain System Volume (SYSVOL     share),CN=File Replication Service,CN=System")
    originalFRSObj = DescendantObject(frsSysvolObj,
        "CN=" + tlInfo.OriginalDC.Name)
    if originalFRSObj ≠ null then
        newfrsObj = DuplicateObject(originalFRSObj, frsSysVolObj,
            "CN=" + tlInfo.newDC.Name, tlInfo)
    endIf
endif


pmsgOut^.V1.pwszCloneDCname := tlInfo.newDC.Name
pmsgOut^.V1.cPasswordLength := 120
pmsgOut^.V1.pwsNewDCAccountPassword:= a 120-byte sequence of randomly
  generated characters between ASCII 32 (space) and ASCII 122 ('z')
pmsgOut^.V1.pwszSite := newDCSiteObj!name

return 0
 
Show:
© 2014 Microsoft