/*++ 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 #include #include #include #include // // 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; }