You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1124 lines
29 KiB
1124 lines
29 KiB
/*++
|
|
|
|
Microsoft Windows
|
|
|
|
Copyright (C) Microsoft Corporation, 1998 - 2001
|
|
|
|
Module Name:
|
|
|
|
time.c
|
|
|
|
Abstract:
|
|
|
|
Handles the various functions for the time functionality of netdom
|
|
|
|
--*/
|
|
#include "pch.h"
|
|
#pragma hdrstop
|
|
#include <netdom.h>
|
|
|
|
|
|
DWORD
|
|
NetDompTimeGetDc(
|
|
IN PWSTR Domain,
|
|
IN PWSTR DestServer,
|
|
IN PND5_AUTH_INFO AuthInfo,
|
|
OUT PWSTR *Dc
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will find the DC to use as a time source for the given machine
|
|
|
|
Arguments:
|
|
|
|
Domain - Domain to get a time source from
|
|
|
|
DestServer - Server for which we need a time source
|
|
|
|
AuthInfo - Auth info to connect to the destination server for
|
|
|
|
Dc - Where the dc name is returned. Freed via NetApiBufferFree
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_PARAMETER - No object name was supplied
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
PDOMAIN_CONTROLLER_INFO DcInfo = NULL;
|
|
BOOL Retry = FALSE;
|
|
WCHAR FlatName[ CNLEN + 1 ];
|
|
ULONG Len = CNLEN + 1;
|
|
|
|
//
|
|
// Get a server name
|
|
//
|
|
Win32Err = DsGetDcName( NULL,
|
|
Domain,
|
|
NULL,
|
|
NULL,
|
|
DS_GOOD_TIMESERV_PREFERRED,
|
|
&DcInfo );
|
|
|
|
//
|
|
// If we have a destination server specified, make sure that we
|
|
// aren't talking to ourselves... That would kind of defeat the purpose
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS && DestServer ) {
|
|
|
|
if ( !_wcsicmp( DcInfo->DomainControllerName + 2, DestServer ) ) {
|
|
|
|
Retry = TRUE;
|
|
|
|
} else {
|
|
|
|
//
|
|
// Handle the case where we have a Dns dc name and a netbios server name
|
|
//
|
|
if ( wcslen( DestServer ) <= CNLEN && FLAG_ON( DcInfo->Flags, DS_IS_DNS_NAME ) ) {
|
|
|
|
if ( !DnsHostnameToComputerName( DcInfo->DomainControllerName + 2,
|
|
FlatName,
|
|
&Len ) ) {
|
|
|
|
Win32Err = GetLastError();
|
|
|
|
} else {
|
|
|
|
if ( !_wcsicmp( FlatName, DestServer ) ) {
|
|
|
|
Retry = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have a dc name specified, so connect to that machine, and try it again, with
|
|
// the AvoidSelf flag. If we can't (like this is an NT4 PDC) then return that we
|
|
// can't find a dc
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS && Retry ) {
|
|
|
|
NetApiBufferFree( DcInfo );
|
|
DcInfo = NULL;
|
|
|
|
Win32Err = NetpManageIPCConnect( DestServer,
|
|
AuthInfo->User,
|
|
AuthInfo->Password,
|
|
NETSETUPP_CONNECT_IPC );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = DsGetDcName( DestServer,
|
|
Domain,
|
|
NULL,
|
|
NULL,
|
|
DS_GOOD_TIMESERV_PREFERRED | DS_AVOID_SELF,
|
|
&DcInfo );
|
|
|
|
NetpManageIPCConnect( DestServer,
|
|
AuthInfo->User,
|
|
AuthInfo->Password,
|
|
NETSETUPP_DISCONNECT_IPC );
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the name if everything worked
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = NetApiBufferAllocate( ( wcslen( DcInfo->DomainControllerName + 2 ) + 1 ) *
|
|
sizeof( WCHAR ),
|
|
(PVOID*)Dc );
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
wcscpy( *Dc, DcInfo->DomainControllerName + 2 );
|
|
}
|
|
}
|
|
|
|
NetApiBufferFree( DcInfo );
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NetDompEnableSystimePriv(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will enable the systemtime privilege for the current thread
|
|
|
|
Arguments:
|
|
|
|
VOID
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_PARAMETER - No object name was supplied
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
HANDLE ThreadToken;
|
|
TOKEN_PRIVILEGES Enabled, Previous;
|
|
DWORD PreviousSize;
|
|
|
|
Status = NtOpenThreadToken( NtCurrentThread(),
|
|
TOKEN_READ | TOKEN_WRITE,
|
|
TRUE,
|
|
&ThreadToken );
|
|
|
|
if ( Status == STATUS_NO_TOKEN ) {
|
|
|
|
Status = NtOpenProcessToken( NtCurrentProcess(),
|
|
TOKEN_WRITE | TOKEN_READ,
|
|
&ThreadToken );
|
|
}
|
|
|
|
if ( NT_SUCCESS( Status ) ) {
|
|
|
|
Enabled.PrivilegeCount = 1;
|
|
Enabled.Privileges[0].Luid.LowPart = SE_SYSTEMTIME_PRIVILEGE;
|
|
Enabled.Privileges[0].Luid.HighPart = 0;
|
|
Enabled.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
|
|
PreviousSize = sizeof( Previous );
|
|
|
|
Status = NtAdjustPrivilegesToken( ThreadToken,
|
|
FALSE,
|
|
&Enabled,
|
|
sizeof( Enabled ),
|
|
&Previous,
|
|
&PreviousSize );
|
|
}
|
|
|
|
return( RtlNtStatusToDosError( Status ) );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NetDompGetTimeTripLength(
|
|
IN PWSTR Server,
|
|
IN OUT PDWORD TripLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will get an approximate elapsed time for getting the time from a domain
|
|
controller
|
|
|
|
Arguments:
|
|
|
|
Server - Server to get the elapsed trip time for
|
|
|
|
TripLength - Number of ticks it takes to get the time
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function succeeded
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
ULONG StartTime, EndTime, ElapsedTime = 0, i;
|
|
PTIME_OF_DAY_INFO TOD;
|
|
#define NETDOMP_NUM_TRIPS 2
|
|
|
|
//
|
|
// Get the average from several time trips
|
|
//
|
|
for ( i = 0; i < NETDOMP_NUM_TRIPS && Win32Err == ERROR_SUCCESS; i++ ) {
|
|
|
|
StartTime = GetTickCount();
|
|
Win32Err = NetRemoteTOD( Server, ( LPBYTE * )&TOD );
|
|
EndTime = GetTickCount();
|
|
ElapsedTime += ( EndTime - StartTime );
|
|
|
|
NetApiBufferFree( TOD );
|
|
}
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
*TripLength = ElapsedTime / NETDOMP_NUM_TRIPS;
|
|
}
|
|
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
DWORD
|
|
NetDompResetSingleClient(
|
|
IN PWSTR Server,
|
|
IN PWSTR Dc,
|
|
IN PND5_AUTH_INFO ObjectAuthInfo,
|
|
IN DWORD DcDelay
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sync the time between and NT5 client and the specified domain controller
|
|
|
|
Arguments:
|
|
|
|
Server - Server to reset the time for
|
|
|
|
Dc - Domain controller to sync the time against
|
|
|
|
ObjectAuthInfo - User info to connect to the server as
|
|
|
|
DcDelay - The amount of time it takes to talk to the dc
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function succeeded
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
BOOL Connected = FALSE;
|
|
//PSTR ServerA = NULL;
|
|
|
|
//
|
|
// Set up a connection to the client machine
|
|
//
|
|
Win32Err = NetpManageIPCConnect( Server,
|
|
ObjectAuthInfo->User,
|
|
ObjectAuthInfo->Password,
|
|
NETSETUPP_CONNECT_IPC );
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Connected = TRUE;
|
|
|
|
} else {
|
|
|
|
goto ResetSingleError;
|
|
}
|
|
|
|
//if ( Server ) {
|
|
//
|
|
// Win32Err = NetApiBufferAllocate( wcstombs( NULL, Server, wcslen( Server ) + 1 ) + 3,
|
|
// &ServerA );
|
|
// if ( Win32Err != ERROR_SUCCESS ) {
|
|
//
|
|
// goto ResetSingleError;
|
|
// }
|
|
//
|
|
// if ( *Server == L'\\' ) {
|
|
//
|
|
// strcpy( ServerA, "\\\\" );
|
|
// wcstombs( ServerA + 2, Server, wcslen( Server ) + 1 );
|
|
//
|
|
// } else {
|
|
//
|
|
// wcstombs( ServerA, Server, wcslen( Server ) + 1 );
|
|
// }
|
|
//}
|
|
|
|
Win32Err = W32TimeSyncNow( Server,
|
|
FALSE, // no wait
|
|
TimeSyncFlag_HardResync );
|
|
|
|
ResetSingleError:
|
|
|
|
if ( Connected ) {
|
|
|
|
NetpManageIPCConnect( Server,
|
|
ObjectAuthInfo->User,
|
|
ObjectAuthInfo->Password,
|
|
NETSETUPP_DISCONNECT_IPC );
|
|
}
|
|
|
|
//NetApiBufferFree( ServerA );
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
DWORD
|
|
NetDompVerifySingleClient(
|
|
IN PWSTR Server,
|
|
IN PWSTR Dc,
|
|
IN PND5_AUTH_INFO ObjectAuthInfo,
|
|
IN DWORD DcDelay,
|
|
IN BOOL * InSync
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will verify that the time between the specified server and domain controller
|
|
is within the acceptable skew
|
|
|
|
Arguments:
|
|
|
|
Server - Server to verify the time for
|
|
|
|
Dc - Domain controller to verify the time against
|
|
|
|
ObjectAuthInfo - User and password to connect to the client as
|
|
|
|
DcDelay - How long does it take to get the time from the domain controller
|
|
|
|
InSync - Where the results are returned.
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function succeeded
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
SYSTEMTIME StartTime, EndTime;
|
|
PTIME_OF_DAY_INFO DcTOD = NULL, ClientTOD = NULL;
|
|
BOOL Connected = FALSE;
|
|
FILETIME StartFile, EndFile;
|
|
LARGE_INTEGER ElapsedTime, TimeDifference, DcTime, ClientTime, UpdatedDcTime, TimeSkew,
|
|
AllowedSkew;
|
|
TIME_FIELDS TimeFields;
|
|
LARGE_INTEGER SystemTime;
|
|
|
|
//
|
|
// Set the allowable time skew. 600,000,000L is the number of 100 nanoseconds in a minute
|
|
//
|
|
#define NETDOMP_VERIFY_SKEW 0xB2D05E00
|
|
|
|
//
|
|
// Assume the clocks are fine
|
|
//
|
|
*InSync = TRUE;
|
|
|
|
//
|
|
// Set up a connection to the client machine
|
|
//
|
|
Win32Err = NetpManageIPCConnect( Server,
|
|
ObjectAuthInfo->User,
|
|
ObjectAuthInfo->Password,
|
|
NETSETUPP_CONNECT_IPC );
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Connected = TRUE;
|
|
|
|
} else {
|
|
|
|
goto VerifySingleError;
|
|
}
|
|
|
|
//
|
|
// Ok, first, we get the time on the dc, then we get the time on the client, keeping in mind
|
|
// how long that takes,
|
|
//
|
|
Win32Err = NetRemoteTOD( Dc, ( LPBYTE * )&DcTOD );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = NetRemoteTOD( Server, ( LPBYTE * )&ClientTOD );
|
|
|
|
}
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto VerifySingleError;
|
|
}
|
|
|
|
//
|
|
// Ok, now we've gotten all the info we need, assemble it... Note that we are only computing
|
|
// the difference in time here...
|
|
//
|
|
SystemTimeToFileTime( &StartTime, &StartFile );
|
|
SystemTimeToFileTime( &EndTime, &EndFile );
|
|
|
|
|
|
ElapsedTime = RtlLargeIntegerSubtract( *( PLARGE_INTEGER )&EndFile,
|
|
*( PLARGE_INTEGER )&StartFile );
|
|
|
|
|
|
TimeFields.Hour = ( WORD )DcTOD->tod_hours;
|
|
TimeFields.Minute = ( WORD )DcTOD->tod_mins;
|
|
TimeFields.Second = ( WORD )DcTOD->tod_secs;
|
|
TimeFields.Milliseconds = ( WORD )DcTOD->tod_hunds * 10;
|
|
TimeFields.Day = ( WORD )DcTOD->tod_day;
|
|
TimeFields.Month = ( WORD )DcTOD->tod_month;
|
|
TimeFields.Year = ( WORD )DcTOD->tod_year;
|
|
|
|
if ( !RtlTimeFieldsToTime( &TimeFields, &DcTime ) ) {
|
|
|
|
Win32Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
TimeFields.Hour = ( WORD )ClientTOD->tod_hours;
|
|
TimeFields.Minute = ( WORD )ClientTOD->tod_mins;
|
|
TimeFields.Second = ( WORD )ClientTOD->tod_secs;
|
|
TimeFields.Milliseconds = ( WORD )ClientTOD->tod_hunds * 10;
|
|
TimeFields.Day = ( WORD )ClientTOD->tod_day;
|
|
TimeFields.Month = ( WORD )ClientTOD->tod_month;
|
|
TimeFields.Year = ( WORD )ClientTOD->tod_year;
|
|
|
|
if ( !RtlTimeFieldsToTime( &TimeFields, &ClientTime ) ) {
|
|
|
|
Win32Err = ERROR_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Add the time it takes to get the time from the dc.
|
|
//
|
|
UpdatedDcTime = RtlLargeIntegerAdd( DcTime, ElapsedTime );
|
|
|
|
//
|
|
// Compute the difference in time
|
|
//
|
|
if ( RtlLargeIntegerGreaterThan( UpdatedDcTime, ClientTime ) ) {
|
|
|
|
TimeSkew = RtlLargeIntegerSubtract( UpdatedDcTime,
|
|
ClientTime );
|
|
} else {
|
|
|
|
TimeSkew = RtlLargeIntegerSubtract( ClientTime,
|
|
UpdatedDcTime );
|
|
}
|
|
|
|
//
|
|
// Now, see if there is a time difference greater than the allowable skew
|
|
//
|
|
AllowedSkew = RtlConvertUlongToLargeInteger( NETDOMP_VERIFY_SKEW );
|
|
|
|
if ( RtlLargeIntegerGreaterThan( TimeSkew, AllowedSkew ) ) {
|
|
|
|
*InSync = FALSE;
|
|
}
|
|
|
|
|
|
|
|
|
|
VerifySingleError:
|
|
|
|
if ( Connected ) {
|
|
|
|
NetpManageIPCConnect( Server,
|
|
ObjectAuthInfo->User,
|
|
ObjectAuthInfo->Password,
|
|
NETSETUPP_DISCONNECT_IPC );
|
|
}
|
|
|
|
NetApiBufferFree( ClientTOD );
|
|
NetApiBufferFree( DcTOD );
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
NetDompDisplayTimeVerify(
|
|
IN PWSTR Server,
|
|
IN DWORD Results,
|
|
IN BOOL InSync
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will display the results of the time verification
|
|
|
|
Arguments:
|
|
|
|
Server - Server which had the time verified
|
|
|
|
Results - The error code of the verification attempt
|
|
|
|
InSync - Whether the clocks are within the skew. Only valid if Results is ERROR_SUCCESS
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
--*/
|
|
{
|
|
NetDompDisplayMessage( MSG_TIME_COMPUTER, Server );
|
|
if ( Results != ERROR_SUCCESS ) {
|
|
|
|
NetDompDisplayErrorMessage( Results );
|
|
|
|
} else {
|
|
|
|
NetDompDisplayMessage( InSync ? MSG_TIME_SUCCESS : MSG_TIME_FAILURE );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NetDompVerifyTime(
|
|
IN PWSTR Domain,
|
|
IN PWSTR Server, OPTIONAL
|
|
IN PND5_AUTH_INFO DomainAuthInfo,
|
|
IN PND5_AUTH_INFO ObjectAuthInfo,
|
|
IN PWSTR Dc,
|
|
IN BOOL AllWorkstation,
|
|
IN BOOL AllServer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will verify the time between some or all of the servers/workstations in a
|
|
domain against the specified domain controller
|
|
|
|
Arguments:
|
|
|
|
Domain - Domain containing the servers/workstations
|
|
|
|
Server - Name of a specific machine to verify the time for
|
|
|
|
DomainAuthInfo - User and password for the domain controller
|
|
|
|
ObjectAuthInfo - User and password for the servers/workstations
|
|
|
|
Dc - Name of a domain controller in the domain to use as a time source
|
|
|
|
AllWorkstation - If TRUE, verify the time for all the workstations
|
|
|
|
AllServer - If TRUE, verify the time for all the servers
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function succeeded
|
|
|
|
ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS, Err2;
|
|
BOOL DcSession = FALSE, InSync;
|
|
DWORD DcDelay;
|
|
LPUSER_INFO_0 UserList = NULL;
|
|
PWSTR FullDc = NULL, Lop;
|
|
ULONG ResumeHandle = 0, Count = 0, TotalCount = 0, i, j;
|
|
ULONG Types[] = {
|
|
FILTER_WORKSTATION_TRUST_ACCOUNT,
|
|
FILTER_SERVER_TRUST_ACCOUNT
|
|
};
|
|
BOOL ProcessType[ sizeof( Types ) / sizeof( ULONG ) ];
|
|
|
|
ProcessType[ 0 ] = AllWorkstation;
|
|
ProcessType[ 1 ] = AllServer;
|
|
|
|
//
|
|
// Make sure that there is something to do
|
|
//
|
|
if ( !Server && !AllWorkstation && !AllServer ) {
|
|
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
//
|
|
// Build a full machine name
|
|
//
|
|
if ( Dc && *Dc != L'\\' ) {
|
|
|
|
Win32Err = NetApiBufferAllocate( ( wcslen( Dc ) + 3 ) * sizeof( WCHAR ),
|
|
( PVOID * )&FullDc );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
swprintf( FullDc, L"\\\\%ws", Dc );
|
|
}
|
|
|
|
} else {
|
|
|
|
FullDc = Dc;
|
|
}
|
|
|
|
|
|
//
|
|
// Set up a session
|
|
//
|
|
Win32Err = NetpManageIPCConnect( FullDc,
|
|
DomainAuthInfo->User,
|
|
DomainAuthInfo->Password,
|
|
NETSETUPP_CONNECT_IPC );
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
DcSession = FALSE;
|
|
}
|
|
|
|
//
|
|
// See how long it takes to get to the dc
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = NetDompGetTimeTripLength( Dc,
|
|
&DcDelay );
|
|
}
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto VerifyTimeError;
|
|
}
|
|
|
|
|
|
NetDompDisplayMessage( MSG_TIME_VERIFY );
|
|
|
|
//
|
|
// Verify a single machine
|
|
//
|
|
if ( Server ) {
|
|
|
|
Win32Err = NetDompVerifySingleClient( Server,
|
|
Dc,
|
|
ObjectAuthInfo,
|
|
DcDelay,
|
|
&InSync );
|
|
NetDompDisplayTimeVerify( Server,
|
|
Win32Err,
|
|
InSync );
|
|
}
|
|
|
|
//
|
|
// Verify all the workstations/servers, if requested.
|
|
//
|
|
for ( i = 0; i < sizeof( Types ) / sizeof( ULONG ); i++ ) {
|
|
|
|
if ( !ProcessType[ i ] ) {
|
|
|
|
continue;
|
|
}
|
|
|
|
do {
|
|
|
|
Win32Err = NetUserEnum( FullDc,
|
|
0,
|
|
Types[ i ],
|
|
( LPBYTE * )&UserList,
|
|
MAX_PREFERRED_LENGTH,
|
|
&Count,
|
|
&TotalCount,
|
|
&ResumeHandle );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_MORE_DATA ) {
|
|
|
|
for ( j = 0; j < Count; j++ ) {
|
|
|
|
Lop = wcsrchr( UserList[ j ].usri0_name, L'$' );
|
|
if ( Lop ) {
|
|
|
|
*Lop = UNICODE_NULL;
|
|
}
|
|
|
|
Err2 = NetDompVerifySingleClient( UserList[ j ].usri0_name,
|
|
Dc,
|
|
ObjectAuthInfo,
|
|
DcDelay,
|
|
&InSync );
|
|
NetDompDisplayTimeVerify( UserList[ j ].usri0_name,
|
|
Err2,
|
|
InSync );
|
|
|
|
}
|
|
NetApiBufferFree( UserList );
|
|
}
|
|
|
|
} while ( Win32Err == ERROR_MORE_DATA );
|
|
|
|
}
|
|
|
|
VerifyTimeError:
|
|
|
|
if ( DcSession ) {
|
|
|
|
NetpManageIPCConnect( FullDc,
|
|
DomainAuthInfo->User,
|
|
DomainAuthInfo->Password,
|
|
NETSETUPP_DISCONNECT_IPC );
|
|
}
|
|
|
|
if ( FullDc != Dc ) {
|
|
|
|
NetApiBufferFree( FullDc );
|
|
}
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
NetDompResetTime(
|
|
IN PWSTR Domain,
|
|
IN PWSTR Server, OPTIONAL
|
|
IN PND5_AUTH_INFO DomainAuthInfo,
|
|
IN PND5_AUTH_INFO ObjectAuthInfo,
|
|
IN PWSTR Dc,
|
|
IN BOOL AllWorkstation,
|
|
IN BOOL AllServer
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will reset the time between some or all of the servers/workstations in a
|
|
domain against the specified domain controller
|
|
|
|
Arguments:
|
|
|
|
Domain - Domain containing the servers/workstations
|
|
|
|
Server - Name of a specific machine to reset the time for
|
|
|
|
DomainAuthInfo - User and password for the domain controller
|
|
|
|
ObjectAuthInfo - User and password for the servers/workstations
|
|
|
|
Dc - Name of a domain controller in the domain to use as a time source
|
|
|
|
AllWorkstation - If TRUE, reset the time for all the workstations
|
|
|
|
AllServer - If TRUE, reset the time for all the servers
|
|
|
|
Return Value:
|
|
|
|
ERROR_SUCCESS - The function succeeded
|
|
|
|
ERROR_INVALID_PARAMETER - No server, workstation or machine was specified
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS, Err2;
|
|
BOOL DcSession = FALSE, InSync;
|
|
DWORD DcDelay;
|
|
LPUSER_INFO_0 UserList = NULL;
|
|
PWSTR FullDc = NULL, Lop;
|
|
ULONG ResumeHandle = 0, Count = 0, TotalCount = 0, i, j;
|
|
ULONG Types[] = {
|
|
FILTER_WORKSTATION_TRUST_ACCOUNT,
|
|
FILTER_SERVER_TRUST_ACCOUNT
|
|
};
|
|
BOOL ProcessType[ sizeof( Types ) / sizeof( ULONG ) ];
|
|
|
|
ProcessType[ 0 ] = AllWorkstation;
|
|
ProcessType[ 1 ] = AllServer;
|
|
|
|
//
|
|
// Make sure that there is something to do
|
|
//
|
|
if ( !Server && !AllWorkstation && !AllServer ) {
|
|
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
if ( Dc && *Dc != L'\\' ) {
|
|
|
|
Win32Err = NetApiBufferAllocate( ( wcslen( Dc ) + 3 ) * sizeof( WCHAR ),
|
|
( PVOID * )&FullDc );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
swprintf( FullDc, L"\\\\%ws", Dc );
|
|
}
|
|
|
|
} else {
|
|
|
|
FullDc = Dc;
|
|
}
|
|
|
|
|
|
|
|
Win32Err = NetpManageIPCConnect( FullDc,
|
|
DomainAuthInfo->User,
|
|
DomainAuthInfo->Password,
|
|
NETSETUPP_CONNECT_IPC );
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
DcSession = FALSE;
|
|
}
|
|
|
|
//
|
|
// Get the trip time to the dc
|
|
//
|
|
if ( Win32Err == ERROR_SUCCESS ) {
|
|
|
|
Win32Err = NetDompGetTimeTripLength( Dc,
|
|
&DcDelay );
|
|
}
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto ResetTimeError;
|
|
}
|
|
|
|
|
|
NetDompDisplayMessage( MSG_TIME_VERIFY );
|
|
|
|
//
|
|
// Reset the client, if needed
|
|
//
|
|
if ( Server ) {
|
|
|
|
Win32Err = NetDompVerifySingleClient( Server,
|
|
Dc,
|
|
ObjectAuthInfo,
|
|
DcDelay,
|
|
&InSync );
|
|
if ( Win32Err == ERROR_SUCCESS && !InSync ) {
|
|
|
|
Win32Err = NetDompResetSingleClient( Server,
|
|
Dc,
|
|
ObjectAuthInfo,
|
|
DcDelay );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Do all the workstations/servers, if required
|
|
//
|
|
for ( i = 0; i < sizeof( Types ) / sizeof( ULONG ); i++ ) {
|
|
|
|
if ( !ProcessType[ i ] ) {
|
|
|
|
continue;
|
|
}
|
|
|
|
do {
|
|
|
|
Win32Err = NetUserEnum( FullDc,
|
|
0,
|
|
Types[ i ],
|
|
( LPBYTE * )&UserList,
|
|
MAX_PREFERRED_LENGTH,
|
|
&Count,
|
|
&TotalCount,
|
|
&ResumeHandle );
|
|
|
|
if ( Win32Err == ERROR_SUCCESS || Win32Err == ERROR_MORE_DATA ) {
|
|
|
|
for ( j = 0; j < Count; j++ ) {
|
|
|
|
Lop = wcsrchr( UserList[ j ].usri0_name, L'$' );
|
|
if ( Lop ) {
|
|
|
|
*Lop = UNICODE_NULL;
|
|
}
|
|
|
|
Err2 = NetDompVerifySingleClient( UserList[ j ].usri0_name,
|
|
Dc,
|
|
ObjectAuthInfo,
|
|
DcDelay,
|
|
&InSync );
|
|
|
|
if ( Err2 == ERROR_SUCCESS && !InSync ) {
|
|
|
|
Err2 = NetDompResetSingleClient( UserList[ j ].usri0_name,
|
|
Dc,
|
|
ObjectAuthInfo,
|
|
DcDelay );
|
|
}
|
|
}
|
|
NetApiBufferFree( UserList );
|
|
}
|
|
|
|
} while ( Win32Err == ERROR_MORE_DATA );
|
|
|
|
}
|
|
|
|
ResetTimeError:
|
|
|
|
if ( DcSession ) {
|
|
|
|
NetpManageIPCConnect( FullDc,
|
|
DomainAuthInfo->User,
|
|
DomainAuthInfo->Password,
|
|
NETSETUPP_DISCONNECT_IPC );
|
|
}
|
|
|
|
if ( FullDc != Dc ) {
|
|
|
|
NetApiBufferFree( FullDc );
|
|
}
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|
|
DWORD
|
|
NetDompHandleTime(ARG_RECORD * rgNetDomArgs)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will handle the NETDOM TIME requirements
|
|
|
|
Arguments:
|
|
|
|
Args - List of command line arguments
|
|
|
|
Return Value:
|
|
|
|
ERROR_INVALID_PARAMETER - No object name was supplied
|
|
|
|
--*/
|
|
{
|
|
DWORD Win32Err = ERROR_SUCCESS;
|
|
PWSTR Domain = NULL, Dc = NULL;
|
|
ND5_AUTH_INFO DomainUser, ObjectUser;
|
|
ULONG i;
|
|
|
|
PWSTR Object = rgNetDomArgs[eObject].strValue;
|
|
|
|
if (!Object)
|
|
{
|
|
DisplayHelp(ePriTime);
|
|
return( ERROR_INVALID_PARAMETER );
|
|
}
|
|
|
|
RtlZeroMemory( &DomainUser, sizeof( ND5_AUTH_INFO ) );
|
|
RtlZeroMemory( &ObjectUser, sizeof( ND5_AUTH_INFO ) );
|
|
|
|
//
|
|
// Validate the args
|
|
//
|
|
Win32Err = NetDompValidateSecondaryArguments(rgNetDomArgs,
|
|
eObject,
|
|
eCommDomain,
|
|
eCommUserNameO,
|
|
eCommPasswordO,
|
|
eCommUserNameD,
|
|
eCommPasswordD,
|
|
eQueryServer,
|
|
eQueryWksta,
|
|
eCommVerify,
|
|
eCommReset,
|
|
eCommVerbose,
|
|
eArgEnd);
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
DisplayHelp(ePriTime);
|
|
goto HandleTimeExit;
|
|
}
|
|
|
|
|
|
//
|
|
// Verify that we don't have too many arguments
|
|
//
|
|
if ( CmdFlagOn(rgNetDomArgs, eCommVerify) &&
|
|
CmdFlagOn(rgNetDomArgs, eCommReset) ) {
|
|
|
|
NetDompDisplayUnexpectedParameter(rgNetDomArgs[eCommReset].strArg1);
|
|
|
|
Win32Err = ERROR_INVALID_PARAMETER;
|
|
goto HandleTimeExit;
|
|
}
|
|
|
|
//
|
|
// Ok, make sure that we have a specified domain...
|
|
//
|
|
Win32Err = NetDompGetDomainForOperation(rgNetDomArgs,
|
|
Object,
|
|
TRUE,
|
|
&Domain);
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto HandleTimeExit;
|
|
}
|
|
|
|
//
|
|
// Get the password and user if it exists
|
|
//
|
|
if ( CmdFlagOn(rgNetDomArgs, eCommUserNameD) ) {
|
|
|
|
Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
|
|
eCommUserNameD,
|
|
Domain,
|
|
&DomainUser);
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto HandleTimeExit;
|
|
}
|
|
}
|
|
|
|
if ( CmdFlagOn(rgNetDomArgs, eCommUserNameO) ) {
|
|
|
|
Win32Err = NetDompGetUserAndPasswordForOperation(rgNetDomArgs,
|
|
eCommUserNameO,
|
|
Object,
|
|
&ObjectUser );
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto HandleTimeExit;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Get the name of a domain controller
|
|
//
|
|
Win32Err = NetDompTimeGetDc( Domain,
|
|
Object,
|
|
&ObjectUser,
|
|
&Dc );
|
|
|
|
if ( Win32Err != ERROR_SUCCESS ) {
|
|
|
|
goto HandleTimeExit;
|
|
}
|
|
|
|
//
|
|
// Now, see what we are supposed to do
|
|
//
|
|
if ( CmdFlagOn(rgNetDomArgs, eCommVerify) ) {
|
|
|
|
Win32Err = NetDompVerifyTime( Domain,
|
|
Object,
|
|
&DomainUser,
|
|
&ObjectUser,
|
|
Dc,
|
|
CmdFlagOn(rgNetDomArgs, eQueryWksta),
|
|
CmdFlagOn(rgNetDomArgs, eQueryServer) );
|
|
|
|
}
|
|
|
|
if ( CmdFlagOn(rgNetDomArgs, eCommReset) ) {
|
|
|
|
Win32Err = NetDompResetTime( Domain,
|
|
Object,
|
|
&DomainUser,
|
|
&ObjectUser,
|
|
Dc,
|
|
CmdFlagOn(rgNetDomArgs, eQueryWksta),
|
|
CmdFlagOn(rgNetDomArgs, eQueryServer) );
|
|
|
|
}
|
|
|
|
|
|
HandleTimeExit:
|
|
|
|
NetApiBufferFree( Domain );
|
|
NetApiBufferFree( Dc );
|
|
|
|
NetDompFreeAuthIdent( &DomainUser );
|
|
NetDompFreeAuthIdent( &ObjectUser );
|
|
|
|
if (NO_ERROR != Win32Err)
|
|
{
|
|
NetDompDisplayErrorMessage(Win32Err);
|
|
}
|
|
|
|
return( Win32Err );
|
|
}
|
|
|
|
|