4.1.27.2 Server Behavior of the IDL_DRSVerifyNames Method
Informative summary of behavior: The server resolves each of a sequence of object names and returns its DSName and the values of zero or more of its attributes. The type of the input object name is indicated by the dwFlags field in the request. The IDL_DRSVerifyNames method verifies the names of both deleted and normal objects.
-
ULONG IDL_DRSVerifyNames( [in, ref] DRS_HANDLE hDrs, [in] DWORD dwInVersion, [in, ref, switch_is(dwInVersion)] DRS_MSG_VERIFYREQ *pmsgIn, [out, ref] DWORD *pdwOutVersion, [out, ref, switch_is(*pdwOutVersion)] DRS_MSG_VERIFYREPLY *pmsgOut); msgIn: DRS_MSG_VERIFYREQ_V1 msgOut: DRS_MSG_VERIFYREPLY_V1 nc, d: DSName o: sequence of DSName i, j, k: int domainName, username: unicodestring done: boolean attribute: ATTRTYP FilterPAS: PARTIAL_ATTR_VECTOR_V1_EXT GCPas: PARTIAL_ATTR_VECTOR_V1_EXT referredDomain: unicodestring ValidateDRSInput(hDrs, 8) pdwOutVersion^ := 1 pmsgOut^.V1.error := 0 pmsgOut^.V1.cNames := 0 pmsgOut^.V1.rpEntInf := null pmsgOut^.V1.PrefixTable.PrefixCount := 0 pmsgOut^.V1.PrefixTable.pPrefixEntry := null /* Perform input validation and access check */ if dwInVersion ≠ 0x1 then return ERROR_DS_DRA_INVALID_PARAMETER endif msgIn := pmsgIn^.V1 if msgIn.dwFlags ≠ DRS_VERIFY_DSNAMES and msgIn.dwFlags ≠ DRS_VERIFY_SAM_ACCOUNT_NAMES and msgIn.dwFlags ≠ DRS_VERIFY_SIDS and msgIn.dwFlags ≠ DRS_VERIFY_FPOS then return ERROR_DS_DRA_INVALID_PARAMETER endif if msgIn.cNames > 0 and msgIn.rpNames = null then return ERROR_DS_DRA_INVALID_PARAMETER endif if (msgIn.dwFlags = DRS_VERIFY_SIDS or msgIn.dwFlags = DRS_VERIFY_SAM_ACCOUNT_NAMES or msgIn.dwFlags = DRS_VERIFY_FPOS) and not IsGC() then return ERROR_DS_GC_REQUIRED endif if msgIn.dwFlags = DRS_VERIFY_DSNAMES and not IsGC() then for i := 0 to msgIn.cNames-1 if DefaultNC() ≠ GetObjectNC(msgIn.rpNames[i]^) then return ERROR_DS_GC_REQUIRED endif endfor endif /* Compute output */ msgOut.PrefixTable := dc.prefixTable for i := 0 to msgIn.cNames - 1 d := msgIn.rpNames[i] o := null done := false if msgIn.dwFlags = DRS_VERIFY_SAM_ACCOUNT_NAMES then domainName := DomainNameFromNT4AccountName(d.dn) username := UserNameFromNT4AccountName(d.dn) if domainName ≠ null and username ≠ null and IsDomainNameInTrustedForest(domainName, referredDomain) then /* Provide a hint as to which forest this name could be coming * from. Note that 0xFFFF0009 is a hardcoded attribute ID * recognized by clients of this method. This attribute ID does * not correspond to any attribute defined in the schema. */ msgOut.rpEntInf[i].pName := null msgOut.rpEntInf[i].AttrBlock.AttrCount := 1 msgOut.rpEntInt[i].AttrBlock.pAttr[0].AttrTyp := 0xFFFF0009 msgOut.rpEntInf[i].AttrBlock.pAttr[0].AttrVal.valCount := 1 msgOut.rpEntInf[i].AttrBlock.pAttr[0].AttrVal.pAVal[0].valLen := Length in characters of domainName, excluding any terminating null msgOut.rpEntInf[i].AttrBlock.pAttr[0].AttrVal.pAVal[0].pAVal := referredDomain done := true endif endif if not done /* locate object or objects in question */ if msgIn.dwFlags = DRS_VERIFY_DSNAMES then if ObjExists(d) then o := {d} endif else if msgIn.dwFlags = DRS_VERIFY_SIDS then o := select all v from all-ts-included where v!objectSid = d.sid and foreignSecurityPrincipal not in v!objectClass else if msgIn.dwFlags = DRS_VERIFY_SAM_ACCOUNT_NAMES then if domainName ≠ null and username ≠ null then nc := select one v from all where v!nETBIOSName = domainName and GetObjectNC(v)= v /* The following query returns both normal objects and tombstones */ o := select all v from subtree-ts-included nc where v!sAMAccountName = username else o := select all v from all-ts-included where v!userPrincipalName = d.dn endif else if msgIn.dwFlags = DRS_VERIFY_FPOS then o := select all v from all-ts-included where v!objectSid = d.sid and foreignSecurityPrincipal in v!objectClass endif /* Compute returned info and get requested attributes */ if o.length = 1 and AccessCheckCAR(GetObjectNC(o[0]), DS-Replication-Get-Changes) then msgOut.rpEntInf[i].pName = o[0]!distinguishedName if MasterReplicaExists(GetObjectNC(o[0])) then msgOut.rpEntInf[i].ulFlags := ENTINF_FROM_MASTER else msgOut.rpEntEnf[i].ulFlags := 0 endif msgOut.rpEntInf[i].AttrBlock.AttrCount := msgIn.RequiredAttrs.AttrCount FilterPas := FilteredPAS() GCPas := GCPAS() for j := 0 to msgIn.RequiredAttrs.AttrCount - 1 if AmILHServer() then if (not (msgIn.RequiredAttrs.pAttr[j].AttrType in FilterPas && msgIn.RequiredAttrs.pAttr[j].AttrType in GCPas)) then /* skip requested attributes not part of both FilterPAS and GCPas */ msgOut.rpEntInf[i] := null continue; endif else /* pre-LH server */ if (not (msgIn.RequiredAttrs.pAttr[j].AttrType in GCPas)) then /* skip requested attributes not part of GCPas */ msgOut.rpEntInf[i] := null continue; endif endif attribute := LocalAttidFromRemoteAttid( msgIn.PrefixTable, msgIn.RequiredAttrs.pAttr[j].attrTyp) msgOut.rpEntInf[i].AttrBlock.pAttr[j].attrTyp := attribute k := 0 foreach val in GetAttrVals(o, attribute, false) msgOut.rpEntInf[i].AttrBlock.pAttr[j].AttrVal.pAVal := ADR(ATTRVALFromValue(val, Syntax(attribute), dc.prefixTable)) msgOut.rpEntInf[i].AttrBlock.pAttr[j].AttrVal.valCount := k + 1 endfor endfor else msgOut.rpEntInf[i] := null endif endif endfor /* i := */ pmsgOut^.V1 := msgOut return 0