/*++ Copyright (C) Microsoft Corporation, 2002 Module Name: selbinding.hxx Abstract: Manipulation of the selective binding registry settings. Revision History: MauricF 03-20-02 Consolodate access to selective binding settings across rpccfg/rpcnsh/rpctrans.lib --*/ #include #include DWORD GetSelectiveBindingVersion( IN DWORD dwSize, IN LPVOID lpBuffer, OUT SB_VER *pVer ) /*++ Routine Description: Determines the version of the selective binding settings in this buffer. the appropriate Arguments: dwSize - Size of the buffer lpBuffer - The buffer containing the settings pVer - Pointer to the version we fill in Return Value: ERROR_OUTOFMEMORY ERROR_SUCCESS - if the buffer is corrupt -> *pVer==SB_VER_UNKNOWN, if its default settings *pVer==SB_VER_DEFAULT --*/ { SUBNET_REG_ENTRY *pRegEntry; ASSERT(pVer != NULL); //Initialize the out params *pVer = SB_VER_UNKNOWN; //If NULL, then we treat it as default settings if ((dwSize == 0) || (lpBuffer == NULL)) { *pVer = SB_VER_DEFAULT; return ERROR_SUCCESS; } //If its not large enough to hold the flag, then //it isn't new format, could be the old format if (dwSize < sizeof(DWORD)) { *pVer = SB_VER_INDICES; return ERROR_SUCCESS; } //We can now cast the buffer as the structure, but don't //access anything but the flag just yet pRegEntry = (SUBNET_REG_ENTRY*) lpBuffer; //If it doesn't contain our flag at the begining, its //not new format, could be a differnet format though if (((ULONG)'4vPI') != pRegEntry->dwFlag) { *pVer = SB_VER_INDICES; return ERROR_SUCCESS; } //At this point it is either new format or unknown, it is not old format //If its not large enough to hold the header, its unknown if (dwSize < sizeof(SUBNET_REG_ENTRY)) { return ERROR_SUCCESS; } //Now we can access the rest of thee header //If the size is not consistent with the number of subnets //it claims to be holding then it is unknown if (dwSize != (sizeof(SUBNET_REG_ENTRY) + sizeof(DWORD) * pRegEntry->dwCount)) { return ERROR_SUCCESS; } //If it is holding zero subnets, its unknown (this is not valid for SB_VER_SUBNETS) if (pRegEntry->dwCount == 0) { return ERROR_SUCCESS; } //Make sure the admit flag is either zero or one if ((pRegEntry->dwAdmit != 0) && (pRegEntry->dwAdmit != 1)) { return ERROR_SUCCESS; } //Looks legit *pVer = SB_VER_SUBNETS; return ERROR_SUCCESS; } DWORD GetSelectiveBindingBuffer( OUT LPDWORD lpSize, OUT LPVOID *lppBuffer ) /*++ Routine Description: Retrieves the buffer from the registry and allocates space for you. Arguments: lpSize - This is filled in with the size of the buffer. lppBuffer - This will point to a buffer containing the registry entry, can't be NULL Return Value: ERROR_OUTOFMEMORY ERROR_ACCESS_DENIED - The user did not have access to the registry key. ERROR_SUCCESS - lppBuffer will point to a buffer containing the registry key or NULL if the key could not be found or is of zero size. --*/ { HKEY hKey; DWORD dwStatus; DWORD dwDummy; ASSERT((lpSize != NULL) && (lppBuffer != NULL)); //Init the out params *lppBuffer = NULL; *lpSize = 0; // Open the handle to our registry entry dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RPC_SELECTIVE_BINDING_KEY_PATH, 0, KEY_READ, &hKey ); if (dwStatus != ERROR_SUCCESS) { ASSERT((dwStatus == ERROR_FILE_NOT_FOUND) || (dwStatus == ERROR_ACCESS_DENIED) || (dwStatus == ERROR_OUTOFMEMORY) || (dwStatus == ERROR_NOT_ENOUGH_MEMORY)); if (dwStatus == ERROR_FILE_NOT_FOUND) { //Default settings return ERROR_SUCCESS; } return dwStatus; } // Query for the size of the buffer dwStatus = RegQueryValueEx(hKey, RPC_SELECTIVE_BINDING_VALUE, 0, &dwDummy, NULL, lpSize); if (dwStatus != ERROR_SUCCESS) { ASSERT(dwStatus == ERROR_OUTOFMEMORY); RegCloseKey(hKey); return dwStatus; } // If the size is zero, we will map this to default settings if (*lpSize == 0) { RegCloseKey(hKey); return ERROR_SUCCESS; } // Allocate the buffer *lppBuffer = new char[*lpSize]; if (*lppBuffer == NULL) { RegCloseKey(hKey); return ERROR_OUTOFMEMORY; } // Get the buffer for real this time dwStatus = RegQueryValueEx(hKey, RPC_SELECTIVE_BINDING_VALUE, 0, &dwDummy, (LPBYTE)*lppBuffer, lpSize); if (dwStatus != ERROR_SUCCESS) { ASSERT(dwStatus == ERROR_OUTOFMEMORY); delete [] *lppBuffer; } RegCloseKey(hKey); return dwStatus; } DWORD GetSelectiveBindingSettings( OUT SB_VER *pVer, OUT LPDWORD lpSize, OUT LPVOID *lppSettings ) /*++ Routine Description: Retrieves the version and version specific setting information. *lppSettings will point to the settings if *pVer == SB_VER_INDICES or SB_VER_SUBNETS, other wise *lppSettings will be NULL Arguments: Return Value: ERROR_SUCCESS ERROR_ACCESS_DENIED ERROR_OUTOFMEMORY --*/ { DWORD dwStatus = ERROR_SUCCESS; LPVOID lpBuffer = NULL; DWORD dwSize = 0; ASSERT((pVer != NULL) && (lpSize != NULL) && (lppSettings != NULL)); *lppSettings = NULL; // Get the selective binding buffer dwStatus = GetSelectiveBindingBuffer(&dwSize, &lpBuffer); if (dwStatus != ERROR_SUCCESS) { ASSERT((dwStatus == ERROR_ACCESS_DENIED) || (dwStatus == ERROR_OUTOFMEMORY)); return dwStatus; } // Get the selective binding version dwStatus = GetSelectiveBindingVersion(dwSize, lpBuffer, pVer); if (dwStatus != ERROR_SUCCESS) { ASSERT(0); delete [] lpBuffer; return dwStatus; } // Depending on the version, fill in the appropriate structure switch (*pVer) { case SB_VER_INDICES: dwStatus = GetSelectiveBindingIndices(dwSize, lpBuffer, lpSize, (VER_INDICES_SETTINGS**) lppSettings); break; case SB_VER_SUBNETS: dwStatus = GetSelectiveBindingSubnets(dwSize, lpBuffer, lpSize, (VER_SUBNETS_SETTINGS**) lppSettings); break; case SB_VER_UNKNOWN: case SB_VER_DEFAULT: break; default: ASSERT(0); } ASSERT((dwStatus == ERROR_SUCCESS) || (dwStatus == ERROR_OUTOFMEMORY)); return dwStatus; } DWORD GetSelectiveBindingSubnets( IN DWORD dwSize, IN LPVOID lpBuffer, OUT LPDWORD lpSize, OUT VER_SUBNETS_SETTINGS **lppSettings ) /*++ Routine Description: Allocates and fills in a settings structure based off an SB_VER_SUBNETS buffer. Arguments: IN dwSize - size of the SB_VER_SUBNETS buffer IN lpBuffer - pointer to the SB_VER_SUBNETS buffer OUT lppSettings - filled in with a pointer to te subnet settings Return Value: ERROR_SUCCESS ERROR_OUTOFMEMORY --*/ { SUBNET_REG_ENTRY *pEntry; ASSERT((lpBuffer != NULL) && (lppSettings != NULL)); // Cast the buffer as a SUBNET_REG_ENTRY pEntry = (SUBNET_REG_ENTRY*)lpBuffer; // Calculate the size to allocate for VER_SUBNETS_SETTINGS *lpSize = sizeof(VER_SUBNETS_SETTINGS) + pEntry->dwCount*sizeof(DWORD); *lppSettings = (VER_SUBNETS_SETTINGS*) new char [*lpSize]; if (*lppSettings == NULL) return ERROR_OUTOFMEMORY; // Copy in the relevent fields (*lppSettings)->bAdmit = (BOOL)pEntry->dwAdmit; (*lppSettings)->dwCount = pEntry->dwCount; memcpy((*lppSettings)->dwSubnets, pEntry->dwSubnets, pEntry->dwCount*sizeof(DWORD)); return ERROR_SUCCESS; } DWORD GetSelectiveBindingIndices( IN DWORD dwSize, IN LPVOID lpBuffer, OUT LPDWORD lpSize, OUT VER_INDICES_SETTINGS **lppSettings ) /*++ Routine Description: Allocates and fills in a settings structure based off an SB_VER_INDICES buffer. Arguments: IN dwSize - size of the SB_VER_INDICES buffer IN lpBuffer - pointer to the SB_VER_INDICES buffer OUT lppSettings - filled in with a pointer to the indices settings Return Value: ERROR_SUCCESS ERROR_OUTOFMEMORY --*/ { DWORD dwStatus = ERROR_SUCCESS; DWORD dwCount=0; LPVOID lpTmp = NULL; DWORD dwIndex; DWORD idx; ASSERT((lpBuffer != NULL) && (lppSettings != NULL)); // Count how many indices there are lpTmp = lpBuffer; while (NextIndex((char**)&lpTmp) != -1) dwCount++; // Calculate the size to allocate for VER_INDICES_SETTINGS *lpSize = sizeof(VER_INDICES_SETTINGS) + dwCount*sizeof(DWORD); *lppSettings = (VER_INDICES_SETTINGS*) new char [*lpSize]; if (*lppSettings == NULL) return ERROR_OUTOFMEMORY; // Step through and get each index lpTmp = lpBuffer; idx = 0; (*lppSettings)->dwCount = dwCount; for (idx = 0; idx dwIndices[idx] = NextIndex((char**)&lpTmp); return ERROR_SUCCESS; } DWORD DeleteSelectiveBinding() /*++ Routine Description: Deletes the linkage key, this indicates we should use the default settings for selective binding (listen on all interfaces). Arguments: Return Value: ERROR_SUCCESS ERROR_ACCESS_DENIED --*/ { HKEY hKey; DWORD dwStatus; // Attempt to open the key dwStatus = RegOpenKeyEx(HKEY_LOCAL_MACHINE, RPC_SETTINGS_PATH, 0, KEY_ALL_ACCESS, &hKey ); if (dwStatus != ERROR_SUCCESS) { ASSERT((dwStatus == ERROR_ACCESS_DENIED) || (dwStatus == ERROR_FILE_NOT_FOUND)); return dwStatus; } // Delete the selective binding key dwStatus = RegDeleteKey(hKey, RPC_SELECTIVE_BINDING_KEY); ASSERT((dwStatus == ERROR_SUCCESS) || (dwStatus == ERROR_FILE_NOT_FOUND)); RegCloseKey(hKey); return ERROR_SUCCESS; } DWORD SetSelectiveBindingSubnets( IN DWORD dwCount, IN LPDWORD lpSubnetTable, IN BOOL bAdmit ) /*++ Routine Description: This converts the inputs into a buffer which we write to the registry using SetSelectiveBindingBuffer. Arguments: bAdmit - True for Admit (Add) list False for Deny (Delete) list. dwCount - The number of subnets we are setting. It is illegal to set zero subnets. lpSubnetTable - This is the array of subnets we wish to create an Admit or Deny list from. Return Value: ERROR_ACCESS_DENIED ERROR_OUTOFMEMORY ERROR_SUCCESS --*/ { SUBNET_REG_ENTRY *pRegEntry; DWORD dwSize; DWORD dwStatus; ASSERT((dwCount !=0) && (lpSubnetTable != NULL)); //Calculate the size of the buffer dwSize = sizeof(SUBNET_REG_ENTRY) + dwCount*sizeof(DWORD); pRegEntry = (SUBNET_REG_ENTRY*) new char[dwSize]; if (pRegEntry == NULL) return ERROR_OUTOFMEMORY; //Fill in the structure pRegEntry->dwFlag = ((ULONG)'4vPI'); pRegEntry->dwCount = dwCount; pRegEntry->dwAdmit = (bAdmit ? ((DWORD)0x01) : ((DWORD)0x00)); memcpy(pRegEntry->dwSubnets, lpSubnetTable, dwCount*sizeof(DWORD)); //Write this to the registry dwStatus = SetSelectiveBindingBuffer(dwSize, (LPVOID)pRegEntry); delete [] pRegEntry; pRegEntry = NULL; return dwStatus; } DWORD SetSelectiveBindingBuffer( IN DWORD dwSize, IN LPVOID lpBuffer ) /*++ Routine Description: Writes the buffer to the selective binding key in the registry Arguments: dwSize - This is the size of the buffer. lpBuffer - This is the buffer we write to the registry. Return Value: ERROR_ACCESS_DENIED - The user did not have permission to write to this key ERROR_SUCCESS --*/ { HKEY hKey; DWORD dwStatus; DWORD dwDummy; ASSERT((dwSize != 0) && (lpBuffer != NULL)); // Attempt to create the key, this will succeed even if the key already exists dwStatus = RegCreateKeyEx(HKEY_LOCAL_MACHINE, RPC_SELECTIVE_BINDING_KEY_PATH, 0, "", REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKey, &dwDummy ); if (dwStatus != ERROR_SUCCESS) { ASSERT(dwStatus == ERROR_ACCESS_DENIED); return dwStatus; } // Write the value dwStatus = RegSetValueEx(hKey, "Bind", 0, REG_BINARY, (LPBYTE)lpBuffer, dwSize ); ASSERT(dwStatus == ERROR_SUCCESS); RegCloseKey(hKey); return dwStatus; } DWORD NextIndex( IN OUT char **Ptr ) /*++ Routine Description: Retrieves the next index from the buffer, and moves the pointer to the start of the following index. Arguments: Ptr - A pointer to the old registry format for storing indices. Each index is stored as a string, (must be ASCII when its passed to this function). The Ptr gets updated to point to the following index. Return Value: The index retrieved or -1 if the end of the buffer has been reached. --*/ { char *Index = (char *)*Ptr ; if (*Index == 0) { return -1; } while (*(char *)*Ptr) ((char *)*Ptr)++ ; ((char *)*Ptr)++ ; return (DWORD) atol(Index) ; }