Export (0) Print
Expand All

4.1.8.3 Server Behavior of the IDL_DRSGetMemberships Method

Informative summary of behavior: The IDL_DRSGetMemberships method constructs a directed graph G(V,A). The vertex set of the graph includes all the objects in the scope of the forest if the server is a GC, or in the scope of the default domain NC otherwise. The arc set of the graph includes all the tuples [initial: u,final: v] if u is a member of v and both u and v are in the scope. This graph represents the membership relation in the given scope.

For a GroupMembersTransitive request, a reversed graph of G is used because member relation is queried rather than membership. The reversed graph has the same vertex set as G, but the arcs in the arc set are in the opposite direction as those in A.

For other types of requests, a subgraph of G is used. The vertex set of this subgraph consists of only the DSName values of interest for that particular request type, and the arc set is reduced to the arcs that link two vertices in the vertex set of the subgraph.

Starting from the graph, this method computes a set of objects for each DSName in the input parameters. The set could be either transitive closure of the object or the immediate neighbors of the object in the graph, depending on the type of request. The union of these sets is returned as the result.

ULONG
IDL_DRSGetMemberships(
    [in, ref] DRS_HANDLE hDrs,
    [in] DWORD dwInVersion,
    [in, ref, switch_is(dwInVersion)] DRS_MSG_REVMEMB_REQ *pmsgIn,
    [out, ref] DWORD *pdwOutVersion,
    [out, ref, switch_is(*pdwOutVersion)]
        DRS_MSG_REVMEMB_REPLY *pmsgOut)

msgIn: DRS_MSG_REVMEMB_REQ_V1
vSet, wSet, uSet: set of DSName
aSet, aSetR: ArcSet
u,v,w: DSName
op, i: integer
transitive: boolean
t: SID

ValidateDRSInput(hDrs, 9)

pdwOutVersion^ := 1
pmsgOut^.V1.errCode := 0
pmsgOut^.V1.cDsNames := 0
pmsgOut^.V1.cSidHistory := 0
pmsgOut^.V1.ppDsNames := null
pmsgOut^.V1.pAttributes := null
pmsgOut^.V1.ppSidHistory := null

msgIn := pmsgIn^.V1

if dwInVersion ≠ 1 then
  return ERROR_DS_DRA_INVALID_PARAMETER
endif
if not AccessCheckCAR(DefaultNC(), DS-Replication-Get-Changes) then
  return ERROR_DS_DRA_ACCESS_DENIED
endif

op := msgIn.OperationType
if (op = RevMembGetUniversalGroups) and not IsGC() then
  return ERROR_DS_GC_REQUIRED
endif

/* Construct a membership graph. */
/* Vertices */
if IsGC() then
  vSet := select all v from all where true
else
  vSet := select all v from subtree DefaultNC() where true
Endif

/* Edges */
aSet := {}
aSetR := {}
foreach v in vSet
  foreach u in vSet
    if (u in v!memberOf) 
        or (u = GetDSNameFromPrimaryGroupId(v!primaryGroupId)) then
      aSet  := aSet  + {[initial: v, final: u]}
      aSetR := aSetR + {[initial: u, final: v]}
    endif
  endfor
endfor

/* Calculate GroupMembersTransitive. */
if op = GroupMembersTransitive then
  wSet := {}
  for i := 0 to msgIn.ppDsNames.cDsNames - 1
    u := msgIn.ppDsNames[i]
    if u in vSet then
      wSet := wSet + (Closure(uSet, aSetR, u) - {u})
    endif
  endfor

  foreach w in wSet
    pmsgOut^.V1.ppDsNames[pmsgOut^.V1.cDsNames] := w
    pmsgOut^.V1.cDsNames:= pmsgOut^.V1.cDsNames + 1
  endfor

  return 0
endif

/* Calculate all other cases (where op ≠ GroupMembersInTransitive).*/
transitive := op in {RevMembGetAccountGroups, 
                     RevMembGetResourceGroups, 
                     RevMembGetUniversalGroups}

/* Get the initial result set from the graph. */
wSet := {}
for i := 0 to msgIn.ppDsNames.cDsNames - 1
  u := msgIn.ppDsNames[i]
  if u in vSet then
    /* Get the subgraph by applying the predicate IsMatchedGroup
     * on each element in the vertex set, plus u itself. */
    uSet := {u} + select all v from vSet where 
         IsMatchedGroup(v, op, msgIn.pLimitingDomain^)
    if transitive then
      wSet := wSet + (Closure(uSet, aSet, u) - {u})
    else
      wSet := wSet + (Neighbors(uSet, aSet, u) - {u})
    endif
    if((u!userAccountControl & ADS_UF_WORKSTATION_TRUST_ACCOUNT =
           ADS_UF_WORKSTATION_TRUST_ACCOUNT) or
        (u!userAccountControl & ADS_UF_PARTIAL_SECRETS_ACCOUNT =
           ADS_UF_PARTIAL_SECRETS_ACCOUNT))

        wSet := wSet + GetDSNameOfEnterpriseRODCsGroup()
    endif
  endif
endfor

/* Construct the result message. */
pmsgOut^.V1.cSidHistory := 0
pmsgOut^.V1.cDsNames := 0

foreach w in wSet
  foreach t in w!sIDHistory
    if not (t in pmsgOut^.V1.ppSidHistory) then
      pmsgOut^.V1.ppSidHistory[pmsgOut^.V1.cSidHistory] := t
      pmsgOut^.V1.cSidHistory := pmsgOut^.V1.cSidHistory + 1
    endif
  endfor
  
  pmsgOut^.V1.ppDsNames[pmsgOut^.V1.cDsNames] := w

  if (DRS_REVMEMB_FLAG_GET_ATTRIBUTES in msgIn.dwFlags) then
    pmsgOut^.V1.pAttributes[pmsgOut^.V1.cDsNames] := 
        {SE_GROUP_MANDATORY,SE_GROUP_ENABLED_BY_DEFAULT,
         SE_GROUP_ENABLED}
  else 
    pmsgOut^.V1.pAttributes[pmsgOut^.V1.cDsNames] := 0
  endif
  pmsgOut^.V1.cDsNames := pmsgOut^.V1.cDsNames + 1
endfor

return 0
 
Show:
© 2015 Microsoft