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) and (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