You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1496 lines
44 KiB
1496 lines
44 KiB
//*************************************************************
|
|
//
|
|
// Functions to apply policy
|
|
//
|
|
// Microsoft Confidential
|
|
// Copyright (c) Microsoft Corporation 1995
|
|
// All rights reserved
|
|
//
|
|
//*************************************************************
|
|
|
|
#include "uenv.h"
|
|
#include <regstr.h>
|
|
#include <winnetwk.h>
|
|
#include <lm.h>
|
|
#include <strsafe.h>
|
|
//
|
|
// Update mode constants
|
|
//
|
|
|
|
#define UM_OFF 0
|
|
#define UM_AUTOMATIC 1
|
|
#define UM_MANUAL 2
|
|
|
|
|
|
//
|
|
// Prefix constants for value names
|
|
//
|
|
|
|
#define NUM_PREFIX 3
|
|
#define PREFIX_UNKNOWN 0
|
|
#define PREFIX_DELETE 1
|
|
#define PREFIX_SOFT 2
|
|
#define PREFIX_DELVALS 3
|
|
|
|
|
|
//
|
|
// Max size of a value's data
|
|
//
|
|
|
|
#define MAX_VALUE_DATA 4096
|
|
|
|
//
|
|
// Default group size
|
|
//
|
|
|
|
#define DEFAULT_GROUP_SIZE 8192
|
|
|
|
|
|
//
|
|
// Registry value names
|
|
//
|
|
|
|
TCHAR g_szUpdateModeValue[] = TEXT("UpdateMode");
|
|
TCHAR g_szNetPathValue[] = TEXT("NetworkPath");
|
|
TCHAR g_szLogonKey[] = WINLOGON_KEY;
|
|
CHAR g_szPolicyHandler[] = "PolicyHandler"; // This needs to be ANSI
|
|
TCHAR g_szTmpKeyName[] = TEXT("AdminConfigData");
|
|
TCHAR g_szPrefixDel[] = TEXT("**del.");
|
|
TCHAR g_szPrefixSoft[] = TEXT("**soft.");
|
|
TCHAR g_szPrefixDelvals[] = TEXT("**delvals.");
|
|
|
|
|
|
//
|
|
// Function proto-types
|
|
//
|
|
|
|
HKEY OpenUserKey(HKEY hkeyRoot, LPCTSTR pszName, BOOL * pfFoundSpecific);
|
|
UINT MergeRegistryData(HKEY hkeySrc, HKEY hkeyDst, LPTSTR pszKeyNameBuffer,
|
|
UINT cbKeyNameBuffer);
|
|
UINT CopyKeyValues(HKEY hkeySrc,HKEY hkeyDst);
|
|
BOOL HasSpecialPrefix(LPTSTR szValueName, DWORD * pdwPrefix,
|
|
LPTSTR szStrippedValueName, DWORD dwBufSize);
|
|
BOOL GetGroupProcessingOrder(HKEY hkeyHiveRoot,LPTSTR * pGroupBuffer, DWORD * pdwGroupSize);
|
|
BOOL FindGroupInList(LPTSTR pszGroupName, LPTSTR pszGroupList);
|
|
LPTSTR GetUserGroups (LPCTSTR lpServerName, LPCTSTR lpUserName, HANDLE hToken, DWORD * puEntriesRead);
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// ApplySystemPolicy()
|
|
//
|
|
// Purpose: Entry point for Windows NT4 System Policy.
|
|
//
|
|
// Parameters: dwFlags - Flags
|
|
// hToken - User's token
|
|
// hKeyCurrentUser - Registry to the root of the user's hive
|
|
// lpUserName - User's name
|
|
// lpPolicyPath - Path to the policy file (ntconfig.pol). Can be NULL.
|
|
// lpServerName - Domain controller name used for group
|
|
// membership look up. Can be NULL.
|
|
//
|
|
// Return: TRUE if successful
|
|
// FALSE if an error occurs
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 05/30/95 ericflo Created
|
|
// 10/12/98 ericflo Update for NT5
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL WINAPI ApplySystemPolicy (DWORD dwFlags, HANDLE hToken, HKEY hKeyCurrentUser,
|
|
LPCTSTR lpUserName, LPCTSTR lpPolicyPath,
|
|
LPCTSTR lpServerName)
|
|
{
|
|
LONG lResult;
|
|
BOOL bResult = FALSE;
|
|
BOOL fFoundUser=FALSE;
|
|
HKEY hkeyMain=NULL, hkeyRoot=NULL, hkeyUser, hkeyLogon;
|
|
DWORD dwUpdateMode=UM_AUTOMATIC;
|
|
DWORD dwData, dwSize;
|
|
TCHAR szFilePath[MAX_PATH];
|
|
TCHAR szLocalPath[MAX_PATH];
|
|
TCHAR szTempDir[MAX_PATH];
|
|
TCHAR szTempKey[100];
|
|
CHAR szHandler[MAX_PATH+50]; // This needs to be ANSI
|
|
TCHAR szComputerName[MAX_PATH];
|
|
TCHAR szBuffer[MAX_PATH+1];
|
|
WIN32_FILE_ATTRIBUTE_DATA fad;
|
|
LPTSTR lpEnd;
|
|
HANDLE hOldToken;
|
|
DWORD dwRet = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Verbose output
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Entering")));
|
|
|
|
|
|
|
|
//
|
|
// Initialize szFilePath
|
|
//
|
|
|
|
szFilePath[0] = TEXT('\0');
|
|
|
|
|
|
//
|
|
// Check the registry to see if update is specified and get update path
|
|
//
|
|
|
|
lResult = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
REGSTR_PATH_UPDATE,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyMain);
|
|
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
|
|
|
|
//
|
|
// Look for the update mode.
|
|
//
|
|
|
|
dwSize=sizeof(dwUpdateMode);
|
|
if (RegQueryValueEx(hkeyMain,g_szUpdateModeValue,NULL,NULL,
|
|
(LPBYTE) &dwUpdateMode,&dwSize) != ERROR_SUCCESS) {
|
|
dwUpdateMode = UM_OFF;
|
|
}
|
|
|
|
|
|
//
|
|
// if manual update is specified, also get the path to update from
|
|
// (UNC path or path with drive letter)
|
|
//
|
|
|
|
|
|
if (dwUpdateMode==UM_MANUAL) {
|
|
|
|
dwSize=sizeof(szTempDir);
|
|
|
|
lResult = RegQueryValueEx(hkeyMain, g_szNetPathValue, NULL, NULL,
|
|
(LPBYTE) szTempDir, &dwSize);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
TCHAR szErr[MAX_PATH];
|
|
|
|
RegCloseKey(hkeyMain);
|
|
ReportError(hToken, PI_NOUI, 1, EVENT_MISSINGPOLICYFILEENTRY, GetErrString(lResult, szErr));
|
|
return FALSE;
|
|
}
|
|
|
|
dwRet = ExpandEnvironmentStrings (szTempDir, szFilePath, MAX_PATH);
|
|
|
|
if (dwRet > MAX_PATH || dwRet == 0) { //Fixing bug 548728
|
|
RegCloseKey(hkeyMain);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkeyMain);
|
|
}
|
|
|
|
|
|
//
|
|
// If this machine has policy turned off, then we can exit now.
|
|
//
|
|
|
|
if (dwUpdateMode == UM_OFF) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Policy is turned off on this machine.")));
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//
|
|
// If we are running in automatic mode, use the supplied
|
|
// policy file.
|
|
//
|
|
|
|
if (dwUpdateMode == UM_AUTOMATIC) {
|
|
|
|
if (lpPolicyPath && *lpPolicyPath) {
|
|
hr = StringCchCopy (szFilePath, ARRAYSIZE(szFilePath), lpPolicyPath);
|
|
if (FAILED(hr)) {
|
|
SetLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If we don't have a policy file, then we can exit now.
|
|
//
|
|
|
|
if (szFilePath[0] == TEXT('\0')) {
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: No Policy file. Leaving.")));
|
|
return TRUE;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: PolicyPath is: <%s>."), szFilePath));
|
|
|
|
|
|
//
|
|
// Impersonate the user
|
|
//
|
|
|
|
if (!ImpersonateUser(hToken, &hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to impersonate user")));
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Test if the policy file exists
|
|
//
|
|
|
|
if (!GetFileAttributesEx (szFilePath, GetFileExInfoStandard, &fad)) {
|
|
|
|
lResult = GetLastError();
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
|
|
}
|
|
|
|
|
|
if ( (lResult == ERROR_FILE_NOT_FOUND) ||
|
|
(lResult == ERROR_PATH_NOT_FOUND) ) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: No policy file.")));
|
|
return TRUE;
|
|
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Failed to query for policy file with error %d."), lResult));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Create a temporary file name
|
|
//
|
|
|
|
dwSize = ARRAYSIZE(szBuffer);
|
|
|
|
if (!GetUserProfileDirectory(hToken, szBuffer, &dwSize)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to query user profile directory with error %d."), GetLastError()));
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
if (!GetTempFileName (szBuffer, TEXT("prf"), 0, szLocalPath)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to create temporary filename with error %d."), GetLastError()));
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the policy hive
|
|
//
|
|
|
|
if (!CopyFile(szFilePath, szLocalPath, FALSE)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to copy policy file with error %d."), GetLastError()));
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Revert to being 'ourself'
|
|
//
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to revert to self")));
|
|
}
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Local PolicyPath is: <%s>."), szLocalPath));
|
|
|
|
|
|
//
|
|
// Query for the computer name
|
|
//
|
|
|
|
dwSize = ARRAYSIZE(szComputerName);
|
|
if (!GetComputerName(szComputerName, &dwSize)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: GetComputerName failed.")));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Check to see if an installable policy handler has been added. If
|
|
// so, call it and let it do the work.
|
|
//
|
|
|
|
lResult = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
|
|
g_szLogonKey,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyLogon);
|
|
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
HANDLE hDLL = NULL;
|
|
BOOL fRet;
|
|
PFNPROCESSPOLICIES pfn;
|
|
|
|
|
|
dwSize = ARRAYSIZE(szHandler);
|
|
lResult = RegQueryValueExA(hkeyLogon,
|
|
g_szPolicyHandler,
|
|
NULL, NULL,
|
|
(LPBYTE) szHandler,
|
|
&dwSize);
|
|
|
|
|
|
RegCloseKey(hkeyLogon);
|
|
|
|
if (lResult == ERROR_SUCCESS) {
|
|
LPSTR lpEntryPoint = szHandler;
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Machine has a custom Policy Handler of: %S."), szHandler));
|
|
|
|
//
|
|
// Search for the ,
|
|
//
|
|
|
|
while (*lpEntryPoint && *lpEntryPoint != ',') {
|
|
lpEntryPoint++;
|
|
}
|
|
|
|
|
|
//
|
|
// Check if we found the ,
|
|
//
|
|
|
|
if (*lpEntryPoint) {
|
|
|
|
*lpEntryPoint = '\0';
|
|
lpEntryPoint++;
|
|
|
|
|
|
hDLL = LoadLibraryA(szHandler);
|
|
|
|
if (hDLL) {
|
|
|
|
pfn = (PFNPROCESSPOLICIES) GetProcAddress(hDLL, lpEntryPoint);
|
|
|
|
if (pfn != NULL) {
|
|
|
|
//
|
|
// Call the function.
|
|
// Note that the parameters are UNICODE.
|
|
//
|
|
|
|
fRet = (*pfn) (NULL,
|
|
szLocalPath,
|
|
lpUserName,
|
|
szComputerName,
|
|
0);
|
|
|
|
|
|
//
|
|
// if callout policy downloader returns FALSE, then we don't
|
|
// do any processing on our own. If it returns TRUE then we
|
|
// go ahead and process policies normally, in addition to whatever
|
|
// he may have done.
|
|
//
|
|
|
|
if (!fRet) {
|
|
FreeLibrary(hDLL);
|
|
bResult = TRUE;
|
|
goto Exit;
|
|
}
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to find entry point %S in policy dll. Error %d."),
|
|
lpEntryPoint, GetLastError()));
|
|
}
|
|
|
|
FreeLibrary(hDLL);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to load %S with error %d."),
|
|
szHandler, GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Load the policy hive into registry
|
|
//
|
|
|
|
hr = StringCchPrintf (szTempKey, ARRAYSIZE(szTempKey), TEXT("%s (%d)"), g_szTmpKeyName, GetTickCount());
|
|
|
|
if (FAILED(hr)) {
|
|
SetLastError(HRESULT_CODE(hr));
|
|
goto Exit;
|
|
}
|
|
|
|
lResult = MyRegLoadKey(HKEY_USERS, szTempKey, szLocalPath);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to load policy hive. Error = %d"), lResult));
|
|
goto Exit;
|
|
}
|
|
|
|
//
|
|
// Open the policy hive.
|
|
//
|
|
|
|
lResult = RegOpenKeyEx (HKEY_USERS,
|
|
szTempKey,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyMain);
|
|
|
|
if (lResult != ERROR_SUCCESS) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to open policy hive. Error = %d"), lResult));
|
|
MyRegUnLoadKey(HKEY_USERS, szTempKey);
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// For user and machine policies, see if there is an appropriate entry
|
|
// in policy file (either a key with user/computer name,
|
|
// or a default user or workstation entry). If there is, then merge
|
|
// information under that key into registry. (If there isn't, it's
|
|
// not an error-- just nothing to do.)
|
|
//
|
|
|
|
if (dwFlags & SP_FLAG_APPLY_USER_POLICY) {
|
|
|
|
//
|
|
// Merge user-specific policies if user name was specified
|
|
//
|
|
|
|
if (RegOpenKeyEx(hkeyMain,
|
|
REGSTR_KEY_POL_USERS,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyRoot) == ERROR_SUCCESS) {
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Looking for user specific policy.")));
|
|
|
|
hkeyUser = OpenUserKey(hkeyRoot, lpUserName, &fFoundUser);
|
|
|
|
if (hkeyUser) {
|
|
MergeRegistryData(hkeyUser,hKeyCurrentUser,szBuffer, ARRAYSIZE(szBuffer));
|
|
RegCloseKey(hkeyUser);
|
|
}
|
|
|
|
RegCloseKey(hkeyRoot);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Merge group specific policies if user name specified, and we
|
|
// *didn't* find a specific user entry above
|
|
//
|
|
|
|
if (!fFoundUser && lpServerName && *lpServerName) {
|
|
HKEY hkeyGroups, hkeyGroup;
|
|
LPTSTR GroupBuffer, ApiBuf;
|
|
DWORD dwGroupSize = DEFAULT_GROUP_SIZE;
|
|
DWORD uEntriesRead;
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Processing group(s) policy.")));
|
|
|
|
GroupBuffer = GlobalAlloc(GPTR, DEFAULT_GROUP_SIZE * sizeof(TCHAR));
|
|
|
|
if (GroupBuffer) {
|
|
|
|
//
|
|
// if there is a group processing order specified in policy hive,
|
|
// then process groups
|
|
//
|
|
|
|
if (RegOpenKeyEx(hkeyMain,
|
|
REGSTR_KEY_POL_USERGROUPS,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyGroups) == ERROR_SUCCESS) {
|
|
|
|
|
|
if (GetGroupProcessingOrder(hkeyMain, &GroupBuffer, &dwGroupSize)) {
|
|
|
|
//
|
|
// Enumerate the groups that this user belongs to
|
|
//
|
|
|
|
ApiBuf = GetUserGroups (lpServerName, lpUserName, hToken, &uEntriesRead);
|
|
|
|
if (ApiBuf) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: User belongs to %d groups."), uEntriesRead));
|
|
|
|
if (uEntriesRead) {
|
|
|
|
//
|
|
// Walk through the list of groups (ordered lowest priority
|
|
// to highest priority). for each group, if the user belongs
|
|
// to it then download policies for that group.
|
|
//
|
|
|
|
LPTSTR pszGroup = GroupBuffer;
|
|
TCHAR szKeyNameBuffer[MAX_PATH+1];
|
|
|
|
while (*pszGroup) {
|
|
|
|
//
|
|
// Does user belong to this group?
|
|
//
|
|
|
|
if (FindGroupInList(pszGroup, ApiBuf)) {
|
|
|
|
//
|
|
// Open the key in the hive for this group
|
|
//
|
|
|
|
if (RegOpenKeyEx (hkeyGroups,
|
|
pszGroup,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyGroup) == ERROR_SUCCESS) {
|
|
|
|
|
|
//
|
|
// Merge group policies
|
|
//
|
|
|
|
MergeRegistryData(hkeyGroup,
|
|
hKeyCurrentUser,
|
|
szKeyNameBuffer,
|
|
ARRAYSIZE(szKeyNameBuffer));
|
|
|
|
RegCloseKey (hkeyGroup);
|
|
}
|
|
}
|
|
|
|
pszGroup += lstrlen(pszGroup) + 1;
|
|
}
|
|
}
|
|
|
|
GlobalFree (ApiBuf);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to get user's groups.")));
|
|
}
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to get group processing order.")));
|
|
}
|
|
|
|
RegCloseKey(hkeyGroups);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to allocate memory for group policy. Error = %d"), GetLastError()));
|
|
}
|
|
|
|
GlobalFree (GroupBuffer);
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to allocate memory for group policy. Error = %d"), GetLastError()));
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if (dwFlags & SP_FLAG_APPLY_MACHINE_POLICY) {
|
|
|
|
//
|
|
// Merge machine-specific policies if computer name was specified
|
|
//
|
|
|
|
if (RegOpenKeyEx(hkeyMain,
|
|
REGSTR_KEY_POL_COMPUTERS,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyRoot) == ERROR_SUCCESS) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Looking for machine specific policy.")));
|
|
|
|
hkeyUser = OpenUserKey(hkeyRoot, szComputerName, &fFoundUser);
|
|
|
|
if (hkeyUser) {
|
|
MergeRegistryData(hkeyUser, HKEY_LOCAL_MACHINE, szBuffer, ARRAYSIZE(szBuffer));
|
|
RegCloseKey(hkeyUser);
|
|
}
|
|
|
|
RegCloseKey(hkeyRoot);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Close the policy key
|
|
//
|
|
|
|
RegCloseKey(hkeyMain);
|
|
|
|
|
|
//
|
|
// Unload the policy hive.
|
|
//
|
|
|
|
if (!MyRegUnLoadKey(HKEY_USERS, szTempKey)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to unload policy hive. Error = %d"), lResult));
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
//
|
|
// Success
|
|
//
|
|
|
|
bResult = TRUE;
|
|
|
|
Exit:
|
|
|
|
//
|
|
// Delete the policy files
|
|
//
|
|
|
|
if (!DeleteFile (szLocalPath)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to delete policy file <%s>. Error %d"),
|
|
szLocalPath, GetLastError()));
|
|
}
|
|
|
|
hr = StringCchCat (szLocalPath, ARRAYSIZE(szLocalPath), c_szLog);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
if (!DeleteFile (szLocalPath)) {
|
|
DebugMsg((DM_WARNING, TEXT("ApplySystemPolicy: Failed to delete policy log file <%s>. Error %d"),
|
|
szLocalPath, GetLastError()));
|
|
}
|
|
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("ApplySystemPolicy: Leaving with %d"), bResult));
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// OpenUserKey()
|
|
//
|
|
// Purpose: Attempts to open the user specific key, or the
|
|
// .default key.
|
|
//
|
|
// Parameters: hkeyRoot - Root key
|
|
// pszName - User name
|
|
// fFoundSpecific - Found the requested key
|
|
//
|
|
// Return: hkey if successful
|
|
// NULL if not
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/13/95 ericflo Ported
|
|
//
|
|
//*************************************************************
|
|
|
|
HKEY OpenUserKey(HKEY hkeyRoot,LPCTSTR pszName, BOOL *pfFoundSpecific)
|
|
{
|
|
HKEY hkeyTest;
|
|
*pfFoundSpecific = FALSE;
|
|
|
|
//
|
|
// See if there is a subkey under the specified key with the given
|
|
// user name
|
|
//
|
|
|
|
if ((RegOpenKeyEx(hkeyRoot,
|
|
pszName,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyTest)) == ERROR_SUCCESS) {
|
|
|
|
*pfFoundSpecific = TRUE;
|
|
DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: Found specific entry for %s ignoring .Default."), pszName));
|
|
return hkeyTest;
|
|
}
|
|
|
|
//
|
|
// If not, see if there is a default key
|
|
//
|
|
|
|
if ((RegOpenKeyEx(hkeyRoot,
|
|
REGSTR_KEY_POL_DEFAULT,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyTest)) == ERROR_SUCCESS) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: No entry for %s, using .Default instead."), pszName));
|
|
return hkeyTest;
|
|
}
|
|
|
|
|
|
//
|
|
// No entry for this name in policy file
|
|
//
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("OpenUserKey: No user/machine specific policy and no .Default policy.")));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// MergeRegistryData()
|
|
//
|
|
// Purpose: Merges hkeySrc and subkeys into hkeyDst.
|
|
//
|
|
// Parameters: hkeySrc - Source
|
|
// hkeyDst - Destination
|
|
// pszKeyNameBuffer - Key name
|
|
// cbKeyNameBuffer - Size of key name buffer
|
|
//
|
|
//
|
|
// Return: ERROR_SUCCESS if successful
|
|
// otherwise an error value
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/13/95 ericflo Ported
|
|
//
|
|
//*************************************************************
|
|
|
|
UINT MergeRegistryData(HKEY hkeySrc, HKEY hkeyDst, LPTSTR pszKeyNameBuffer,
|
|
UINT cbKeyNameBuffer)
|
|
{
|
|
UINT nIndex = 0,uRet=ERROR_SUCCESS;
|
|
|
|
//
|
|
// Look for any subkeys of the source key
|
|
//
|
|
|
|
while ((uRet=RegEnumKey(hkeySrc,nIndex,pszKeyNameBuffer,
|
|
cbKeyNameBuffer)) == ERROR_SUCCESS) {
|
|
|
|
HKEY hkeySubkeySrc,hkeySubkeyDst;
|
|
|
|
|
|
//
|
|
// Create the subkey under the destination key
|
|
//
|
|
|
|
if ((uRet=RegCreateKey(hkeyDst,pszKeyNameBuffer,
|
|
&hkeySubkeyDst)) != ERROR_SUCCESS)
|
|
return uRet;
|
|
|
|
if ((uRet=RegOpenKey(hkeySrc, pszKeyNameBuffer,
|
|
&hkeySubkeySrc)) != ERROR_SUCCESS) {
|
|
RegCloseKey(hkeySubkeyDst);
|
|
return uRet;
|
|
}
|
|
|
|
|
|
//
|
|
// Copy the key values from source subkey to destination subkey
|
|
//
|
|
|
|
uRet=CopyKeyValues(hkeySubkeySrc,hkeySubkeyDst);
|
|
|
|
if (uRet == ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Merge recursively on subkeys of these keys, if any
|
|
//
|
|
|
|
uRet = MergeRegistryData(hkeySubkeySrc,hkeySubkeyDst,pszKeyNameBuffer,
|
|
cbKeyNameBuffer);
|
|
}
|
|
|
|
RegCloseKey(hkeySubkeySrc);
|
|
RegCloseKey(hkeySubkeyDst);
|
|
|
|
if (uRet != ERROR_SUCCESS) {
|
|
return uRet;
|
|
}
|
|
|
|
nIndex ++;
|
|
}
|
|
|
|
|
|
if (uRet == ERROR_NO_MORE_ITEMS) {
|
|
uRet=ERROR_SUCCESS;
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// CopyKeyValues()
|
|
//
|
|
// Purpose: Copies all key values from hkeySrc to hkeyDst
|
|
//
|
|
// Parameters: hkeySrc - Source
|
|
// hkeyDst - destination
|
|
//
|
|
// Return: Error code
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/14/95 ericflo Ported
|
|
//
|
|
//*************************************************************
|
|
|
|
UINT CopyKeyValues(HKEY hkeySrc, HKEY hkeyDst)
|
|
{
|
|
DWORD dwSubkeyCount,dwMaxSubkeyNameLen,dwMaxClassNameLen,dwValueCount,
|
|
dwMaxValueNameLen,dwMaxValueDataLen,dwDescriptorLen,dwClassNameLen;
|
|
FILETIME ftLastWriteTime;
|
|
UINT uRet=ERROR_SUCCESS;
|
|
TCHAR szClassName[255];
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Do RegQueryInfoKey to find out if there are values for the source key,
|
|
// and the size of value name and value data buffes to alloc
|
|
//
|
|
|
|
dwClassNameLen = ARRAYSIZE(szClassName);
|
|
|
|
uRet=RegQueryInfoKey(hkeySrc,szClassName,&dwClassNameLen,NULL,&dwSubkeyCount,
|
|
&dwMaxSubkeyNameLen,&dwMaxClassNameLen,&dwValueCount,&dwMaxValueNameLen,
|
|
&dwMaxValueDataLen,&dwDescriptorLen,&ftLastWriteTime);
|
|
|
|
if (uRet != ERROR_SUCCESS) {
|
|
return uRet;
|
|
}
|
|
|
|
|
|
//
|
|
// If there are values...
|
|
//
|
|
|
|
|
|
if (dwValueCount) {
|
|
TCHAR ValueName[MAX_PATH];
|
|
LPBYTE ValueData;
|
|
DWORD dwType,dwValueNameSize,dwValueDataSize;
|
|
UINT nIndex = 0;
|
|
|
|
|
|
ValueData = GlobalAlloc (GPTR, MAX_VALUE_DATA);
|
|
|
|
if (!ValueData) {
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// the "**delvals" control code is special, must be processed
|
|
// first; look for it now and if it exists delete all existing
|
|
// values under this key in destination registry
|
|
//
|
|
|
|
if (RegQueryValueEx(hkeySrc,g_szPrefixDelvals,NULL,NULL,NULL,NULL) == ERROR_SUCCESS) {
|
|
|
|
DeleteAllValues(hkeyDst);
|
|
}
|
|
|
|
//
|
|
// Enumerate the values of the source key, and create each value
|
|
// under the destination key
|
|
//
|
|
|
|
do {
|
|
dwValueNameSize = MAX_PATH;
|
|
dwValueDataSize = MAX_VALUE_DATA;
|
|
|
|
if ((uRet=RegEnumValue(hkeySrc,nIndex, ValueName,
|
|
&dwValueNameSize,NULL,&dwType, ValueData,
|
|
&dwValueDataSize)) == ERROR_SUCCESS) {
|
|
|
|
DWORD dwPrefix;
|
|
|
|
//
|
|
// Look for special prefixes which indicate we should treat
|
|
// these values specially
|
|
//
|
|
TCHAR StrippedValueName[MAX_PATH];
|
|
|
|
if (HasSpecialPrefix(ValueName, &dwPrefix, StrippedValueName, MAX_PATH)) { // Fixing bug 548903
|
|
|
|
//
|
|
// ValueName now contains real value name stripped
|
|
// of prefix, filled in above by HasSpecialPrefix().
|
|
// Adjust value name size, the value name will shorten
|
|
// because the prefix has been removed.
|
|
//
|
|
|
|
hr = StringCchCopy(ValueName, MAX_PATH, StrippedValueName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
dwValueNameSize = lstrlen (ValueName) + 1;
|
|
|
|
switch (dwPrefix) {
|
|
|
|
case PREFIX_DELETE:
|
|
|
|
//
|
|
// Delete this value in destination
|
|
//
|
|
|
|
RegDeleteValue(hkeyDst, ValueName);
|
|
uRet = ERROR_SUCCESS;
|
|
DebugMsg((DM_VERBOSE, TEXT("Deleted value: %s"), ValueName));
|
|
break;
|
|
|
|
case PREFIX_SOFT:
|
|
|
|
//
|
|
// "soft" value, only set this if it doesn't already
|
|
// exist in destination
|
|
//
|
|
|
|
{
|
|
|
|
TCHAR TmpValueData[MAX_PATH+1];
|
|
DWORD dwSize=sizeof(TmpValueData);
|
|
|
|
if (RegQueryValueEx(hkeyDst, ValueName,
|
|
NULL,NULL,(LPBYTE) TmpValueData,
|
|
&dwSize) != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// The value doesn't exist, set the value.
|
|
//
|
|
|
|
uRet=RegSetValueEx(hkeyDst, ValueName, 0,
|
|
dwType, ValueData,
|
|
dwValueDataSize);
|
|
|
|
} else {
|
|
|
|
//
|
|
// Value already exists, nothing to do
|
|
//
|
|
|
|
uRet = ERROR_SUCCESS;
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case PREFIX_DELVALS:
|
|
// processed early on above, fall through and ignore
|
|
|
|
default:
|
|
|
|
//
|
|
// Got some prefix that we don't understand... presumably,
|
|
// from a future version. Ignore this value, rather than
|
|
// propagating it into the registry, prefix and all.
|
|
// This will give us less backward compatibility headaches
|
|
// down the road.
|
|
//
|
|
|
|
uRet = ERROR_SUCCESS; // nothing to do
|
|
|
|
break;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Copy the value normally to destination key
|
|
//
|
|
|
|
uRet=RegSetValueEx(hkeyDst,ValueName,0,
|
|
dwType,ValueData,dwValueDataSize);
|
|
|
|
#if DBG
|
|
if (uRet == ERROR_SUCCESS) {
|
|
|
|
switch (dwType) {
|
|
case REG_SZ:
|
|
case REG_EXPAND_SZ:
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s => %s [OK]"),
|
|
ValueName, (LPTSTR)ValueData));
|
|
break;
|
|
|
|
case REG_DWORD:
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s => %d [OK]"),
|
|
ValueName, (DWORD)*ValueData));
|
|
break;
|
|
|
|
default:
|
|
DebugMsg((DM_VERBOSE, TEXT("CopyKeyValues: %s was set successfully"),
|
|
ValueName));
|
|
}
|
|
|
|
} else {
|
|
DebugMsg((DM_WARNING, TEXT("CopyKeyValues: Failed to set %s with error %d."),
|
|
ValueName, uRet));
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
|
|
nIndex++;
|
|
|
|
} while (uRet == ERROR_SUCCESS);
|
|
|
|
|
|
if (uRet == ERROR_NO_MORE_ITEMS) {
|
|
uRet=ERROR_SUCCESS;
|
|
}
|
|
|
|
GlobalFree (ValueData);
|
|
}
|
|
|
|
return uRet;
|
|
}
|
|
|
|
|
|
//*************************************************************
|
|
//
|
|
// HasSpecialPrefix()
|
|
//
|
|
// Purpose: Checks to see if szValueName has a special prefix (a la
|
|
// "**<something>." Returns TRUE if it does, FALSE otherwise.
|
|
// if TRUE, returns the numerical index of the prefix in *pdwPrefix,
|
|
// and copies the rest of value name (after the ".") into
|
|
// szStrippedValueName. Buffer for szStrippedValueName must be at
|
|
// least as large as szValueName. It is safe to pass the same
|
|
// buffer to szValueName and szStrippedValueName and have the name
|
|
// modified in place.
|
|
//
|
|
// Parameters: szValueName - Value Name
|
|
// pdwPrefix - Index of the prefix
|
|
// szStrippedValueName - Value name without the **
|
|
//
|
|
//
|
|
// Return: TRUE if value name has a prefix
|
|
// FALSE if it does not
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/14/95 ericflo Ported
|
|
//
|
|
//*************************************************************
|
|
|
|
typedef struct tagPREFIXMAP {
|
|
const LPTSTR pszPrefix;
|
|
DWORD dwPrefixIndex;
|
|
} PREFIXMAP;
|
|
|
|
|
|
|
|
BOOL HasSpecialPrefix(LPTSTR szValueName, DWORD * pdwPrefix,
|
|
LPTSTR szStrippedValueName, DWORD dwBufSize)
|
|
{
|
|
|
|
PREFIXMAP PrefixMap[] = {
|
|
{g_szPrefixDel, PREFIX_DELETE},
|
|
{g_szPrefixSoft, PREFIX_SOFT},
|
|
{g_szPrefixDelvals, PREFIX_DELVALS}
|
|
};
|
|
UINT nCount,nLen;
|
|
HRESULT hr = S_OK;
|
|
|
|
|
|
//
|
|
// Does the value name begin with "**"?
|
|
//
|
|
|
|
if (!szValueName || (lstrlen(szValueName) < 2) ||
|
|
szValueName[0] != TEXT('*') || szValueName[1] != TEXT('*'))
|
|
|
|
return FALSE; // not a special prefix
|
|
|
|
|
|
//
|
|
// Try all the prefixes we know to try to find a match
|
|
//
|
|
|
|
for (nCount = 0; nCount < ARRAYSIZE(PrefixMap); nCount++) {
|
|
nLen = lstrlen (PrefixMap[nCount].pszPrefix);
|
|
|
|
if (CompareString (LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE,
|
|
szValueName, nLen,
|
|
PrefixMap[nCount].pszPrefix, nLen) == 2) {
|
|
|
|
*pdwPrefix = PrefixMap[nCount].dwPrefixIndex;
|
|
|
|
//
|
|
// make a copy of the value name, sans prefix, into
|
|
// the stripped value name buffer
|
|
//
|
|
|
|
hr = StringCchCopy (szStrippedValueName, dwBufSize, szValueName + nLen);
|
|
if (FAILED(hr)) {
|
|
SetLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// this is a prefix, but not one we know.
|
|
//
|
|
|
|
*pdwPrefix = PREFIX_UNKNOWN;
|
|
hr = StringCchCopy (szStrippedValueName, dwBufSize, szValueName);
|
|
if (FAILED(hr)) {
|
|
SetLastError(HRESULT_CODE(hr));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// GetGroupProcessingOrder()
|
|
//
|
|
// Purpose: Gets the list of groups in order
|
|
//
|
|
// Parameters: hkeyHiveRoot - Registry key
|
|
// GroupBuffer - Pointer to group buffer
|
|
// pdwBufferSize - Buffer size
|
|
//
|
|
// Return: Number of entries if successful
|
|
// 0 if an error occurs
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/14/95 ericflo Ported
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL GetGroupProcessingOrder(HKEY hkeyHiveRoot, LPTSTR * pGroupBuffer,
|
|
DWORD * pdwGroupSize)
|
|
{
|
|
DWORD cEntries,cMaxValueName,cMaxData;
|
|
HKEY hkeyGroupData;
|
|
UINT uRet;
|
|
LPTSTR GroupBuffer = *pGroupBuffer;
|
|
LPTSTR lpTemp;
|
|
DWORD dwGroupSize = *pdwGroupSize;
|
|
TCHAR szValueName[11], szGroupName[48+1]; // netware groups can be up to 48 chars
|
|
DWORD dwUsed = 0, dwSize; // amount of buffer used
|
|
UINT nLen,nRead=0;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Open the group data key
|
|
//
|
|
|
|
uRet = RegOpenKeyEx(hkeyHiveRoot,
|
|
REGSTR_KEY_POL_USERGROUPDATA,
|
|
0,
|
|
KEY_READ,
|
|
&hkeyGroupData);
|
|
|
|
if (uRet != ERROR_SUCCESS) {
|
|
|
|
//
|
|
// Group data key doesn't exist (most likely), no downloading to do
|
|
//
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// Find out the number of values in group data key
|
|
//
|
|
|
|
if ((RegQueryInfoKey (hkeyGroupData,NULL,NULL,NULL,NULL,NULL,
|
|
NULL,&cEntries,&cMaxValueName,&cMaxData,NULL,NULL ) != ERROR_SUCCESS) ||
|
|
!cEntries) {
|
|
|
|
RegCloseKey(hkeyGroupData);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// The values are stored as "1"="<group name>", "2"="<group name>", etc.
|
|
// where 1 is most important. we will pack the names into a buffer lowest
|
|
// priority to highest. So if we have n values, start with value name "<n>"
|
|
// and work down to "1".
|
|
//
|
|
|
|
while (cEntries) {
|
|
|
|
hr = StringCchPrintf(szValueName, ARRAYSIZE(szValueName), TEXT("%lu"), cEntries);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
dwSize = sizeof(szGroupName);
|
|
|
|
if (RegQueryValueEx(hkeyGroupData,szValueName,NULL,NULL,
|
|
(LPBYTE) szGroupName,&dwSize) == ERROR_SUCCESS) {
|
|
|
|
nLen = lstrlen(szGroupName) + 1;
|
|
|
|
//
|
|
// Resize buffer if neccessary (add 1 for extra terminating null)
|
|
//
|
|
|
|
if (nLen + dwUsed + 1 > dwGroupSize) {
|
|
|
|
//
|
|
// add a little extra so we don't realloc on every item
|
|
//
|
|
|
|
dwGroupSize = dwGroupSize + nLen + 256;
|
|
|
|
lpTemp = GlobalReAlloc(GroupBuffer,
|
|
(dwGroupSize * sizeof(TCHAR)),
|
|
GMEM_MOVEABLE);
|
|
|
|
if (!lpTemp) {
|
|
|
|
RegCloseKey(hkeyGroupData);
|
|
return FALSE;
|
|
}
|
|
|
|
GroupBuffer = lpTemp;
|
|
}
|
|
|
|
hr = StringCchPrintf(GroupBuffer + dwUsed, dwGroupSize - dwUsed, szGroupName);
|
|
ASSERT(SUCCEEDED(hr));
|
|
|
|
dwUsed += nLen;
|
|
nRead++;
|
|
}
|
|
|
|
cEntries --;
|
|
}
|
|
|
|
//
|
|
// Doubly null-terminate buffer
|
|
//
|
|
|
|
*(GroupBuffer + dwUsed) = TEXT('\0');
|
|
|
|
RegCloseKey(hkeyGroupData);
|
|
|
|
*pGroupBuffer = GroupBuffer;
|
|
*pdwGroupSize = dwGroupSize;
|
|
|
|
return (nRead > 0);
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// FindGroupInList()
|
|
//
|
|
// Purpose: Determines if the requested group
|
|
// is in the list of groups
|
|
//
|
|
// Parameters: pszGroupName - Group looking for
|
|
// pszGroupList - List of groups null seperated
|
|
//
|
|
// Return: TRUE if found
|
|
// FALSE if not
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/15/95 ericflo Ported
|
|
//
|
|
//*************************************************************
|
|
|
|
BOOL FindGroupInList(LPTSTR pszGroupName, LPTSTR pszGroupList)
|
|
{
|
|
|
|
while (*pszGroupList) {
|
|
|
|
if (!lstrcmpi(pszGroupList,pszGroupName)) {
|
|
DebugMsg((DM_VERBOSE, TEXT("FindGroupInList: User is a member of the %s group."), pszGroupName));
|
|
return TRUE;
|
|
}
|
|
|
|
pszGroupList += lstrlen(pszGroupList) + 1;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("FindGroupInList: User is NOT a member of the %s group."), pszGroupName));
|
|
return FALSE;
|
|
}
|
|
|
|
//*************************************************************
|
|
//
|
|
// GetUserGroups()
|
|
//
|
|
// Purpose: Retrieves a list of groups this user belongs to
|
|
//
|
|
// Parameters: lpServerName - Server name
|
|
// lpUserName - User name
|
|
// hToken - User's token
|
|
// puEntriesRead - Number of groups
|
|
//
|
|
// Return: Pointer to list if successful
|
|
// Null if not
|
|
//
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 9/15/95 ericflo Created
|
|
//
|
|
//*************************************************************
|
|
|
|
LPTSTR GetUserGroups (LPCTSTR lpServerName, LPCTSTR lpUserName,
|
|
HANDLE hToken, DWORD * puEntriesRead)
|
|
{
|
|
UINT nIndex;
|
|
NET_API_STATUS status;
|
|
LPBYTE lpGroups, lpTemp;
|
|
PGROUP_INFO_0 pgi0;
|
|
DWORD dwEntriesRead, dwTotalEntries;
|
|
DWORD cchSizeNeeded;
|
|
LPTSTR lpGroupNames, lpName;
|
|
PNETAPI32_API pNetAPI32;
|
|
HANDLE hOldToken;
|
|
HRESULT hr = S_OK;
|
|
|
|
//
|
|
// Load netapi32
|
|
//
|
|
|
|
pNetAPI32 = LoadNetAPI32();
|
|
|
|
if (!pNetAPI32) {
|
|
DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to load netapi32 with %d."),
|
|
GetLastError()));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Impersonate the user
|
|
//
|
|
|
|
if (!ImpersonateUser(hToken, &hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to impersonate user")));
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Query for the groups
|
|
//
|
|
|
|
status = pNetAPI32->pfnNetUserGetGroups (lpServerName, lpUserName,
|
|
0, &lpGroups, 0xFFFFFFFF, &dwEntriesRead,
|
|
&dwTotalEntries);
|
|
|
|
if (status == NERR_Success) {
|
|
|
|
//
|
|
// NetUserGetGroups opens a named pipe to the server. To close
|
|
// it, we need to call NetUserGetInfo on the local machine
|
|
//
|
|
|
|
if (pNetAPI32->pfnNetUserGetInfo (NULL, lpUserName,
|
|
0, &lpTemp) == NERR_Success) {
|
|
pNetAPI32->pfnNetApiBufferFree (lpTemp);
|
|
}
|
|
|
|
|
|
} else {
|
|
DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: NetUserGetGroups failed with %d"), status));
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to revert to self")));
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
//
|
|
// Revert to self
|
|
//
|
|
|
|
if (!RevertToUser(&hOldToken)) {
|
|
DebugMsg((DM_WARNING, TEXT("GetUserGroups: Failed to revert to self")));
|
|
}
|
|
|
|
|
|
//
|
|
// NetUserGetGroups returns names packed in structures with fixed-length
|
|
// fields. Need to copy that into caller's buffer packed with the names
|
|
// packed end-to-end.
|
|
//
|
|
// Count the total buffer size we need, which will be smaller than the
|
|
// API buffer to NetUserGetGroups because we're not using fixed-length
|
|
// fields
|
|
//
|
|
|
|
cchSizeNeeded = 1;
|
|
pgi0 = (PGROUP_INFO_0) lpGroups;
|
|
|
|
for (nIndex=0; nIndex < dwEntriesRead; nIndex++) {
|
|
|
|
cchSizeNeeded += lstrlen(pgi0->grpi0_name) + 1;
|
|
pgi0++;
|
|
}
|
|
|
|
*puEntriesRead = dwEntriesRead;
|
|
|
|
//
|
|
// Build the list of group names
|
|
//
|
|
|
|
lpGroupNames = GlobalAlloc (GPTR, cchSizeNeeded * sizeof (TCHAR));
|
|
|
|
if (!lpGroupNames) {
|
|
pNetAPI32->pfnNetApiBufferFree (lpGroups);
|
|
return NULL;
|
|
}
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: User is a member of the following global groups:")));
|
|
|
|
lpName = lpGroupNames;
|
|
pgi0 = (PGROUP_INFO_0) lpGroups;
|
|
|
|
for (nIndex=0; nIndex < dwEntriesRead; nIndex++) {
|
|
|
|
DebugMsg((DM_VERBOSE, TEXT("GetUserGroups: %s"), pgi0->grpi0_name));
|
|
hr = StringCchCopy (lpName, cchSizeNeeded - (lpName - lpGroupNames), pgi0->grpi0_name);
|
|
ASSERT(SUCCEEDED(hr));
|
|
lpName += lstrlen(pgi0->grpi0_name) + 1;
|
|
pgi0++;
|
|
}
|
|
|
|
//
|
|
// Free the memory allocated by NetUserGetGroups
|
|
//
|
|
|
|
pNetAPI32->pfnNetApiBufferFree (lpGroups);
|
|
|
|
return lpGroupNames;
|
|
}
|