4.1.10.5.12 ProcessFsmoRoleRequest

 procedure ProcessFsmoRoleRequest(
   hDrs: DRS_HANDLE,
   msgIn: DRS_MSG_GETCHGREQ_V10,
   var msgOut: DRS_MSG_GETCHGREPLY_NATIVE) 

Informative summary of behavior: The ProcessFsmoRoleRequest procedure performs the requested FSMO role operation indicated by msgIn.ulExtendedOp.

  
 fsmoObj: DSName
 clientDsaObj: DSName
 serverObj: DSName: DSName
 rodcObj: DSNAME: DSName
 clientComputerObj: DSName
 clientRidSetObj: DSName
 ownerDsaObj: DSName
 scope: set of DSName
 ridAllocLoHi: ULONGLONG
 ridAllocHi: DWORD
 ridReqHi: DWORD
 ridAvailLoHi: ULONGLONG
 ridAvailLo: DWORD
 ridAvailHi: DWORD
 changedObjs: set of ObjAtts
 changedLinks: set of ObjAttVal
  
 /* Specific error check when at DC functional level Win2K3 */
 if (DSAObj()!msDS-Behavior-Version = DS_BEHAVIOR_WIN2003) and
    (not DRS_WRIT_REP in msgIn.ulFlags) then
   msgOut.ulExtendedRet := EXOP_ERR_PARAM_ERR
   return
 endif
  
 fsmoObj := msgIn.pNC^
 if not ObjExists(fsmoObj) then
   msgOut.ulExtendedRet := EXOP_ERR_UPDATE_ERR
   return
 endif
 if msgIn.uuidDsaObjDest = null then
     msgOut.ulExtendedRet := EXOP_ERR_UPDATE_ERR
   return
 endif
 clientDsaObj := select one o from ConfigNC()where
     o!objectGUID = msgIn.uuidDsaObjDest
 if clientDsaObj = null then
   msgOut.ulExtendedRet := EXOP_ERR_UNKNOWN_CALLER
   return
 endif
  
 scope := {}if msgIn.ulExtendedOp in {EXOP_FSMO_REQ_ROLE, EXOP_FSMO_REQ_PDC,
     EXOP_FSMO_RID_REQ_ROLE} then
   /* Change the FSMO role owner from the server to the client. */
   if fsmoObj!fSMORoleOwner ≠ DSAObj() then
     msgOut.ulExtendedRet := EXOP_ERR_FSMO_NOT_OWNER
     return
   endif
  
   fsmoObj!fSMORoleOwner := clientDsaObj
   scope := GetRoleScope(fsmoObj)
 else if msgIn.ulExtendedOp = EXOP_FSMO_ABANDON_ROLE then
   /* Request a change in the FSMO role owner from the current owner
    * to the server. The server will refuse to take the FSMO role if
    * it is not a full replica and cannot own FSMO. */
      if AmIRODC() then
         msgOut.ulExtendedRet := EXOP_ERR_FSMO_REFUSING_ROLES
      endif
  
   if fsmoObj!fSMORoleOwner ≠ DSAObj() then
     ownerDsaObj := fsmoObj!fSMORoleOwner
     if not ObjExists(ownerDsaObj) then
       msgOut.ulExtendedRet := EXOP_ERR_UNKNOWN_CALLER
       return
     else if ownerDsaObj!isDeleted = true
       msgOut.ulExtendedRet := EXOP_ERR_FSMO_OWNER_DELETED
       return
     endif
  
     Call IDL_DRSGetNCChanges as a client to the server identified by
         ownerDsaObj to perform a EXOP_FSMO_REQ_ROLE extended
         operation; see the client request generation and response
         processing sections
  
     if fsmoObj!fSMORoleOwner ≠ DSAObj() then
       /* Transfer failed. */
       msgOut.ulExtendedRet := EXOP_ERR_COULDNT_CONTACT
       return
     endif
   endif
 else if msgIn.ulExtendedOp = EXOP_FSMO_REQ_RID_ALLOC then
   /* Allocate a block of RIDs for the client DC. */
   if fsmoObj ≠ DefaultNC()!rIDManagerReference then
     msgOut.ulExtendedRet := EXOP_ERR_MISMATCH
     return
   else if fsmoObj!fSMORoleOwner ≠ DSAObj() then
     msgOut.ulExtendedRet := EXOP_ERR_FSMO_NOT_OWNER
     return
   endif
  
   /* Locate or create the RID Set object for the client DC. */
   serverObj := clientDsaObj!parent
   clientComputerObj := serverObj!serverReference
   if clientComputerObj!rIDSetReferences = null then
     clientRidSetObj := An implementation-defined DSName in the
         default NC such that not ObjExists(clientRidSetObj)
     Create object with DSName clientRidSetObj such that
         rIDSet in clientRidSetObj!objectClass
     /* Windows Behavior: Windows sets clientRidSetObj to be a child
      * of clientComputerObj. */
     clientComputerObj!rIDSetReferences := clientRidSetObj
   else
     clientRidSetObj := clientComputerObj!rIDSetReferences
   endif
   /* Get the current RID allocation for the client DC. */
   ridAllocLoHi := clientRidSetObj!rIDAllocationPool
   ridAvailHi := most significant 32 bits of ridAvailLoHi
   ridReqHi := most significant 32 bits of msgIn.liFsmoInfo
   if ridAllocLoHi = 0 or ridAvailHi = 0 or ridReqHi ≥ ridAvailHi then
     /* The client DC has indeed exhausted its current allocation,
      * according to our records. */
  
     /* Get the range of RIDs that have not yet been allocated to any
      * DC. */
     ridAvailLoHi := fsmoObj!rIDAvailablePool
     ridAvailLo := least significant 32 bits of ridAvailLoHi
     ridAvailHi := most significant 32 bits of ridAvailLoHi
  
     /* Select a subset of the unallocated RIDs and allocate them to
      * the client. */
     Assign a value to ridAllocHi according to any implementation-
        defined policy such that ridAvailLo < ridAllocHi < ridAvailHi.
     /* Windows Behavior: By default, Windows sets ridAllocHi to
      * ridAvailLo + 500. */
     ridAllocLoHi := ridAvailLo as least significant 32 bits and
         ridAllocHi as most significant 32 bits
     ridAvailLo := ridAllocHi + 1
     ridAvailLoHi := ridAvailLo as least significant 32 bits and
         ridAvailHi as most significant 32 bits
     fsmoObj!rIDAvailablePool := ridAvailLoHi
     clientRidSetObj!rIDAllocationPool := ridAllocLoHi
     clientRidSetObj!rIDPreviousAllocationPool := 0
     clientRidSetObj!rIDNextRID := 0
     /* Windows Behavior: rIDUsedPool [MS-ADA3] is not used anywhere,
      * but Windows always sets it to zero. */
     clientRidSetObj!rIDUsedPool := 0
  
     msgOut.liFsmoInfo := ridAllocLoHi
   endif
  
   scope := GetRoleScope(fsmoObj) + 
            {clientComputerObj, clientRidSetObj}
 else if EXOP_REPL_SECRETS in msgIn.ulExtendedOp and
         AmILHServer() then
   /* Request replication of a single object with secret. 
    * Secret replication is allowed only if these three conditions
    * hold:
    *   1. Caller is an RODC. An RODC will always be a member of 
    *      "Enterprise Read-Only Domain Controllers" (RID 498) 
    *      [MS-ADTS] section 6.1.1.6.14.
    *   2. The object is configured to reveal secrets.
    *   3. Outbound secret replication is not disabled.
    */
     serverObj := clientDsaObj!parent
   rodcObj := serverObj!serverReference
   if CheckGroupMembership(
           GetCallerAuthorizationInfo(), SidFromStringSid("S-1-5-22"))
       and RevealSecretsForUserAllowed(rodcObj, fsmoObj)
       and (not NTDSDSA_OPT_DISABLE_OUTBOUND_REPL
                 in DSAObj()!options
            or DRS_SYNC_FORCED in msgIn.ulFlags) then 
     scope := {fsmoObj}
   else
     scope := {}
   endif
 else if EXOP_REPL_OBJ in msgIn.ulExtendedOp
   if AmILHServer() = true and 
       NTDSDSA_OPT_DISABLE_OUTBOUND_REPL in DSAObj()!options and
       not DRS_SYNC_FORCED in msgIn.ulFlags then
     /* replication of single object is disabled */
     pmsgOut.dwDRSError := ERROR_DS_DRA_SOURCE_DISABLED
     return 
   endif
  
   /* Operation is invalid if destination is full replica but this server
    * is not, or if both are partial replicas but this server does not have
    * all the attributes needed by the destination in its PAS. */
   if(not FullReplicaExists(GetObjectNC(msgIn.pNC^)) and 
      not msgIn.pPartialAttrSet = null)
      msgOut.ulExtendedRet := EXOP_ERR_PARAM_ERR
      return
   else if not GetFilteredAttributeSet() ∩ msgIn.pPartialAttrSet = {} then
      msgOut.ulExtendedRet := EXOP_ERR_PARAM_ERR
      return
   endif 
  
   scope := {fsmoObj}
 else
   /* Unrecognized request. */
   msgOut.ulExtendedRet := EXOP_ERR_UNKNOWN_OP
   return
 endif
  
 if scope ≠ {} then
   /* Add updates in scope to the response. */
   GetChangesInScope(scope, msgIn.pUpToDateVecDest, msgIn.ulExtendedOp,
       msgIn.pPartialAttrSet, msgIn.pPartialAttrSet, 
       0, changedObjs, changedLinks)
   foreach o in changedObjs
     AddObjToResponse(
         hDrs, o, GetObjectNC(msgIn.pNC^), msgIn.ulFlags, msgIn.ulExtendedOp, msgOut)
   endfor
   foreach v in changedLinks
     AddLinkToResponse(v, msgIn, msgOut)
   endfor
 endif
  
 msgOut.ulExtendedRet := EXOP_ERR_SUCCESS
 return