Windows-Server-2003/ds/security/gina/common/optlogon.c

445 lines
11 KiB
C

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
optlogon.c
Abstract:
This module contains the shared rountines for the optimized logon.
Author:
Cenk Ergan (cenke) - 2001/05/07
Environment:
User Mode
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <ginacomn.h>
//
// The registry values under ProfileList\%UserSidString% checked when
// determining if we should logon by cached credentials by default.
//
#define GC_PROFILE_LIST_PATH L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList"
#define GC_NEXT_LOGON_CACHEABLE_VALUE_NAME L"NextLogonCacheable"
#define GC_SYNC_LOGON_SCRIPT_VALUE_NAME L"RunLogonScriptSync"
#define GC_OPTIMIZED_LOGON_VALUE_NAME L"OptimizedLogonStatus"
/***************************************************************************\
* GcCheckIfProfileAllowsCachedLogon
*
* Returns whether profile settings are not compatible with doing fast-cached
* logons every logon, e.g. roaming profile, remote home directory etc.
*
* History:
* 03-23-01 Cenke Created
\***************************************************************************/
DWORD
GcCheckIfProfileAllowsCachedLogon(
PUNICODE_STRING HomeDirectory,
PUNICODE_STRING ProfilePath,
PWCHAR UserSidString,
PDWORD NextLogonCacheable
)
{
DWORD ErrorCode;
DWORD LogonCacheable;
DWORD UserPreference;
//
// Start with the assumption that the logon is not cacheable.
//
ErrorCode = ERROR_SUCCESS;
LogonCacheable = FALSE;
//
// Is the home directory on the network (i.e. a UNC path)?
//
if (HomeDirectory &&
HomeDirectory->Length > 4 &&
GcIsUNCPath(HomeDirectory->Buffer)) {
goto cleanup;
}
//
// Is the profile path on the network (i.e. a UNC path)?
//
if (ProfilePath &&
ProfilePath->Length > 4 &&
GcIsUNCPath(ProfilePath->Buffer)) {
//
// Check if the user has explicitly requested his roaming profile to
// be local on this machine.
//
UserPreference = GcGetUserPreferenceValue(UserSidString);
//
// If user preference is not 0, then the roaming user profile is not
// set to be local on this machine: we can't do optimized logon.
//
if (UserPreference) {
goto cleanup;
}
}
//
// The logon is cacheable.
//
LogonCacheable = TRUE;
cleanup:
if (ErrorCode == ERROR_SUCCESS) {
*NextLogonCacheable = LogonCacheable;
}
return ErrorCode;
}
/***************************************************************************\
* GcCheckIfLogonScriptsRunSync
*
* Returns whether logons scripts are to be run synchronously.
* Default is asynchronous.
*
* History:
* 04-25-01 Cenke Created
\***************************************************************************/
BOOL
GcCheckIfLogonScriptsRunSync(
PWCHAR UserSidString
)
{
DWORD ErrorCode;
BOOL bSync = FALSE;
ErrorCode = GcAccessProfileListUserSetting(UserSidString,
FALSE,
GC_SYNC_LOGON_SCRIPT_VALUE_NAME,
&(DWORD)bSync);
if (ErrorCode != ERROR_SUCCESS) {
bSync = FALSE;
}
return bSync;
}
/***************************************************************************\
* GcAccessProfileListUserSetting
*
* Queries or sets a DWORD value for the specified user under the local
* machine profile list key.
*
* History:
* 05-01-01 Cenke Created
\***************************************************************************/
DWORD
GcAccessProfileListUserSetting (
PWCHAR UserSidString,
BOOL SetValue,
PWCHAR ValueName,
PDWORD Value
)
{
HKEY ProfileListKey;
HKEY UserProfileKey;
ULONG Result;
DWORD ErrorCode;
DWORD ValueType;
DWORD Size;
//
// Initialize locals.
//
UserProfileKey = NULL;
ProfileListKey = NULL;
//
// Open the ProfileList registry key.
//
Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
GC_PROFILE_LIST_PATH,
0,
KEY_READ,
&ProfileListKey);
if (Result != ERROR_SUCCESS) {
ErrorCode = Result;
goto cleanup;
}
//
// Open the user's profile key under the ProfileList key using user's SID.
//
Result = RegOpenKeyEx(ProfileListKey,
UserSidString,
0,
KEY_READ | KEY_WRITE,
&UserProfileKey);
if (Result != ERROR_SUCCESS) {
ErrorCode = Result;
goto cleanup;
}
if (SetValue) {
//
// Set the value.
//
Result = RegSetValueEx(UserProfileKey,
ValueName,
0,
REG_DWORD,
(BYTE *) Value,
sizeof(DWORD));
if (Result != ERROR_SUCCESS) {
ErrorCode = Result;
goto cleanup;
}
} else {
//
// Query the value.
//
Size = sizeof(DWORD);
Result = RegQueryValueEx(UserProfileKey,
ValueName,
0,
&ValueType,
(BYTE *) Value,
&Size);
if (Result != ERROR_SUCCESS) {
ErrorCode = Result;
goto cleanup;
}
}
//
// We are done.
//
ErrorCode = ERROR_SUCCESS;
cleanup:
if (ProfileListKey) {
RegCloseKey(ProfileListKey);
}
if (UserProfileKey) {
RegCloseKey(UserProfileKey);
}
return ErrorCode;
}
/***************************************************************************\
* GcGetNextLogonCacheable
*
* Returns whether we are allowed to perform a cached logon at the next logon.
* For instance, if last time we logged on using cached credentials, our attempt
* at background logon failed for a reason (e.g. password expired) we want to
* force the user to hit the network logon path to deal with.
*
* History:
* 03-23-01 Cenke Created
\***************************************************************************/
DWORD
GcGetNextLogonCacheable(
PWCHAR UserSidString,
PDWORD NextLogonCacheable
)
{
DWORD ErrorCode;
ErrorCode = GcAccessProfileListUserSetting(UserSidString,
FALSE,
GC_NEXT_LOGON_CACHEABLE_VALUE_NAME,
NextLogonCacheable);
return ErrorCode;
}
/***************************************************************************\
* GcSetNextLogonCacheable
*
* Sets whether we are allowed to perform a cached logon at the next logon.
* For instance, if after logging on the user with cached credentials our attempt
* at background logon fails for a reason (e.g. password expired) we want to
* force the user to hit the network logon path to deal with.
*
* History:
* 03-23-01 Cenke Created
\***************************************************************************/
DWORD
GcSetNextLogonCacheable(
PWCHAR UserSidString,
DWORD NextLogonCacheable
)
{
DWORD ErrorCode;
ErrorCode = GcAccessProfileListUserSetting(UserSidString,
TRUE,
GC_NEXT_LOGON_CACHEABLE_VALUE_NAME,
&NextLogonCacheable);
return ErrorCode;
}
/***************************************************************************\
* GcSetOptimizedLogonStatus
*
* Saves optimized logon status for the user in the profile list.
*
* History:
* 03-23-01 Cenke Created
\***************************************************************************/
DWORD
GcSetOptimizedLogonStatus(
PWCHAR UserSidString,
DWORD OptimizedLogonStatus
)
{
DWORD ErrorCode;
ErrorCode = GcAccessProfileListUserSetting(UserSidString,
TRUE,
GC_OPTIMIZED_LOGON_VALUE_NAME,
&OptimizedLogonStatus);
return ErrorCode;
}
/***************************************************************************\
* GcGetUserPreferenceValue
*
* Gets user preference flags on whether the user's roaming profile is set
* to be local on this machine.
*
* History:
* 05-01-01 Cenke Copied from gina\userenv\profile.cpp
\***************************************************************************/
#define SYSTEM_POLICIES_KEY TEXT("Software\\Policies\\Microsoft\\Windows\\System")
#define PROFILE_LOCALONLY TEXT("LocalProfile")
#define USER_PREFERENCE TEXT("UserPreference")
#define USERINFO_LOCAL 0
#define USERINFO_UNDEFINED 99
const TCHAR c_szBAK[] = TEXT(".bak");
DWORD
GcGetUserPreferenceValue(
LPTSTR SidString
)
{
TCHAR LocalProfileKey[MAX_PATH];
DWORD RegErr, dwType, dwSize, dwTmpVal, dwRetVal = USERINFO_UNDEFINED;
LPTSTR lpEnd;
HKEY hkeyProfile, hkeyPolicy;
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE,
SYSTEM_POLICIES_KEY,
0, KEY_READ,
&hkeyPolicy) == ERROR_SUCCESS) {
dwSize = sizeof(dwTmpVal);
RegQueryValueEx(hkeyPolicy,
PROFILE_LOCALONLY,
NULL, &dwType,
(LPBYTE) &dwTmpVal,
&dwSize);
RegCloseKey (hkeyPolicy);
if (dwTmpVal == 1) {
dwRetVal = USERINFO_LOCAL;
return dwRetVal;
}
}
if (SidString != NULL) {
//
// Query for the UserPreference value
//
lstrcpy(LocalProfileKey, GC_PROFILE_LIST_PATH);
lpEnd = GcCheckSlash (LocalProfileKey);
lstrcpy(lpEnd, SidString);
RegErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
LocalProfileKey,
0,
KEY_READ,
&hkeyProfile);
if (RegErr == ERROR_SUCCESS) {
dwSize = sizeof(dwRetVal);
RegQueryValueEx(hkeyProfile,
USER_PREFERENCE,
NULL,
&dwType,
(LPBYTE) &dwRetVal,
&dwSize);
RegCloseKey (hkeyProfile);
}
lstrcat(LocalProfileKey, c_szBAK);
RegErr = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
LocalProfileKey,
0,
KEY_READ,
&hkeyProfile);
if (RegErr == ERROR_SUCCESS) {
dwSize = sizeof(dwRetVal);
RegQueryValueEx(hkeyProfile,
USER_PREFERENCE,
NULL,
&dwType,
(LPBYTE) &dwRetVal,
&dwSize);
RegCloseKey (hkeyProfile);
}
}
return dwRetVal;
}