651 lines
14 KiB
C++
651 lines
14 KiB
C++
/*++
|
|
|
|
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;
|
|
}
|
|
|