|
|
/********************************************************************/ /** Copyright(c) 1995 Microsoft Corporation. **/ /********************************************************************/
//***
//
// Filename: creds.c
//
// Description: Routines for storing and retrieving user Lsa secret
// dial parameters.
//
//
// History: 11/02/95 Anthony Discolo created
// May 11,1995 NarenG modified for router.
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntlsa.h>
#include <ntmsv1_0.h>
#include <llinfo.h>
#include <rasman.h>
#include <raserror.h>
#include <mprerror.h>
#include <stdlib.h>
#include <string.h>
#define MPR_CREDENTIALS_KEY TEXT("MprCredentials%d")
#define MAX_REGISTRY_VALUE_LENGTH ((64*1024) - 1)
typedef struct _MPRPARAMSENTRY { LIST_ENTRY ListEntry; WCHAR szPhoneBookEntryName[MAX_INTERFACE_NAME_LEN + 1]; WCHAR szUserName[UNLEN + 1]; WCHAR szPassword[PWLEN + 1]; WCHAR szDomain[DNLEN + 1];
} MPRPARAMSENTRY, *PMPRPARAMSENTRY;
//**
//
// Call: ReadDialParamsBlob
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD ReadDialParamsBlob( IN LPWSTR lpwsServer, OUT PVOID *ppvData, OUT LPDWORD lpdwSize ) { NTSTATUS status; DWORD dwRetCode = NO_ERROR; DWORD dwIndex; DWORD dwSize = 0; PVOID pvData = NULL; PVOID pvNewData = NULL; UNICODE_STRING unicodeKey; UNICODE_STRING unicodeServer; PUNICODE_STRING punicodeValue = NULL; OBJECT_ATTRIBUTES objectAttributes; LSA_HANDLE hPolicy; WCHAR wchKey[sizeof(MPR_CREDENTIALS_KEY) + 10 ];
//
// Initialize return value.
//
*ppvData = NULL; *lpdwSize = 0;
//
// Open the LSA secret space for reading.
//
InitializeObjectAttributes( &objectAttributes, NULL, 0L, NULL, NULL );
RtlInitUnicodeString( &unicodeServer, lpwsServer );
status = LsaOpenPolicy( &unicodeServer, &objectAttributes, POLICY_READ, &hPolicy );
if ( status != STATUS_SUCCESS ) { return( LsaNtStatusToWinError( status ) ); }
for( dwIndex = 0; TRUE; dwIndex++ ) { //
// Format the key string.
//
wsprintf( wchKey, MPR_CREDENTIALS_KEY, dwIndex );
RtlInitUnicodeString( &unicodeKey, wchKey );
//
// Get the value.
//
status = LsaRetrievePrivateData( hPolicy, &unicodeKey, &punicodeValue );
if ( status != STATUS_SUCCESS ) { dwRetCode = LsaNtStatusToWinError( status );
if ( dwRetCode == ERROR_FILE_NOT_FOUND ) { dwRetCode = NO_ERROR; }
break; } if ( punicodeValue == NULL ) { dwRetCode = ERROR_NOT_ENOUGH_MEMORY; break; }
//
// Concatenate the strings.
//
pvNewData = LocalAlloc( LPTR, dwSize + punicodeValue->Length );
if ( pvNewData == NULL ) { dwRetCode = ERROR_NOT_ENOUGH_MEMORY; break; }
if ( pvData != NULL ) { RtlCopyMemory( pvNewData, pvData, dwSize ); ZeroMemory( pvData, dwSize ); LocalFree( pvData ); pvData = NULL; }
RtlCopyMemory( (PBYTE)pvNewData + dwSize, punicodeValue->Buffer, punicodeValue->Length );
pvData = pvNewData; dwSize += punicodeValue->Length; SecureZeroMemory(punicodeValue->Buffer, punicodeValue->Length); LsaFreeMemory( punicodeValue ); punicodeValue = NULL; }
LsaClose( hPolicy );
if ( dwRetCode != NO_ERROR ) { if ( pvData != NULL ) { ZeroMemory( pvData, dwSize ); LocalFree( pvData ); }
pvData = NULL; dwSize = 0; }
if ( punicodeValue != NULL ) { LsaFreeMemory( punicodeValue ); }
*ppvData = pvData; *lpdwSize = dwSize;
return( dwRetCode ); }
//**
//
// Call: WriteDialParamsBlob
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD WriteDialParamsBlob( IN LPWSTR lpwsServer, IN PVOID pvData, IN DWORD dwcbData ) { NTSTATUS status; DWORD dwIndex = 0; DWORD dwRetCode = NO_ERROR; DWORD dwcb = 0; UNICODE_STRING unicodeKey, unicodeValue; UNICODE_STRING unicodeServer; OBJECT_ATTRIBUTES objectAttributes; LSA_HANDLE hPolicy; WCHAR wchKey[sizeof(MPR_CREDENTIALS_KEY) + 10 ];
//
// Open the LSA secret space for writing.
//
InitializeObjectAttributes( &objectAttributes, NULL, 0L, NULL, NULL );
RtlInitUnicodeString( &unicodeServer, lpwsServer );
status = LsaOpenPolicy( &unicodeServer, &objectAttributes, POLICY_WRITE, &hPolicy);
if (status != STATUS_SUCCESS) { return LsaNtStatusToWinError(status); }
while( dwcbData ) { //
// Format the key string.
//
wsprintf( wchKey, MPR_CREDENTIALS_KEY, dwIndex++ );
RtlInitUnicodeString( &unicodeKey, wchKey );
//
// Write some of the key.
//
dwcb = ( dwcbData > MAX_REGISTRY_VALUE_LENGTH ) ? MAX_REGISTRY_VALUE_LENGTH : dwcbData;
unicodeValue.Length = unicodeValue.MaximumLength = (USHORT)dwcb;
unicodeValue.Buffer = pvData;
status = LsaStorePrivateData( hPolicy, &unicodeKey, &unicodeValue );
if ( status != STATUS_SUCCESS ) { dwRetCode = LsaNtStatusToWinError(status); break; }
//
// Move the pointer to the unwritten part
// of the value.
//
pvData = (PBYTE)pvData + dwcb;
dwcbData -= dwcb; }
if ( dwRetCode != NO_ERROR ) { LsaClose( hPolicy );
return( dwRetCode ); }
//
// Delete any extra keys.
//
for (;;) { //
// Format the key string.
//
wsprintf( wchKey, MPR_CREDENTIALS_KEY, dwIndex++ );
RtlInitUnicodeString( &unicodeKey, wchKey );
//
// Delete the key.
//
status = LsaStorePrivateData( hPolicy, &unicodeKey, NULL );
if ( status != STATUS_SUCCESS ) { break; } }
LsaClose( hPolicy );
return( NO_ERROR ); }
//**
//
// Call: DialParamsBlobToList
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description: Take a string read from the user's registry key and produce
// a list of MPRPARAMSENTRY structures. If one of the structures
// has the same dwUID field as the dwUID passed in, then this
// function returns a pointer to this structure.
//
// This string encodes the data for multiple MPRPARAMSENTRY
// structures. The format of an encoded MPRPARAMSENTRY is as
// follows:
//
// <szPhoneBookEntryName>\0<szUserName>\0<szPassword>\0<szDomain>\0
//
PMPRPARAMSENTRY DialParamsBlobToList( IN PVOID pvData, IN LPWSTR lpwsPhoneBookEntryName, OUT PLIST_ENTRY pHead ) { PWCHAR p; PMPRPARAMSENTRY pParams, pFoundParams;
p = (PWCHAR)pvData;
pFoundParams = NULL;
for (;;) { pParams = LocalAlloc(LPTR, sizeof (MPRPARAMSENTRY));
if ( pParams == NULL ) { break; }
wcscpy( pParams->szPhoneBookEntryName, p );
if (_wcsicmp(pParams->szPhoneBookEntryName,lpwsPhoneBookEntryName) == 0) { pFoundParams = pParams; } while (*p) p++; p++;
wcscpy(pParams->szUserName, p); while (*p) p++; p++;
wcscpy(pParams->szPassword, p); while (*p) p++; p++;
wcscpy(pParams->szDomain, p); while (*p) p++; p++;
InsertTailList(pHead, &pParams->ListEntry);
if (*p == L'\0') break; }
return( pFoundParams ); }
//**
//
// Call: DialParamsListToBlob
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
PVOID DialParamsListToBlob( IN PLIST_ENTRY pHead, OUT LPDWORD lpcb ) { DWORD dwcb, dwSize; PVOID pvData; PWCHAR p; PLIST_ENTRY pEntry; PMPRPARAMSENTRY pParams;
//
// Estimate a buffer size large enough to hold the new entry.
//
dwSize = *lpcb + sizeof (MPRPARAMSENTRY) + 32;
if ( ( pvData = LocalAlloc(LPTR, dwSize) ) == NULL ) { return( NULL ); }
//
// Enumerate the list and convert each entry back to a string.
//
dwSize = 0;
p = (PWCHAR)pvData;
for (pEntry = pHead->Flink; pEntry != pHead; pEntry = pEntry->Flink ) { pParams = CONTAINING_RECORD(pEntry, MPRPARAMSENTRY, ListEntry);
wcscpy(p, pParams->szPhoneBookEntryName); dwcb = wcslen(pParams->szPhoneBookEntryName) + 1; p += dwcb; dwSize += dwcb;
wcscpy(p, pParams->szUserName); dwcb = wcslen(pParams->szUserName) + 1; p += dwcb; dwSize += dwcb;
wcscpy(p, pParams->szPassword); dwcb = wcslen(pParams->szPassword) + 1; p += dwcb; dwSize += dwcb;
wcscpy(p, pParams->szDomain); dwcb = wcslen(pParams->szDomain) + 1; p += dwcb; dwSize += dwcb; }
*p = L'\0'; dwSize++; dwSize *= sizeof (WCHAR);
//
// Set the exact length here.
//
*lpcb = dwSize;
return( pvData ); }
//**
//
// Call: FreeParamsList
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description: Will free the list of structures.
//
VOID FreeParamsList( IN PLIST_ENTRY pHead ) { PLIST_ENTRY pEntry; PMPRPARAMSENTRY pParams;
while( !IsListEmpty(pHead) ) { pEntry = RemoveHeadList(pHead); pParams = CONTAINING_RECORD(pEntry, MPRPARAMSENTRY, ListEntry); SecureZeroMemory( pParams, sizeof( MPRPARAMSENTRY ) ); LocalFree(pParams); } }
//**
//
// Call: RemoveCredentials
//
// Returns: NO_ERROR - Success
// Non-zero returns - Failure
//
// Description:
//
DWORD RemoveCredentials( IN LPWSTR lpwsInterfaceName, IN LPVOID pvData, IN OUT LPDWORD lpdwSize ) { PWCHAR pWalker = (PWCHAR)pvData; DWORD dwIndex;
//
// There is no list to remove from.
//
if ( pvData == NULL ) { return( ERROR_NO_SUCH_INTERFACE ); }
for (;;) { //
// If we found the interface we want to remove, we jump past it
//
if ( _wcsicmp( (LPWSTR)pWalker, lpwsInterfaceName ) == 0 ) { PWCHAR pInterface = pWalker; DWORD dwEntrySize = 0;
//
// Jump past the 4 fields.
//
for ( dwIndex = 0; dwIndex < 4; dwIndex++ ) { while (*pWalker) pWalker++, dwEntrySize++;
pWalker++, dwEntrySize++; }
//
// If this was the last entry in the list
//
if (*pWalker == L'\0') { ZeroMemory( pInterface, dwEntrySize ); } else { CopyMemory( pInterface, pWalker, *lpdwSize - ( (PBYTE)pWalker - (PBYTE)pvData ) ); }
*lpdwSize -= dwEntrySize;
return( NO_ERROR ); } else { //
// Not found so skip over this entry
//
for ( dwIndex = 0; dwIndex < 4; dwIndex++ ) { while (*pWalker) pWalker++; pWalker++; } }
if (*pWalker == L'\0') break; }
return( ERROR_NO_SUCH_INTERFACE ); }
//**
//
// Call: MprAdminInterfaceSetCredentials
//
// Returns: NO_ERROR - success
// ERROR_INVALID_PARAMETER
//
// Description:
//
DWORD APIENTRY MprAdminInterfaceSetCredentialsInternal( IN LPWSTR lpwsServer OPTIONAL, IN LPWSTR lpwsInterfaceName, IN LPWSTR lpwsUserName OPTIONAL, IN LPWSTR lpwsDomainName OPTIONAL, IN LPWSTR lpwsPassword OPTIONAL ) { DWORD dwRetCode; DWORD dwSize; PVOID pvData; LIST_ENTRY paramList; PMPRPARAMSENTRY pParams = NULL;
if ( lpwsInterfaceName == NULL ) { return( ERROR_INVALID_PARAMETER ); }
if ( wcslen( lpwsInterfaceName ) > MAX_INTERFACE_NAME_LEN ) { return( ERROR_INVALID_PARAMETER ); }
if ( lpwsUserName != NULL ) { if ( wcslen( lpwsUserName ) > UNLEN ) { return( ERROR_INVALID_PARAMETER ); } }
if ( lpwsPassword != NULL ) { if ( wcslen( lpwsPassword ) > PWLEN ) { return( ERROR_INVALID_PARAMETER ); } }
if ( lpwsDomainName != NULL ) { if ( wcslen( lpwsDomainName ) > DNLEN ) { return( ERROR_INVALID_PARAMETER ); } }
//
// Read the existing dial params string from the registry.
//
dwRetCode = ReadDialParamsBlob( lpwsServer, &pvData, &dwSize );
if ( dwRetCode != NO_ERROR ) { return( dwRetCode ); }
//
// If everything was NULL, we want to delete credentials for this interface
//
if ( ( lpwsUserName == NULL ) && ( lpwsDomainName == NULL ) && ( lpwsPassword == NULL ) ) { dwRetCode = RemoveCredentials( lpwsInterfaceName, pvData, &dwSize );
if ( dwRetCode != NO_ERROR ) { ZeroMemory ( pvData, dwSize ); LocalFree( pvData );
return( dwRetCode ); } } else { //
// Parse the string into a list, and search for the phonebook entry.
//
InitializeListHead( ¶mList );
if ( pvData != NULL ) { pParams = DialParamsBlobToList(pvData,lpwsInterfaceName,¶mList);
//
// We're done with pvData, so free it.
//
ZeroMemory ( pvData, dwSize );
LocalFree( pvData );
pvData = NULL; }
//
// If there is no existing information for this entry, create a new one.
//
if ( pParams == NULL ) { pParams = LocalAlloc(LPTR, sizeof (MPRPARAMSENTRY) );
if (pParams == NULL) { FreeParamsList( ¶mList );
return( ERROR_NOT_ENOUGH_MEMORY ); }
InsertTailList( ¶mList, &pParams->ListEntry ); }
//
// Set the new uid for the entry.
//
wcscpy( pParams->szPhoneBookEntryName, lpwsInterfaceName );
if ( lpwsUserName != NULL ) { wcscpy( pParams->szUserName, lpwsUserName ); }
if ( lpwsPassword != NULL ) { wcscpy( pParams->szPassword, lpwsPassword ); }
if ( lpwsDomainName != NULL ) { wcscpy( pParams->szDomain, lpwsDomainName ); }
//
// Convert the new list back to a string, so we can store it back into
// the registry.
//
pvData = DialParamsListToBlob( ¶mList, &dwSize );
FreeParamsList( ¶mList );
if ( pvData == NULL ) { return( ERROR_NOT_ENOUGH_MEMORY ); } }
//
// Write it back to the registry.
//
dwRetCode = WriteDialParamsBlob( lpwsServer, pvData, dwSize );
if ( pvData != NULL ) { SecureZeroMemory( pvData, dwSize ); LocalFree( pvData ); }
return( dwRetCode ); }
//**
//
// Call: MprAdminInterfaceGetCredentials
//
// Returns: NO_ERROR - success
// ERROR_INVALID_PARAMETER
//
// Description:
//
DWORD APIENTRY MprAdminInterfaceGetCredentialsInternal( IN LPWSTR lpwsServer OPTIONAL, IN LPWSTR lpwsInterfaceName, IN LPWSTR lpwsUserName OPTIONAL, IN LPWSTR lpwsPassword OPTIONAL, IN LPWSTR lpwsDomainName OPTIONAL ) { DWORD dwRetCode; DWORD dwSize; PVOID pvData; LIST_ENTRY paramList; PMPRPARAMSENTRY pParams = NULL;
if ( lpwsInterfaceName == NULL ) { return( ERROR_INVALID_PARAMETER ); }
if ( ( lpwsUserName == NULL ) && ( lpwsDomainName == NULL ) && ( lpwsPassword == NULL ) ) { return( ERROR_INVALID_PARAMETER ); }
//
// Read the existing dial params string from the registry.
//
dwRetCode = ReadDialParamsBlob( lpwsServer, &pvData, &dwSize );
if ( dwRetCode != NO_ERROR ) { return( dwRetCode ); }
//
// Parse the string into a list, and search for the lpwsInterfaceName entry.
//
InitializeListHead( ¶mList );
if ( pvData != NULL ) { pParams = DialParamsBlobToList( pvData, lpwsInterfaceName, ¶mList );
//
// We're done with pvData, so free it.
//
ZeroMemory( pvData, dwSize ); LocalFree( pvData ); }
//
// If the entry doesn't have any saved parameters, then return.
//
if ( pParams == NULL ) { FreeParamsList( ¶mList );
return( ERROR_CANNOT_FIND_PHONEBOOK_ENTRY ); }
//
// Otherwise, copy the fields to the caller's buffer.
//
if ( lpwsUserName != NULL ) { wcscpy( lpwsUserName, pParams->szUserName ); }
if ( lpwsPassword != NULL ) { wcscpy( lpwsPassword, pParams->szPassword ); }
if ( lpwsDomainName != NULL ) { wcscpy( lpwsDomainName, pParams->szDomain ); }
FreeParamsList( ¶mList );
return( NO_ERROR ); }
|