windows-nt/Source/XPSP1/NT/ds/netapi/svcdlls/logonsrv/client/ssiapi.c

3623 lines
105 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1987-1992 Microsoft Corporation
Module Name:
ssiapi.c
Abstract:
Authentication and replication API routines (client side).
Author:
Cliff Van Dyke (cliffv) 30-Jul-1991
Environment:
User mode only.
Contains NT-specific code.
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
--*/
#include <nt.h> // LARGE_INTEGER definition
#include <ntrtl.h> // LARGE_INTEGER definition
#include <nturtl.h> // LARGE_INTEGER definition
#include <rpc.h> // Needed by logon.h
#include <ntrpcp.h> // needed by rpcasync.h
#include <rpcasync.h> // I_RpcExceptionFilter
#include <logon_c.h> // includes lmcons.h, lmaccess.h, netlogon.h, ssi.h, windef.h
#include <debuglib.h> // IF_DEBUG()
#include <lmerr.h> // NERR_* defines
#include <lmapibuf.h> // NetApiBufferFree()
#include <netdebug.h> // NetpKdPrint
#include <netlibnt.h> // NetpNtStatusToApiStatus()
#include "..\server\ssiapi.h"
#include <winsock2.h> // Needed by nlcommon.h
#include <netlib.h> // Needed by nlcommon.h
#include <ntddbrow.h> // Needed by nlcommon.h
#include "nlcommon.h"
#include <netlogp.h>
#include <tstring.h> // NetpCopyStrToWStr()
#include <align.h> // ROUND_UP_COUNT ...
#include <strarray.h> // NetpIsTStrArrayEmpty
#include <ftnfoctx.h> // NetpMergeFtinfo
NTSTATUS
I_NetServerReqChallenge(
IN LPWSTR PrimaryName OPTIONAL,
IN LPWSTR ComputerName,
IN PNETLOGON_CREDENTIAL ClientChallenge,
OUT PNETLOGON_CREDENTIAL ServerChallenge
)
/*++
Routine Description:
This is the client side of I_NetServerReqChallenge.
I_NetLogonRequestChallenge is the first of two functions used by a client
to process an authentication with a domain controller (DC). (See
I_NetServerAuthenticate below.) It is called for
a BDC (or member server) authenticating with a PDC for replication
purposes.
This function passes a challenge to the PDC and the PDC passes a challenge
back to the caller.
Arguments:
PrimaryName -- Supplies the name of the PrimaryDomainController we wish to
authenticate with.
ComputerName -- Name of the BDC or member server making the call.
ClientChallenge -- 64 bit challenge supplied by the BDC or member server.
ServerChallenge -- Receives 64 bit challenge from the PDC.
Return Value:
The status of the operation.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerReqChallenge(
PrimaryName,
ComputerName,
ClientChallenge,
ServerChallenge );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerReqChallenge rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerAuthenticate(
IN LPWSTR PrimaryName OPTIONAL,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_CREDENTIAL ClientCredential,
OUT PNETLOGON_CREDENTIAL ServerCredential
)
/*++
Routine Description:
This is the client side of I_NetServerAuthenticate
I_NetServerAuthenticate is the second of two functions used by a client
Netlogon service to authenticate with another Netlogon service.
(See I_NetServerReqChallenge above.) Both a SAM or UAS server authenticates
using this function.
This function passes a credential to the DC and the DC passes a credential
back to the caller.
Arguments:
PrimaryName -- Supplies the name of the DC we wish to authenticate with.
AccountName -- Name of the Account to authenticate with.
SecureChannelType -- The type of the account being accessed. This field
must be set to UasServerSecureChannel to indicate a call from
downlevel (LanMan 2.x and below) BDC or member server.
ComputerName -- Name of the BDC or member server making the call.
ClientCredential -- 64 bit credential supplied by the BDC or member server.
ServerCredential -- Receives 64 bit credential from the PDC.
Return Value:
The status of the operation.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerAuthenticate(
PrimaryName,
AccountName,
AccountType,
ComputerName,
ClientCredential,
ServerCredential );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerAuthenticate rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerAuthenticate2(
IN LPWSTR PrimaryName OPTIONAL,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_CREDENTIAL ClientCredential,
OUT PNETLOGON_CREDENTIAL ServerCredential,
IN OUT PULONG NegotiatedFlags
)
/*++
Routine Description:
This is the client side of I_NetServerAuthenticate
I_NetServerAuthenticate is the second of two functions used by a client
Netlogon service to authenticate with another Netlogon service.
(See I_NetServerReqChallenge above.) Both a SAM or UAS server authenticates
using this function.
This function passes a credential to the DC and the DC passes a credential
back to the caller.
Arguments:
PrimaryName -- Supplies the name of the DC we wish to authenticate with.
AccountName -- Name of the Account to authenticate with.
SecureChannelType -- The type of the account being accessed. This field
must be set to UasServerSecureChannel to indicate a call from
downlevel (LanMan 2.x and below) BDC or member server.
ComputerName -- Name of the BDC or member server making the call.
ClientCredential -- 64 bit credential supplied by the BDC or member server.
ServerCredential -- Receives 64 bit credential from the PDC.
NegotiatedFlags -- Specifies flags indicating what features the BDC supports.
Returns a subset of those flags indicating what features the PDC supports.
The PDC/BDC should ignore any bits that it doesn't understand.
Return Value:
The status of the operation.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerAuthenticate2(
PrimaryName,
AccountName,
AccountType,
ComputerName,
ClientCredential,
ServerCredential,
NegotiatedFlags );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerAuthenticate2 rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerAuthenticate3(
IN LPWSTR PrimaryName OPTIONAL,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_CREDENTIAL ClientCredential,
OUT PNETLOGON_CREDENTIAL ServerCredential,
IN OUT PULONG NegotiatedFlags,
OUT PULONG AccountRid
)
/*++
Routine Description:
This is the client side of I_NetServerAuthenticate
I_NetServerAuthenticate is the second of two functions used by a client
Netlogon service to authenticate with another Netlogon service.
(See I_NetServerReqChallenge above.) Both a SAM or UAS server authenticates
using this function.
This function passes a credential to the DC and the DC passes a credential
back to the caller.
Arguments:
PrimaryName -- Supplies the name of the DC we wish to authenticate with.
AccountName -- Name of the Account to authenticate with.
SecureChannelType -- The type of the account being accessed. This field
must be set to UasServerSecureChannel to indicate a call from
downlevel (LanMan 2.x and below) BDC or member server.
ComputerName -- Name of the BDC or member server making the call.
ClientCredential -- 64 bit credential supplied by the BDC or member server.
ServerCredential -- Receives 64 bit credential from the PDC.
NegotiatedFlags -- Specifies flags indicating what features the BDC supports.
Returns a subset of those flags indicating what features the PDC supports.
The PDC/BDC should ignore any bits that it doesn't understand.
AccountRid - Returns the relative ID of the account used for authentication.
Return Value:
The status of the operation.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerAuthenticate3(
PrimaryName,
AccountName,
AccountType,
ComputerName,
ClientCredential,
ServerCredential,
NegotiatedFlags,
AccountRid );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerAuthenticate3 rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerPasswordSet(
IN LPWSTR PrimaryName OPTIONAL,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN PENCRYPTED_LM_OWF_PASSWORD UasNewPassword
)
/*++
Routine Description:
This function is used to change the password for the account being
used to maintain a secure channel. This function can only be called
by a server which has previously authenticated with a DC by calling
I_NetServerAuthenticate.
The call is made differently depending on the account type:
* A domain account password is changed from the PDC in the
trusting domain. The I_NetServerPasswordSet call is made to any
DC in the trusted domain.
* A server account password is changed from the specific server.
The I_NetServerPasswordSet call is made to the PDC in the domain
the server belongs to.
* A workstation account password is changed from the specific
workstation. The I_NetServerPasswordSet call is made to a DC in
the domain the server belongs to.
For domain accounts and workstation accounts, the server being called
may be a BDC in the specific domain. In that case, the BDC will
validate the request and pass it on to the PDC of the domain using
the server account secure channel. If the PDC of the domain is
currently not available, the BDC will return STATUS_NO_LOGON_SERVERS. Since
the UasNewPassword is passed encrypted by the session key, such a BDC
will decrypt the UasNewPassword using the original session key and
will re-encrypt it with the session key for its session to its PDC
before passing the request on.
This function uses RPC to contact the DC named by PrimaryName.
Arguments:
PrimaryName -- Name of the PDC to change the servers password
with. NULL indicates this call is a local call being made on
behalf of a UAS server by the XACT server.
AccountName -- Name of the account to change the password for.
AccountType -- The type of account being accessed. This field must
be set to UasServerAccount to indicate a call from a downlevel
ComputerName -- Name of the BDC or member making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
UasNewPassword -- The new password for the server. This
Password is generated by automatic means using
random number genertaor seeded with the current Time
It is assumed that the machine generated password
was used as key to encrypt STD text and "sesskey"
obtained via Challenge/Authenticate sequence was
used to further encrypt it before passing to this api.
i.e. UasNewPassword = E2(E1(STD_TXT, PW), SK)
Return Value:
NT status code.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerPasswordSet(
PrimaryName,
AccountName,
AccountType,
ComputerName,
Authenticator,
ReturnAuthenticator,
UasNewPassword );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerPasswordSet rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerPasswordSet2(
IN LPWSTR PrimaryName OPTIONAL,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN PNL_TRUST_PASSWORD ClearNewPassword
)
/*++
Routine Description:
This function is used to change the password for the account being
used to maintain a secure channel. This function can only be called
by a server which has previously authenticated with a DC by calling
I_NetServerAuthenticate.
The call is made differently depending on the account type:
* A domain account password is changed from the PDC in the
trusting domain. The I_NetServerPasswordSet call is made to any
DC in the trusted domain.
* A server account password is changed from the specific server.
The I_NetServerPasswordSet call is made to the PDC in the domain
the server belongs to.
* A workstation account password is changed from the specific
workstation. The I_NetServerPasswordSet call is made to a DC in
the domain the server belongs to.
For domain accounts and workstation accounts, the server being called
may be a BDC in the specific domain. In that case, the BDC will
validate the request and pass it on to the PDC of the domain using
the server account secure channel. If the PDC of the domain is
currently not available, the BDC will return STATUS_NO_LOGON_SERVERS. Since
the UasNewPassword is passed encrypted by the session key, such a BDC
will decrypt the UasNewPassword using the original session key and
will re-encrypt it with the session key for its session to its PDC
before passing the request on.
This function uses RPC to contact the DC named by PrimaryName.
Arguments:
PrimaryName -- Name of the PDC to change the servers password
with. NULL indicates this call is a local call being made on
behalf of a UAS server by the XACT server.
AccountName -- Name of the account to change the password for.
AccountType -- The type of account being accessed. This field must
be set to UasServerAccount to indicate a call from a downlevel
ComputerName -- Name of the BDC or member making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
ClearNewPassword - The new password for the server.
Appropriately encrypted.
Return Value:
NT status code.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerPasswordSet2(
PrimaryName,
AccountName,
AccountType,
ComputerName,
Authenticator,
ReturnAuthenticator,
ClearNewPassword );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerPasswordSet2 rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NTSTATUS
I_NetDatabaseDeltas (
IN LPWSTR PrimaryName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN DWORD DatabaseID,
IN OUT PNLPR_MODIFIED_COUNT DomainModifiedCount,
OUT PNETLOGON_DELTA_ENUM_ARRAY *DeltaArray,
IN DWORD PreferredMaximumLength
)
/*++
Routine Description:
This function is used by a SAM BDC or SAM member server to request
SAM-style account delta information from a SAM PDC. This function
can only be called by a server which has previously authenticated
with the PDC by calling I_NetServerAuthenticate. This function uses
RPC to contact the Netlogon service on the PDC.
This function returns a list of deltas. A delta describes an
individual domain, user or group and all of the field values for that
object. The PDC maintains a list of deltas not including all of the
field values for that object. Rather, the PDC retrieves the field
values from SAM and returns those values from this call. The PDC
optimizes the data returned on this call by only returning the field
values for a particular object once on a single invocation of this
function. This optimizes the typical case where multiple deltas
exist for a single object (e.g., an application modified many fields
of the same user during a short period of time using different calls
to the SAM service).
Arguments:
PrimaryName -- Name of the PDC to retrieve the deltas from.
ComputerName -- Name of the BDC or member server making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
DomainModifiedCount -- Specifies the DomainModifiedCount of the
last delta retrieved by the server. Returns the
DomainModifiedCount of the last delta returned from the PDC
on this call.
DeltaArray -- Receives a pointer to a buffer where the information
is placed. The information returned is an array of
NETLOGON_DELTA_ENUM structures.
PreferredMaximumLength - Preferred maximum length of returned
data (in 8-bit bytes). This is not a hard upper limit, but
serves as a guide to the server. Due to data conversion
between systems with different natural data sizes, the actual
amount of data returned may be greater than this value.
Return Value:
STATUS_SUCCESS -- The function completed successfully.
STATUS_SYNCHRONIZATION_REQUIRED -- The replicant is totally out of sync and
should call I_NetDatabaseSync to do a full synchronization with
the PDC.
STATUS_MORE_ENTRIES -- The replicant should call again to get more
data.
STATUS_ACCESS_DENIED -- The replicant should re-authenticate with
the PDC.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
*DeltaArray = NULL; // Force RPC to allocate
Status = NetrDatabaseDeltas(
PrimaryName,
ComputerName,
Authenticator,
ReturnAuthenticator,
DatabaseID,
DomainModifiedCount,
DeltaArray,
PreferredMaximumLength );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
NetpKdPrint(("I_NetDatabaseDeltas rc = %lu 0x%lx\n", Status, Status));
return Status;
}
NTSTATUS
I_NetDatabaseSync (
IN LPWSTR PrimaryName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN DWORD DatabaseID,
IN OUT PULONG SamSyncContext,
OUT PNETLOGON_DELTA_ENUM_ARRAY *DeltaArray,
IN DWORD PreferredMaximumLength
)
/*++
Routine Description:
This function is used by a SAM BDC or SAM member server to request
the entire SAM database from a SAM PDC in SAM-style format. This
function can only be called by a server which has previously
authenticated with the PDC by calling I_NetServerAuthenticate. This
function uses RPC to contact the Netlogon service on the PDC.
This function uses the find-first find-next model to return portions
of the SAM database at a time. The SAM database is returned as a
list of deltas like those returned from I_NetDatabaseDeltas. The
following deltas are returned for each domain:
* One AddOrChangeDomain delta, followed by
* One AddOrChangeGroup delta for each group, followed by,
* One AddOrChangeUser delta for each user, followed by
* One ChangeGroupMembership delta for each group
Arguments:
PrimaryName -- Name of the PDC to retrieve the deltas from.
ComputerName -- Name of the BDC or member server making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
SamSyncContext -- Specifies context needed to continue the
operation. The caller should treat this as an opaque
value. The value should be zero before the first call.
DeltaArray -- Receives a pointer to a buffer where the information
is placed. The information returned is an array of
NETLOGON_DELTA_ENUM structures.
PreferredMaximumLength - Preferred maximum length of returned
data (in 8-bit bytes). This is not a hard upper limit, but
serves as a guide to the server. Due to data conversion
between systems with different natural data sizes, the actual
amount of data returned may be greater than this value.
Return Value:
STATUS_SUCCESS -- The function completed successfully.
STATUS_SYNCHRONIZATION_REQUIRED -- The replicant is totally out of sync and
should call I_NetDatabaseSync to do a full synchronization with
the PDC.
STATUS_MORE_ENTRIES -- The replicant should call again to get more
data.
STATUS_ACCESS_DENIED -- The replicant should re-authenticate with
the PDC.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
*DeltaArray = NULL; // Force RPC to allocate
Status = NetrDatabaseSync(
PrimaryName,
ComputerName,
Authenticator,
ReturnAuthenticator,
DatabaseID,
SamSyncContext,
DeltaArray,
PreferredMaximumLength );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetDatabaseSync rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NTSTATUS
I_NetDatabaseSync2 (
IN LPWSTR PrimaryName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN DWORD DatabaseID,
IN SYNC_STATE RestartState,
IN OUT PULONG SamSyncContext,
OUT PNETLOGON_DELTA_ENUM_ARRAY *DeltaArray,
IN DWORD PreferredMaximumLength
)
/*++
Routine Description:
This function is used by a SAM BDC or SAM member server to request
the entire SAM database from a SAM PDC in SAM-style format. This
function can only be called by a server which has previously
authenticated with the PDC by calling I_NetServerAuthenticate. This
function uses RPC to contact the Netlogon service on the PDC.
This function uses the find-first find-next model to return portions
of the SAM database at a time. The SAM database is returned as a
list of deltas like those returned from I_NetDatabaseDeltas. The
following deltas are returned for each domain:
* One AddOrChangeDomain delta, followed by
* One AddOrChangeGroup delta for each group, followed by,
* One AddOrChangeUser delta for each user, followed by
* One ChangeGroupMembership delta for each group
Arguments:
PrimaryName -- Name of the PDC to retrieve the deltas from.
ComputerName -- Name of the BDC or member server making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
RestartState -- Specifies whether this is a restart of the full sync and how
to interpret SyncContext. This value should be NormalState unless this
is the restart of a full sync.
However, if the caller is continuing a full sync after a reboot,
the following values are used:
GroupState - SyncContext is the global group rid to continue with.
UserState - SyncContext is the user rid to continue with
GroupMemberState - SyncContext is the global group rid to continue with
AliasState - SyncContext should be zero to restart at first alias
AliasMemberState - SyncContext should be zero to restart at first alias
One cannot continue the LSA database in this way.
SamSyncContext -- Specifies context needed to continue the
operation. The caller should treat this as an opaque
value. The value should be zero before the first call.
DeltaArray -- Receives a pointer to a buffer where the information
is placed. The information returned is an array of
NETLOGON_DELTA_ENUM structures.
PreferredMaximumLength - Preferred maximum length of returned
data (in 8-bit bytes). This is not a hard upper limit, but
serves as a guide to the server. Due to data conversion
between systems with different natural data sizes, the actual
amount of data returned may be greater than this value.
Return Value:
STATUS_SUCCESS -- The function completed successfully.
STATUS_SYNCHRONIZATION_REQUIRED -- The replicant is totally out of sync and
should call I_NetDatabaseSync to do a full synchronization with
the PDC.
STATUS_MORE_ENTRIES -- The replicant should call again to get more
data.
STATUS_ACCESS_DENIED -- The replicant should re-authenticate with
the PDC.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
*DeltaArray = NULL; // Force RPC to allocate
Status = NetrDatabaseSync2(
PrimaryName,
ComputerName,
Authenticator,
ReturnAuthenticator,
DatabaseID,
RestartState,
SamSyncContext,
DeltaArray,
PreferredMaximumLength );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetDatabaseSync rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NET_API_STATUS NET_API_FUNCTION
I_NetAccountDeltas (
IN LPWSTR PrimaryName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN PUAS_INFO_0 RecordId,
IN DWORD Count,
IN DWORD Level,
OUT LPBYTE Buffer,
IN DWORD BufferSize,
OUT PULONG CountReturned,
OUT PULONG TotalEntries,
OUT PUAS_INFO_0 NextRecordId
)
/*++
Routine Description:
This function is used by a UAS BDC or UAS member server to request
UAS-style account change information. This function can only be
called by a server which has previously authenticated with the PDC by
calling I_NetServerAuthenticate.
This function is only called by the XACT server upon receipt of a
I_NetAccountDeltas XACT SMB from a UAS BDC or a UAS member server.
As such, many of the parameters are opaque since the XACT server
doesn't need to interpret any of that data. This function uses RPC
to contact the Netlogon service.
The LanMan 3.0 SSI Functional Specification describes the operation
of this function.
Arguments:
PrimaryName -- Must be NULL to indicate this call is a local call
being made on behalf of a UAS server by the XACT server.
ComputerName -- Name of the BDC or member making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
RecordId -- Supplies an opaque buffer indicating the last record
received from a previous call to this function.
Count -- Supplies the number of Delta records requested.
Level -- Reserved. Must be zero.
Buffer -- Returns opaque data representing the information to be
returned.
BufferSize -- Size of buffer in bytes.
CountReturned -- Returns the number of records returned in buffer.
TotalEntries -- Returns the total number of records available.
NextRecordId -- Returns an opaque buffer identifying the last
record received by this function.
Return Value:
Status code
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = NetrAccountDeltas (
PrimaryName,
ComputerName,
Authenticator,
ReturnAuthenticator,
RecordId,
Count,
Level,
Buffer,
BufferSize,
CountReturned,
TotalEntries,
NextRecordId );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetAccountDeltas rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
I_NetAccountSync (
IN LPWSTR PrimaryName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN DWORD Reference,
IN DWORD Level,
OUT LPBYTE Buffer,
IN DWORD BufferSize,
OUT PULONG CountReturned,
OUT PULONG TotalEntries,
OUT PULONG NextReference,
OUT PUAS_INFO_0 LastRecordId
)
/*++
Routine Description:
This function is used by a UAS BDC or UAS member server to request
the entire user accounts database. This function can only be called
by a server which has previously authenticated with the PDC by
calling I_NetServerAuthenticate.
This function is only called by the XACT server upon receipt of a
I_NetAccountSync XACT SMB from a UAS BDC or a UAS member server. As
such, many of the parameters are opaque since the XACT server doesn't
need to interpret any of that data. This function uses RPC to
contact the Netlogon service.
The LanMan 3.0 SSI Functional Specification describes the operation
of this function.
"Reference" and "NextReference" are treated as below.
1. "Reference" should hold either 0 or value of "NextReference"
from previous call to this API.
2. Send the modals and ALL group records in the first call. The API
expects the bufffer to be large enough to hold this info (worst
case size would be
MAXGROUP * (sizeof(struct group_info_1) + MAXCOMMENTSZ)
+ sizeof(struct user_modals_info_0)
which, for now, will be 256 * (26 + 49) + 16 = 19216 bytes
Arguments:
PrimaryName -- Must be NULL to indicate this call is a local call
being made on behalf of a UAS server by the XACT server.
ComputerName -- Name of the BDC or member making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
Reference -- Supplies find-first find-next handle returned by the
previous call to this function or 0 if it is the first call.
Level -- Reserved. Must be zero.
Buffer -- Returns opaque data representing the information to be
returned.
BufferLen -- Length of buffer in bytes.
CountReturned -- Returns the number of records returned in buffer.
TotalEntries -- Returns the total number of records available.
NextReference -- Returns a find-first find-next handle to be
provided on the next call.
LastRecordId -- Returns an opaque buffer identifying the last
record received by this function.
Return Value:
Status code.
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = NetrAccountSync (
PrimaryName,
ComputerName,
Authenticator,
ReturnAuthenticator,
Reference,
Level,
Buffer,
BufferSize,
CountReturned,
TotalEntries,
NextReference,
LastRecordId );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetAccountSync rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
I_NetLogonControl(
IN LPCWSTR ServerName OPTIONAL,
IN DWORD FunctionCode,
IN DWORD QueryLevel,
OUT LPBYTE *QueryInformation
)
/*++
Routine Description:
This function controls various aspects of the Netlogon service. It
can be used to request that a BDC ensure that its copy of the SAM
database is brought up to date. It can, also, be used to determine
if a BDC currently has a secure channel open to the PDC.
Only an Admin, Account Operator or Server Operator may call this
function.
Arguments:
ServerName - The name of the remote server.
FunctionCode - Defines the operation to be performed. The valid
values are:
FunctionCode Values
NETLOGON_CONTROL_QUERY - No operation. Merely returns the
information requested.
NETLOGON_CONTROL_REPLICATE: Forces the SAM database on a BDC
to be brought in sync with the copy on the PDC. This
operation does NOT imply a full synchronize. The
Netlogon service will merely replicate any outstanding
differences if possible.
NETLOGON_CONTROL_SYNCHRONIZE: Forces a BDC to get a
completely new copy of the SAM database from the PDC.
This operation will perform a full synchronize.
NETLOGON_CONTROL_PDC_REPLICATE: Forces a PDC to ask each BDC
to replicate now.
QueryLevel - Indicates what information should be returned from
the Netlogon Service. Must be 1.
QueryInformation - Returns a pointer to a buffer which contains the
requested information. The buffer must be freed using
NetApiBufferFree.
Return Value:
NERR_Success: the operation was successful
ERROR_NOT_SUPPORTED: Function code is not valid on the specified
server. (e.g. NETLOGON_CONTROL_REPLICATE was passed to a PDC).
--*/
{
NET_API_STATUS NetStatus;
NETLOGON_CONTROL_QUERY_INFORMATION RpcQueryInformation;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
RpcQueryInformation.NetlogonInfo1 = NULL; // Force RPC to allocate
NetStatus = NetrLogonControl (
(LPWSTR) ServerName OPTIONAL,
FunctionCode,
QueryLevel,
&RpcQueryInformation );
*QueryInformation = (LPBYTE) RpcQueryInformation.NetlogonInfo1;
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetLogonControl rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
I_NetLogonControl2(
IN LPCWSTR ServerName OPTIONAL,
IN DWORD FunctionCode,
IN DWORD QueryLevel,
IN LPBYTE InputData,
OUT LPBYTE *QueryInformation
)
/*++
Routine Description:
This is similar to the I_NetLogonControl function but it accepts
more generic input data according to the function code specified.
This function controls various aspects of the Netlogon service. It
can be used to request that a BDC ensure that its copy of the SAM
database is brought up to date. It can, also, be used to determine
if a BDC currently has a secure channel open to the PDC.
Only an Admin, Account Operator or Server Operator may call this
function.
Arguments:
ServerName - The name of the remote server.
FunctionCode - Defines the operation to be performed. The valid
values are:
FunctionCode Values
NETLOGON_CONTROL_QUERY - No operation. Merely returns the
information requested.
NETLOGON_CONTROL_REPLICATE: Forces the SAM database on a BDC
to be brought in sync with the copy on the PDC. This
operation does NOT imply a full synchronize. The
Netlogon service will merely replicate any outstanding
differences if possible.
NETLOGON_CONTROL_SYNCHRONIZE: Forces a BDC to get a
completely new copy of the SAM database from the PDC.
This operation will perform a full synchronize.
NETLOGON_CONTROL_PDC_REPLICATE: Forces a PDC to ask each BDC
to replicate now.
NETLOGON_CONTROL_REDISCOVER: Forces a DC to rediscover the
specified trusted domain DC.
NETLOGON_CONTROL_TC_QUERY: Query the status of the specified
trusted domain secure channel.
NETLOGON_CONTROL_TC_VERIFY: Verify the status of the specified
trusted domain secure channel. If the current status is
success (which means that the last operation performed
over the secure channel was successful), ping the DC. If the
current status is not success or the ping fails, rediscover
a new DC.
NETLOGON_CONTROL_CHANGE_PASSWORD: Forces a password change on
a secure channel to a trusted domain.
NETLOGON_CONTROL_FORCE_DNS_REG: Forces the DC to re-register all
of its DNS records. QueryLevel parameter must be 1.
NETLOGON_CONTROL_QUERY_DNS_REG: Query the status of DNS updates
performed by netlogon. If there was any DNS registration or
deregistration error for any of the records as they were
updated last time, the query result will be negative;
otherwise the query result will be positive.
QueryLevel parameter must be 1.
QueryLevel - Indicates what information should be returned from
the Netlogon Service.
InputData - According to the function code specified this parameter
will carry input data. NETLOGON_CONTROL_REDISCOVER and
NETLOGON_CONTROL_TC_QUERY function code specify the trusted
domain name (LPWSTR type) here.
QueryInformation - Returns a pointer to a buffer which contains the
requested information. The buffer must be freed using
NetApiBufferFree.
Return Value:
NERR_Success: the operation was successful
ERROR_NOT_SUPPORTED: Function code is not valid on the specified
server. (e.g. NETLOGON_CONTROL_REPLICATE was passed to a PDC).
--*/
{
NET_API_STATUS NetStatus;
NETLOGON_CONTROL_QUERY_INFORMATION RpcQueryInformation;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
// Use new Control2Ex if either QueryLevel or FunctionCode is new
//
RpcQueryInformation.NetlogonInfo1 = NULL; // Force RPC to allocate
switch ( FunctionCode ) {
case NETLOGON_CONTROL_QUERY:
case NETLOGON_CONTROL_REPLICATE:
case NETLOGON_CONTROL_SYNCHRONIZE:
case NETLOGON_CONTROL_PDC_REPLICATE:
case NETLOGON_CONTROL_REDISCOVER:
case NETLOGON_CONTROL_TC_QUERY:
case NETLOGON_CONTROL_TRANSPORT_NOTIFY:
case NETLOGON_CONTROL_BACKUP_CHANGE_LOG:
case NETLOGON_CONTROL_TRUNCATE_LOG:
case NETLOGON_CONTROL_SET_DBFLAG:
case NETLOGON_CONTROL_BREAKPOINT:
if ( QueryLevel >= 1 && QueryLevel <= 3 ) {
NetStatus = NetrLogonControl2 (
(LPWSTR) ServerName OPTIONAL,
FunctionCode,
QueryLevel,
(PNETLOGON_CONTROL_DATA_INFORMATION)InputData,
&RpcQueryInformation );
} else if ( QueryLevel == 4 ) {
NetStatus = NetrLogonControl2Ex (
(LPWSTR) ServerName OPTIONAL,
FunctionCode,
QueryLevel,
(PNETLOGON_CONTROL_DATA_INFORMATION)InputData,
&RpcQueryInformation );
} else {
NetStatus = ERROR_INVALID_LEVEL;
}
break;
case NETLOGON_CONTROL_FIND_USER:
case NETLOGON_CONTROL_UNLOAD_NETLOGON_DLL:
case NETLOGON_CONTROL_CHANGE_PASSWORD:
case NETLOGON_CONTROL_TC_VERIFY:
case NETLOGON_CONTROL_FORCE_DNS_REG:
case NETLOGON_CONTROL_QUERY_DNS_REG:
if ( QueryLevel >= 1 && QueryLevel <= 4 ) {
NetStatus = NetrLogonControl2Ex (
(LPWSTR) ServerName OPTIONAL,
FunctionCode,
QueryLevel,
(PNETLOGON_CONTROL_DATA_INFORMATION)InputData,
&RpcQueryInformation );
} else {
NetStatus = ERROR_INVALID_LEVEL;
}
break;
default:
NetStatus = ERROR_INVALID_LEVEL;
}
*QueryInformation = (LPBYTE) RpcQueryInformation.NetlogonInfo1;
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetLogonControl rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NTSTATUS
I_NetDatabaseRedo(
IN LPWSTR PrimaryName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN LPBYTE ChangeLogEntry,
IN DWORD ChangeLogEntrySize,
OUT PNETLOGON_DELTA_ENUM_ARRAY *DeltaArray
)
/*++
Routine Description:
This function is used by a SAM BDC to request infomation about a single
account. This function can only be called by a server which has previously
authenticated with the PDC by calling I_NetServerAuthenticate. This
function uses RPC to contact the Netlogon service on the PDC.
Arguments:
PrimaryName -- Name of the PDC to retrieve the delta from.
ComputerName -- Name of the BDC making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
ChangeLogEntry -- A description of the account to be queried.
ChangeLogEntrySize -- Size (in bytes) of the ChangeLogEntry.
DeltaArray -- Receives a pointer to a buffer where the information
is placed. The information returned is an array of
NETLOGON_DELTA_ENUM structures.
Return Value:
STATUS_SUCCESS -- The function completed successfully.
STATUS_ACCESS_DENIED -- The replicant should re-authenticate with
the PDC.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
*DeltaArray = NULL; // Force RPC to allocate
Status = NetrDatabaseRedo(
PrimaryName,
ComputerName,
Authenticator,
ReturnAuthenticator,
ChangeLogEntry,
ChangeLogEntrySize,
DeltaArray );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetDatabaseSync rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NTSTATUS
NetEnumerateTrustedDomains (
IN LPWSTR ServerName OPTIONAL,
OUT LPWSTR *DomainNames
)
/*++
Routine Description:
This API returns the names of the domains trusted by the domain ServerName is a member of.
ServerName must be an NT workstation or NT non-DC server.
The returned list does not include the domain ServerName is directly a member of.
Netlogon implements this API by calling LsaEnumerateTrustedDomains on a DC in the
domain ServerName is a member of. However, Netlogon returns cached information if
it has been less than 5 minutes since the last call was made or if no DC is available.
Netlogon's cache of Trusted domain names is maintained in the registry across reboots.
As such, the list is available upon boot even if no DC is available.
Arguments:
ServerName - name of remote server (null for local). ServerName must be an NT workstation
or NT non-DC server.
DomainNames - Returns an allocated buffer containing the list of trusted domains in
MULTI-SZ format (i.e., each string is terminated by a zero character, the next string
immediately follows, the sequence is terminated by zero length domain name). The
buffer should be freed using NetApiBufferFree.
Return Value:
ERROR_SUCCESS - Success.
STATUS_NOT_SUPPORTED - ServerName is not an NT workstation or NT non-DC server.
STATUS_NO_LOGON_SERVERS - No DC could be found and no cached information is available.
STATUS_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
broken and no cached information is available.
STATUS_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
broken or the password is broken and no cached information is available.
--*/
{
NTSTATUS Status = 0;
DOMAIN_NAME_BUFFER DomainNameBuffer;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
DomainNameBuffer.DomainNameByteCount = 0;
DomainNameBuffer.DomainNames = NULL; // Force RPC to allocate
Status = NetrEnumerateTrustedDomains(
ServerName,
&DomainNameBuffer );
if ( NT_SUCCESS(Status) ) {
*DomainNames = (LPWSTR) DomainNameBuffer.DomainNames;
}
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("NetEnumerateDomainNames rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NET_API_STATUS NET_API_FUNCTION
NlpEnumerateNt4DomainTrusts (
IN LPWSTR ServerName OPTIONAL,
IN ULONG Flags,
OUT PDS_DOMAIN_TRUSTSW *Domains,
OUT PULONG DomainCount
)
/*++
Routine Description:
This API returns the names of the domains trusted by the domain ServerName
is a member of. ServerName is an NT4 machine.
Netlogon's cache of Trusted domain names is maintained in a file across reboots.
As such, the list is available upon boot even if no DC is available.
Arguments:
ServerName - name of remote server (null for local).
Flags - Specifies attributes of trusts which should be returned. These are the flags
of the DS_DOMAIN_TRUSTSW strusture. If a trust entry has any of the bits specified
in Flags set, it will be returned.
Domains - Returns an array of trusted domains.
Buffer must be free using NetApiBufferFree().
DomainCount - Returns a count of the number elements in the Domains array.
Return Value:
NO_ERROR - Success.
ERROR_NO_LOGON_SERVERS - No DC could be found and no cached information is available.
ERROR_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
broken and no cached information is available.
ERROR_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
broken or the password is broken and no cached information is available.
ERROR_INVALID_FLAGS - The Flags parameter has invalid bit(s) set.
ERROR_NOT_SUPPORTED - The server specified is not capable of returning the domain
trusts requested.
--*/
{
NET_API_STATUS NetStatus = NO_ERROR;
NTSTATUS Status;
BUFFER_DESCRIPTOR BufferDescriptor;
ULONG LocalDomainCount;
LSA_HANDLE LsaHandle = NULL;
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomainInfo = NULL;
LPWSTR DomainNames = NULL;
PDS_DOMAIN_TRUSTSW TrustedDomain;
ULONG DummySize;
//
// Initialization
//
BufferDescriptor.Buffer = NULL;
LocalDomainCount = 0;
*Domains = NULL;
*DomainCount = 0;
//
// Validate Flags
//
if ( (Flags & DS_DOMAIN_VALID_FLAGS) == 0 ||
(Flags & ~DS_DOMAIN_VALID_FLAGS) != 0 ) {
NetStatus = ERROR_INVALID_FLAGS;
goto Cleanup;
}
//
// This routine uses old APIs which are not capable of returning
// directly trusting domains. So error out if such trusts are requested.
//
if ( (Flags & DS_DOMAIN_DIRECT_INBOUND) != 0 ) {
NetStatus = ERROR_NOT_SUPPORTED;
goto Cleanup;
}
//
// NetEnumerateTrustedDomains targeted at NT4 server returns directly
// trusted domains only. So call it only if such domains are requested.
// Nothing will be returned for domains in forest if such were requested.
//
if ( Flags & DS_DOMAIN_DIRECT_OUTBOUND ) {
LPTSTR_ARRAY TStrArray;
Status = NetEnumerateTrustedDomains (
ServerName,
&DomainNames );
if (!NT_SUCCESS(Status)) {
NetStatus = NetpNtStatusToApiStatus( Status );
if ( NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
NetStatus = ERROR_NOT_SUPPORTED;
}
goto Cleanup;
}
//
// Handle each trusted domain.
//
TStrArray = (LPTSTR_ARRAY) DomainNames;
while ( !NetpIsTStrArrayEmpty(TStrArray) ) {
UNICODE_STRING CurrentNetbiosDomainName;
//
// Add the domain to the list
//
RtlInitUnicodeString( &CurrentNetbiosDomainName, TStrArray );
Status = NlAllocateForestTrustListEntry (
&BufferDescriptor,
&CurrentNetbiosDomainName,
NULL, // No DNS domain name
DS_DOMAIN_DIRECT_OUTBOUND,
0, // No ParentIndex
TRUST_TYPE_DOWNLEVEL,
0, // No TrustAttributes
NULL, // No Domain Sid
NULL, // No DomainGuid
&DummySize,
&TrustedDomain );
if ( !NT_SUCCESS(Status) ) {
NetStatus = NetpNtStatusToApiStatus( Status );
goto Cleanup;
}
//
// Account for the newly allocated entry
//
LocalDomainCount ++;
//
// Move to the next entry
//
TStrArray = NetpNextTStrArrayEntry( TStrArray );
}
}
//
// NetEnumerateDomainTrusts doesn't return primary domain
// in the list of trusted domains. If the primary domain
// is requested, add it here using info from LSA.
//
if ( Flags & DS_DOMAIN_PRIMARY ) {
UNICODE_STRING UncServerNameString;
OBJECT_ATTRIBUTES ObjectAttributes;
//
// First, open the policy database on the server.
//
RtlInitUnicodeString( &UncServerNameString, ServerName );
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
Status = LsaOpenPolicy( &UncServerNameString,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&LsaHandle );
if ( !NT_SUCCESS(Status) ) {
LsaHandle = NULL;
NetStatus = NetpNtStatusToApiStatus( Status );
goto Cleanup;
}
//
// Get the name of the primary domain from LSA
//
Status = LsaQueryInformationPolicy(
LsaHandle,
PolicyPrimaryDomainInformation,
(PVOID *) &PrimaryDomainInfo
);
if ( !NT_SUCCESS(Status) ) {
NetStatus = NetpNtStatusToApiStatus( Status );
goto Cleanup;
}
//
// Now, add it to our list here.
//
Status = NlAllocateForestTrustListEntry (
&BufferDescriptor,
&PrimaryDomainInfo->Name,
NULL, // No DNS domain name
DS_DOMAIN_PRIMARY,
0, // No ParentIndex
TRUST_TYPE_DOWNLEVEL,
0, // No TrustAttributes
PrimaryDomainInfo->Sid,
NULL, // No DomainGuid
&DummySize,
&TrustedDomain );
if ( !NT_SUCCESS(Status) ) {
NetStatus = NetpNtStatusToApiStatus( Status );
goto Cleanup;
}
//
// And account for the newly allocated entry.
//
LocalDomainCount ++;
}
//
// If we made it up to this point, it's a success!
//
NetStatus = NO_ERROR;
Cleanup:
if ( DomainNames != NULL) {
NetApiBufferFree( DomainNames );
}
if ( LsaHandle != NULL ) {
(VOID) LsaClose( LsaHandle );
}
if ( PrimaryDomainInfo != NULL ) {
(void) LsaFreeMemory( PrimaryDomainInfo );
}
//
// Return the trusted domain list
//
if ( NetStatus == NO_ERROR ) {
*Domains = (PDS_DOMAIN_TRUSTSW)BufferDescriptor.Buffer;
*DomainCount = LocalDomainCount;
} else {
if ( BufferDescriptor.Buffer != NULL ) {
NetApiBufferFree( BufferDescriptor.Buffer );
}
*Domains = NULL;
*DomainCount = 0;
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
DsEnumerateDomainTrustsW (
IN LPWSTR ServerName OPTIONAL,
IN ULONG Flags,
OUT PDS_DOMAIN_TRUSTSW *Domains,
OUT PULONG DomainCount
)
/*++
Routine Description:
This API returns the names of the domains trusting and trusted by the domain ServerName
is a member of.
Netlogon's cache of Trusted domain names is maintained in a file across reboots.
As such, the list is available upon boot even if no DC is available.
Arguments:
ServerName - name of remote server (null for local).
Flags - Specifies attributes of trusts which should be returned. These are the flags
of the DS_DOMAIN_TRUSTSW strusture. If a trust entry has any of the bits specified
in Flags set, it will be returned.
Domains - Returns an array of trusted domains.
Buffer must be free using NetApiBufferFree().
DomainCount - Returns a count of the number elements in the Domains array.
Return Value:
NO_ERROR - Success.
ERROR_NO_LOGON_SERVERS - No DC could be found and no cached information is available.
ERROR_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
broken and no cached information is available.
ERROR_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
broken or the password is broken and no cached information is available.
ERROR_INVALID_FLAGS - The Flags parameter has invalid bit(s) set.
ERROR_NOT_SUPPORTED - The server specified is not capable of returning the domain
trusts requested.
--*/
{
NET_API_STATUS NetStatus;
NETLOGON_TRUSTED_DOMAIN_ARRAY LocalDomains;
//
// Validate the Flags parameter
//
if ( (Flags & DS_DOMAIN_VALID_FLAGS) == 0 ||
(Flags & ~DS_DOMAIN_VALID_FLAGS) != 0 ) {
return ERROR_INVALID_FLAGS;
}
//
// Initialization
//
*DomainCount = 0;
*Domains = NULL;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
LocalDomains.Domains = NULL;
LocalDomains.DomainCount = 0;
NetStatus = DsrEnumerateDomainTrusts (
ServerName,
Flags,
&LocalDomains );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
if ( NetStatus == NO_ERROR ) {
*Domains = LocalDomains.Domains;
*DomainCount = LocalDomains.DomainCount;
//
// Handle the case where the server is an NT4 machine
//
} else if ( NetStatus == RPC_S_PROCNUM_OUT_OF_RANGE ) {
NetStatus = NlpEnumerateNt4DomainTrusts (
ServerName,
Flags,
Domains,
DomainCount );
}
IF_DEBUG( LOGON ) {
NetpKdPrint(("DsEnumerateDomainTrustsW rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
DsEnumerateDomainTrustsA (
IN LPSTR ServerName OPTIONAL,
IN ULONG Flags,
OUT PDS_DOMAIN_TRUSTSA *Domains,
OUT PULONG DomainCount
)
/*++
Routine Description:
This API returns the names of the domains trusting and trusted by the domain ServerName
is a member of.
Netlogon's cache of Trusted domain names is maintained in a file across reboots.
As such, the list is available upon boot even if no DC is available.
Arguments:
ServerName - name of remote server (null for local).
Flags - Specifies attributes of trusts which should be returned. These are the flags
of the DS_DOMAIN_TRUSTSW strusture. If a trust entry has any of the bits specified
in Flags set, it will be returned.
Domains - Returns an array of trusted domains.
Buffer must be free using NetApiBufferFree().
DomainCount - Returns a count of the number elements in the Domains array.
ERROR_NOT_SUPPORTED - The server specified is not capable of returning the domain
trusts requested.
Return Value:
NO_ERROR - Success.
ERROR_NO_LOGON_SERVERS - No DC could be found and no cached information is available.
ERROR_NO_TRUST_LSA_SECRET - The client side of the trust relationship is
broken and no cached information is available.
ERROR_NO_TRUST_SAM_ACCOUNT - The server side of the trust relationship is
broken or the password is broken and no cached information is available.
ERROR_INVALID_FLAGS - The Flags parameter has invalid bit(s) set.
--*/
{
NET_API_STATUS NetStatus;
PDS_DOMAIN_TRUSTSW DomainsW = NULL;
LPWSTR UnicodeServerName = NULL;
LPSTR *TmpNetbiosDomainNameArray = NULL;
LPSTR *TmpDnsDomainNameArray = NULL;
ULONG Size;
ULONG NameSize;
ULONG i;
LPBYTE Where;
//
// Initialization
//
*Domains = NULL;
*DomainCount = 0;
//
// Convert input parameters to Unicode.
//
if ( ServerName != NULL ) {
UnicodeServerName = NetpAllocWStrFromAStr( ServerName );
if ( UnicodeServerName == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
//
// Call the Unicode version of the API
//
NetStatus = DsEnumerateDomainTrustsW ( UnicodeServerName,
Flags,
&DomainsW,
DomainCount );
if ( NetStatus != NO_ERROR || *DomainCount == 0 ) {
goto Cleanup;
}
//
// Allocate the buffer to return to the caller
//
// First allocate temprory ANSI arrays to store the domain names. This is needed
// because there is no easy way to compute the size of ANSI names other than to
// allocate them from Unicode strings and then compute the sizes of the resulting
// ANSI strings.
//
NetStatus = NetApiBufferAllocate( (*DomainCount)*sizeof(LPSTR),
(LPVOID *) &TmpNetbiosDomainNameArray );
if ( NetStatus != NO_ERROR ) {
goto Cleanup;
}
NetStatus = NetApiBufferAllocate( (*DomainCount)*sizeof(LPSTR),
(LPVOID *) &TmpDnsDomainNameArray );
if ( NetStatus != NO_ERROR ) {
goto Cleanup;
}
RtlZeroMemory( TmpNetbiosDomainNameArray, (*DomainCount)*sizeof(LPSTR) );
RtlZeroMemory( TmpDnsDomainNameArray, (*DomainCount)*sizeof(LPSTR) );
Size = 0;
for ( i = 0; i < *DomainCount; i++ ) {
Size += sizeof(DS_DOMAIN_TRUSTSA);
//
// Add the size of the Netbios domain name
//
if ( DomainsW[i].NetbiosDomainName != NULL ) {
TmpNetbiosDomainNameArray[i] = NetpAllocAStrFromWStr( DomainsW[i].NetbiosDomainName );
if ( TmpNetbiosDomainNameArray[i] == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Size += lstrlenA( TmpNetbiosDomainNameArray[i] ) + 1;
} else {
TmpNetbiosDomainNameArray[i] = NULL;
}
//
// Add the size of the DNS domain name
//
if ( DomainsW[i].DnsDomainName != NULL ) {
TmpDnsDomainNameArray[i] = NetpAllocAStrFromWStr( DomainsW[i].DnsDomainName );
if ( TmpDnsDomainNameArray[i] == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
Size += lstrlenA( TmpDnsDomainNameArray[i] ) + 1;
} else {
TmpDnsDomainNameArray[i] = NULL;
}
//
// Add the size of the SID
//
if ( DomainsW[i].DomainSid != NULL ) {
Size += RtlLengthSid( DomainsW[i].DomainSid );
}
Size = ROUND_UP_COUNT( Size, ALIGN_DWORD );
}
NetStatus = NetApiBufferAllocate( Size, Domains );
if ( NetStatus != NO_ERROR ) {
goto Cleanup;
}
//
// Loop copying domains to the caller.
//
Where = (LPBYTE) &((*Domains)[*DomainCount]);
for ( i = 0; i < *DomainCount; i++) {
NTSTATUS Status;
//
// Copy constant length variables
//
(*Domains)[i].Flags = DomainsW[i].Flags;
(*Domains)[i].ParentIndex = DomainsW[i].ParentIndex;
(*Domains)[i].TrustType = DomainsW[i].TrustType;
(*Domains)[i].TrustAttributes = DomainsW[i].TrustAttributes;
(*Domains)[i].DomainGuid = DomainsW[i].DomainGuid;
//
// Copy the (DWORD aligned) SID into the return buffer
//
if ( DomainsW[i].DomainSid != NULL ) {
ULONG SidSize;
(*Domains)[i].DomainSid = (PSID) Where;
SidSize = RtlLengthSid( DomainsW[i].DomainSid );
RtlCopyMemory( Where,
DomainsW[i].DomainSid,
SidSize );
Where += SidSize;
} else {
(*Domains)[i].DomainSid = NULL;
}
//
// Copy the Netbios domain name into the return buffer.
//
if ( DomainsW[i].NetbiosDomainName != NULL ) {
NameSize = lstrlenA( TmpNetbiosDomainNameArray[i] ) + 1;
(*Domains)[i].NetbiosDomainName = (LPSTR) Where;
RtlCopyMemory( Where,
TmpNetbiosDomainNameArray[i],
NameSize );
Where += NameSize;
} else {
(*Domains)[i].NetbiosDomainName = NULL;
}
//
// Copy the DNS domain name into the return buffer.
//
if ( DomainsW[i].DnsDomainName != NULL ) {
NameSize = lstrlenA( TmpDnsDomainNameArray[i] ) + 1;
(*Domains)[i].DnsDomainName = (LPSTR) Where;
RtlCopyMemory( Where,
TmpDnsDomainNameArray[i],
NameSize );
Where += NameSize;
} else {
(*Domains)[i].DnsDomainName = NULL;
}
Where = ROUND_UP_POINTER( Where, ALIGN_DWORD);
}
Cleanup:
if ( DomainsW != NULL ) {
NetApiBufferFree( DomainsW );
}
if ( UnicodeServerName != NULL ) {
NetApiBufferFree( UnicodeServerName );
}
if ( TmpNetbiosDomainNameArray != NULL ) {
for ( i = 0; i < *DomainCount; i++ ) {
if ( TmpNetbiosDomainNameArray[i] != NULL ) {
NetApiBufferFree( TmpNetbiosDomainNameArray[i] );
}
}
NetApiBufferFree( TmpNetbiosDomainNameArray );
}
if ( TmpDnsDomainNameArray != NULL ) {
for ( i = 0; i < *DomainCount; i++ ) {
if ( TmpDnsDomainNameArray[i] != NULL ) {
NetApiBufferFree( TmpDnsDomainNameArray[i] );
}
}
NetApiBufferFree( TmpDnsDomainNameArray );
}
if ( NetStatus != NO_ERROR && *Domains != NULL ) {
NetApiBufferFree( *Domains );
*Domains = NULL;
*DomainCount = 0;
}
IF_DEBUG( LOGON ) {
NetpKdPrint(("DsEnumerateDomainTrustsA rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NTSTATUS
I_NetLogonGetDomainInfo(
IN LPWSTR ServerName,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN DWORD QueryLevel,
IN LPBYTE InBuffer,
OUT LPBYTE *OutBuffer
)
/*++
Routine Description:
This function is used by an NT workstation to query information about the
domain it is a member of.
Arguments:
ServerName -- Name of the DC to retrieve the data from.
ComputerName -- Name of the workstation making the call.
Authenticator -- supplied by the workstation.
ReturnAuthenticator -- Receives an authenticator returned by the DC.
QueryLevel - Level of information to return from the DC. Valid values are:
1: Return NETLOGON_DOMAIN_INFO structure.
InBuffer - Buffer to pass to DC
OutBuffer - Returns a pointer to an allocated buffer containing the queried
information.
Return Value:
STATUS_SUCCESS -- The function completed successfully.
STATUS_ACCESS_DENIED -- The workstations should re-authenticate with
the DC.
--*/
{
NTSTATUS Status = 0;
NETLOGON_DOMAIN_INFORMATION NetlogonDomainInfo;
NETLOGON_WORKSTATION_INFORMATION NetlogonWorkstationInfo;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
*OutBuffer = NULL;
RpcTryExcept {
//
// Call RPC version of the API.
//
NetlogonDomainInfo.DomainInfo = NULL; // Force RPC to allocate
NetlogonWorkstationInfo.WorkstationInfo = (PNETLOGON_WORKSTATION_INFO)InBuffer;
Status = NetrLogonGetDomainInfo(
ServerName,
ComputerName,
Authenticator,
ReturnAuthenticator,
QueryLevel,
&NetlogonWorkstationInfo,
&NetlogonDomainInfo );
if ( NT_SUCCESS(Status) ) {
*OutBuffer = (LPBYTE) NetlogonDomainInfo.DomainInfo;
}
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetLogonGetDomainInfo rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NTSTATUS
NetLogonSetServiceBits(
IN LPWSTR ServerName,
IN DWORD ServiceBitsOfInterest,
IN DWORD ServiceBits
)
/*++
Routine Description:
Inidcates whether this DC is currently running the specified service.
For instance,
NetLogonSetServiceBits( DS_KDC_FLAG, DS_KDC_FLAG );
tells Netlogon the KDC is running. And
NetLogonSetServiceBits( DS_KDC_FLAG, 0 );
tells Netlogon the KDC is not running.
This out of proc API can set only a certain set of bits:
DS_TIMESERV_FLAG
DS_GOOD_TIMESERV_FLAG
If other bits are attempted to be set, access denied is returned.
Arguments:
ServerName -- Name of the DC to retrieve the data from.
ServiceBitsOfInterest - A mask of the service bits being changed, set,
or reset by this call. Only the following flags are valid:
DS_KDC_FLAG
DS_DS_FLAG
DS_TIMESERV_FLAG
ServiceBits - A mask indicating what the bits specified by ServiceBitsOfInterest
should be set to.
Return Value:
STATUS_SUCCESS - Success.
STATUS_INVALID_PARAMETER - The parameters have extaneous bits set.
--*/
{
NTSTATUS Status = 0;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrLogonSetServiceBits(
ServerName,
ServiceBitsOfInterest,
ServiceBits );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("NetLogonSetServiceBits rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NET_API_STATUS NET_API_FUNCTION
I_NetlogonGetTrustRid(
IN LPWSTR ServerName OPTIONAL,
IN LPWSTR DomainName OPTIONAL,
OUT PULONG Rid
)
/*++
Routine Description:
Returns the Rid of the account that ServerName uses in its secure channel to DomainName.
Only an Admin or LocalSystem or LocalService may call this function.
Arguments:
ServerName - The name of the remote server.
DomainName - The name (DNS or Netbios) of the domain the trust is to.
NULL implies the domain the machine is a member of.
Rid - Rid is the RID of the account in the specified domain that represents the
trust relationship between the ServerName and DomainName.
Return Value:
NERR_Success: the operation was successful
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = NetrLogonGetTrustRid (
ServerName,
DomainName,
Rid );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetLogonGetTrustRid rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
I_NetlogonComputeServerDigest(
IN LPWSTR ServerName OPTIONAL,
IN ULONG Rid,
IN LPBYTE Message,
IN ULONG MessageSize,
OUT CHAR NewMessageDigest[NL_DIGEST_SIZE],
OUT CHAR OldMessageDigest[NL_DIGEST_SIZE]
)
/*++
Routine Description:
Compute the message digest for Message on the server.
A digest is computed given the message and the password used on
the account identified by teh account RID. Since there may be up
to 2 passwords on the account (for interdomain trust), this routine
returns 2 digets corresponding to the 2 passwords. If the account
has just one password on the server side (true for any account other
than the intedomain trust account) or the two passwords are the same
the 2 digests returned will be identical.
Only an Admin or LocalSystem or LocalService may call this function.
Arguments:
ServerName - The name of the remote server.
Rid - The RID of the account to create the digest for.
The RID must be the RID of a machine account or the API returns an error.
Message - The message to compute the digest for.
MessageSize - The size of Message in bytes.
NewMessageDigest - Returns the 128-bit digest of the message corresponding to
the new account password.
OldMessageDigest - Returns the 128-bit digest of the message corresponding to
the old account password.
Return Value:
NERR_Success: the operation was successful
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = NetrLogonComputeServerDigest(
ServerName,
Rid,
Message,
MessageSize,
NewMessageDigest,
OldMessageDigest );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetLogonComputeServerDigest rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
I_NetlogonComputeClientDigest(
IN LPWSTR ServerName OPTIONAL,
IN LPWSTR DomainName OPTIONAL,
IN LPBYTE Message,
IN ULONG MessageSize,
OUT CHAR NewMessageDigest[NL_DIGEST_SIZE],
OUT CHAR OldMessageDigest[NL_DIGEST_SIZE]
)
/*++
Routine Description:
Compute the message digest for Message on the client.
A digest is computed given the message and the password used on
the account identified by the domain name. Since there are two
passwords on the account on the client side, this routine
returns 2 digests corresponding to the 2 passwords. If the two
passwords are the same the 2 digests returned will be identical.
Only an Admin or LocalSystem or LocalService may call this function.
Arguments:
ServerName - The name of the remote server.
DomainName - The name (DNS or Netbios) of the domain the trust is to.
NULL implies the domain the machine is a member of.
Message - The message to compute the digest for.
MessageSize - The size of Message in bytes.
NewMessageDigest - Returns the 128-bit digest of the message corresponding
to the new password
NewMessageDigest - Returns the 128-bit digest of the message corresponding
to the new password
Return Value:
NERR_Success: the operation was successful
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = NetrLogonComputeClientDigest(
ServerName,
DomainName,
Message,
MessageSize,
NewMessageDigest,
OldMessageDigest );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetLogonComputeClientDigest rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NTSTATUS
I_NetServerPasswordGet(
IN LPWSTR PrimaryName,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNtOwfPassword
)
/*++
Routine Description:
This function is used to by a BDC to get a machine account password
from the PDC in the doamin.
This function can only be called by a server which has previously
authenticated with a DC by calling I_NetServerAuthenticate.
This function uses RPC to contact the DC named by PrimaryName.
Arguments:
PrimaryName -- Computer name of the PDC to remote the call to.
AccountName -- Name of the account to get the password for.
AccountType -- The type of account being accessed.
ComputerName -- Name of the BDC making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
EncryptedNtOwfPassword -- Returns the OWF password of the account.
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerPasswordGet (
PrimaryName,
AccountName,
AccountType,
ComputerName,
Authenticator,
ReturnAuthenticator,
EncryptedNtOwfPassword );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerPasswordGet rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerTrustPasswordsGet(
IN LPWSTR TrustedDcName,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNewOwfPassword,
OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedOldOwfPassword
)
/*++
Routine Description:
This function is used by a trusting side DC/workstation to get the
new and old passwords from the trusted side. The account name
requested must match the account name used at the secure channel
setup time unless the call is made by a BDC to its PDC; the BDC
has full access to the entire trust info.
This function can only be called by a server which has previously
authenticated with a DC by calling I_NetServerAuthenticate.
This function uses RPC to contact the DC named by TrustedDcName.
Arguments:
TrustedDcName -- Computer name of the DC to remote the call to.
AccountName -- Name of the account to get the password for.
AccountType -- The type of account being accessed.
ComputerName -- Name of the DC making the call.
Authenticator -- supplied by this server.
ReturnAuthenticator -- Receives an authenticator returned by the
trusted side DC.
EncryptedNewOwfPassword -- Returns the new OWF password of the account.
EncryptedOldOwfPassword -- Returns the old OWF password of the account.
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrServerTrustPasswordsGet (
TrustedDcName,
AccountName,
AccountType,
ComputerName,
Authenticator,
ReturnAuthenticator,
EncryptedNewOwfPassword,
EncryptedOldOwfPassword );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerTrustPasswordsGet rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NTSTATUS
I_NetServerGetTrustInfo(
IN LPWSTR TrustedDcName,
IN LPWSTR AccountName,
IN NETLOGON_SECURE_CHANNEL_TYPE AccountType,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedNewOwfPassword,
OUT PENCRYPTED_NT_OWF_PASSWORD EncryptedOldOwfPassword,
OUT PNL_GENERIC_RPC_DATA *TrustInfo
)
/*++
Routine Description:
This function is used by a trusting side DC/workstation to get the
trust info (new and old passwords and trust attributes) from the
trusted side. The account name requested must match the account
name used at the secure channel setup time unless the call is made
by a BDC to its PDC; the BDC has full access to the entire trust info.
This function can only be called by a server which has previously
authenticated with a DC by calling I_NetServerAuthenticate.
This function uses RPC to contact the DC named by TrustedDcName.
Arguments:
TrustedDcName -- Computer name of the DC to remote the call to.
AccountName -- Name of the account to get the password for.
AccountType -- The type of account being accessed.
ComputerName -- Name of the DC making the call.
Authenticator -- supplied by this server.
ReturnAuthenticator -- Receives an authenticator returned by the
trusted side DC.
EncryptedNewOwfPassword -- Returns the new OWF password of the account.
EncryptedOldOwfPassword -- Returns the old OWF password of the account.
TrustInfo -- Returns trust info data (currently trust attributes)
Return Value:
NT status code.
--*/
{
NTSTATUS Status;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
*TrustInfo = NULL; // Force RPC to allocate
Status = NetrServerGetTrustInfo(
TrustedDcName,
AccountName,
AccountType,
ComputerName,
Authenticator,
ReturnAuthenticator,
EncryptedNewOwfPassword,
EncryptedOldOwfPassword,
TrustInfo );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetServerGetTrustInfo rc = %lu 0x%lx\n", Status, Status));
}
return Status;
}
NET_API_STATUS
NetLogonGetTimeServiceParentDomain(
IN LPWSTR ServerName OPTIONAL,
OUT LPWSTR *DomainName,
OUT PBOOL PdcSameSite
)
/*++
Routine Description:
Returns the domain name of the domain that is logically the "parent" of this
domain. The returned domain name is suitable for passing into the
NetLogonGetTrustRid and NetLogonComputeClientDigest API.
On a workstation or member server, the returned domain name is that of the
domain that ServerName is a member of.
On a DC that is at the root of the forest, ERROR_NO_SUCH_DOMAIN is returned.
On a DC that is at the root of a tree in the forest, the name of a trusted
domain that is also at the root of a tree in the forest is returned.
On any other DC, the name of the domain that is directly the parent domain
is returned.
(See the notes on multiple hosted domains in the code below.)
Only an Admin or LocalSystem may call this function.
Arguments:
ServerName - The name of the remote server.
DomainName - Returns the name of the parent domain.
The returned buffer should be freed using NetApiBufferFree
PdcSameSite - Return TRUE if the PDC of ServerName's domain is in the same
site as ServerName.
(This value should be ignored if ServerName is not a DC.)
Return Value:
NERR_Success: the operation was successful
ERROR_NO_SUCH_DOMAIN: This server is a DC in the domain that is at the
root of the forest.
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
*DomainName = NULL;
NetStatus = NetrLogonGetTimeServiceParentDomain (
ServerName,
DomainName,
PdcSameSite );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
DsDeregisterDnsHostRecordsW (
IN LPWSTR ServerName OPTIONAL,
IN LPWSTR DnsDomainName OPTIONAL,
IN GUID *DomainGuid OPTIONAL,
IN GUID *DsaGuid OPTIONAL,
IN LPWSTR DnsHostName
)
/*++
Routine Description:
This function deletes all DNS entries associated with a particular
NtDsDsa object.
This routine does NOT delete A records registered by the DC. We have
no way of finding out the IP addresses of the long gone DC.
Only an Admin, Account Operator or Server Operator may call this
function.
Arguments:
ServerName - name of remote server (null for local).
DnsDomainName - DNS domain name of the domain the DC was in.
This need not be a domain hosted by this DC.
If NULL, it is implied to be the DnsHostName with the leftmost label
removed.
DomainGuid - Domain Guid of the domain.
If NULL, GUID specific names will not be removed.
DsaGuid - GUID of the NtdsDsa object that will be deleted.
If NULL, NtdsDsa specific names will not be removed.
DnsHostName - DNS host name of the DC whose DNS records are being deleted.
Return Value:
NO_ERROR - Success.
ERROR_NOT_SUPPORTED - The server specified is not a DC.
ERROR_ACCESS_DENIED - The caller is not allowed to perform this operation.
--*/
{
NET_API_STATUS NetStatus;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = DsrDeregisterDnsHostRecords (
ServerName,
DnsDomainName,
DomainGuid,
DsaGuid,
DnsHostName );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("DsDeregisterDnsHostRecordsW rc = %lu 0x%lx\n",
NetStatus, NetStatus));
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
DsDeregisterDnsHostRecordsA (
IN LPSTR ServerName OPTIONAL,
IN LPSTR DnsDomainName OPTIONAL,
IN GUID *DomainGuid OPTIONAL,
IN GUID *DsaGuid OPTIONAL,
IN LPSTR DnsHostName
)
/*++
Routine Description:
This function deletes all DNS entries associated with a particular
NtDsDsa object.
This routine does NOT delete A records registered by the DC. We have
no way of finding out the IP addresses of the long gone DC.
Only an Admin, Account Operator or Server Operator may call this
function.
Arguments:
ServerName - name of remote server (null for local).
DnsDomainName - DNS domain name of the domain the DC was in.
This need not be a domain hosted by this DC.
If NULL, it is implied to be the DnsHostName with the leftmost label
removed.
DomainGuid - Domain Guid of the domain specified
by DnsDomainName. If NULL, GUID specific names will not be removed.
DsaGuid - GUID of the NtdsDsa object that will be deleted.
If NULL, NtdsDsa specific names will not be removed.
DnsHostName - DNS host name of the DC whose DNS records are being deleted.
Return Value:
NO_ERROR - Success.
ERROR_NOT_SUPPORTED - The server specified is not a DC.
ERROR_ACCESS_DENIED - The caller is not allowed to perform this operation.
--*/
{
NET_API_STATUS NetStatus;
LPWSTR UnicodeServerName = NULL;
LPWSTR UnicodeDnsDomainName = NULL;
LPWSTR UnicodeDnsHostName = NULL;
//
// Convert input parameters to Unicode.
//
if ( ServerName != NULL ) {
UnicodeServerName = NetpAllocWStrFromAStr( ServerName );
if ( UnicodeServerName == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
if ( DnsDomainName != NULL ) {
UnicodeDnsDomainName = NetpAllocWStrFromAStr( DnsDomainName );
if ( UnicodeDnsDomainName == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
if ( DnsHostName != NULL ) {
UnicodeDnsHostName = NetpAllocWStrFromAStr( DnsHostName );
if ( UnicodeDnsHostName == NULL ) {
NetStatus = ERROR_NOT_ENOUGH_MEMORY;
goto Cleanup;
}
}
//
// Call the Unicode routine
//
NetStatus = DsDeregisterDnsHostRecordsW (
UnicodeServerName,
UnicodeDnsDomainName,
DomainGuid,
DsaGuid,
UnicodeDnsHostName );
Cleanup:
if ( UnicodeServerName != NULL ) {
NetApiBufferFree( UnicodeServerName );
}
if ( UnicodeDnsDomainName != NULL ) {
NetApiBufferFree( UnicodeDnsDomainName );
}
if ( UnicodeDnsHostName != NULL ) {
NetApiBufferFree( UnicodeDnsHostName );
}
return NetStatus;
}
NET_API_STATUS NET_API_FUNCTION
DsGetForestTrustInformationW (
IN LPCWSTR ServerName OPTIONAL,
IN LPCWSTR TrustedDomainName OPTIONAL,
IN DWORD Flags,
OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
)
/*++
Routine Description:
DsGetForestTrustInformation returns an array of FTInfo records. The records can
be TLN or domain NscType records.
The TLN records returned by DsGetForestTrustInformation are collected from three
sources:
* The DNS domain names of each tree in the forest.
* The values of the Upn-Suffixes attribute on the Partitions container object
within the config container.
* The values of the Spn-Suffixes attribute on the Partitions container object
within the config container.
Each of these names is a candidate for being a TLN returned from the API.
However, some names are not returned if they are a suffix of one of the other
TLN candidates. For instance, if acme.com is a Upn Suffix and a.acme.com is
the dns domain name of one of the trees in the forest, only acme.com will be
returned.
The domain records returned from DsGetForestTrustInformation are collected by
internally calling DsEnumerateDomainTrusts with the DS_DOMAIN_IN_FOREST.
For each domain returned from that API, the Dns domain name, netbios domain name
and domain sid are returned in the domain FTinfo entry.
This section describes the DS_GFTI_UPDATE_TDO flag bit in more detail. When
this bit is specified, the FTinfo records written to the TDO is a combination
of the FTInfo records currently on the TDO and the FTInfo records returned from
the trusted domain. The merge is done as described for the
DsMergeForestTrustInformationW API.
Arguments:
ServerName - The name of the domain controller this API is remoted to.
The caller must be an "Authenticated User" on ServerName.
If NULL is specified, the local server is implied.
TrustedDomainName - The name of the TrustedDomain that the forest trust information
is to be gathered for. If TrustedDomainName is NULL, the forest trust
information for the domain hosted by ServerName is returned.
If TrustedDomainInformation is not null, it must specify the netbios domain
name or dns domain name of an outbound trusted domain with the
TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set. In that case, this API obtains
the forest trust information by making an RPC call over netlogon's secure
channel to obtain the forest trust information from that domain.
Flags - Specifies a set of bits that modify the behavior of the API.
Valid bits are:
DS_GFTI_UPDATE_TDO - If this bit is set, the API will update
the FTinfo attribute of the TDO named by the TrustedDomainName
parameter. The TrustedDomainName parameter may not be NULL.
The caller must have access to modify the FTinfo attribute or
ERROR_ACCESS_DENIED will be returned. The algorithm describing
how the FTinfo from the trusted domain is merged with the FTinfo
from the TDO is described below.
This bit in only valid if ServerName specifies the PDC of its domain.
ForestTrustInfo - Returns a pointer to a structure containing a count and an
array of FTInfo records describing the namespaces claimed by the
domain specified by TrustedDomainName. The Accepted field and Time
field of all returned records will be zero. The buffer should be freed
by calling NetApiBufferFree.
Return Value:
NO_ERROR - Success.
ERROR_INVALID_FLAGS - An invalid value was passed for FLAGS
ERROR_INVALID_FUNCTION - The domain specified by TrustedDomainName does not have the
TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set on the TDO on the trusted DC.
ERROR_NO_SUCH_DOMAIN - The domain specified by TrustedDomainName does not exist or
does not have that TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set on the TDO on ServerName.
--*/
{
NET_API_STATUS NetStatus;
PLSA_FOREST_TRUST_INFORMATION LocalForestTrustInfo = NULL;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
NetStatus = DsrGetForestTrustInformation (
(LPWSTR) ServerName,
(LPWSTR) TrustedDomainName,
Flags,
&LocalForestTrustInfo );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
NetStatus = RpcExceptionCode();
} RpcEndExcept;
if ( NetStatus == NO_ERROR ) {
*ForestTrustInfo = LocalForestTrustInfo;
}
return NetStatus;
}
NTSTATUS
I_NetGetForestTrustInformation (
IN LPWSTR ServerName OPTIONAL,
IN LPWSTR ComputerName,
IN PNETLOGON_AUTHENTICATOR Authenticator,
OUT PNETLOGON_AUTHENTICATOR ReturnAuthenticator,
IN DWORD Flags,
OUT PLSA_FOREST_TRUST_INFORMATION *ForestTrustInfo
)
/*++
Routine Description:
The secure channel version of DsGetForestTrustInformation.
The inbound secure channel identified by ComputerName must be for an interdomain trust
and the inbound TDO must have the TRUST_ATTRIBUTE_FOREST_TRANSITIVE bit set.
Arguments:
ServerName - The name of the domain controller this API is remoted to.
ComputerName -- Name of the DC server making the call.
Authenticator -- supplied by the server.
ReturnAuthenticator -- Receives an authenticator returned by the PDC.
Flags - Specifies a set of bits that modify the behavior of the API.
No values are currently defined. The caller should pass zero.
ForestTrustInfo - Returns a pointer to a structure containing a count and an
array of FTInfo records describing the namespaces claimed by the
domain specified by TrustedDomainName. The Accepted field and Time
field of all returned records will be zero. The buffer should be freed
by calling NetApiBufferFree.
Return Value:
STATUS_SUCCESS -- The function completed successfully.
STATUS_ACCESS_DENIED -- The replicant should re-authenticate with
the PDC.
--*/
{
NTSTATUS Status;
//
// Do the RPC call with an exception handler since RPC will raise an
// exception if anything fails. It is up to us to figure out what
// to do once the exception is raised.
//
RpcTryExcept {
//
// Call RPC version of the API.
//
Status = NetrGetForestTrustInformation(
ServerName,
ComputerName,
Authenticator,
ReturnAuthenticator,
Flags,
ForestTrustInfo );
} RpcExcept( I_RpcExceptionFilter(RpcExceptionCode()) ) {
Status = I_RpcMapWin32Status(RpcExceptionCode());
} RpcEndExcept;
IF_DEBUG( LOGON ) {
NetpKdPrint(("I_NetGetForestTrustInformation rc = %lu 0x%lx\n",
Status, Status));
}
return Status;
}
NET_API_STATUS NET_API_FUNCTION
DsMergeForestTrustInformationW(
IN LPCWSTR DomainName,
IN PLSA_FOREST_TRUST_INFORMATION NewForestTrustInfo,
IN PLSA_FOREST_TRUST_INFORMATION OldForestTrustInfo OPTIONAL,
OUT PLSA_FOREST_TRUST_INFORMATION *MergedForestTrustInfo
)
/*++
Routine Description:
This function merges the changes from a new FTinfo into an old FTinfo and
produces the resultant FTinfo.
This routine will be modified in future releases to support new forest trust record
types. It is intended that the OldForestTrustInfo describes the FTinfo as currently
stored on the local TDO. It is intended that the NewForestTrustInfo is the FTinfo as
returned from DsGetForestTrustInformationW for DomainName. The MergedForestTrustInfo is
the resultant ForestTrustInfo that should be written to the local TDO. Don't use this
routine for any other purpose.
The merged FTinfo records are a combinition of the new and old records.
Here's where the merged records come from:
??? Add more here about where records are valid etc.
* The TLN exclusion records are copied from the TDO intact.
* The TLN record from the trusted domain that maps to the dns domain name of the
TDO is copied enabled. This reflects the LSA requirement that such a TLN not
be disabled. For instance, if the TDO is for a.acme.com and there is a TLN for
a.acme.com that TLN will be enabled. Also, if the TDO is for a.acme.com and
there is a TLN for acme.com, that TLN will be enabled.
* All other TLN records from the trusted domain are copied disabled with the
following exceptions. If there is an enabled TLN on the TDO, all TLNs from the
trusted domain that equal (or are subordinate to) the TDO TLN are marked as
enabled. This follows the philosophy that new TLNs are imported as disabled.
For instance, if the TDO had an enabled TLN for a.acme.com that TLN will still
be enabled after the automatic update. If the TDO had an enabled TLN for
acme.com and the trusted forest now has a TLN for a.acme.com, the resultant
FTinfo will have an enabled TLN for a.acme.com.
* The domain records from the trusted domain are copied enabled with the
following exceptions. If there is a disabled domain record on the TDO whose
dns domain name, or domain sid exactly matches the domain record, then the domain
remains disabled. If there is a domain record on the TDO whose netbios name is
disabled and whose netbios name exactly matches the netbios name on a domain
record, then the netbios name is disabled.
Arguments:
TrustedDomainName - Trusted domain that is to be updated.
NewForestTrustInfo - Specified the new array of FTinfo records as returned from the
TrustedDomainName.
The Flags field and Time field of the TLN entries are ignored.
OldForestTrustInfo - Specified the array of FTinfo records as returned from the
TDO. This field may be NULL if there is no existing records.
MergedForestTrustInfo - Returns the resulant FTinfo records.
The caller should free this buffer using MIDL_user_free.
Return Value:
NO_ERROR: Success
--*/
{
NTSTATUS Status;
UNICODE_STRING DomainNameString;
RtlInitUnicodeString( &DomainNameString, DomainName );
//
// Call the worker routine
//
Status = NetpMergeFtinfo( &DomainNameString,
NewForestTrustInfo,
OldForestTrustInfo,
MergedForestTrustInfo );
return NetpNtStatusToApiStatus( Status );
}