//************************************************************* // // Functions to apply policy // // Microsoft Confidential // Copyright (c) Microsoft Corporation 1995 // All rights reserved // //************************************************************* #include "uenv.h" #include #include #include #include // // 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 // "**." 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"="", "2"="", 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 "" // 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; }