|
|
/*++
SUPPORT.CXX
Copyright (C) 1999 Microsoft Corporation, all rights reserved.
DESCRIPTION: support functions for ktpass
Created, May 21, 1999 by DavidCHR.
CONTENTS: ReadRegistryStrings
--*/
#include "everything.hxx"
NTSTATUS OpenLsa( VOID ) { OBJECT_ATTRIBUTES oa; NTSTATUS Status; UNICODE_STRING ServerString;
RtlInitUnicodeString( &ServerString, ServerName );
InitializeObjectAttributes(&oa,NULL,0,NULL,NULL);
Status = LsaOpenPolicy(&ServerString,&oa,MAXIMUM_ALLOWED,&LsaHandle); return(Status); }
NTSTATUS OpenLocalLsa( OUT PLSA_HANDLE phLsa ) {
static LSA_HANDLE hLsa = NULL; NTSTATUS N = STATUS_SUCCESS;
if ( !hLsa ) {
N = LsaConnectUntrusted( &hLsa );
if ( !NT_SUCCESS( N ) ) { printf( "Failed to connect to the local LSA: 0x%x\n", N ); }
}
if ( NT_SUCCESS( N ) ) {
*phLsa = hLsa;
} else {
hLsa = NULL;
}
return N;
}
/*++**************************************************************
NAME: ReadActualPassword
convenience routine for reading the password for a particular account. Disables command line echo for the duration.
MODIFIES: Password -- receives the new password
TAKES: Description -- descriptive string to insert into prompts and error messages. flags -- see everything.h: PROMPT_USING_POSSESSIVE_CASE PROMPT_FOR_PASSWORD_TWICE
RETURNS: TRUE when the function succeeds. FALSE otherwise. LASTERROR: not set
LOGGING: printf on failure CREATED: Apr 7, 1999 LOCKING: none CALLED BY: anyone FREE WITH: n/a -- no resources are allocated CONTENTS: CallAuthPackage
**************************************************************--*/
BOOL ReadActualPassword( IN LPWSTR Description, IN ULONG flags, OUT LPWSTR Password ) {
HANDLE hConsole; DWORD dwMode; BOOL ret = FALSE; ULONG Length; WCHAR TempPassword[ MAX_PASSWD_LEN ];
hConsole = GetStdHandle( STD_INPUT_HANDLE ); if ( hConsole ) {
// get the old console settings.
if ( GetConsoleMode( hConsole, &dwMode ) ) {
// now turn off typing echo
if ( SetConsoleMode( hConsole, dwMode &~ ENABLE_ECHO_INPUT ) ) {
fprintf( stderr, ( flags & PROMPT_USING_POSSESSIVE_CASE ) ? "Enter password for %ws: " : "Enter %ws password: ", Description );
if ( !_getws( Password ) ) {
fprintf( stderr, "EOF on input. Aborted.\n" ); goto restoreConsoleMode;
}
if ( flags & PROMPT_FOR_PASSWORD_TWICE ) {
fprintf( stderr, "\nNow re-enter password to confirm: " ); if ( !_getws( TempPassword ) ) {
fprintf( stderr, "EOF on input. Aborted.\n" ); goto restoreConsoleMode; } }
fprintf( stderr, "\n" );
if ( flags & PROMPT_FOR_PASSWORD_TWICE ) {
// verify that the two passwords are the same.
if ( wcscmp( Password, TempPassword ) == 0 ) { ret = TRUE; } else { fprintf( stderr, "Passwords do not match.\n" ); }
} else {
ret = TRUE;
}
restoreConsoleMode: // restore echo
SetConsoleMode( hConsole, dwMode );
} else {
fprintf( stderr, "Failed to disable line echo for password entry of %ws: 0x%x.\n", Description, GetLastError() );
} } else {
fprintf( stderr, "Failed to retrieve current console settings: 0x%x\n", GetLastError() );
}
} else {
fprintf( stderr, "Failed to obtain console handle so we could disable line input echo: 0x%x\n", GetLastError() );
}
return ret;
}
/*++**************************************************************
NAME: ReadOptionallyStarredPassword
if the given password is "*", read a new password from stdin. Otherwise, return the given password.
MODIFIES: pPassword -- receives the real password
TAKES: Password -- password to check for * Description, flags -- as ReadActualPassword
RETURNS: TRUE when the function succeeds. FALSE otherwise. LASTERROR: not set
LOGGING: printf on failure CREATED: Apr 7, 1999 LOCKING: none CALLED BY: anyone FREE WITH: free() **************************************************************--*/
BOOL ReadOptionallyStarredPassword( IN LPWSTR InPassword, IN ULONG flags, IN LPWSTR Description, OUT LPWSTR *pPassword ) {
ULONG Length; LPWSTR OutPass; BOOL ReadPass; BOOL ret = FALSE;
Length = lstrlenW( InPassword );
if ( ( 1 == Length ) && ( L'*' == InPassword[ 0 ] ) ) { ReadPass = TRUE; Length = MAX_PASSWD_LEN; } else {
ReadPass = FALSE; }
Length++; // null character
Length *= sizeof( WCHAR );
OutPass = (LPWSTR) malloc( Length );
if ( OutPass != NULL ) {
if ( ReadPass ) {
ret = ReadActualPassword( Description, flags, OutPass );
} else {
lstrcpyW( OutPass, InPassword );
ret = TRUE;
}
if ( ret ) {
*pPassword = OutPass; } else {
free( OutPass );
} } else {
fprintf( stderr, "Failed to allocate memory for %ws password.\n", Description );
}
return ret; } /*++**************************************************************
NAME: CallAuthPackage
convenience routine to centralize calls to LsaCallAuthentication Package.
MODIFIES: ppvOutput -- data returned by LsaCallAuthPackage pulOutputSize -- returned size of that buffer
TAKES: pvData -- submission data for that same api ulInputSize -- sizeof the given buffer
RETURNS: a status code indicating success or failure LOGGING: none CREATED: Apr 13, 1999 LOCKING: none CALLED BY: anyone, most notably ChangeViaKpasswd FREE WITH: ppvOutput with LsaFreeReturnBuffer **************************************************************--*/
NTSTATUS CallAuthPackage( IN PVOID pvData, IN ULONG ulInputSize, OUT PVOID *ppvOutput, OUT PULONG pulOutputSize ) {
// These are globals that are specific to this function.
static STRING Name = { 0 }; static ULONG PackageId = 0; static BOOL NameSetup = FALSE; LSA_HANDLE hLsa; NTSTATUS N;
if ( NT_SUCCESS( N = OpenLocalLsa( &hLsa ) ) ) {
if ( !NameSetup ) {
RtlInitString( &Name, MICROSOFT_KERBEROS_NAME_A );
N = LsaLookupAuthenticationPackage( hLsa, &Name, &PackageId );
NameSetup = NT_SUCCESS( N );
}
if ( NT_SUCCESS( N ) ) {
NTSTATUS SubStatus;
N = LsaCallAuthenticationPackage( hLsa, PackageId, pvData, ulInputSize, ppvOutput, pulOutputSize, &SubStatus );
if ( !NT_SUCCESS( N ) || !NT_SUCCESS( SubStatus ) ) {
printf( "CallAuthPackage failed, status 0x%x, substatus 0x%x.\n", N, SubStatus );
}
if ( NT_SUCCESS( N ) ) { N = SubStatus; } }
}
return N; }
VOID InitStringAndMoveOn( IN LPWSTR RealString, IN OUT LPWSTR *pCursor, IN OUT PUNICODE_STRING pString ) {
ULONG Length;
Length = lstrlenW( RealString ) +1;
memcpy( *pCursor, RealString, Length * sizeof( WCHAR ) );
RtlInitUnicodeString( pString, *pCursor );
*pCursor += Length;
// ASSERT( **pCursor == L'\0' );
}
NTSTATUS ChangeViaKpasswd( LPWSTR * Parameters ) {
LPWSTR OldPassword, NewPassword; NTSTATUS ret = STATUS_UNSUCCESSFUL; PKERB_CHANGEPASSWORD_REQUEST pPasswd = NULL; LPWSTR Cursor; PVOID pvTrash; ULONG size, ulTrash;
if ( !GlobalDomainSetting ) {
printf( "Can't change password without /domain.\n" ); ret = STATUS_INVALID_PARAMETER;
} else if ( !( ReadOptionallyStarredPassword( Parameters[ 0 ], 0, // no flags
L"your old", &OldPassword ) && ReadOptionallyStarredPassword( Parameters[ 1 ], PROMPT_FOR_PASSWORD_TWICE, L"your new", &NewPassword ) ) ) {
printf( "Failed to validate passwords for password change.\n" ); ret = STATUS_INTERNAL_ERROR;
} else {
size = lstrlenW( GlobalDomainSetting ) + 1; size += lstrlenW( GlobalClientName ) + 1; size += lstrlenW( OldPassword ) + 1; size += lstrlenW( NewPassword ) + 1;
// all strings above this line
size *= sizeof( WCHAR ); size += sizeof( *pPasswd ) ; // buffer
pPasswd = (PKERB_CHANGEPASSWORD_REQUEST) malloc( size );
if ( pPasswd ) {
// start at the end of the password-request buffer
Cursor = (LPWSTR) &( pPasswd[1] );
pPasswd->MessageType = KerbChangePasswordMessage;
InitStringAndMoveOn( GlobalDomainSetting, &Cursor, &pPasswd->DomainName );
InitStringAndMoveOn( GlobalClientName, &Cursor, &pPasswd->AccountName );
InitStringAndMoveOn( OldPassword, &Cursor, &pPasswd->OldPassword );
InitStringAndMoveOn( NewPassword, &Cursor, &pPasswd->NewPassword );
pPasswd->Impersonating = FALSE; // TRUE; // FALSE;
ret = CallAuthPackage( pPasswd, size, (PVOID *) &pvTrash, &ulTrash );
if ( NT_SUCCESS( ret ) ) {
printf( "Password changed.\n" );
} else {
printf( "Failed to change password: 0x%x\n", ret );
}
// zero the buffer to minimize exposure of the password.
memset( pPasswd, 0, size );
free( pPasswd );
} else {
printf( "Failed to allocate %ld-byte password change request.\n", size );
ret = STATUS_NO_MEMORY;
}
// zero the buffers to minimize exposure of the passwords
memset( NewPassword, 0, lstrlenW( NewPassword ) * sizeof( WCHAR ) ); memset( OldPassword, 0, lstrlenW( OldPassword ) * sizeof( WCHAR ) );
free( NewPassword ); free( OldPassword );
}
return ret;
}
DWORD OpenKerberosKey( OUT PHKEY KerbHandle ) { DWORD RegErr; HKEY ServerHandle = NULL; DWORD Disposition;
RegErr = RegConnectRegistry( ServerName, HKEY_LOCAL_MACHINE, &ServerHandle ); if (RegErr) { printf("Failed to connect to registry: %d (0x%x) \n",RegErr, RegErr); goto Cleanup; }
RegErr = RegCreateKeyEx( ServerHandle, KERB_KERBEROS_KEY, 0, NULL, 0, // no options
KEY_CREATE_SUB_KEY, NULL, KerbHandle, &Disposition ); if (RegErr) { printf("Failed to create Kerberos key: %d (0x%x)\n",RegErr, RegErr); goto Cleanup; } Cleanup: if (ServerHandle) { RegCloseKey(ServerHandle); } return(RegErr); }
DWORD OpenSubKey( IN LPWSTR * Parameters, OUT PHKEY phKey ) {
DWORD RegErr; HKEY KerbHandle = NULL; HKEY DomainHandle = NULL; HKEY DomainRoot = NULL; DWORD Disposition; LPWSTR OldServerNames = NULL; LPWSTR NewServerNames = NULL; ULONG OldKdcLength = 0; ULONG NewKdcLength = 0; ULONG Type;
RegErr = OpenKerberosKey(&KerbHandle);
if ( RegErr == ERROR_SUCCESS ) { RegErr = RegCreateKeyEx( KerbHandle, KERB_DOMAINS_SUBKEY, 0, NULL, 0, // no options
KEY_CREATE_SUB_KEY, NULL, &DomainRoot, &Disposition );
if ( RegErr == ERROR_SUCCESS ) { if ( Parameters && Parameters[ 0 ] ) { RegErr = RegCreateKeyEx( DomainRoot, Parameters[0], 0, NULL, 0, // no options
KEY_CREATE_SUB_KEY | KEY_SET_VALUE | KEY_QUERY_VALUE, NULL, &DomainHandle, &Disposition );
if ( RegErr == ERROR_SUCCESS ) { *phKey = DomainHandle; } else { printf("Failed to create %ws key: 0x%x\n", Parameters[ 0 ], RegErr); } RegCloseKey( DomainRoot );
} else /* return the domain root if no domain is requested. */ { *phKey = DomainRoot; } } else { printf( "Failed to create key %ws: 0x%x\n", Parameters[ 0 ], RegErr ); }
RegCloseKey( KerbHandle ); } else { printf( "Failed to open Kerberos Key: 0x%x\n", RegErr ); }
return RegErr; }
|