Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1367 lines
36 KiB

/*++
Microsoft Windows
Copyright (C) Microsoft Corporation, 1998 - 2001
Module Name:
ndutil.cxx
Abstract:
Common functions to be shared between the netdom features
--*/
#include "pch.h"
#pragma hdrstop
#include <netdom.h>
bool
CmdFlagOn(ARG_RECORD * rgNetDomArgs, NETDOM_ARG_ENUM eArgIndex)
{
if (!rgNetDomArgs || eArgIndex >= eArgEnd)
{
ASSERT(FALSE);
return false;
}
return rgNetDomArgs[eArgIndex].bDefined == TRUE;
}
BOOL
NetDompGetUserConfirmation(
IN DWORD PromptResId,
IN PWSTR pwzName
)
/*++
Routine Description:
Prompt the user to press the y or n button.
Arguments:
PrompteResId - Resource ID of the prompt to be displayed
pwzName - Optional name to put in the prompt string
Return Value:
TRUE if the user pressed y or Y, FALSE otherwise.
--*/
{
if (!PromptResId)
{
ASSERT(FALSE);
return IDNO;
}
WCHAR wzBuf[MAX_PATH+1], wzTitle[31];
PWSTR pwzMsg = NULL;
int nRet = 0, cchPrompt = 0;
cchPrompt = LoadString(g_hInstance, PromptResId, wzBuf, MAX_PATH);
if (!cchPrompt)
{
printf("LoadString FAILED!\n");
return FALSE;
}
if (!LoadString(g_hInstance, IDS_PROMPT_TITLE, wzTitle, 30))
{
printf("LoadString FAILED!\n");
return FALSE;
}
if (pwzName)
{
size_t cchBuf = cchPrompt + wcslen(pwzName) + 1;
if (NetApiBufferAllocate(cchBuf * sizeof(WCHAR),
(PVOID*)&pwzMsg) != ERROR_SUCCESS)
{
printf("Memory allocation FAILED!\n");
return FALSE;
}
HRESULT hr = StringCchPrintf(pwzMsg, cchBuf, wzBuf, pwzName);
if (FAILED(hr))
{
ASSERT(FALSE);
printf("NetDompGetUserConfirmation assertion failed!\n");
return FALSE;
}
}
else
{
pwzMsg = wzBuf;
}
nRet = MessageBox(GetFocus(),
pwzMsg,
wzTitle,
MB_YESNO |
MB_ICONEXCLAMATION |
MB_DEFAULT_DESKTOP_ONLY |
MB_SETFOREGROUND |
MB_DEFBUTTON2);
if (pwzName)
{
NetApiBufferFree(pwzMsg);
}
return (nRet == IDYES);
}
DWORD
NetDompGetPasswordString(
DWORD PromptResId,
PWSTR Buffer,
ULONG BufferLength
)
/*++
Routine Description:
This function will get the password string for an account object. It reads it from
the user input
Arguments:
PromptResId - Resource ID of the prompt to be displayed
Buffer - The buffer in which to return the password
BufferLength - Length of the buffer (in characters)
Return Value:
ERROR_SUCCESS - The call succeeded
NERR_BufTooSmall - The password entered was larger than would fit in the buffer
--*/
{
ULONG Win32Err = ERROR_SUCCESS;
DWORD CurrentMode, Read = 0;
HANDLE InputHandle = GetStdHandle( STD_INPUT_HANDLE );
PWSTR TempBuf = NULL;
// Display the password prompt, if specified
if ( PromptResId != 0 )
{
NetDompDisplayMessage( PromptResId );
}
BufferLength -= 1; /* make space for null terminator */
// If input is from console, turn off echo
if ( FileIsConsole ( InputHandle ) )
{
if (!GetConsoleMode( InputHandle, &CurrentMode ) )
{
return GetLastError();
}
SetConsoleMode( InputHandle, ~( ENABLE_ECHO_INPUT ) & CurrentMode );
}
// Read the password and copy to Buffer
Read = ReadFromIn ( &TempBuf );
if ( (Read == -1) || ( (Read + 1) > BufferLength ) )
{
Win32Err = NERR_BufTooSmall;
}
else
{
HRESULT hr = StringCchCopy ( Buffer, Read + 1, TempBuf );
if ( FAILED (hr) )
{
Win32Err = NERR_BufTooSmall;
}
}
if ( TempBuf )
{
LocalFree ( TempBuf );
}
// Restore console echo setting
if ( FileIsConsole ( InputHandle ) )
{
SetConsoleMode( InputHandle, CurrentMode );
}
// Clear the line for the next prompt
if ( PromptResId ) {
printf( "\n" );
}
return( Win32Err );
}
DWORD
NetDompGetDomainForOperation(ARG_RECORD * rgNetDomArgs,
PWSTR Server OPTIONAL,
BOOL CanDefaultToCurrent,
PWSTR *DomainName)
/*++
Routine Description:
This function will get name of the domain for the current operation. It does this
by parsing the command line parameters. If no argument is found, it uses the default
domain for that machine
Arguments:
Args - List of arguments, can be NULL if CanDefaultToCurrent is true
Server - Optional name of servre for which we wish to have the default domain
CanDefaultToCurrent - if TRUE and the domain name not specified on the command line,
use the current domain for the specified machine
DomainName - Where the domain name is returned. Freed via NetApiBufferFree().
Return Value:
ERROR_SUCCESS - The call succeeded
ERROR_INVALID_PARAMETER - The domain name was not specified and it was requried
--*/
{
if (!DomainName)
{
ASSERT(DomainName);
return ERROR_INVALID_PARAMETER;
}
DWORD Win32Err = ERROR_SUCCESS;
ULONG i;
NETSETUP_JOIN_STATUS JoinStatus;
*DomainName = NULL;
//
// See the name is specifed
//
if (rgNetDomArgs && CmdFlagOn(rgNetDomArgs, eCommDomain)) {
Win32Err = NetDompGetArgumentString(rgNetDomArgs,
eCommDomain,
DomainName);
}
//
// If so, convert it
//
if ( Win32Err == ERROR_SUCCESS || CanDefaultToCurrent) {
if ( *DomainName == NULL ) {
if ( CanDefaultToCurrent ) {
//
// See if we can use the current domain
//
Win32Err = NetGetJoinInformation( Server,
DomainName,
&JoinStatus );
if ( Win32Err == ERROR_SUCCESS ) {
if ( JoinStatus != NetSetupDomainName ) {
NetApiBufferFree( *DomainName );
NetDompDisplayMessage( MSG_NETDOM5_DOMAIN_REQUIRED );
Win32Err = ERROR_INVALID_PARAMETER;
}
}
else if (RPC_S_PROCNUM_OUT_OF_RANGE == Win32Err)
{
// Must be an NT4 or earlier machine.
//
WKSTA_INFO_100 * pWkstaInfo = NULL;
Win32Err = NetWkstaGetInfo(Server, 100, (LPBYTE*)&pWkstaInfo);
if (NERR_Success == Win32Err)
{
if (!pWkstaInfo->wki100_langroup)
{
return ERROR_INVALID_PARAMETER;
}
Win32Err = NetApiBufferAllocate(
(wcslen(pWkstaInfo->wki100_langroup) + 1) * sizeof(WCHAR),
(PVOID*)DomainName);
if (ERROR_SUCCESS == Win32Err)
{
// NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
wcscpy(*DomainName, pWkstaInfo->wki100_langroup);
}
NetApiBufferFree(pWkstaInfo);
}
}
} else {
NetDompDisplayMessage( MSG_NETDOM5_DOMAIN_REQUIRED );
Win32Err = ERROR_INVALID_PARAMETER;
}
}
} else {
//
// Hmm, guess we don't have what we need
//
NetDompDisplayMessage( MSG_NETDOM5_DOMAIN_REQUIRED );
Win32Err = ERROR_INVALID_PARAMETER;
}
return( Win32Err );
}
typedef struct _ND5_USER_FLAG_MAP {
NETDOM_ARG_ENUM UserFlag;
NETDOM_ARG_ENUM PasswordFlag;
ULONG PasswordPromptId;
} ND5_USER_FLAG_MAP, *PND5_USER_FLAG_MAP;
DWORD
NetDompGetUserAndPasswordForOperation(ARG_RECORD * rgNetDomArgs,
NETDOM_ARG_ENUM eUserType,
PWSTR DefaultDomain,
PND5_AUTH_INFO AuthIdent)
/*++
Routine Description:
This function will get the user name and password from the command line, as required. If
necessary, the function will cause a prompt for the password to be displayed and processed
Arguments:
eUserType - Whether to prompt for object or domain user
DefaultDomain - Default domain for the operation, in case a relative name was supplied
AuthIdent - Structure to initialize with the user name and password
Return Value:
ERROR_SUCCESS - The call succeeded
ERROR_INVALID_PARAMETER - The domain name was not specified and it was requried
--*/
{
DWORD Win32Err = ERROR_SUCCESS;
PWSTR SpecifiedUser = NULL, SpecifiedPassword = NULL;
PWSTR pwzUserWoDomain = NULL, pwzUsersDomain = NULL;
size_t cchDomain = 0;
ND5_USER_FLAG_MAP FlagMap[] = {
{ eCommUserNameD, eCommPasswordD, MSG_NETDOM5_USERD_PWD },
{ eCommUserNameO, eCommPasswordO, MSG_NETDOM5_USERO_PWD },
{ eMoveUserNameF, eMovePasswordF, MSG_NETDOM5_USERF_PWD },
};
if (!rgNetDomArgs || !AuthIdent)
{
ASSERT(rgNetDomArgs);
ASSERT(AuthIdent);
return ERROR_INVALID_PARAMETER;
}
//
// Return success if the name wasn't supplied
//
if (!CmdFlagOn(rgNetDomArgs, eUserType))
{
return(ERROR_SUCCESS);
}
// NOTICE-2002/02/27-ericb - SecurityPush: zeroing the structure pointed to by AuthIdent.
RtlZeroMemory( AuthIdent, sizeof( ND5_AUTH_INFO ) );
//
// See if the name is specifed
//
SpecifiedUser = rgNetDomArgs[eUserType].strValue;
//
// If so, use it
//
if ( SpecifiedUser ) {
size_t cchUser = 0;
HRESULT hr = StringCchLength(SpecifiedUser, MAXSTR, &cchUser);
if (FAILED(hr))
{
ASSERT(FALSE);
return HRESULT_CODE(hr);
}
if ( wcschr( SpecifiedUser, L'\\' ) || wcschr( SpecifiedUser, L'@' ) ) {
Win32Err = NetApiBufferAllocate((cchUser + 1) * sizeof(WCHAR),
(PVOID*)&(AuthIdent->User));
if ( Win32Err == ERROR_SUCCESS && AuthIdent->User) {
// NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
wcscpy(AuthIdent->User, SpecifiedUser);
}
else
{
return ERROR_NOT_ENOUGH_MEMORY;
}
} else {
if (cchUser < 1) {
Win32Err = NetApiBufferAllocate(sizeof(WCHAR), (PVOID*)&(AuthIdent->User));
if (ERROR_SUCCESS == Win32Err && AuthIdent->User) {
*(AuthIdent->User) = L'\0';
}
else
{
return ERROR_NOT_ENOUGH_MEMORY;
}
} else {
if ( !DefaultDomain ) {
return ERROR_INVALID_PARAMETER;
} else {
hr = StringCchLength(DefaultDomain, MAXSTR, &cchDomain);
if (FAILED(hr))
{
ASSERT(FALSE);
return HRESULT_CODE(hr);
}
size_t cchLength = cchDomain + 1 + cchUser + 1;
Win32Err = NetApiBufferAllocate((cchLength + 1) * sizeof(WCHAR),
(PVOID*)&(AuthIdent->User));
if ( Win32Err == ERROR_SUCCESS ) {
// NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
wcscpy( AuthIdent->User, DefaultDomain );
wcscat( AuthIdent->User, L"\\" );
wcscat( AuthIdent->User, SpecifiedUser);
}
}
}
}
if (pwzUserWoDomain = wcschr(AuthIdent->User, L'\\')) {
cchDomain = pwzUserWoDomain - AuthIdent->User;
Win32Err = NetApiBufferAllocate((cchDomain + 1) * sizeof(WCHAR),
(PVOID*)&(AuthIdent->pwzUsersDomain));
if ( Win32Err == ERROR_SUCCESS ) {
wcsncpy(AuthIdent->pwzUsersDomain, AuthIdent->User, cchDomain);
AuthIdent->pwzUsersDomain[cchDomain] = L'\0';
pwzUserWoDomain++;
if (pwzUserWoDomain) {
Win32Err = NetApiBufferAllocate((wcslen(pwzUserWoDomain) + 1) * sizeof(WCHAR),
(PVOID*)&(AuthIdent->pwzUserWoDomain));
if ( Win32Err == ERROR_SUCCESS ) {
// NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
wcscpy(AuthIdent->pwzUserWoDomain, pwzUserWoDomain);
}
}
}
}
} else {
Win32Err = ERROR_INVALID_PARAMETER;
}
//
// Now, the password if it exists
//
if ( Win32Err == ERROR_SUCCESS ) {
NETDOM_ARG_ENUM ePasswordArg;
ULONG PasswordPrompt = 0;
for (ULONG i = 0; i < sizeof( FlagMap ) / sizeof( ND5_USER_FLAG_MAP ); i++ ) {
if ( eUserType == FlagMap[ i ].UserFlag ) {
ePasswordArg = FlagMap[ i ].PasswordFlag;
PasswordPrompt = FlagMap[ i ].PasswordPromptId;
break;
}
}
ASSERT( ePasswordArg != eArgBegin );
//
// Now, get the password
//
SpecifiedPassword = rgNetDomArgs[ePasswordArg].strValue;
if (SpecifiedPassword)
{
size_t cchPw = 0;
HRESULT hr = StringCchLength(SpecifiedPassword, MAXSTR, &cchPw);
if (FAILED(hr))
{
ASSERT(FALSE);
return HRESULT_CODE(hr);
}
if (1 == cchPw && L'*' == *SpecifiedPassword) {
//
// Prompt for it...
//
Win32Err = NetApiBufferAllocate( ( PWLEN + 1 ) * sizeof( WCHAR ),
(PVOID*)&( AuthIdent->Password ) );
if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) {
Win32Err = NetDompGetPasswordString( PasswordPrompt,
AuthIdent->Password,
PWLEN );
}
else
{
return ERROR_NOT_ENOUGH_MEMORY;
}
} else {
//
// It's a password, so go with it..
//
Win32Err = NetApiBufferAllocate((cchPw + 1) * sizeof(WCHAR),
(PVOID*)&(AuthIdent->Password));
if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) {
// NOTICE-2002/02/27-ericb - SecurityPush: buffer allocated large enough.
wcscpy(AuthIdent->Password, SpecifiedPassword);
}
else
{
return ERROR_NOT_ENOUGH_MEMORY;
}
}
}
// Password not specified, create an empty one.
//
if( AuthIdent->Password == NULL )
{
Win32Err = NetApiBufferAllocate(sizeof(WCHAR), (PVOID*)&(AuthIdent->Password));
if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) {
*AuthIdent->Password = L'\0';
}
else
{
return ERROR_NOT_ENOUGH_MEMORY;
}
}
}
if ( Win32Err != ERROR_SUCCESS ) {
NetDompFreeAuthIdent( AuthIdent );
}
return( Win32Err );
}
DWORD
NetDompGetArgumentString(ARG_RECORD * rgNetDomArgs,
NETDOM_ARG_ENUM eArgToGet,
PWSTR *ArgString)
/*++
Routine Description:
This function will get the string associated with a command line parameter, if it exists.
Arguments:
Args - List of arguments
ArgToGet - Argument to get the string for
ArgString - Where the arg string is returned if found. Freed via NetApiBufferFree
Return Value:
ERROR_SUCCESS - The call succeeded
--*/
{
if (!rgNetDomArgs || !ArgString)
{
ASSERT(rgNetDomArgs);
ASSERT(ArgString);
return ERROR_INVALID_PARAMETER;
}
DWORD Win32Err = ERROR_SUCCESS;
*ArgString = NULL;
if (eArgToGet >= eArgEnd)
{
return ERROR_INVALID_PARAMETER;
}
if (!rgNetDomArgs[eArgToGet].strValue)
{
// Allow null strings.
//
return ERROR_SUCCESS;
}
// NOTICE-2002/02/27-ericb - SecurityPush: rgNetDomArgs strValue tested for
// non-null above. If non-null, the string is assigned by ParseCmd.
Win32Err = NetApiBufferAllocate((wcslen(rgNetDomArgs[eArgToGet].strValue) + 1) *
sizeof(WCHAR),
(PVOID*)ArgString);
if ( Win32Err == ERROR_SUCCESS ) {
wcscpy(*ArgString, rgNetDomArgs[eArgToGet].strValue);
}
return( Win32Err );
}
BOOL
NetDompGetArgumentBoolean(ARG_RECORD * rgNetDomArgs,
NETDOM_ARG_ENUM eArgToGet)
/*++
Routine Description:
This function will determine whether the given command line argument was present on the
command line or not.
Arguments:
Args - List of arguments
ArgToGet - Argument to get the string for
Return Value:
TRUE - The argument was found
FALSE - The argument wasn't found
--*/
{
if (!rgNetDomArgs)
{
ASSERT(FALSE);
return FALSE;
}
if (eArgToGet >= eArgEnd)
{
ASSERT(FALSE);
return FALSE;
}
return rgNetDomArgs[eArgToGet].bDefined;
}
DWORD
NetDompControlService(
IN PWSTR Server,
IN PWSTR Service,
IN DWORD ServiceOptions
)
/*++
Routine Description:
This function will control the given service on the given machine.
Arguments:
Server - Machine on which to control the service
Service - Service to control
ServiceOptions - What do with the service. Uses standard SvcCtrl bits
Return Value:
ERROR_SUCCESS - The operation succeeded
--*/
{
DWORD Win32Err = ERROR_SUCCESS;
SC_HANDLE ScMgr, Svc;
DWORD OpenMode;
//
// Open the service control manager
//
ScMgr = OpenSCManager( Server,
SERVICES_ACTIVE_DATABASE,
GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE );
if ( ScMgr == NULL ) {
Win32Err = GetLastError();
} else {
//
// Set the open mode
//
if( FLAG_ON( ServiceOptions, SERVICE_STOP ) ) {
LOG_VERBOSE(( MSG_VERBOSE_SVC_STOP, Service ));
OpenMode = SERVICE_STOP |
SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_QUERY_STATUS |
SERVICE_CHANGE_CONFIG;
} else if( FLAG_ON( ServiceOptions, SERVICE_START ) ) {
LOG_VERBOSE(( MSG_VERBOSE_SVC_START, Service ));
OpenMode = SERVICE_START;
} else {
LOG_VERBOSE(( MSG_VERBOSE_SVC_CONFIG, Service ));
OpenMode = SERVICE_CHANGE_CONFIG | SERVICE_QUERY_CONFIG;
}
if ( FLAG_ON( ServiceOptions, SERVICE_STOP ) ) {
Win32Err = NetpStopService( Service,
ScMgr );
}
if ( Win32Err == ERROR_SUCCESS ) {
//
// Open the service
//
Svc = OpenService( ScMgr,
Service,
OpenMode );
if ( Svc == NULL ) {
Win32Err = GetLastError();
} else {
if ( FLAG_ON( ServiceOptions, SERVICE_START ) ) {
//
// See about changing its state
//
if ( StartService( Svc, 0, NULL ) == FALSE ) {
Win32Err = GetLastError();
if ( Win32Err == ERROR_SERVICE_ALREADY_RUNNING ) {
Win32Err = ERROR_SUCCESS;
}
}
} else {
if ( ChangeServiceConfig( Svc,
SERVICE_NO_CHANGE,
ServiceOptions,
SERVICE_NO_CHANGE,
NULL, NULL, 0, NULL, NULL, NULL,
NULL ) == FALSE ) {
Win32Err = GetLastError();
}
}
CloseServiceHandle( Svc );
}
}
CloseServiceHandle( ScMgr );
}
return( Win32Err );
}
DWORD
EnablePrivilege( PCWSTR PrivilegeName )
{
HANDLE hToken; // handle to process token
TOKEN_PRIVILEGES tkp; // pointer to token structure
// Get the current process token handle so we can get the specified
// privilege.
if (!OpenProcessToken( GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
return GetLastError();
// Get the LUID for the specified privilege.
if (!LookupPrivilegeValue(NULL, PrivilegeName,
&tkp.Privileges[0].Luid))
return GetLastError();
tkp.PrivilegeCount = 1; // one privilege to set
tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
AdjustTokenPrivileges(hToken, FALSE, &tkp, 0,
(PTOKEN_PRIVILEGES) NULL, 0);
// Cannot test the return value of AdjustTokenPrivileges.
CloseHandle(hToken);
if ( GetLastError() != ERROR_SUCCESS )
return GetLastError();
return ERROR_SUCCESS;
}
DWORD
NetDompRestartAsRequired(ARG_RECORD * rgNetDomArgs,
PWSTR Machine,
PWSTR User,
DWORD PreliminaryStatus,
DWORD MsgID)
/*++
Routine Description:
This function will (remotely) shutdown a machine if the command line arguments indicate
that it should
Arguments:
Args - List of arguments
ArgCount - Number of arguments in the list
Machine - Machine which should be restarted
User - The user who connected to the machine, doing whatever operation needed a reboot.
If NULL is specified, the current user is used.
PreliminaryStatus - Status from the operation. If it's not SUCCESS, the restart isn't
attempted
MsgID - Message ID of string to display on system being shut down.
Return Value:
ERROR_SUCCESS - The operation succeeded
--*/
{
if (!rgNetDomArgs || !Machine || !MsgID)
{
ASSERT(rgNetDomArgs);
ASSERT(Machine);
ASSERT(MsgID);
return ERROR_INVALID_PARAMETER;
}
DWORD Win32Err = PreliminaryStatus;
BOOL Restart = FALSE;
PWSTR UserName = NULL, DisplayString = NULL, Delay, End;
ULONG Length = 0, RestartDelay = 30;
if ( PreliminaryStatus != ERROR_SUCCESS ) {
return( PreliminaryStatus );
}
//
// See if the argument is specified
//
Restart = NetDompGetArgumentBoolean(rgNetDomArgs,
eCommRestart);
if ( Restart ) {
//
// Get the delay time
//
RestartDelay = rgNetDomArgs[eCommRestart].nValue;
//
// Get the user display name
//
if ( User ) {
UserName = User;
} else {
// NOTICE-2002/02/27-ericb - SecurityPush: The first call to GetUserName returns
// the length required which is used to allocate the buffer.
Length = 0;
GetUserName( UserName, &Length );
Win32Err = NetApiBufferAllocate( Length * sizeof( WCHAR ),
(PVOID*)&UserName );
if ( Win32Err == ERROR_SUCCESS ) {
if ( !GetUserName( UserName, &Length ) ) {
Win32Err = GetLastError();
}
}
}
//
// Build the message to display, and schedule the shutdown
//
if ( Win32Err == ERROR_SUCCESS ) {
// NOTICE-2002/02/27-ericb - SecurityPush: checked parameters at beginning
// of the function.
Length = FormatMessageW( FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_ARGUMENT_ARRAY,
NULL,
MsgID,
0,
( PWSTR )&DisplayString,
0,
( va_list * )&UserName );
if ( Length == 0 ) {
Win32Err = GetLastError();
} else {
LOG_VERBOSE(( MSG_VERBOSE_REBOOTING, Machine ));
// NTRAID#NTBUG9-620218-2002/05/13-ericb
DWORD dwReason = SHTDN_REASON_FLAG_PLANNED |
SHTDN_REASON_MINOR_RECONFIG |
SHTDN_REASON_MAJOR_OPERATINGSYSTEM;
//If Machine is localMachine, Enable SE_SHUTDOWN_NAME privilege
if( IsLocalMachine( Machine ) ){
if( ( Win32Err = EnablePrivilege(SE_SHUTDOWN_NAME) ) == ERROR_SUCCESS ){
if ( InitiateSystemShutdownEx(Machine,
DisplayString,
RestartDelay,
TRUE,
TRUE,
dwReason) == FALSE ) {
Win32Err = GetLastError();
}
}
}
else
{
if (InitiateSystemShutdownEx(Machine,
DisplayString,
RestartDelay,
TRUE,
TRUE,
dwReason) == FALSE)
{
Win32Err = GetLastError();
}
if (RPC_S_PROCNUM_OUT_OF_RANGE == Win32Err)
{
// Machine must be running a pre-Win2k OS.
//
if (InitiateSystemShutdown(Machine,
DisplayString,
RestartDelay,
TRUE,
TRUE) == FALSE)
{
Win32Err = GetLastError();
}
else
{
Win32Err = NO_ERROR;
}
}
}
}
}
}
if ( Win32Err != ERROR_SUCCESS ) {
NetDompDisplayMessage( MSG_NO_RESTART );
NetDompDisplayErrorMessage( Win32Err );
}
LocalFree( DisplayString );
if ( UserName != User ) {
NetApiBufferFree( UserName );
}
return( Win32Err );
}
DWORD
NetDompCheckDomainMembership(
IN PWSTR Server,
IN PND5_AUTH_INFO AuthInfo,
IN BOOL EstablishSessionIfRequried,
IN OUT BOOL * DomainMember
)
/*++
Routine Description:
This function will determine whether the specified machine is a member of a domain or not
Arguments:
Server - Machine in question
AuthInfo - User name and password used to connect to the machine if necessary
EstablishSessionIfRequired - Establish an authenticated session to the machine if necessary
DomainMember - Gets set to TRUE if the machine is a domain member. Otherwise, it's FALSE.
Return Value:
ERROR_SUCCESS - The operation succeeded
--*/
{
DWORD Win32Err = ERROR_SUCCESS;
NTSTATUS Status;
LSA_HANDLE LsaHandle = NULL;
PPOLICY_PRIMARY_DOMAIN_INFO PolicyPDI = NULL;
OBJECT_ATTRIBUTES OA;
UNICODE_STRING ServerU;
*DomainMember = FALSE;
//
// Establish a session, if necessary
//
if ( Server && EstablishSessionIfRequried ) {
LOG_VERBOSE(( MSG_VERBOSE_ESTABLISH_SESSION, Server ));
Win32Err = NetpManageIPCConnect( Server,
AuthInfo->User,
AuthInfo->Password,
NETSETUPP_CONNECT_IPC );
}
//
// See if it's a domain member. Use the LSA apis, since this might be an
// NT4 box.
//
if ( Win32Err == ERROR_SUCCESS ) {
if ( Server ) {
RtlInitUnicodeString( &ServerU, Server );
}
InitializeObjectAttributes( &OA, NULL, 0, NULL, NULL );
Status = LsaOpenPolicy( Server ? &ServerU : NULL,
&OA,
MAXIMUM_ALLOWED,
&LsaHandle );
if ( NT_SUCCESS( Status ) ) {
Status = LsaQueryInformationPolicy( LsaHandle,
PolicyPrimaryDomainInformation,
( PVOID * )&PolicyPDI );
if ( NT_SUCCESS( Status ) ) {
if ( PolicyPDI->Sid ) {
*DomainMember = TRUE;
}
LsaFreeMemory( PolicyPDI );
}
LsaClose( LsaHandle );
}
Win32Err = RtlNtStatusToDosError( Status );
}
//
// Tear down the session
//
if ( Server && EstablishSessionIfRequried ) {
LOG_VERBOSE(( MSG_VERBOSE_DELETE_SESSION, Server ));
NetpManageIPCConnect( Server,
AuthInfo->User,
AuthInfo->Password,
NETSETUPP_DISCONNECT_IPC );
}
return( Win32Err );
}
DWORD
NetDompValidateSecondaryArguments(ARG_RECORD * rgNetDomArgs,
NETDOM_ARG_ENUM eFirstValidParam, ...)
//PND5_ARG Args,
/*++
Routine Description:
This function will determine whether the supplied command line options are
valid for this operation or not
Return Value:
ERROR_SUCCESS - The operation succeeded
ERROR_INVALID_PARAMETER - A bad parameter was specified
--*/
{
if (!rgNetDomArgs)
{
ASSERT(FALSE);
return ERROR_INVALID_PARAMETER;
}
DWORD Win32Err = ERROR_SUCCESS;
va_list ArgList;
for (int i = eArgBegin; i < eArgEnd; i++)
{
if (rgNetDomArgs[i].bDefined)
{
int j = eFirstValidParam;
bool fFound = false;
va_start(ArgList, eFirstValidParam);
while (j != eArgEnd)
{
if (i == j)
{
fFound = true;
break;
}
j = va_arg(ArgList, int);
}
if (!fFound)
{
NetDompDisplayUnexpectedParameter(rgNetDomArgs[i].strArg1);
return ERROR_INVALID_PARAMETER;
}
}
}
va_end(ArgList);
return(Win32Err);
}
DWORD
NetDompGenerateRandomPassword(
IN PWSTR Buffer,
IN ULONG Length
)
/*++
Routine Description:
This function will generate a random password of the specified length
Arguments:
Buffer - Place to put the randomly generated password
Length - Length of the password (in characters) to generate
Return Value:
ERROR_SUCCESS - The operation succeeded
--*/
{
DWORD Win32Err = ERROR_SUCCESS;
HCRYPTPROV CryptProvider = 0;
LARGE_INTEGER Time;
ULONG Seed, i;
UCHAR Filler;
NtQuerySystemTime( &Time );
Seed = ( ( PLONG )( &Time ) )[ 0 ] ^ ( ( PLONG )( &Time ) )[ 1 ];
Filler = ( UCHAR )( RtlRandom( &Seed ) % ( 254 ) + 1 ); // Generate a fill character to use
//
// Generate a random password.
//
if ( CryptAcquireContext( &CryptProvider,
NULL,
NULL,
PROV_RSA_FULL,
CRYPT_VERIFYCONTEXT ) ) {
if ( CryptGenRandom( CryptProvider,
Length * sizeof( WCHAR ),
( LPBYTE )Buffer ) ) {
Buffer[ Length ] = UNICODE_NULL;
//
// Make sure there are no NULL's in the middle of the list
//
for ( i = 0; i < Length; i++ ) {
if ( Buffer[ i ] == UNICODE_NULL ) {
Buffer[ i ] = Filler;
}
}
} else {
Win32Err = GetLastError();
}
CryptReleaseContext( CryptProvider, 0 );
} else {
Win32Err = GetLastError();
}
return( Win32Err );
}
VOID
NetDompFreeAuthIdent(
IN PND5_AUTH_INFO pAuthIdent
)
{
if (pAuthIdent->User)
NetApiBufferFree(pAuthIdent->User);
if (pAuthIdent->Password)
NetApiBufferFree(pAuthIdent->Password);
if (pAuthIdent->pwzUserWoDomain)
NetApiBufferFree(pAuthIdent->pwzUserWoDomain);
if (pAuthIdent->pwzUsersDomain)
NetApiBufferFree(pAuthIdent->pwzUsersDomain);
}
//+----------------------------------------------------------------------------
//
// Function: IsLocalMachine
//
// Synopsis: Checks if pwzMachine is the local machine.
//
// NOTICE-2002/08/01-shasan - Added code so that function can be used
// even if the machine name passed in has \\ before it.
//
//-----------------------------------------------------------------------------
BOOL
IsLocalMachine(PCWSTR pwzMachine)
{
if (!pwzMachine)
{
ASSERT(false);
return FALSE;
}
// Skip the initial \\ if present
if ( wcslen (pwzMachine) >= 2 )
{
if ( *pwzMachine == L'\\' && * (pwzMachine + 1) == L'\\' )
pwzMachine += 2;
}
// NOTICE-2002/02/27-ericb - SecurityPush: the SDK docs say the buffer
// should be large enough for MAX_COMPUTERNAME_LENGTH + 1 characters but
// don't explicitly say if the null is included in that count. So add one
// more to make sure there is room for the null.
WCHAR szLocalComputer[MAX_COMPUTERNAME_LENGTH + 2];
DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1 ;
WCHAR szLocalComputerDns[DNS_MAX_NAME_LENGTH + 2];
DWORD nDnsSize = DNS_MAX_NAME_LENGTH + 1;
if (!GetComputerName(szLocalComputer, &nSize))
return FALSE;
if (_wcsnicmp(pwzMachine, szLocalComputer, nSize) == 0)
return TRUE;
// The netBIOS name hasnt matched, check if the DNS name matches
if ( !GetComputerNameEx ( ComputerNamePhysicalDnsFullyQualified, szLocalComputerDns, &nDnsSize ) )
return FALSE;
if ( _wcsnicmp ( pwzMachine, szLocalComputerDns, nDnsSize ) == 0)
return TRUE;
else
return FALSE;
}