1480 lines
38 KiB
C
1480 lines
38 KiB
C
/*++
|
||
|
||
Copyright (c) 1993, 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
credentl.c
|
||
|
||
Abstract:
|
||
|
||
This module contains credential management routines supported by
|
||
NetWare Workstation service.
|
||
|
||
Author:
|
||
|
||
Rita Wong (ritaw) 15-Feb-1993
|
||
|
||
Revision History:
|
||
|
||
13-Apr-1994 Added change password code written by ColinW, AndyHe,
|
||
TerenceS, and RitaW.
|
||
|
||
--*/
|
||
|
||
#include <nw.h>
|
||
#include <nwreg.h>
|
||
#include <nwlsa.h>
|
||
#include <nwauth.h>
|
||
#include <nwxchg.h>
|
||
#include <nwapi.h>
|
||
|
||
|
||
//-------------------------------------------------------------------//
|
||
// //
|
||
// Global variables //
|
||
// //
|
||
//-------------------------------------------------------------------//
|
||
|
||
//
|
||
// Variables to coordinate reading of user logon credential from the
|
||
// registry if the user logged on before the workstation is started.
|
||
//
|
||
STATIC BOOL NwLogonNotifiedRdr;
|
||
|
||
|
||
STATIC
|
||
DWORD
|
||
NwpRegisterLogonProcess(
|
||
OUT PHANDLE LsaHandle,
|
||
OUT PULONG AuthPackageId
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
NwpGetServiceCredentials(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthPackageId
|
||
);
|
||
|
||
STATIC
|
||
DWORD
|
||
NwpGetCredentialInLsa(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthPackageId,
|
||
IN PLUID LogonId,
|
||
OUT LPWSTR *UserName,
|
||
OUT LPWSTR *Password
|
||
);
|
||
|
||
STATIC
|
||
VOID
|
||
NwpGetInteractiveCredentials(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthPackageId
|
||
);
|
||
|
||
DWORD
|
||
NwrLogonUser(
|
||
IN LPWSTR Reserved OPTIONAL,
|
||
IN PLUID LogonId,
|
||
IN LPWSTR UserName,
|
||
IN LPWSTR Password OPTIONAL,
|
||
IN LPWSTR PreferredServerName OPTIONAL,
|
||
IN LPWSTR NdsPreferredServerName OPTIONAL,
|
||
OUT LPWSTR LogonCommand OPTIONAL,
|
||
IN DWORD LogonCommandLength,
|
||
IN DWORD PrintOption
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function logs on the user to NetWare network. It passes the
|
||
user logon credential to the redirector to be used as the default
|
||
credential when attaching to any server.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Must be NULL.
|
||
|
||
UserName - Specifies the name of the user who logged on.
|
||
|
||
Password - Specifies the password of the user who logged on.
|
||
|
||
PreferredServerName - Specifies the user's preferred server.
|
||
|
||
LogonCommand - Receives the string which is the command to execute
|
||
on the command prompt for the user if logon is successful.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or error from redirector.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LUID SystemId = SYSTEM_LUID ;
|
||
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
EnterCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
status = NwRdrLogonUser(
|
||
LogonId,
|
||
UserName,
|
||
wcslen(UserName) * sizeof(WCHAR),
|
||
Password,
|
||
(ARGUMENT_PRESENT(Password) ?
|
||
wcslen(Password) * sizeof(WCHAR) :
|
||
0),
|
||
PreferredServerName,
|
||
(ARGUMENT_PRESENT(PreferredServerName) ?
|
||
wcslen(PreferredServerName) * sizeof(WCHAR) :
|
||
0),
|
||
NdsPreferredServerName,
|
||
(ARGUMENT_PRESENT(NdsPreferredServerName) ?
|
||
wcslen(NdsPreferredServerName) * sizeof(WCHAR) :
|
||
0),
|
||
PrintOption
|
||
);
|
||
|
||
if (status == NO_ERROR || status == NW_PASSWORD_HAS_EXPIRED) {
|
||
NwLogonNotifiedRdr = TRUE;
|
||
if (RtlEqualLuid(LogonId, &SystemId))
|
||
GatewayLoggedOn = TRUE ;
|
||
}
|
||
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
|
||
if (ARGUMENT_PRESENT(LogonCommand) && (LogonCommandLength >= sizeof(WCHAR))) {
|
||
LogonCommand[0] = 0;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NwrLogoffUser(
|
||
IN LPWSTR Reserved OPTIONAL,
|
||
IN PLUID LogonId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function tells the redirector to log off the interactive
|
||
user.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Must be NULL.
|
||
|
||
LogonId - PLUID identifying the logged on process. if NULL, then gateway.
|
||
|
||
Return Value:
|
||
|
||
|
||
--*/
|
||
{
|
||
DWORD status = NO_ERROR ;
|
||
LUID SystemId = SYSTEM_LUID ;
|
||
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
EnterCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
if (GatewayLoggedOn || !RtlEqualLuid(LogonId, &SystemId))
|
||
status = NwRdrLogoffUser(LogonId);
|
||
|
||
if (status == NO_ERROR && RtlEqualLuid(LogonId, &SystemId))
|
||
GatewayLoggedOn = FALSE ;
|
||
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
return status ;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NwrSetInfo(
|
||
IN LPWSTR Reserved OPTIONAL,
|
||
IN DWORD PrintOption,
|
||
IN LPWSTR PreferredServerName OPTIONAL
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets the preferred server and print option in
|
||
the redirector for the interactive user.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Must be NULL.
|
||
|
||
PreferredServerName - Specifies the user's preferred server.
|
||
|
||
PrintOption - Specifies the user's print option flag
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or error from redirector.
|
||
|
||
--*/
|
||
{
|
||
DWORD err;
|
||
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
err = NwRdrSetInfo(
|
||
PrintOption,
|
||
NwPacketBurstSize, // just reset to current
|
||
PreferredServerName,
|
||
(PreferredServerName != NULL ?
|
||
wcslen( PreferredServerName) * sizeof( WCHAR ) : 0 ),
|
||
NwProviderName, // just reset to current
|
||
wcslen( NwProviderName ) * sizeof( WCHAR )
|
||
);
|
||
|
||
return err;
|
||
}
|
||
|
||
DWORD
|
||
NwrSetLogonScript(
|
||
IN LPWSTR Reserved OPTIONAL,
|
||
IN DWORD ScriptOptions
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function sets logon script related info. Currently, all that is
|
||
supported is to turn the Run Logon Scripts Synchronously flag on and off.
|
||
We do this using the global flag and not per user because at NPLogonNotify
|
||
time we dont have per user registry yet. And rather than turn on & leave
|
||
on, we turn on as need so that users that dont run NW scripts dont need
|
||
wait.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Must be NULL.
|
||
|
||
ScriptOptions - options for logon scripts.
|
||
|
||
Return Value:
|
||
|
||
Win32 error from calls made.
|
||
|
||
--*/
|
||
{
|
||
DWORD dwSync, err = NO_ERROR ;
|
||
HKEY hKeyWinLogon = NULL, hKeyNWC = NULL ;
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
|
||
if (!IsTerminalServer()) {
|
||
|
||
// Setting global flags isn't multi-user, see userinit.c for multi-user implementation
|
||
|
||
//
|
||
// *** Note that in this function we intentionally do not impersonate ***
|
||
// *** since we are modifying registry under \SOFTWARE & \SYSTEM. ***
|
||
//
|
||
|
||
//
|
||
// Check the parameters.
|
||
//
|
||
if (ScriptOptions == SYNC_LOGONSCRIPT) {
|
||
dwSync = 1 ; // this is value WinLogon needs to sync login scripts.
|
||
} else if (ScriptOptions == RESET_SYNC_LOGONSCRIPT) {
|
||
dwSync = 0 ;
|
||
} else {
|
||
return(ERROR_INVALID_PARAMETER) ;
|
||
}
|
||
|
||
//
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentVersion\Services\NwcWorkstation
|
||
// \Parameters. We use this location to record the fact we temporarily
|
||
// turned on the Sync Scripts Flag.
|
||
//
|
||
err = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_REGKEY,
|
||
0,
|
||
KEY_READ | KEY_WRITE, // desired access
|
||
&hKeyNWC) ;
|
||
if ( err ) {
|
||
return err ;
|
||
}
|
||
|
||
//
|
||
// We are resetting. Check if we turned the flag on. If no, then leave
|
||
// it be.
|
||
//
|
||
if (ScriptOptions == RESET_SYNC_LOGONSCRIPT) {
|
||
DWORD dwType, dwValue = 0 ;
|
||
DWORD dwSize = sizeof(dwValue) ;
|
||
|
||
err = RegQueryValueExW(
|
||
hKeyNWC,
|
||
NW_SYNCLOGONSCRIPT_VALUENAME,
|
||
NULL,
|
||
&dwType, // ignored
|
||
(LPBYTE) &dwValue,
|
||
&dwSize) ;
|
||
|
||
if ((err != NO_ERROR) || (dwValue == 0)) {
|
||
//
|
||
// value not there or zero. ie. assume we didnt set. quit now.
|
||
//
|
||
goto ExitPoint ;
|
||
}
|
||
}
|
||
|
||
//
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion
|
||
// \WinLogon.
|
||
//
|
||
err = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
WINLOGON_REGKEY,
|
||
0,
|
||
KEY_READ | KEY_WRITE, // desired access
|
||
&hKeyWinLogon) ;
|
||
if ( err ) {
|
||
goto ExitPoint ;
|
||
}
|
||
|
||
//
|
||
// We are setting. Check if flag is already on. If yes, then leave
|
||
// it be.
|
||
//
|
||
if (ScriptOptions == SYNC_LOGONSCRIPT) {
|
||
DWORD dwType, dwValue = 0 ;
|
||
DWORD dwSize = sizeof(dwValue) ;
|
||
|
||
err = RegQueryValueExW(
|
||
hKeyWinLogon,
|
||
SYNCLOGONSCRIPT_VALUENAME,
|
||
NULL,
|
||
&dwType, // ignored
|
||
(LPBYTE) &dwValue,
|
||
&dwSize) ;
|
||
|
||
if ((err == NO_ERROR) && (dwValue == 1)) {
|
||
//
|
||
// already on. nothing to do. just return.
|
||
//
|
||
goto ExitPoint ;
|
||
}
|
||
}
|
||
//
|
||
// Write out value to make logon scripts synchronous. Or to reset it.
|
||
//
|
||
err = RegSetValueExW(
|
||
hKeyWinLogon,
|
||
SYNCLOGONSCRIPT_VALUENAME,
|
||
0,
|
||
REG_DWORD,
|
||
(LPBYTE) &dwSync, // either 1 or 0.
|
||
sizeof(dwSync)) ;
|
||
|
||
if (err == NO_ERROR) {
|
||
DWORD dwValue = (ScriptOptions == SYNC_LOGONSCRIPT) ? 1 : 0 ;
|
||
//
|
||
// We have successfully set WinLogon flag. Record (or clear)
|
||
// our own flag.
|
||
//
|
||
err = RegSetValueExW(
|
||
hKeyNWC,
|
||
NW_SYNCLOGONSCRIPT_VALUENAME,
|
||
0,
|
||
REG_DWORD,
|
||
(LPBYTE) &dwValue,
|
||
sizeof(dwValue)) ;
|
||
}
|
||
|
||
} //if IsTerminalServer()
|
||
ExitPoint:
|
||
|
||
if (hKeyWinLogon)
|
||
(void) RegCloseKey( hKeyWinLogon );
|
||
if (hKeyNWC)
|
||
(void) RegCloseKey( hKeyNWC );
|
||
|
||
return err;
|
||
}
|
||
|
||
|
||
DWORD
|
||
NwrValidateUser(
|
||
IN LPWSTR Reserved OPTIONAL,
|
||
IN LPWSTR PreferredServerName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function checks whether the user can be authenticated
|
||
successfully on the given server.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Must be NULL.
|
||
|
||
PreferredServerName - Specifies the user's preferred server.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or error that occurred during authentication.
|
||
|
||
--*/
|
||
{
|
||
DWORD status ;
|
||
UNREFERENCED_PARAMETER(Reserved);
|
||
|
||
|
||
if ( ( PreferredServerName != NULL )
|
||
&& ( *PreferredServerName != 0 )
|
||
)
|
||
{
|
||
//
|
||
// Impersonate the client
|
||
//
|
||
if ((status = NwImpersonateClient()) != NO_ERROR)
|
||
{
|
||
return status ;
|
||
}
|
||
|
||
status = NwConnectToServer( PreferredServerName ) ;
|
||
|
||
(void) NwRevertToSelf() ;
|
||
|
||
return status ;
|
||
|
||
}
|
||
|
||
return NO_ERROR;
|
||
}
|
||
|
||
|
||
VOID
|
||
NwInitializeLogon(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function initializes the data in the workstation which handles
|
||
user logon. It is called by the initialization thread.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Initialize logon flag. When the redirector LOGON FsCtl has been
|
||
// called, this flag will be set to TRUE. Initialize the
|
||
// critical section to serialize access to NwLogonNotifiedRdr flag.
|
||
//
|
||
NwLogonNotifiedRdr = FALSE;
|
||
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NwGetLogonCredential(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reads the user and service logon IDs from the registry so
|
||
that it can get the credentials from LSA.
|
||
|
||
It handles the case where the user has logged on before the workstation
|
||
is started. This function is called by the initialization thread
|
||
after opening up the RPC interface so that if user logon is happening
|
||
concurrently, the provider is given a chance to call the NwrLogonUser API
|
||
first, making it no longer necessary for the workstation to also
|
||
retrieve the credential from the registry.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD status;
|
||
|
||
HANDLE LsaHandle;
|
||
ULONG AuthPackageId = 0;
|
||
|
||
|
||
EnterCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
if (NwLogonNotifiedRdr) {
|
||
//
|
||
// Logon credential's already made known to the redirector by
|
||
// the provider calling the NwrLogonUser API.
|
||
//
|
||
#if DBG
|
||
IF_DEBUG(LOGON) {
|
||
KdPrint(("\nNWWORKSTATION: Redirector already has logon credential\n"));
|
||
}
|
||
#endif
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
return;
|
||
}
|
||
|
||
#if DBG
|
||
IF_DEBUG(LOGON) {
|
||
KdPrint(("NWWORKSTATION: Main init--NwGetLogonCredential\n"));
|
||
}
|
||
#endif
|
||
|
||
status = NwpRegisterLogonProcess(&LsaHandle, &AuthPackageId);
|
||
|
||
if (status != NO_ERROR) {
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Tell the redirector about service credentials
|
||
//
|
||
NwpGetServiceCredentials(LsaHandle, AuthPackageId);
|
||
//
|
||
// Tell the redirector about interactive credentials
|
||
//
|
||
NwpGetInteractiveCredentials(LsaHandle, AuthPackageId);
|
||
|
||
(void) LsaDeregisterLogonProcess(LsaHandle);
|
||
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
}
|
||
|
||
STATIC
|
||
VOID
|
||
NwpGetServiceCredentials(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthPackageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reads the service logon IDs from the registry
|
||
so that it can get the service credentials from LSA. It then
|
||
notifies the redirector of the service logons.
|
||
|
||
Arguments:
|
||
|
||
LsaHandle - Supplies the handle to LSA.
|
||
|
||
AuthPackageId - Supplies the NetWare authentication package ID.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LONG RegError;
|
||
|
||
LPWSTR UserName = NULL;
|
||
LPWSTR Password = NULL;
|
||
|
||
HKEY ServiceLogonKey;
|
||
DWORD Index = 0;
|
||
WCHAR LogonIdKey[NW_MAX_LOGON_ID_LEN];
|
||
LUID LogonId;
|
||
|
||
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_SERVICE_LOGON_REGKEY,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ,
|
||
&ServiceLogonKey
|
||
);
|
||
|
||
if (RegError == ERROR_SUCCESS) {
|
||
|
||
do {
|
||
|
||
RegError = RegEnumKeyW(
|
||
ServiceLogonKey,
|
||
Index,
|
||
LogonIdKey,
|
||
sizeof(LogonIdKey) / sizeof(WCHAR)
|
||
);
|
||
|
||
if (RegError == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Got a logon id key.
|
||
//
|
||
|
||
NwWStrToLuid(LogonIdKey, &LogonId);
|
||
|
||
status = NwpGetCredentialInLsa(
|
||
LsaHandle,
|
||
AuthPackageId,
|
||
&LogonId,
|
||
&UserName,
|
||
&Password
|
||
);
|
||
|
||
if (status == NO_ERROR) {
|
||
|
||
(void) NwRdrLogonUser(
|
||
&LogonId,
|
||
UserName,
|
||
wcslen(UserName) * sizeof(WCHAR),
|
||
Password,
|
||
wcslen(Password) * sizeof(WCHAR),
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0,
|
||
NW_PRINT_OPTION_DEFAULT
|
||
);
|
||
|
||
//
|
||
// Freeing the UserName pointer frees both the
|
||
// username and password buffers.
|
||
//
|
||
(void) LsaFreeReturnBuffer((PVOID) UserName);
|
||
|
||
}
|
||
|
||
}
|
||
else if (RegError != ERROR_NO_MORE_ITEMS) {
|
||
KdPrint(("NWWORKSTATION: NwpGetServiceCredentials failed to enum logon IDs RegError=%lu\n",
|
||
RegError));
|
||
}
|
||
|
||
Index++;
|
||
|
||
} while (RegError == ERROR_SUCCESS);
|
||
|
||
(void) RegCloseKey(ServiceLogonKey);
|
||
}
|
||
}
|
||
|
||
|
||
STATIC
|
||
VOID
|
||
NwpGetInteractiveCredentials(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthPackageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reads the interactive logon IDs from the registry
|
||
so that it can get the interactive credentials from LSA. It then
|
||
notifies the redirector of the interactive logons.
|
||
|
||
Arguments:
|
||
|
||
LsaHandle - Supplies the handle to LSA.
|
||
|
||
AuthPackageId - Supplies the NetWare authentication package ID.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
LONG RegError;
|
||
|
||
LPWSTR UserName = NULL;
|
||
LPWSTR Password = NULL;
|
||
|
||
HKEY InteractiveLogonKey;
|
||
DWORD Index = 0;
|
||
WCHAR LogonIdName[NW_MAX_LOGON_ID_LEN];
|
||
LUID LogonId;
|
||
DWORD PrintOption;
|
||
HKEY WkstaOptionKey = NULL;
|
||
HKEY CurrentUserOptionKey = NULL;
|
||
HKEY OneLogonKey;
|
||
LPWSTR UserSid = NULL;
|
||
PDWORD pPrintOption = NULL;
|
||
LPWSTR PreferredServer = NULL;
|
||
LPWSTR NdsPreferredServer = NULL;
|
||
|
||
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_INTERACTIVE_LOGON_REGKEY,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ,
|
||
&InteractiveLogonKey
|
||
);
|
||
|
||
if (RegError == ERROR_SUCCESS) {
|
||
|
||
do {
|
||
|
||
RegError = RegEnumKeyW(
|
||
InteractiveLogonKey,
|
||
Index,
|
||
LogonIdName,
|
||
sizeof(LogonIdName) / sizeof(WCHAR)
|
||
);
|
||
|
||
if (RegError == ERROR_SUCCESS) {
|
||
|
||
//
|
||
// Got a logon id key.
|
||
//
|
||
|
||
NwWStrToLuid(LogonIdName, &LogonId);
|
||
|
||
status = NwpGetCredentialInLsa(
|
||
LsaHandle,
|
||
AuthPackageId,
|
||
&LogonId,
|
||
&UserName,
|
||
&Password
|
||
);
|
||
|
||
if (status == NO_ERROR) {
|
||
|
||
UserSid = NULL;
|
||
|
||
//
|
||
// Open the <LogonIdName> key under Logon
|
||
//
|
||
RegError = RegOpenKeyExW(
|
||
InteractiveLogonKey,
|
||
LogonIdName,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ,
|
||
&OneLogonKey
|
||
);
|
||
|
||
if ( RegError != ERROR_SUCCESS ) {
|
||
KdPrint(("NWWORKSTATION: NwpGetInteractiveLogonCredential: RegOpenKeyExW failed, Not interactive Logon: Error %d\n", GetLastError()));
|
||
}
|
||
else {
|
||
|
||
//
|
||
// Read the SID value.
|
||
//
|
||
status = NwReadRegValue(
|
||
OneLogonKey,
|
||
NW_SID_VALUENAME,
|
||
(LPWSTR *) &UserSid
|
||
);
|
||
|
||
(void) RegCloseKey(OneLogonKey);
|
||
|
||
if ( status != NO_ERROR ) {
|
||
KdPrint(("NWWORKSTATION: NwpGetInteractiveLogonCredential: Could not read SID from reg %lu\n", status));
|
||
UserSid = NULL;
|
||
}
|
||
}
|
||
|
||
if ( UserSid ) {
|
||
|
||
PrintOption = NW_PRINT_OPTION_DEFAULT;
|
||
PreferredServer = NULL;
|
||
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet
|
||
// \Services\NWCWorkstation\Parameters\Option
|
||
//
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_OPTION_REGKEY,
|
||
REG_OPTION_NON_VOLATILE, // options
|
||
KEY_READ, // desired access
|
||
&WkstaOptionKey
|
||
);
|
||
|
||
if (RegError != ERROR_SUCCESS) {
|
||
KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials: RegOpenKeyExW Parameter\\Option returns unexpected error %lu!!\n",
|
||
RegError));
|
||
goto NoOption;
|
||
}
|
||
|
||
//
|
||
// Open the <UserSid> key under Option
|
||
//
|
||
RegError = RegOpenKeyExW(
|
||
WkstaOptionKey,
|
||
UserSid,
|
||
REG_OPTION_NON_VOLATILE,
|
||
KEY_READ,
|
||
&CurrentUserOptionKey
|
||
);
|
||
|
||
if (RegError != ERROR_SUCCESS) {
|
||
KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials: RegOpenKeyExW Parameter\\Option\\SID returns unexpected error %lu!!\n",
|
||
RegError));
|
||
(void) RegCloseKey(WkstaOptionKey);
|
||
goto NoOption;
|
||
}
|
||
|
||
//
|
||
// Read the preferred server value.
|
||
//
|
||
status = NwReadRegValue(
|
||
CurrentUserOptionKey,
|
||
NW_SERVER_VALUENAME,
|
||
&PreferredServer
|
||
);
|
||
|
||
if (status != NO_ERROR) {
|
||
KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials: Could not read preferred server from reg %lu\n", status));
|
||
PreferredServer = NULL;
|
||
}
|
||
|
||
//
|
||
// Read the preferred NDS server value (if one exists).
|
||
//
|
||
|
||
status = NwReadRegValue(
|
||
CurrentUserOptionKey,
|
||
NW_NDS_SERVER_VALUENAME,
|
||
&NdsPreferredServer
|
||
);
|
||
|
||
if (status != NO_ERROR) {
|
||
|
||
#if DBG
|
||
IF_DEBUG(LOGON) {
|
||
KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read preferred NDS server from reg %lu\n", status));
|
||
}
|
||
#endif
|
||
|
||
NdsPreferredServer = NULL;
|
||
}
|
||
//
|
||
// Read the print option value.
|
||
//
|
||
status = NwReadRegValue(
|
||
CurrentUserOptionKey,
|
||
NW_PRINTOPTION_VALUENAME,
|
||
(LPWSTR *) &pPrintOption
|
||
);
|
||
if (status != NO_ERROR) {
|
||
#if DBG
|
||
IF_DEBUG(LOGON) {
|
||
KdPrint(("NWWORKSTATION: NwGetLogonCredential: Could not read print option from reg %lu\n", status));
|
||
}
|
||
#endif
|
||
PrintOption = NW_PRINT_OPTION_DEFAULT;
|
||
}
|
||
else {
|
||
if ( pPrintOption != NULL ) {
|
||
PrintOption = *pPrintOption;
|
||
(void) LocalFree((HLOCAL) pPrintOption);
|
||
pPrintOption = NULL;
|
||
}
|
||
else {
|
||
PrintOption = NW_PRINT_OPTION_DEFAULT;
|
||
}
|
||
}
|
||
|
||
(void) RegCloseKey(CurrentUserOptionKey);
|
||
(void) RegCloseKey(WkstaOptionKey);
|
||
|
||
NoOption:
|
||
(void) NwRdrLogonUser(
|
||
&LogonId,
|
||
UserName,
|
||
wcslen(UserName) * sizeof(WCHAR),
|
||
Password,
|
||
wcslen(Password) * sizeof(WCHAR),
|
||
PreferredServer,
|
||
((PreferredServer != NULL) ?
|
||
wcslen(PreferredServer) * sizeof(WCHAR) :
|
||
0),
|
||
|
||
NdsPreferredServer,
|
||
((NdsPreferredServer != NULL) ?
|
||
wcslen(NdsPreferredServer) * sizeof(WCHAR) :
|
||
0),
|
||
PrintOption
|
||
);
|
||
|
||
//
|
||
// Freeing the UserName pointer frees both the
|
||
// username and password buffers.
|
||
//
|
||
(void) LsaFreeReturnBuffer((PVOID) UserName);
|
||
|
||
if (UserSid != NULL) {
|
||
(void) LocalFree((HLOCAL) UserSid);
|
||
UserSid = NULL;
|
||
}
|
||
|
||
if (PreferredServer != NULL) {
|
||
(void) LocalFree((HLOCAL) PreferredServer);
|
||
PreferredServer = NULL;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
}
|
||
else if (RegError != ERROR_NO_MORE_ITEMS) {
|
||
KdPrint(("NWWORKSTATION: NwpGetInteractiveCredentials failed to enum logon IDs RegError=%lu\n",
|
||
RegError));
|
||
}
|
||
|
||
Index++;
|
||
|
||
} while (RegError == ERROR_SUCCESS);
|
||
|
||
(void) RegCloseKey(InteractiveLogonKey);
|
||
}
|
||
}
|
||
|
||
DWORD
|
||
NwGatewayLogon(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function reads the gateway logon credential from the registry,
|
||
LSA secret, and does the gateway logon.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD status = NO_ERROR;
|
||
LONG RegError;
|
||
LUID LogonId = SYSTEM_LUID ;
|
||
DWORD GatewayEnabled, RegValueType, GatewayEnabledSize ;
|
||
|
||
HKEY WkstaKey = NULL;
|
||
LPWSTR GatewayAccount = NULL;
|
||
|
||
PUNICODE_STRING Password = NULL;
|
||
PUNICODE_STRING OldPassword = NULL;
|
||
|
||
|
||
//
|
||
// Open HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services
|
||
// \NWCWorkstation\Parameters
|
||
//
|
||
RegError = RegOpenKeyExW(
|
||
HKEY_LOCAL_MACHINE,
|
||
NW_WORKSTATION_REGKEY,
|
||
REG_OPTION_NON_VOLATILE, // options
|
||
KEY_READ, // desired access
|
||
&WkstaKey
|
||
);
|
||
|
||
if (RegError != ERROR_SUCCESS) {
|
||
return RegError;
|
||
}
|
||
|
||
//
|
||
// Check to see if it is enabled
|
||
//
|
||
RegValueType = REG_DWORD ;
|
||
GatewayEnabled = 0 ;
|
||
GatewayEnabledSize = sizeof(GatewayEnabled) ;
|
||
RegError = RegQueryValueExW(
|
||
WkstaKey,
|
||
NW_GATEWAY_ENABLE,
|
||
NULL,
|
||
&RegValueType,
|
||
(LPBYTE)&GatewayEnabled,
|
||
&GatewayEnabledSize) ;
|
||
|
||
if (status != NO_ERROR || GatewayEnabled == 0) {
|
||
goto CleanExit;
|
||
}
|
||
|
||
|
||
//
|
||
// Read the gateway account from the registry.
|
||
//
|
||
status = NwReadRegValue(
|
||
WkstaKey,
|
||
NW_GATEWAYACCOUNT_VALUENAME,
|
||
&GatewayAccount
|
||
);
|
||
|
||
if (status != NO_ERROR) {
|
||
goto CleanExit;
|
||
}
|
||
|
||
//
|
||
// Read the password from its secret object in LSA.
|
||
//
|
||
status = NwGetPassword(
|
||
GATEWAY_USER,
|
||
&Password, // Must be freed with LsaFreeMemory
|
||
&OldPassword // Must be freed with LsaFreeMemory
|
||
);
|
||
|
||
if (status != NO_ERROR) {
|
||
goto CleanExit;
|
||
}
|
||
|
||
EnterCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
status = NwRdrLogonUser(
|
||
&LogonId,
|
||
GatewayAccount,
|
||
((GatewayAccount != NULL) ?
|
||
wcslen(GatewayAccount) * sizeof(WCHAR) :
|
||
0),
|
||
Password->Buffer,
|
||
Password->Length,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0,
|
||
NwGatewayPrintOption );
|
||
|
||
if (status == NO_ERROR)
|
||
GatewayLoggedOn = TRUE ;
|
||
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
if (status != NO_ERROR)
|
||
{
|
||
//
|
||
// log the error in the event log
|
||
//
|
||
|
||
WCHAR Number[16] ;
|
||
LPWSTR InsertStrings[1] ;
|
||
|
||
wsprintfW(Number, L"%d", status) ;
|
||
InsertStrings[0] = Number ;
|
||
|
||
NwLogEvent(EVENT_NWWKSTA_GATEWAY_LOGON_FAILED,
|
||
1,
|
||
InsertStrings,
|
||
0) ;
|
||
}
|
||
else
|
||
{
|
||
|
||
//
|
||
// create the gateway redirections if any. not fatal if error.
|
||
// the function will log any errors to event log.
|
||
//
|
||
if (Password->Length)
|
||
{
|
||
LPWSTR Passwd = (LPWSTR) LocalAlloc(LPTR,
|
||
Password->Length + sizeof(WCHAR)) ;
|
||
if (Passwd)
|
||
{
|
||
wcsncpy(Passwd,
|
||
Password->Buffer,
|
||
Password->Length / sizeof(WCHAR)) ;
|
||
(void) NwCreateRedirections(GatewayAccount,
|
||
Passwd) ;
|
||
RtlZeroMemory((LPBYTE)Passwd,
|
||
Password->Length) ;
|
||
(void) LocalFree((HLOCAL)Passwd);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
(void) NwCreateRedirections(GatewayAccount,
|
||
NULL) ;
|
||
}
|
||
}
|
||
|
||
|
||
CleanExit:
|
||
|
||
if (Password != NULL) {
|
||
if (Password->Buffer)
|
||
RtlZeroMemory(Password->Buffer, Password->Length) ;
|
||
(void) LsaFreeMemory((PVOID) Password);
|
||
}
|
||
|
||
if (OldPassword != NULL) {
|
||
if (OldPassword->Buffer)
|
||
RtlZeroMemory(OldPassword->Buffer, OldPassword->Length) ;
|
||
(void) LsaFreeMemory((PVOID) OldPassword);
|
||
}
|
||
|
||
if (GatewayAccount != NULL) {
|
||
(void) LocalFree((HLOCAL) GatewayAccount);
|
||
}
|
||
|
||
(void) RegCloseKey(WkstaKey);
|
||
return status ;
|
||
}
|
||
|
||
DWORD
|
||
NwGatewayLogoff(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function logs off the gateway account.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
|
||
DWORD status = NO_ERROR;
|
||
LUID LogonId = SYSTEM_LUID ;
|
||
|
||
EnterCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
if (GatewayLoggedOn)
|
||
{
|
||
status = NwRdrLogoffUser(&LogonId);
|
||
|
||
if (status == NO_ERROR)
|
||
GatewayLoggedOn = FALSE ;
|
||
}
|
||
|
||
LeaveCriticalSection(&NwLoggedOnCritSec);
|
||
|
||
return status ;
|
||
|
||
}
|
||
|
||
STATIC
|
||
DWORD
|
||
NwpRegisterLogonProcess(
|
||
OUT PHANDLE LsaHandle,
|
||
OUT PULONG AuthPackageId
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function registers the workstation service as a logon process
|
||
so that it can call LSA to retrieve user credentials.
|
||
|
||
Arguments:
|
||
|
||
LsaHandle - Receives the handle to LSA.
|
||
|
||
AuthPackageId - Receives the NetWare authentication package ID.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD status = NO_ERROR;
|
||
NTSTATUS ntstatus;
|
||
STRING InputString;
|
||
LSA_OPERATIONAL_MODE SecurityMode = 0;
|
||
|
||
//
|
||
// Register this process as a logon process so that we can call
|
||
// NetWare authentication package.
|
||
//
|
||
RtlInitString(&InputString, "Client Service for NetWare");
|
||
|
||
ntstatus = LsaRegisterLogonProcess(
|
||
&InputString,
|
||
LsaHandle,
|
||
&SecurityMode
|
||
);
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
KdPrint(("NWPROVAU: NwInitializeLogon: LsaRegisterLogonProcess returns x%08lx\n",
|
||
ntstatus));
|
||
return RtlNtStatusToDosError(ntstatus);
|
||
}
|
||
|
||
//
|
||
// Look up the Netware authentication package
|
||
//
|
||
RtlInitString(&InputString, NW_AUTH_PACKAGE_NAME);
|
||
|
||
ntstatus = LsaLookupAuthenticationPackage(
|
||
*LsaHandle,
|
||
&InputString,
|
||
AuthPackageId
|
||
);
|
||
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
KdPrint(("NWPROVAU: NwpSetCredential: LsaLookupAuthenticationPackage returns x%08lx\n",
|
||
ntstatus));
|
||
|
||
(void) LsaDeregisterLogonProcess(*LsaHandle);
|
||
}
|
||
|
||
status = RtlNtStatusToDosError(ntstatus);
|
||
|
||
return status;
|
||
}
|
||
|
||
STATIC
|
||
DWORD
|
||
NwpGetCredentialInLsa(
|
||
IN HANDLE LsaHandle,
|
||
IN ULONG AuthPackageId,
|
||
IN PLUID LogonId,
|
||
OUT LPWSTR *UserName,
|
||
OUT LPWSTR *Password
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function retrieves the username and password information
|
||
from LSA given the logon ID.
|
||
|
||
Arguments:
|
||
|
||
LsaHandle - Supplies the handle to LSA.
|
||
|
||
AuthPackageId - Supplies the NetWare authentication package ID.
|
||
|
||
LogonId - Supplies the logon ID.
|
||
|
||
UserName - Receives a pointer to the username.
|
||
|
||
Password - Receives a pointer to the password.
|
||
|
||
Return Value:
|
||
|
||
NO_ERROR or reason for failure.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
NTSTATUS ntstatus;
|
||
NTSTATUS AuthPackageStatus;
|
||
|
||
NWAUTH_GET_CREDENTIAL_REQUEST GetCredRequest;
|
||
PNWAUTH_GET_CREDENTIAL_RESPONSE GetCredResponse;
|
||
ULONG ResponseLength;
|
||
|
||
UNICODE_STRING PasswordStr;
|
||
|
||
//
|
||
// Ask authentication package for credential.
|
||
//
|
||
GetCredRequest.MessageType = NwAuth_GetCredential;
|
||
RtlCopyLuid(&GetCredRequest.LogonId, LogonId);
|
||
|
||
ntstatus = LsaCallAuthenticationPackage(
|
||
LsaHandle,
|
||
AuthPackageId,
|
||
&GetCredRequest,
|
||
sizeof(GetCredRequest),
|
||
(PVOID *) &GetCredResponse,
|
||
&ResponseLength,
|
||
&AuthPackageStatus
|
||
);
|
||
|
||
if (NT_SUCCESS(ntstatus)) {
|
||
ntstatus = AuthPackageStatus;
|
||
}
|
||
if (! NT_SUCCESS(ntstatus)) {
|
||
KdPrint(("NWPROVAU: NwpGetCredentialInLsa: LsaCallAuthenticationPackage returns x%08lx\n",
|
||
ntstatus));
|
||
status = RtlNtStatusToDosError(ntstatus);
|
||
}
|
||
else {
|
||
|
||
*UserName = GetCredResponse->UserName;
|
||
*Password = GetCredResponse->Password;
|
||
|
||
//
|
||
// Decode the password.
|
||
//
|
||
RtlInitUnicodeString(&PasswordStr, GetCredResponse->Password);
|
||
RtlRunDecodeUnicodeString(NW_ENCODE_SEED, &PasswordStr);
|
||
|
||
status = NO_ERROR;
|
||
}
|
||
|
||
return status;
|
||
}
|
||
|
||
DWORD
|
||
NwrChangePassword(
|
||
IN LPWSTR Reserved OPTIONAL,
|
||
IN DWORD UserLuid,
|
||
IN LPWSTR UserName,
|
||
IN LPWSTR OldPassword,
|
||
IN LPWSTR NewPassword,
|
||
IN LPWSTR TreeName
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function changes the password for the specified user on
|
||
the list of servers. If we encounter a failure on changing
|
||
password for a particular server, we:
|
||
|
||
1) Send the new password over to the server to verify if it is
|
||
already the current password.
|
||
|
||
2) If not, return ERROR_INVALID_PASSWORD and the index into
|
||
the Servers array indicating the server which failed so that
|
||
we can prompt the user to enter an alternate old password.
|
||
|
||
When the password has been changed successfully on a server, we
|
||
notify the redirector so that the cached credential can be updated.
|
||
|
||
NOTE: All errors returned from this routine, except for the fatal
|
||
ERROR_NOT_ENOUGH_MEMORY error, indicates that the password
|
||
could not be changed on a particular server indexed by
|
||
LastProcessed. The client-side continues to call us with
|
||
the remaining list of servers.
|
||
|
||
If you add to this routine to return other fatal errors,
|
||
please make sure the client-side code aborts from calling
|
||
us with the rest of the servers on getting those errors.
|
||
|
||
Arguments:
|
||
|
||
Reserved - Must be NULL.
|
||
|
||
|
||
Return Value:
|
||
|
||
ERROR_BAD_NETPATH - Could not connect to the server indexed by
|
||
LastProcessed.
|
||
|
||
ERROR_BAD_USERNAME - The username could not be found on the server
|
||
indexed by LastProcessed.
|
||
|
||
ERROR_INVALID_PASSWORD - The change password operation failed on
|
||
the server indexed by LastProcessed.
|
||
|
||
ERROR_NOT_ENOUGH_MEMORY - Out of memory error. This fatal error
|
||
will terminate the client-side from trying to process password
|
||
change request on the remaining servers.
|
||
|
||
--*/
|
||
{
|
||
DWORD status;
|
||
NTSTATUS ntstatus;
|
||
HANDLE hNwRdr = NULL;
|
||
UNICODE_STRING UserNameStr;
|
||
UNICODE_STRING OldPasswordStr;
|
||
UNICODE_STRING NewPasswordStr;
|
||
UNICODE_STRING TreeNameStr;
|
||
BOOL fImpersonateClient = FALSE;
|
||
|
||
UNREFERENCED_PARAMETER( Reserved ) ;
|
||
UNREFERENCED_PARAMETER( UserLuid ) ;
|
||
|
||
RtlInitUnicodeString( &UserNameStr, UserName );
|
||
|
||
RtlInitUnicodeString( &OldPasswordStr, OldPassword );
|
||
RtlRunDecodeUnicodeString( NW_ENCODE_SEED2, &OldPasswordStr );
|
||
|
||
RtlInitUnicodeString( &NewPasswordStr, NewPassword );
|
||
RtlRunDecodeUnicodeString( NW_ENCODE_SEED2, &NewPasswordStr );
|
||
|
||
RtlInitUnicodeString( &TreeNameStr, TreeName );
|
||
|
||
//
|
||
// Impersonate the client
|
||
//
|
||
if ((status = NwImpersonateClient()) != NO_ERROR)
|
||
{
|
||
goto ErrorExit;
|
||
}
|
||
|
||
fImpersonateClient = TRUE;
|
||
|
||
//
|
||
// Open a NDS tree connection handle to \\treename
|
||
//
|
||
ntstatus = NwNdsOpenTreeHandle( &TreeNameStr, &hNwRdr );
|
||
|
||
if ( ntstatus != STATUS_SUCCESS )
|
||
{
|
||
status = RtlNtStatusToDosError(ntstatus);
|
||
goto ErrorExit;
|
||
}
|
||
|
||
(void) NwRevertToSelf() ;
|
||
fImpersonateClient = FALSE;
|
||
|
||
ntstatus = NwNdsChangePassword( hNwRdr,
|
||
&TreeNameStr,
|
||
&UserNameStr,
|
||
&OldPasswordStr,
|
||
&NewPasswordStr );
|
||
|
||
if ( ntstatus != NO_ERROR )
|
||
{
|
||
status = RtlNtStatusToDosError(ntstatus);
|
||
goto ErrorExit;
|
||
}
|
||
|
||
CloseHandle( hNwRdr );
|
||
hNwRdr = NULL;
|
||
|
||
return NO_ERROR ;
|
||
|
||
ErrorExit:
|
||
|
||
if ( fImpersonateClient )
|
||
(void) NwRevertToSelf() ;
|
||
|
||
if ( hNwRdr )
|
||
CloseHandle( hNwRdr );
|
||
|
||
hNwRdr = NULL;
|
||
|
||
return status;
|
||
}
|
||
|