/*++ 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 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. --*/ { WCHAR wzBuf[MAX_PATH], wzTitle[30]; PWSTR pwzMsg; int nRet; if (!LoadString(g_hInstance, PromptResId, wzBuf, MAX_PATH)) { printf("LoadString FAILED!\n"); return FALSE; } if (!LoadString(g_hInstance, IDS_PROMPT_TITLE, wzTitle, 30)) { printf("LoadString FAILED!\n"); return FALSE; } if (pwzName) { if (NetApiBufferAllocate((wcslen(wzBuf) + wcslen(pwzName) + 1) * sizeof(WCHAR), (PVOID*)&pwzMsg) != ERROR_SUCCESS) { printf("Memory allocation FAILED!\n"); return FALSE; } wsprintf(pwzMsg, wzBuf, pwzName); } 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: PrompteResId - 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, Length = 0; HANDLE InputHandle = GetStdHandle( STD_INPUT_HANDLE ); WCHAR CurrentChar; PWSTR CurrentBufPtr = Buffer; // // Display the password prompt, if specified // if ( PromptResId != 0 ) { NetDompDisplayMessage( PromptResId ); } BufferLength -= 1; /* make space for null terminator */ // // Turn off echo // if (!GetConsoleMode( InputHandle, &CurrentMode )) { return GetLastError(); } SetConsoleMode( InputHandle, ( ~( ENABLE_ECHO_INPUT | ENABLE_LINE_INPUT ) ) & CurrentMode ); // // Read from the console // while ( TRUE ) { if ( ReadConsole( InputHandle, &CurrentChar, 1, &Read, NULL ) == FALSE ) { Win32Err = GetLastError(); break; } if ( Read != 1 || CurrentChar == 0xd ) { break; } // // Process the backspace // if ( CurrentChar == 0x8 ) { if ( CurrentBufPtr != Buffer ) { CurrentBufPtr--; Length--; } } else { if ( Length == BufferLength ) { Win32Err = NERR_BufTooSmall; break; } *CurrentBufPtr = CurrentChar; Length++; CurrentBufPtr++; } } // // Null terminate // *CurrentBufPtr = L'\0'; 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 --*/ { 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 { 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; ULONG Length; ULONG i, PasswordPrompt; PWSTR SpecifiedUser = NULL, SpecifiedPassword = NULL; PWSTR pwzUserWoDomain, pwzUsersDomain; size_t cchDomain; ND5_USER_FLAG_MAP FlagMap[] = { { eCommUserNameD, eCommPasswordD, MSG_NETDOM5_USERD_PWD }, { eCommUserNameO, eCommPasswordO, MSG_NETDOM5_USERO_PWD }, { eMoveUserNameF, eMovePasswordF, MSG_NETDOM5_USERF_PWD }, }; if (!AuthIdent) { return ERROR_INVALID_PARAMETER; } RtlZeroMemory( AuthIdent, sizeof( ND5_AUTH_INFO ) ); // // Return success if the name wasn't supplied // if (!CmdFlagOn(rgNetDomArgs, eUserType)) { return(ERROR_SUCCESS); } // // See the name is specifed // SpecifiedUser = rgNetDomArgs[eUserType].strValue; // // If so, use it // if ( SpecifiedUser ) { if ( wcschr( SpecifiedUser, L'\\' ) || wcschr( SpecifiedUser, L'@' ) ) { Win32Err = NetApiBufferAllocate((wcslen(SpecifiedUser ) + 1) * sizeof(WCHAR), (PVOID*)&(AuthIdent->User)); if ( Win32Err == ERROR_SUCCESS && AuthIdent->User) { wcscpy(AuthIdent->User, SpecifiedUser); } else { return ERROR_NOT_ENOUGH_MEMORY; } } else { if (wcslen(SpecifiedUser) < 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 { Length = wcslen(DefaultDomain) + 1 + wcslen(SpecifiedUser) + 1; Win32Err = NetApiBufferAllocate((Length + 1) * sizeof(WCHAR), (PVOID*)&(AuthIdent->User)); if ( Win32Err == ERROR_SUCCESS ) { 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 ) { wcscpy(AuthIdent->pwzUserWoDomain, pwzUserWoDomain); } } } } } else { Win32Err = ERROR_INVALID_PARAMETER; } // // Now, the password if it exists // if ( Win32Err == ERROR_SUCCESS ) { NETDOM_ARG_ENUM ePasswordArg; for ( 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 ( !wcscmp( SpecifiedPassword, L"*" ) ) { // // 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((wcslen(SpecifiedPassword) + 1) * sizeof(WCHAR), (PVOID*)&(AuthIdent->Password)); if ( Win32Err == ERROR_SUCCESS && AuthIdent->Password) { 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 --*/ { DWORD Win32Err = ERROR_SUCCESS; *ArgString = NULL; if (eArgToGet >= eArgEnd) { return ERROR_INVALID_PARAMETER; } if (!rgNetDomArgs[eArgToGet].strValue) { // Allow null strings. // return ERROR_SUCCESS; } 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 (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 EnableShutDownPrivilege() { HANDLE hToken; // handle to process token TOKEN_PRIVILEGES tkp; // pointer to token structure // Get the current process token handle so we can get shutdown // privilege. if (!OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken )) return GetLastError(); // Get the LUID for shutdown privilege. if( !LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid) ) return GetLastError(); tkp.PrivilegeCount = 1; // one privilege to set tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; // Get shutdown privilege for this process. AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES) NULL, 0); // Cannot test the return value of AdjustTokenPrivileges. 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 --*/ { 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 { Length = 0; GetUserName( NULL, &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 ) { 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 )); //If Machine is localMachine, Enable SE_SHUTDOWN_NAME privilege if( IsLocalMachine( Machine ) ){ if( ( Win32Err = EnableShutDownPrivilege() ) == ERROR_SUCCESS ){ if ( InitiateSystemShutdown( Machine, DisplayString, RestartDelay, TRUE, TRUE ) == FALSE ) { Win32Err = GetLastError(); } } } else if ( InitiateSystemShutdown( Machine, DisplayString, RestartDelay, TRUE, TRUE ) == FALSE ) { Win32Err = GetLastError(); } } } } 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 --*/ { 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); } BOOL IsLocalMachine( LPWSTR Machine ) { WCHAR szLocalComputer[MAX_COMPUTERNAME_LENGTH + 1]; DWORD nSize = MAX_COMPUTERNAME_LENGTH + 1 ; if( !GetComputerName( szLocalComputer, &nSize ) ) return FALSE; if( _wcsicmp( Machine, szLocalComputer ) == 0 ) return TRUE; else return FALSE; }