|
|
/*++
Copyright (c) 1987-1994 Microsoft Corporation
Module Name:
notify.c
Abstract:
Sample SubAuthentication Package.
Author:
Yi-Hsin Sung (yihsins) 27-Feb-1995
Revisions:
Environment:
User mode only. Contains NT-specific code. Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntsam.h>
#include <ntlsa.h>
#include <windef.h>
#include <winbase.h>
#include <winuser.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#include <nwsutil.h>
#include <fpnwcomm.h>
#include <usrprop.h>
#include <fpnwapi.h>
#include <nwsutil.h>
#define SW_DLL_NAME L"swclnt.dll"
#define PASSWORD_PROC_NAME "SwPasswordChangeNotify"
#define NOTIFY_PROC_NAME "SwDeltaChangeNotify"
#define NO_GRACE_LOGIN_LIMIT 0xFF
typedef DWORD (*PWPROC)( LPWSTR pUserName, ULONG RelativeId, LPWSTR pPassword );
DWORD GetNCPLSASecret( VOID );
BOOL fTriedToGetSW = FALSE; BOOL fTriedToGetNCP = FALSE; HINSTANCE hinstSW = NULL; PWPROC ProcPasswordChange = NULL; PSAM_DELTA_NOTIFICATION_ROUTINE ProcDeltaChange = NULL; BOOL fGotSecret = FALSE; char szNWSecretValue[NCP_LSA_SECRET_LENGTH] = "";
NTSTATUS PasswordChangeNotify( PUNICODE_STRING UserName, ULONG RelativeId, PUNICODE_STRING Password ) { DWORD err = NO_ERROR; PUSER_INFO_2 pUserInfo2 = NULL; LPWSTR pszUser = NULL; LPWSTR pszPassword = NULL;
//
// If password is NULL, we can't get the cleartext password. Hence,
// ignore this notification. Same for UserName.
//
if ( (Password == NULL) || (Password->Buffer == NULL) ) return STATUS_SUCCESS;
if ( (UserName == NULL) || (UserName->Buffer == NULL) ) return STATUS_SUCCESS;
//
// if neither DSMN nor FPNW are installed, blow out of here as there's
// nothing to do.
//
if ( ( fTriedToGetSW && hinstSW == NULL ) && ( fTriedToGetNCP && fGotSecret == FALSE) ) { return STATUS_SUCCESS; }
//
// Make sure user name and password are null terminated
//
pszUser = LocalAlloc( LMEM_ZEROINIT, UserName->Length + sizeof(WCHAR));
if ( pszUser == NULL ) return STATUS_NO_MEMORY;
pszPassword = LocalAlloc( LMEM_ZEROINIT, Password->Length + sizeof(WCHAR));
if ( pszPassword == NULL ) { LocalFree( pszUser ); return STATUS_NO_MEMORY; }
memcpy( pszUser, UserName->Buffer, UserName->Length ); memcpy( pszPassword, Password->Buffer, Password->Length ); CharUpper( pszPassword );
//
// First, try to change the small world password if it is installed.
//
if ( !fTriedToGetSW ) { hinstSW = LoadLibrary( SW_DLL_NAME ); fTriedToGetSW = TRUE; }
if (( hinstSW != NULL ) && ( ProcPasswordChange == NULL )) { ProcPasswordChange = (PWPROC) GetProcAddress( hinstSW, PASSWORD_PROC_NAME ); }
if ( ProcPasswordChange != NULL ) { err = (ProcPasswordChange)( pszUser, RelativeId, pszPassword ); }
#if DBG
if ( err ) { KdPrint(("[FPNWCLNT] SwPasswordChangeNotify of user %ws changing returns %d.\n", pszUser, err )); } #endif
//
// we require that the PDC be rebooted after either DSMN or FPNW is
// installed anywhere in the domain for the first server... if we
// decide we shouldn't require a reboot, change the code such that
// it looks for the LSA secret everytime, not just first time through.
//
if ( !fTriedToGetNCP ) {
fTriedToGetNCP = TRUE;
//
// Get the LSA secret used to encrypt the password
//
err = GetNCPLSASecret(); }
if ( !fGotSecret ) {
goto CleanUp; }
//
// Next, change the netware password residue in the user parms field
//
err = NetUserGetInfo( NULL, pszUser, 2, (LPBYTE *) &pUserInfo2 );
if ( !err ) { WCHAR PropertyFlag; UNICODE_STRING PropertyValue;
err = RtlNtStatusToDosError( NetpParmsQueryUserProperty( pUserInfo2->usri2_parms, NWPASSWORD, &PropertyFlag, &PropertyValue ));
if ( !err && PropertyValue.Length != 0 ) { //
// This is a netware-enabled user, we need to store
// the new password residue into the user parms
//
NT_PRODUCT_TYPE ProductType; WCHAR szEncryptedNWPassword[NWENCRYPTEDPASSWORDLENGTH]; DWORD dwUserId; WORD wGraceLoginRemaining; WORD wGraceLoginAllowed;
LocalFree( PropertyValue.Buffer );
//
// Get the grace login allowed and remaining value
//
err = RtlNtStatusToDosError( NetpParmsQueryUserProperty( pUserInfo2->usri2_parms, GRACELOGINREMAINING, &PropertyFlag, &PropertyValue ));
if ( !err && ( PropertyValue.Length != 0 )) { wGraceLoginRemaining = (WORD) *(PropertyValue.Buffer); LocalFree( PropertyValue.Buffer );
if ( wGraceLoginRemaining != NO_GRACE_LOGIN_LIMIT ) { // If the grace login remaining is not unlimited,
// then we need to reset grace login remaining to
// the value in grace login allowed. Hence, read the
// grace login allowed value.
err = RtlNtStatusToDosError( NetpParmsQueryUserProperty( pUserInfo2->usri2_parms, GRACELOGINALLOWED, &PropertyFlag, &PropertyValue ));
if ( !err && ( PropertyValue.Length != 0 )) { wGraceLoginAllowed = (WORD) *(PropertyValue.Buffer); LocalFree( PropertyValue.Buffer ); }
} }
if ( !err ) { RtlGetNtProductType( &ProductType );
dwUserId = MapRidToObjectId( RelativeId, pszUser, ProductType == NtProductLanManNt, FALSE );
err = RtlNtStatusToDosError( ReturnNetwareForm( szNWSecretValue, dwUserId, pszPassword, (UCHAR *) szEncryptedNWPassword )); }
if ( !err ) { LPWSTR pNewUserParms = NULL; BOOL fUpdate; UNICODE_STRING uPropertyValue;
uPropertyValue.Buffer = szEncryptedNWPassword; uPropertyValue.Length = uPropertyValue.MaximumLength = sizeof( szEncryptedNWPassword );
err = RtlNtStatusToDosError( NetpParmsSetUserProperty( pUserInfo2->usri2_parms, NWPASSWORD, uPropertyValue, PropertyFlag, &pNewUserParms, &fUpdate ));
if ( !err && fUpdate ) { USER_INFO_1013 userInfo1013; LPWSTR pNewUserParms2 = NULL; LPWSTR pNewUserParms3 = NULL; LARGE_INTEGER currentTime;
//
// Since we're resetting the user's password, let's
// also clear the flag saying the password has
// expired. We do this by putting the current
// time into the NWPasswordSet.
//
NtQuerySystemTime (¤tTime);
uPropertyValue.Buffer = (PWCHAR) ¤tTime; uPropertyValue.Length = sizeof (LARGE_INTEGER); uPropertyValue.MaximumLength = sizeof (LARGE_INTEGER);
NetpParmsSetUserProperty( pNewUserParms, NWTIMEPASSWORDSET, uPropertyValue, (SHORT) 0, // not a set
&pNewUserParms2, &fUpdate );
if (pNewUserParms2 != NULL) { userInfo1013.usri1013_parms = pNewUserParms2; } else { userInfo1013.usri1013_parms = pNewUserParms; }
if ( wGraceLoginRemaining != NO_GRACE_LOGIN_LIMIT ) { // If the grace login remaining is not unlimited,
// then we need to reset grace login remaining to
// the value in grace login allowed.
uPropertyValue.Buffer = (PWCHAR) &wGraceLoginAllowed; uPropertyValue.Length = uPropertyValue.MaximumLength = sizeof(wGraceLoginAllowed);
NetpParmsSetUserProperty( userInfo1013.usri1013_parms, GRACELOGINREMAINING, uPropertyValue, (SHORT) 0, // not a set
&pNewUserParms3, &fUpdate );
if (pNewUserParms3 != NULL) userInfo1013.usri1013_parms = pNewUserParms3; }
err = NetUserSetInfo( NULL, pszUser, USER_PARMS_INFOLEVEL, (LPBYTE) &userInfo1013, NULL );
if (pNewUserParms2 != NULL) NetpParmsUserPropertyFree( pNewUserParms2 );
if (pNewUserParms3 != NULL) NetpParmsUserPropertyFree( pNewUserParms3 ); }
if ( pNewUserParms != NULL ) NetpParmsUserPropertyFree( pNewUserParms ); } }
NetApiBufferFree( pUserInfo2 ); }
#if DBG
if ( err ) { KdPrint(("[FPNWCLNT] Password of user %ws changing returns %d.\n", pszUser, err )); } #endif
CleanUp:
LocalFree( pszUser );
// Need to clear all memory that contains password
memset( pszPassword, 0, Password->Length + sizeof( WCHAR )); LocalFree( pszPassword );
return STATUS_SUCCESS; }
BOOLEAN InitializeChangeNotify ( VOID ) { DWORD err = NO_ERROR;
//
// First, check to see if small world is installed.
//
if ( !fTriedToGetSW ) { hinstSW = LoadLibrary( SW_DLL_NAME ); fTriedToGetSW = TRUE; }
if (( hinstSW != NULL )) {
return TRUE; }
if ( !fTriedToGetNCP ) {
fTriedToGetNCP = TRUE;
//
// Get the LSA secret used to encrypt the password
//
err = GetNCPLSASecret(); }
return (fGotSecret != 0); }
DWORD GetNCPLSASecret( VOID ) { DWORD err; LSA_HANDLE hlsaPolicy; OBJECT_ATTRIBUTES oa; SECURITY_QUALITY_OF_SERVICE sqos; LSA_HANDLE hlsaSecret; UNICODE_STRING uSecretName; UNICODE_STRING *puSecretValue; LARGE_INTEGER lintCurrentSetTime, lintOldSetTime;
sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE); sqos.ImpersonationLevel = SecurityImpersonation; sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; sqos.EffectiveOnly = FALSE;
//
// Set up the object attributes prior to opening the LSA.
//
InitializeObjectAttributes( &oa, NULL, 0L, NULL, NULL );
//
// The InitializeObjectAttributes macro presently store NULL for
// the psqos field, so we must manually copy that
// structure for now.
//
oa.SecurityQualityOfService = &sqos;
err = RtlNtStatusToDosError( LsaOpenPolicy( NULL, &oa, GENERIC_EXECUTE, &hlsaPolicy ));
if ( !err ) { RtlInitUnicodeString( &uSecretName, NCP_LSA_SECRET_KEY ); err = RtlNtStatusToDosError( LsaOpenSecret( hlsaPolicy, &uSecretName, SECRET_QUERY_VALUE, &hlsaSecret ));
if ( !err ) { err = RtlNtStatusToDosError( LsaQuerySecret( hlsaSecret, &puSecretValue, &lintCurrentSetTime, NULL, &lintOldSetTime ));
if ( !err ) { memcpy( szNWSecretValue, puSecretValue->Buffer, NCP_LSA_SECRET_LENGTH );
fGotSecret = TRUE;
(VOID) LsaFreeMemory( puSecretValue ); }
(VOID) LsaClose( hlsaSecret );
}
(VOID) LsaClose( hlsaPolicy ); }
return err;
}
NTSTATUS DeltaNotify( IN PSID DomainSid, IN SECURITY_DB_DELTA_TYPE DeltaType, IN SECURITY_DB_OBJECT_TYPE ObjectType, IN ULONG ObjectRid, IN PUNICODE_STRING ObjectName OPTIONAL, IN PLARGE_INTEGER ModifiedCount, IN PSAM_DELTA_DATA DeltaData OPTIONAL ) { NTSTATUS err = NO_ERROR;
//
// Try to notify small world of SAM changes if it is installed.
//
if ( !fTriedToGetSW ) { hinstSW = LoadLibrary( SW_DLL_NAME ); fTriedToGetSW = TRUE; }
if ( ( hinstSW != NULL ) && ( ProcDeltaChange == NULL )) { ProcDeltaChange = (PSAM_DELTA_NOTIFICATION_ROUTINE) GetProcAddress( hinstSW, NOTIFY_PROC_NAME ); }
if ( ProcDeltaChange != NULL ) { err = (ProcDeltaChange)( DomainSid, DeltaType, ObjectType, ObjectRid, ObjectName, ModifiedCount, DeltaData ); }
#if DBG
if ( err ) { KdPrint(("[FPNWCLNT] SwDeltaChangeNotify of type %d on rid 0x%x returns %d.\n", DeltaType, ObjectRid, err )); } #endif
return(STATUS_SUCCESS); }
|