Export (0) Print
Expand All

4.1.11.3 Server Behavior of the IDL_DRSGetNT4ChangeLog Method

Informative summary of behavior: If the server is the PDC emulator FSMO role owner, it returns either a sequence of PDC change log entries or the NT4 replication state, or both, as requested by the client.

Multiple calls of this method may be required to retrieve the entire PDC change log. The client passes pRestart = null on the first call in a series of calls; the server returns a sequence of change log entries, including the first, a pointer to an opaque cookie, and a result code. If the server returns no change log entries, it returns null instead of a pointer to a cookie. If the server returns the result code zero, the sequence of change log entries in the response includes the final entry in the log.

The cookie encodes the serial number of the last change log entry returned. If the server returns ERROR_MORE_DATA, the final change log entry in the response was not the final entry in the change log. The client can make another call, with pRestart pointing to the cookie. The server processes this call identically to a call with pRestart = null, except that it returns change log entries starting with the entry following the last previously returned entry, as indicated by the cookie. By making enough calls the client can retrieve the entire change log.

If the client includes a cookie that is either corrupted or identifies a nonexistent change log entry (possibly because the cookie is too old), the server returns ERROR_INVALID_PARAMETER. If there are change log entries to return, but the client specifies a bound on the size of the returned change log entries that is too small to hold even a single entry, the server returns ERROR_INSUFFICIENT_BUFFER.

The NT4 replication state is a small, fixed-size structure and the server simply copies it into the response.

When the client requests both the PDC change log and the NT4 replication state, the server processes the PDC change log request first. If an error occurs during this processing the server does not process the request for NT4 replication state. If an error occurs while processing the NT4 replication state request, the server returns no indication to the client that the PDC change log request succeeded.

ULONG
IDL_DRSGetNT4ChangeLog(
    [in, ref] DRS_HANDLE hDrs,
    [in] DWORD dwInVersion,
    [in, ref, switch_is(dwInVersion)] DRS_MSG_NT4_CHGLOG_REQ *pmsgIn,
    [out, ref] DWORD *pdwOutVersion,
    [out, ref, switch_is(*pdwOutVersion)]
        DRS_MSG_NT4_CHGLOG_REPLY *pmsgOut)

msgIn: DRS_MSG_NT4_CHGLOG_REQ_V1
readStatus, ntStatus: DWORD
sequenceNumber: integer
nextIndexToBeReturned, lastIndexToBeReturned: integer
lastReturnedSerialNumber: LONGLONG
lastReturnedIndex: integer
pChangeLog: ADDRESS OF CHANGE_LOG_ENTRIES

ValidateDRSInput(hDrs, 11)

pdwOutVersion^ := 1
pmsgOut^.V1.cbRestart := 0
pmsgOut^.V1.cbLog := 0
pmsgOut^.V1.ReplicationState.SamSerialNumber := 0
pmsgOut^.V1.ReplicationState.SamCreationTime := 0
pmsgOut^.V1.ReplicationState.BuiltinSerialNumber := 0
pmsgOut^.V1.ReplicationState.BuiltinCreationTime := 0
pmsgOut^.V1.ReplicationState.LsaSerialNumber := 0
pmsgOut^.V1.ReplicationState.LsaCreationTime := 0
pmsgOut^.V1.ActualNtStatus := 0 
pmsgOut^.V1.pRestart := null
pmsgOut^.V1.pLog := null

/* Validate the request version */
if dwInVersion ≠ 1 then
  return ERROR_DS_DRA_INVALID_PARAMETER
endif
msgIn := pmsgIn^.V1

/* Access check */
if not AccessCheckCAR(DefaultNC(), DS-Replication-Get-Changes) then
  return ERR0R_ACCESS_DENIED
endif

/* The DC must own the PDC role */
if not IsPDC() then
  return ERROR_INVALID_DOMAIN_ROLE
endif

