Export (0) Print
Expand All
This topic has not yet been rated - Rate this topic

4.1.18.2 Server Behavior of the IDL_DRSRemoveDsServer Method

Informative summary of behavior: Removes the metadata defining a DC, which consists of the tree of objects rooted at the DC's nTDSDSA object as well as the rIDSet objects and DRS SPNs associated with the DC's computer object. This method is typically used when a DC is demoted. As part of the demotion process, the DC being demoted calls this method on another DC (either in the same domain, if such a DC exists, or in the parent domain, if there are no other DCs in the same domain but there is a parent domain) to remove the metadata of the DC being demoted from the forest. Alternatively, if a DC is removed from the domain without being properly demoted (for example, if the DC suffers a fatal hardware failure), a client may make this call to remove the metadata of the now-nonexistent DC. When pmsgIn^.V1.DomainDN is specified, this method also computes whether the DC is the last replica of its default domain NC.

The behavior of this method has two variants. If pmsgIn^.V1.fCommit is false, the method is read-only with regard to abstract state; that is, it does not make any changes to the directory contents. In this mode, the main purpose of the method is to compute pmsgOut^.V1.fLastDcInDomain (and so there is little point to calling the method in this mode without setting pmsgIn^.V1.DomainDN). For example, prior to removing the DC's metadata, a client application might try to determine whether any DCs would be left in the domain, so that it can warn the user if the user is removing the last DC in the domain.

When pmsgIn^.V1.fCommit is true, the second variant of the behavior is performed. In this mode, the method actually removes the DC metadata. The pmsgOut^.V1.fLastDcInDomain value is also computed in this mode (provided that pmsgIn^.V1.DomainDN was passed in). This method undoes the effects of the IDL_DRSAddEntry method when IDL_DRSAddEntry is used to create an nTDSDSA object. The removal of the DC's metadata signals other DCs in the forest that this particular DC no longer exists.

ULONG
IDL_DRSRemoveDsServer(
    [in, ref] DRS_HANDLE hDrs,
    [in] DWORD dwInVersion,
    [in, ref, switch_is(dwInVersion)]
        DRS_MSG_RMSVRREQ *pmsgIn,
    [out, ref] DWORD *pdwOutVersion,
    [out, ref, switch_is(*pdwOutVersion)]
        DRS_MSG_RMSVRREPLY *pmsgOut);

serverDn: unicodestring
domainDn: unicodestring
server: DSName
ntdsdsa: DSName
otherNtdsdsa: DSName
spnsToRemove: set of unicodestring
computerDn: unicodestring
computer: DSName
objectsToDelete: set of DSName
rt: ULONG
ValidateDRSInput(hDrs, 14)

serverDn := pmsgIn^.V1.ServerDN
domainDn := pmsgIn^.V1.DomainDN

pdwOutVersion^ := 1
pmsgOut^.V1.fLastDcInDomain = false

/* Basic parameter validation */
if dwInVersion ≠ 1 then
  return ERROR_INVALID_PARAMETER
endif

if serverDn = null or serverDn = "" then
  return ERROR_INVALID_PARAMETER
endif

/* Note that DomainDN may be null, but it cannot be empty. */
if domainDn = "" then
  return ERROR_INVALID_PARAMETER
endif

/* Compute fLastDcInDomain if domainDn is non-null. */
if domainDn ≠ null then
  otherNtdsdsa := select one o from subtree ConfigNC() where
    (o!objectCategory = nTDSDSA)
    and
    (domainDn in o!hasMasterNCs or domainDn in o!msDS-hasMasterNCs)
    and
    (o ≠ ntdsdsa)
  if otherNtdsdsa = null then
    pmsgOut^.V1.fLastDcInDomain = true
  else
    pmsgOut^.V1.fLastDcInDomain = false
  endif
endif

/* If nothing to commit, processing is complete. */
if not pmsgIn^.V1.fCommit then
  return 0
endif

ntdsdsa := DescendantObject([dn: serverDn], "CN=NTDS Settings,")
if ntdsdsa = null then
  return ERROR_DS_CANT_FIND_DSA_OBJ
endif

/* Perform the actual DC metadata removal. */

/* Locate the computer object for the DC's account. */
server := ntdsdsa!parent
computerDn := server!serverReference
computer := null
if computerDn ≠ null then
  computer := GetDSNameFromDN(computerDn)
endif

/* Remove the subtree of objects rooted at the DC's ntdsDsa object.*/

if not AccessCheckObject(ntdsdsa, RIGHT_DS_DELETE_TREE) then
  return ERROR_ACCESS_DENIED
endif

rt := RemoveObj(ntdsdsa,true)
if rt ≠ 0 then
  return rt
endif

/* If the DC's computer account exists, remove rIDSet objects and 
 * remove the DRS SPNs from the computer object. */

if computer ≠ null then
  foreach r in computer!rIDSetReferences
    if (not AccessCheckObject(r, RIGHT_DELETE)) and
       (not AccessCheckObject(r.parent, RIGHT_DS_DELETE_CHILD)) then
      return ERROR_ACCESS_DENIED
    endif

    RemoveObj(r, false)
  endfor
  foreach spn in computer!servicePrincipalName  
    if StartsWith(spn, "ldap/") or
       StartsWith(spn, "GC/") or
       StartsWith(spn, "E3514235-4B06-11D1-AB04-00C04FC2DCD2/") then
      spnsToRemove := spnsToRemove + {spn}
    endif
  endfor

  if not AccessCheckAttr(computer, servicePrincipalName, 
      RIGHT_DS_WRITE_PROPERTY) then
    return ERROR_ACCESS_DENIED
  endif

  computer!servicePrincipalName := 
    computer!servicePrincipalName - spnsToRemove
endif

return 0
 
Did you find this helpful?
(1500 characters remaining)
Thank you for your feedback
Show:
© 2014 Microsoft. All rights reserved.