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 has to have the control access right DS-Clone-Domain-Controller on the default NC. When called, this RPC method:
Validates that the caller has permission to perform the operation.
Creates new account and other objects for the new domain controller account by copying information from the existing domain controller.
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