ntStatus := 0
readStatus := 0
if DRS_NT4_CHGLOG_GET_CHANGE_LOG in msgIn.dwFlags then
  /* Return NT4 change log entries. */

  /* Determine the position of the first entry in the change log that
   * needs to be returned. If pRestart = null, this is the first
   * entry of the change log, otherwise it is the entry following the
   * entry identified in the cookie pRestart^. */
  if msgIn.pRestart = null then
    sequenceNumber := 1
    nextIndexToBeReturned := 0
  else
    sequenceNumber :=
        (Sequence number extracted from msgIn.pRestart^) + 1
    lastReturnedSerialNumber :=
        Serial number extracted from msgIn.pRestart^
    lastReturnedIndex := select one i in dc.pdcChangeLog where
        dc.pdcChangeLog[i].SerialNumber = lastReturnedSerialNumber
    if lastReturnedIndex = null then
      /* Cookie is old or corrupted.
       * The STATUS code STATUS_INVALID_PARAMETER corresponds to
       * the Windows error code ERROR_INVALID_PARAMETER. */
      ntStatus := STATUS_INVALID_PARAMETER
    else
      nextIndexToBeReturned := lastReturnedIndex + 1
    endif
  endif

  if ntStatus = 0 and nextIndexToBeReturned ≥ dc.pdcChangeLog.length
      then
    /* No entries to be returned, complete the response message */
    pmsgOut^.V1.pLog := null
    pmsgOut^.V1.cbLog := 0
    pmsgOut^.V1.pRestart := null
    pmsgOut^.V1.cbRestart := 0
  endif

  if ntStatus = 0 and 
      nextIndexToBeReturned < dc.pdcChangeLog.length then
    /* Entries to be returned. First, determine how many entries fit
     * into the response message */
    lastIndexToBeReturned := the largest integer q such that
        q < dc.pdcChangeLog.length and
          the size in bytes of
          dc.pdcChangeLog[nextIndexToBeReturned .. q]
            is <= msgIn.PreferredMaximumLength
    if lastIndexToBeReturned < nextIndexToBeReturned then
      /* Client's PreferredMaximumLength is too small for a single
       * entry, so return no entries.
       * The STATUS code STATUS_BUFFER_TOO_SMALL corresponds to
       * the Windows error code ERROR_INSUFFICIENT_BUFFER. */
      ntStatus := STATUS_BUFFER_TOO_SMALL
    else
      /* Client's PreferredMaximumLength is large enough for one or
       * more entries. Fill in pChangeLog^ from dc.pdcChangeLog */
      pChangeLog^.Size := 0x00000010
      pChangeLog^.Version := 0x00000001
      pChangeLog^.SequenceNumber := sequenceNumber
      pChangeLog^.Flags := 0x00000000
      pChangeLog^.ChangeLogEntries := 
         dc.pdcChangeLog[nextIndexToBeReturned .. 
                         lastIndexToBeReturned]
      if a fatal error occurred while retrieving dc.pdcChangeLog then
        ntStatus :=
            STATUS code of error that occurred, high-order bit set
      end
    endif
    if ntStatus = 0 then
      /*  No errors, complete the response message */
      pmsgOut^.V1.pLog := pChangeLog
      pmsgOut^.V1.cbLog := size in bytes of pmsgOut^.V1.pLog^
      /* Construct a new cookie */
      lastReturnedSerialNumber :=
          dc.pdcChangeLog[lastIndexToBeReturned].SerialNumber
      pmsgOut^.V1.pRestart := 
          ADDRESS OF implementation-specific struct
          encapsulating lastReturnedSerialNumber and sequenceNumber
      pmsgOut^.V1.cbRestart := size in bytes of pmsgOut^.V1.pRestart^
      if lastIndexToBeReturned < dc.pdcChangeLog.length - 1 then
        /* There are more entries to be returned.
         * The STATUS code STATUS_MORE_ENTRIES corresponds to
         * the Windows error code ERROR_MORE_DATA. */
        ntStatus := STATUS_MORE_ENTRIES
      endif
    endif /* Response complete */
  endif /* Entries returned */
endif /* Processed change log request */

/* Save the status code from the previous operation */
readStatus := ntStatus

if ntStatus < 0x80000000 and
    DRS_NT4_CHGLOG_GET_SERIAL_NUMBERS in msgIn.dwFlags then
  /* Return NT4 replication state. */
  pmsgOut^.V1.ReplicationState.SamSerialNumber :=
      dc.nt4ReplicationState.SamNT4ReplicationUSN
  pmsgOut^.V1.ReplicationState.SamCreationTime :=
      dc.nt4ReplicationState.SamCreationTime
  pmsgOut^.V1.ReplicationState.BuiltinSerialNumber :=
      dc.nt4ReplicationState.BuiltinNT4ReplicationUSN
  pmsgOut^.V1.ReplicationState.BuiltinCreationTime :=
      dc.nt4ReplicationState.BuiltinCreationTime
  pmsgOut^.V1.ReplicationState.LsaSerialNumber := 1
  pmsgOut^.V1.ReplicationState.LsaCreationTime := 
      current time on the DC
  if a fatal error occurred while retrieving NT4 replication state 
      then
    ntStatus :=
        STATUS code of error that occurred, high-order bit set
  end
endif

if ntStatus < 0x80000000 then
  pmsgOut^.V1.ActualStatus := readStatus
else
  pmsgOut^.V1.ActualStatus := ntStatus
endif

return GetWindowsErrorCode(ntStatus)
 
Show:
© 2014 Microsoft