/*++ Copyright(c) 1995 Microsoft Corporation MODULE NAME rasprocs.c ABSTRACT RAS utility routines. AUTHOR Anthony Discolo (adiscolo) 23-Mar-1995 REVISION HISTORY Original version from Gurdeep --*/ #define UNICODE #define _UNICODE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "reg.h" #include "table.h" #include "addrmap.h" #include "access.h" #include "misc.h" #include "process.h" #include "rasprocs.h" #include "tapiproc.h" #include "imperson.h" extern HKEY hkeyCUG; extern PHASH_TABLE pDisabledAddressesG; // // rasdlui command line strings. // #define RASAUTOUI_EXE L"rasautou.exe" // .exe name #define RASAUTOUI_NOENTRY L"rasautou -a \"%s\"" #define RASAUTOUI_CUSTOMDIALENTRY L"rasautou -d \"%s\" -p \"%s\" -e \"%s\"" #define RASAUTOUI_DEFAULTDIALENTRY L"rasautou -a \"%s\" -e \"%s\"" #define RASAUTOUI_DEFAULTDIALENTRY2 L"rasautou -q -a \"%s\" -e \"%s\"" #define RASAUTOUI_REDIALENTRY L"rasautou -r -f \"%s\" -e \"%s\"" // // DLL module handles for rasapi32.dll and rasman.dll. // #define RASAPI_MODULE L"RASAPI32" HANDLE hRasApiG; #define RASMAN_MODULE L"RASMAN" HANDLE hRasManG; // // DLL entrypoints for rasapi32.dll. // #define RASDIAL "RasDialW" FARPROC lpfnRasDialG; #define RASENUMCONNECTIONS "RasEnumConnectionsW" FARPROC lpfnRasEnumConnectionsG; #define RASENUMENTRIES "RasEnumEntriesW" FARPROC lpfnRasEnumEntriesG; #define RASGETCONNECTSTATUS "RasGetConnectStatusW" FARPROC lpfnRasGetConnectStatusG; #define RASGETHPORT "RasGetHport" FARPROC lpfnRasGetHportG; #define RASGETPROJECTIONINFO "RasGetProjectionInfoW" FARPROC lpfnRasGetProjectionInfoG; #define RASGETENTRYPROPERTIES "RasGetEntryPropertiesW" FARPROC lpfnRasGetEntryPropertiesG; #define RASGETAUTODIALADDRESS "RasGetAutodialAddressW" FARPROC lpfnRasGetAutodialAddressG; #define RASSETAUTODIALADDRESS "RasSetAutodialAddressW" FARPROC lpfnRasSetAutodialAddressG; #define RASENUMAUTODIALADDRESSES "RasEnumAutodialAddressesW" FARPROC lpfnRasEnumAutodialAddressesG; #define RASGETAUTODIALENABLE "RasGetAutodialEnableW" FARPROC lpfnRasGetAutodialEnableG; #define RASSETAUTODIALENABLE "RasSetAutodialEnableW" FARPROC lpfnRasSetAutodialEnableG; #define RASAUTODIALADDRESSTONETWORK "RasAutodialAddressToNetwork" FARPROC lpfnRasAutodialAddressToNetworkG; #define RASAUTODIALENTRYTONETWORK "RasAutodialEntryToNetwork" FARPROC lpfnRasAutodialEntryToNetworkG; #define RASCONNECTIONNOTIFICATION "RasConnectionNotificationW" FARPROC lpfnRasConnectionNotificationG; #define RASGETAUTODIALPARAM "RasGetAutodialParamW" FARPROC lpfnRasGetAutodialParamG; #define RASSETAUTODIALPARAM "RasSetAutodialParamW" FARPROC lpfnRasSetAutodialParamG; #define RASQUERYSHAREDAUTODIAL "RasQuerySharedAutoDial" FARPROC lpfnRasQuerySharedAutoDialG; #define RASQUERYSHAREDCONNECTION "RasQuerySharedConnection" FARPROC lpfnRasQuerySharedConnectionG; #define RASQUERYREDIALONLINKFAILURE "RasQueryRedialOnLinkFailure" FARPROC lpfnRasQueryRedialOnLinkFailureG; #define RASGETCREDENTIALS "RasGetCredentialsW" FARPROC lpfnRasGetCredentialsG; #define RASHANGUP "RasHangUpW" FARPROC lpfnRasHangUpG; // // DLL entrypoints for rasman.dll. // #define RASPORTRETRIEVEUSERDATA "RasPortRetrieveUserData" FARPROC lpfnRasPortRetrieveUserDataG; #define RASPORTENUMPROTOCOLS "RasPortEnumProtocols" FARPROC lpfnRasPortEnumProtocolsG; #define RASPORTENUM "RasPortEnum" FARPROC lpfnRasPortEnumG; #define RASINITIALIZE "RasInitialize" FARPROC lpfnRasInitializeG; #define RASREFERENCERASMAN "RasReferenceRasman" FARPROC lpfnRasReferenceRasmanG; #define RASPORTOPEN "RasPortOpen" FARPROC lpfnRasPortOpenG; #define RASPORTCLOSE "RasPortClose" FARPROC lpfnRasPortCloseG; #define RASGETINFO "RasGetInfo" FARPROC lpfnRasGetInfoG; #define RASGETPORTUSERDATA "RasGetPortUserData" FARPROC lpfnRasGetPortUserDataG; #define RASREGISTERREDIALCALLBACK "RasRegisterRedialCallback" FARPROC lpfnRasRegisterRedialCallbackG; // // Hostent cache. // #define HOSTENTCACHESIZ 10 typedef struct _HOSTENT_CACHE { CHAR szDns[ACD_ADDR_INET_LEN]; ULONG ulIpaddr; } HOSTENT_CACHE, *PHOSTENT_CACHE; // // External definitions // VOID AcsRedialOnLinkFailure( LPSTR lpszPhonebook, LPSTR lpszEntry); // // Global variables // CRITICAL_SECTION csRasG; INT nRasReferencesG; BOOLEAN fAutoDialRegChangeG; HKEY hkeyAutoDialRegChangeG; HANDLE hConnectionEventG = NULL; HOSTENT_CACHE hostentCacheG[HOSTENTCACHESIZ]; INT iHostentCacheG = 0; // // Private structure returned by // RasPortRetrieveUserData(). // typedef struct _StoredData { DWORD arg; BOOLEAN fAuthenticated; } StoredData; // // External variables // extern HANDLE hAcdG; extern HANDLE hTerminatingG; BOOLEAN LoadRasDlls() { BOOLEAN fSuccess = FALSE; SC_HANDLE hSCManager, hService; SERVICE_STATUS status; DWORD dwErr, dwcDevices, dwDisp; // // Since these DLLs will be loaded/unloaded // by multiple threads, we must do this under // a mutex. // EnterCriticalSection(&csRasG); // // If the DLLs have already been successfully // loaded, no further processing is necessary. // if (nRasReferencesG) { fSuccess = TRUE; goto done; } #ifdef notdef // // Get a service controller handle on // the rasman service. // hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT); if (hSCManager == NULL) goto done; hService = OpenService( hSCManager, TEXT(RASMAN_SERVICE_NAME), SERVICE_START|SERVICE_QUERY_STATUS); if (hService == NULL) { CloseServiceHandle(hSCManager); goto done; } // // Start the rasman service if necessary. // do { if (!QueryServiceStatus(hService, &status)) break; switch (status.dwCurrentState) { case SERVICE_STOP_PENDING: case SERVICE_START_PENDING: Sleep(500); break; case SERVICE_STOPPED: StartService(hService, 0, NULL); break; case SERVICE_RUNNING: break; } } while (status.dwCurrentState != SERVICE_RUNNING); CloseServiceHandle(hService); CloseServiceHandle(hSCManager); if (status.dwCurrentState != SERVICE_RUNNING) { RASAUTO_TRACE("LoadRasDlls: Could not start rasman service"); goto done; } #endif // // Load rasapi32.dll. // hRasApiG = LoadLibrary(RASAPI_MODULE); if (hRasApiG == NULL) { RASAUTO_TRACE("LoadRasDlls: couldn't load rasapi32.dll"); goto done; } lpfnRasDialG = GetProcAddress(hRasApiG, RASDIAL); lpfnRasEnumConnectionsG = GetProcAddress(hRasApiG, RASENUMCONNECTIONS); lpfnRasEnumEntriesG = GetProcAddress(hRasApiG, RASENUMENTRIES); lpfnRasGetConnectStatusG = GetProcAddress(hRasApiG, RASGETCONNECTSTATUS ); lpfnRasGetHportG = GetProcAddress(hRasApiG, RASGETHPORT); lpfnRasGetProjectionInfoG = GetProcAddress(hRasApiG, RASGETPROJECTIONINFO); lpfnRasGetEntryPropertiesG = GetProcAddress(hRasApiG, RASGETENTRYPROPERTIES); lpfnRasGetAutodialAddressG = GetProcAddress(hRasApiG, RASGETAUTODIALADDRESS); lpfnRasSetAutodialAddressG = GetProcAddress(hRasApiG, RASSETAUTODIALADDRESS); lpfnRasEnumAutodialAddressesG = GetProcAddress(hRasApiG, RASENUMAUTODIALADDRESSES); lpfnRasGetAutodialEnableG = GetProcAddress(hRasApiG, RASGETAUTODIALENABLE); lpfnRasSetAutodialEnableG = GetProcAddress(hRasApiG, RASSETAUTODIALENABLE); lpfnRasAutodialAddressToNetworkG = GetProcAddress(hRasApiG, RASAUTODIALADDRESSTONETWORK); lpfnRasAutodialEntryToNetworkG = GetProcAddress(hRasApiG, RASAUTODIALENTRYTONETWORK); lpfnRasConnectionNotificationG = GetProcAddress(hRasApiG, RASCONNECTIONNOTIFICATION); lpfnRasGetAutodialParamG = GetProcAddress(hRasApiG, RASGETAUTODIALPARAM); lpfnRasSetAutodialParamG = GetProcAddress(hRasApiG, RASSETAUTODIALPARAM); lpfnRasQuerySharedAutoDialG = GetProcAddress(hRasApiG, RASQUERYSHAREDAUTODIAL); lpfnRasQuerySharedConnectionG = GetProcAddress(hRasApiG, RASQUERYSHAREDCONNECTION); lpfnRasQueryRedialOnLinkFailureG = GetProcAddress(hRasApiG, RASQUERYREDIALONLINKFAILURE); lpfnRasGetCredentialsG = GetProcAddress(hRasApiG, RASGETCREDENTIALS); lpfnRasHangUpG = GetProcAddress(hRasApiG, RASHANGUP); if (!lpfnRasEnumConnectionsG || !lpfnRasEnumEntriesG || !lpfnRasGetConnectStatusG || !lpfnRasGetHportG || !lpfnRasGetProjectionInfoG || !lpfnRasGetAutodialAddressG || !lpfnRasSetAutodialAddressG || !lpfnRasEnumAutodialAddressesG || !lpfnRasGetAutodialEnableG || !lpfnRasSetAutodialEnableG || !lpfnRasAutodialAddressToNetworkG || !lpfnRasAutodialEntryToNetworkG || !lpfnRasConnectionNotificationG || !lpfnRasGetAutodialParamG || !lpfnRasSetAutodialParamG || !lpfnRasQuerySharedConnectionG || !lpfnRasQuerySharedAutoDialG || !lpfnRasQueryRedialOnLinkFailureG || !lpfnRasGetCredentialsG || !lpfnRasHangUpG) { RASAUTO_TRACE("LoadRasDlls: couldn't find entrypoints in rasapi32.dll"); goto done; } // // Load rasman.dll. // hRasManG = LoadLibrary(RASMAN_MODULE); if (hRasManG == NULL) { RASAUTO_TRACE("LoadRasDlls: couldn't load rasman.dll"); goto done; } lpfnRasPortRetrieveUserDataG = GetProcAddress( hRasManG, RASPORTRETRIEVEUSERDATA); lpfnRasPortEnumProtocolsG = GetProcAddress(hRasManG, RASPORTENUMPROTOCOLS); lpfnRasPortEnumG = GetProcAddress(hRasManG, RASPORTENUM); lpfnRasInitializeG = GetProcAddress(hRasManG, RASINITIALIZE); lpfnRasReferenceRasmanG = GetProcAddress(hRasManG, RASREFERENCERASMAN); lpfnRasPortOpenG = GetProcAddress(hRasManG, RASPORTOPEN); lpfnRasPortCloseG = GetProcAddress(hRasManG, RASPORTCLOSE); lpfnRasGetInfoG = GetProcAddress(hRasManG, RASGETINFO); lpfnRasGetPortUserDataG = GetProcAddress(hRasManG, RASGETPORTUSERDATA); lpfnRasRegisterRedialCallbackG = GetProcAddress( hRasManG, RASREGISTERREDIALCALLBACK); if (!lpfnRasPortRetrieveUserDataG || !lpfnRasPortEnumProtocolsG || !lpfnRasPortEnumG || !lpfnRasInitializeG || !lpfnRasReferenceRasmanG || !lpfnRasPortOpenG || !lpfnRasPortCloseG || !lpfnRasGetInfoG || !lpfnRasGetPortUserDataG || !lpfnRasRegisterRedialCallbackG || (*lpfnRasInitializeG)() || (*lpfnRasReferenceRasmanG)(TRUE)) { RASAUTO_TRACE("LoadRasDlls: couldn't find entrypoints in rasman.dll"); goto done; } // // rasman will let us know when to invoke redial-on-link-failure // and for which phonebook entry. // SetRedialOnLinkFailureHandler((FARPROC)AcsRedialOnLinkFailure); RASAUTO_TRACE("LoadRasDlls: set redial-on-link-failure handler"); // // rasapi32 will let us when new RAS connections // are created or destroyed by signaling our // event. // dwErr = (DWORD)(*lpfnRasConnectionNotificationG)( INVALID_HANDLE_VALUE, hConnectionEventG, RASCN_Connection|RASCN_Disconnection); RASAUTO_TRACE1("LoadRasDlls: RasConnectionNotification returned dwErr=%d", dwErr); fSuccess = !dwErr; done: if (fSuccess) { #ifdef notdef // for now, we don't need multiple references nRasReferencesG++; #endif nRasReferencesG = 1; } else { if (hRasManG != NULL) FreeLibrary(hRasManG); if (hRasApiG != NULL) FreeLibrary(hRasApiG); hRasManG = hRasApiG = NULL; } LeaveCriticalSection(&csRasG); return fSuccess; } // LoadRasDlls VOID UnloadRasDlls() { DWORD dwErr; // // Since these DLLs will be loaded/unloaded // by multiple threads, we must do this under // a mutex. // EnterCriticalSection(&csRasG); if (nRasReferencesG) { // // Unregister the callback function for // redial on link failure // (void)(*lpfnRasRegisterRedialCallbackG)(NULL); // // Inform rasman.dll we are unloading it. // (void)(*lpfnRasReferenceRasmanG)(FALSE); if (hRasApiG != NULL) FreeLibrary(hRasApiG); if (hRasManG != NULL) FreeLibrary(hRasManG); nRasReferencesG--; } LeaveCriticalSection(&csRasG); } // UnloadRasDlls BOOLEAN RasDllsLoaded() { BOOLEAN fLoaded; EnterCriticalSection(&csRasG); fLoaded = (BOOLEAN)nRasReferencesG; LeaveCriticalSection(&csRasG); return fLoaded; } // RasDllsLoaded DWORD ActiveConnections( IN BOOLEAN fAuthenticated, OUT LPTSTR **lppEntryNames, OUT HRASCONN **lpphRasConn ) /*++ DESCRIPTION Enumerate the list of active RAS connections, and put the phone book entry names in lppEntryNames. Return the number of entries in the list. ARGUMENTS fAuthenticated: TRUE if the resulting arrays should contain only authenticated entries. lppEntryNames: a pointer which is set to the allocated array of phone book entry names. lpphRasConn: a pointer which is set to the allocated array of RASCONN descriptors corresponding to the phone book entries. RETURN VALUE The number of entries in lppEntryNames. --*/ { RASCONN RasCon; RASCONN *lpRasCon = NULL; DWORD dwStatus; DWORD dwSize; DWORD dwConnections; DWORD dwRealConnections = 0; DWORD dwIndex; RASCONNSTATUS RasConStatus; HPORT hPort; PBYTE lpUserData = NULL; BOOLEAN fEntryAuthenticated; // // Initialize return values. // if (lppEntryNames != NULL) *lppEntryNames = NULL; if (lpphRasConn != NULL) *lpphRasConn = NULL; // // Allow this routine to be called // even when the RAS dlls are not loaded. // if (!RasDllsLoaded()) goto done; // // Get the number of active connections. We // allocate a buffer large enough for one connection // initially, and reallocate it if it's too small. // lpRasCon = LocalAlloc(LPTR, sizeof (RASCONN)); if (lpRasCon == NULL) { RASAUTO_TRACE("ActiveConnections: LocalAlloc failed"); goto done; } lpRasCon[0].dwSize = sizeof (RASCONN); dwSize = sizeof (RASCONN); dwStatus = (DWORD)(*lpfnRasEnumConnectionsG)(lpRasCon, &dwSize, &dwConnections); if (dwStatus == ERROR_BUFFER_TOO_SMALL) { // // Buffer's too small. Reallocate and try again. // LocalFree(lpRasCon); lpRasCon = LocalAlloc(LPTR, dwSize); if (lpRasCon == NULL) { RASAUTO_TRACE("ActiveConnections: LocalAlloc failed"); goto done; } lpRasCon[0].dwSize = sizeof (RASCONN); dwStatus = (DWORD)(*lpfnRasEnumConnectionsG)( lpRasCon, &dwSize, &dwConnections); } if (dwStatus) { RASAUTO_TRACE1( "ActiveConnections: RasEnumConnections failed (dwStatus=0x%x)", dwStatus); goto done; } // // Short-circuit the rest if there // are no connections. // if (!dwConnections) goto done; // // Allocate the user's return buffers, // if necessary. // if (lppEntryNames != NULL) { *lppEntryNames = LocalAlloc(LPTR, (dwConnections+1) * sizeof (LPTSTR)); if (*lppEntryNames == NULL) { RASAUTO_TRACE("ActiveConnections: LocalAlloc failed"); goto done; } } if (lpphRasConn != NULL) { *lpphRasConn = LocalAlloc(LPTR, (dwConnections+1) * sizeof (HRASCONN)); if (*lpphRasConn == NULL) { RASAUTO_TRACE("ActiveConnections: LocalAlloc failed"); goto done; } } // // Go through each connection, and // check to see if the connection's // passed the authentication phase yet. // for (dwIndex = 0; dwIndex < dwConnections; dwIndex++) { RasConStatus.dwSize = sizeof (RASCONNSTATUS); dwStatus = (DWORD)(*lpfnRasGetConnectStatusG)( lpRasCon[dwIndex].hrasconn, &RasConStatus); if (dwStatus) { RASAUTO_TRACE2( "ActiveConnections: RasGetConnectStatus(%S) failed (dwStatus=0x%x)", lpRasCon[dwIndex].szEntryName, dwStatus); continue; } // // If the connection is not connected, // then skip it. // RASAUTO_TRACE2("ActiveConnections: state for hrasconn 0x%x is %d", lpRasCon[dwIndex].hrasconn, RasConStatus.rasconnstate); // // If the caller specified only authenticated entries // and the entry is not yet connected, then skip it. // if (fAuthenticated && RasConStatus.rasconnstate != RASCS_Connected) continue; if (lppEntryNames != NULL) { (*lppEntryNames)[dwRealConnections] = CopyString(lpRasCon[dwIndex].szEntryName); } if (lpphRasConn != NULL) (*lpphRasConn)[dwRealConnections] = lpRasCon[dwIndex].hrasconn; RASAUTO_TRACE2( "ActiveConnections: (%S, 0x%x)", lpRasCon[dwIndex].szEntryName, lpRasCon[dwIndex].hrasconn); dwRealConnections++; } done: if (lpRasCon != NULL) LocalFree(lpRasCon); if (lpUserData != NULL) LocalFree(lpUserData); if (!dwRealConnections) { if (lppEntryNames != NULL) { if (*lppEntryNames != NULL) { LocalFree(*lppEntryNames); *lppEntryNames = NULL; } } if (lpphRasConn != NULL) { if (*lpphRasConn != NULL) { LocalFree(*lpphRasConn); *lpphRasConn = NULL; } } } return dwRealConnections; } // ActiveConnections LPTSTR AddressToNetwork( LPTSTR pszAddress ) { DWORD dwErr, dwSize; LPTSTR pszNetwork = NULL; // // Map an address to a network name // by calling a (currently) private rasapi32 API. // dwSize = 0; dwErr = (DWORD)(*lpfnRasAutodialAddressToNetworkG)(pszAddress, NULL, &dwSize); if (dwErr) goto done; pszNetwork = LocalAlloc(LPTR, dwSize); if (pszNetwork == NULL) { dwErr = GetLastError(); goto done; } dwErr = (DWORD)(*lpfnRasAutodialAddressToNetworkG)( pszAddress, pszNetwork, &dwSize); done: return (!dwErr ? pszNetwork : NULL); } // AddressToNetwork LPTSTR EntryToNetwork( LPTSTR pszEntry ) { DWORD dwErr, dwSize; LPTSTR pszNetwork = NULL; // // Map an address to a network name // by calling a (currently) private rasapi32 API. // dwSize = 0; dwErr = (DWORD)(*lpfnRasAutodialEntryToNetworkG)(pszEntry, NULL, &dwSize); if (dwErr) goto done; pszNetwork = LocalAlloc(LPTR, dwSize); if (pszNetwork == NULL) { dwErr = GetLastError(); goto done; } dwErr = (DWORD)(*lpfnRasAutodialEntryToNetworkG)( pszEntry, pszNetwork, &dwSize); done: return (!dwErr ? pszNetwork : NULL); } // EntryToNetwork DWORD AutoDialEnabled( IN PBOOLEAN lpfEnabled ) { DWORD dwErr, dwLocationID; BOOL fEnabled; // // If there is no dialing location // defined, then return FALSE. // dwErr = TapiCurrentDialingLocation(&dwLocationID); if (dwErr) { *lpfEnabled = FALSE; return 0; } dwErr = (DWORD)(*lpfnRasGetAutodialEnableG)(dwLocationID, &fEnabled); if (dwErr) return dwErr; *lpfEnabled = (BOOLEAN)fEnabled; return 0; } // AutoDialEnabled DWORD DisableAutoDial() { DWORD dwErr, dwLocationID; dwErr = TapiCurrentDialingLocation(&dwLocationID); if (dwErr) return dwErr; return (DWORD)(*lpfnRasSetAutodialEnableG)(dwLocationID, (BOOL)FALSE); } // DisableAutoDial BOOLEAN PortAvailable( IN LPTSTR lpszDeviceType, IN LPTSTR lpszDeviceName ) /*++ DESCRIPTION Determines whether there is a free port available to dial the specified entry. ARGUMENTS lpszDeviceType: a pointer to the device type string lpszDeviceName: a pointer to the device name string RETURN VALUE TRUE if one or more of the correct port type is free; FALSE otherwise. --*/ { DWORD dwErr; DWORD dwSize = 0, dwEntries, i; RASMAN_PORT *pPorts = NULL; BOOLEAN fFound = FALSE, fOtherType; BOOLEAN fTypeMatch, fNameMatch; LPSTR lpszAnsiDeviceType = NULL, lpszAnsiDeviceName = NULL; // // If fOtherType is TRUE, then we compare // the RASMAN media type with the device type. // fOtherType = (_wcsicmp(lpszDeviceType, RASDT_Modem) && _wcsicmp(lpszDeviceType, RASDT_Isdn) && _wcsicmp(lpszDeviceType, RASDT_X25) && _wcsicmp(lpszDeviceType, L"VPN")); // // Convert lpszDeviceType to Ansi so // we can compare with rasman's version. // lpszAnsiDeviceType = UnicodeStringToAnsiString( lpszDeviceType, NULL, 0); if (lpszAnsiDeviceType == NULL) goto done; lpszAnsiDeviceName = UnicodeStringToAnsiString( lpszDeviceName, NULL, 0); if (lpszAnsiDeviceName == NULL) goto done; // // Get a list of ports. // dwErr = (DWORD)(*lpfnRasPortEnumG)(NULL, NULL, &dwSize, &dwEntries); if (!dwErr || dwErr != ERROR_BUFFER_TOO_SMALL) { RASAUTO_TRACE1("PortAvailable: RasPortEnum failed (dwErr=%d)", dwErr); goto done; } pPorts = LocalAlloc(LPTR, dwSize); if (pPorts == NULL) { RASAUTO_TRACE("PortAvailable: LocalAlloc failed"); goto done; } dwErr = (DWORD)(*lpfnRasPortEnumG)(NULL, pPorts, &dwSize, &dwEntries); if (dwErr) { RASAUTO_TRACE1("PortAvailable: RasPortEnum failed (dwErr=%d)", dwErr); goto done; } for (i = 0; i < dwEntries; i++) { RASMAN_INFO info; RASAUTO_TRACE6( "PortAvailable: lpszAnsiDeviceType=%s, lpszAnsiDeviceName=%s, " "media=%s, type=%s, name=%s, usage=%d", lpszAnsiDeviceType, lpszAnsiDeviceName, pPorts[i].P_MediaName, pPorts[i].P_DeviceType, pPorts[i].P_DeviceName, pPorts[i].P_ConfiguredUsage); RASAUTO_TRACE2("PortAvailable: status=%d, current usage=%d", pPorts[i].P_Status, pPorts[i].P_CurrentUsage); // // Only interested in dial-out and biplex ports. // if (!(pPorts[i].P_ConfiguredUsage & CALL_OUT) && !(pPorts[i].P_ConfiguredUsage & CALL_OUT_ONLY)) continue; RtlZeroMemory(&info, sizeof (info)); // // If the port has already been opened for call out // fail the call. // ZeroMemory(&info, sizeof(RASMAN_INFO)); dwErr = RasGetInfo(NULL, pPorts[i].P_Handle, &info); if(NO_ERROR == dwErr) { if(info.RI_dwFlags & RASMAN_OPEN_CALLOUT) { RASAUTO_TRACE("Port already open for call out"); continue; } } if (pPorts[i].P_Status == OPEN) { dwErr = (DWORD)(*lpfnRasGetInfoG)(NULL, pPorts[i].P_Handle, &info); if (dwErr) { RASAUTO_TRACE1("PortAvailable: RasGetInfo failed (dwErr=%d)", dwErr); goto statecheck; } } #if 0 // // Determine if the connection associated with a // disconnected port has gone away. In this case, // we can close the port and attempt to reopen // it. This is essentially what rasapi32/RasDial() // when it determines if a port is available for // dialing out. // if (pPorts[i].P_Status == OPEN && info.RI_ConnState == DISCONNECTED && info.RI_ConnectionHandle) { RASCONNSTATE connstate; DWORD dwSize = sizeof (RASCONNSTATE); RASAUTO_TRACE1( "PortAvailable: Open disconnected port %d found", pPorts[i].P_Handle); dwErr = (DWORD)(*lpfnRasGetPortUserDataG)( pPorts[i].P_Handle, 3, // PORT_CONNSTATE_INDEX &connstate, &dwSize); RASAUTO_TRACE2( "PortAvailable: RasGetPortUserData(%d), connstate=%d", dwErr, connstate); if (!dwErr && (connstate < RASCS_PrepareForCallback || connstate > RASCS_WaitForCallback)) { RASAUTO_TRACE1( "PortAvailable: RasPortClose(%d)...", pPorts[i].P_Handle); dwErr = (DWORD)(*lpfnRasPortCloseG)(pPorts[i].P_Handle); RASAUTO_TRACE1("PortAvailable: RasPortClose done(%d)", dwErr); // // Since we've closed the port, // update the P_Status field manually. // if (!dwErr) pPorts[i].P_Status = CLOSED; } } #endif // // Only interested in dial-out ports if the port // is closed. Biplex port opens, on the other // hand, may succeed even if the port is // open. // statecheck: if (pPorts[i].P_ConfiguredUsage == CALL_OUT && pPorts[i].P_Status != CLOSED) { RASAUTO_TRACE("Port is not available for call_out"); continue; } fTypeMatch = (!_stricmp(lpszAnsiDeviceType, pPorts[i].P_DeviceType)) || (fOtherType && !_stricmp(lpszAnsiDeviceType, pPorts[i].P_MediaName)); fNameMatch = !_stricmp(lpszAnsiDeviceName, pPorts[i].P_DeviceName); if (fTypeMatch && fNameMatch) { fFound = TRUE; } } done: // // Free resources. // if (lpszAnsiDeviceType != NULL) LocalFree(lpszAnsiDeviceType); if (lpszAnsiDeviceName != NULL) LocalFree(lpszAnsiDeviceName); if (pPorts != NULL) LocalFree(pPorts); return fFound; } // PortAvailable DWORD DisableAddress(PACD_ADDR pAddr) { DWORD retcode = SUCCESS; LPTSTR pszAddress = NULL; LockDisabledAddresses(); ASSERT(NULL != pDisabledAddressesG); pszAddress = AddressToUnicodeString(pAddr); if(NULL == pszAddress) { retcode = ERROR_NOT_ENOUGH_MEMORY; goto done; } PutTableEntry(pDisabledAddressesG, pszAddress, NULL); done: if(NULL != pszAddress) { LocalFree(pszAddress); } UnlockDisabledAddresses(); return retcode; } BOOLEAN StartAutoDialer( IN HANDLE hProcess, IN PACD_ADDR pAddr, IN LPTSTR lpAddress, IN LPTSTR lpEntryName, IN BOOLEAN fSharedAccess, OUT PBOOLEAN pfInvalidEntry ) { NTSTATUS status; BOOLEAN fSuccess = FALSE, fEntryFound = FALSE; BOOLEAN fUseRasDial, fDialerPresent, fDialerKilled; DWORD dwStatus, dwSize, dwIndex, dwEntries, dwCount = 0; TCHAR *pszCmdLine = NULL; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; DWORD dwPreConnections, dwConnections; DWORD dwExitCode = STILL_ACTIVE; HANDLE hToken; IO_STATUS_BLOCK ioStatusBlock; ACD_STATUS connStatus; DWORD dwErr; BOOL fDisableAddress = FALSE; PVOID pEnvBlock = NULL; // // Initialization of various variables. // *pfInvalidEntry = FALSE; memset(&StartupInfo, 0, sizeof (StartupInfo)); memset(&ProcessInfo, 0, sizeof (ProcessInfo)); StartupInfo.cb = sizeof(StartupInfo); StartupInfo.lpDesktop = TEXT("winsta0\\default"); // // Read the phonebook entry to determine whether // we need to load a custom AutoDial UI. // if (lpEntryName != NULL) { DWORD dwIgnore; LPRASENTRY lpEntry; dwErr = (DWORD)(*lpfnRasGetEntryPropertiesG)( NULL, lpEntryName, NULL, &dwSize, NULL, &dwIgnore); if (dwErr == ERROR_CANNOT_FIND_PHONEBOOK_ENTRY) { // // If the phonebook entry has been renamed // or deleted, then ask again for an entry. // lpEntryName = NULL; dwErr = 0; goto fmtcmd; } else if (dwErr != ERROR_BUFFER_TOO_SMALL) { *pfInvalidEntry = TRUE; RASAUTO_TRACE2( "StartAutoDialer: RasGetEntryProperties(%S) failed (dwErr=%d)", RASAUTO_TRACESTRW(lpEntryName), dwErr); goto done; } lpEntry = LocalAlloc(LPTR, dwSize); if (lpEntry == NULL) { RASAUTO_TRACE("StartAutoDialer: LocalAlloc failed"); goto done; } lpEntry->dwSize = sizeof (RASENTRY); dwErr = (DWORD)(*lpfnRasGetEntryPropertiesG)( NULL, lpEntryName, lpEntry, &dwSize, NULL, &dwIgnore); if (dwErr) { *pfInvalidEntry = TRUE; RASAUTO_TRACE2( "StartAutoDialer: RasGetEntryProperties(%S) failed (dwErr=%d)", RASAUTO_TRACESTRW(lpEntryName), dwErr); LocalFree(lpEntry); lpEntry = NULL; goto done; } // // While we have the phonebook entry // verify there is an available port // to dial. // if (!PortAvailable(lpEntry->szDeviceType, lpEntry->szDeviceName)) { RASAUTO_TRACE("StartAutoDialer: no port available"); LocalFree(lpEntry); goto done; } if (*lpEntry->szAutodialDll != L'\0' && *lpEntry->szAutodialFunc != L'\0') { // // Allocate pszCmdLine // pszCmdLine = LocalAlloc( LPTR, ( lstrlen(RASAUTOUI_CUSTOMDIALENTRY) + lstrlen(lpEntry->szAutodialDll) + lstrlen(lpEntry->szAutodialFunc) + lstrlen(lpEntryName) + 1) * sizeof(TCHAR)); if(NULL == pszCmdLine) { RASAUTO_TRACE1("StartAutoDialer: Failed to allocate pszcmdline. 0x%x", dwErr); goto done; } // // Run a special program that loads the // AutoDial DLL and calls the correct // DLL entrypoint. // wsprintf( pszCmdLine, RASAUTOUI_CUSTOMDIALENTRY, lpEntry->szAutodialDll, lpEntry->szAutodialFunc, lpEntryName); } LocalFree(lpEntry); } fmtcmd: // // Ping the driver before we start // the dialing dialer to make sure // the connection is still valid. // if (pAddr) { connStatus.fSuccess = FALSE; RtlCopyMemory(&connStatus.addr, pAddr, sizeof (ACD_ADDR)); status = NtDeviceIoControlFile( hAcdG, NULL, NULL, NULL, &ioStatusBlock, IOCTL_ACD_KEEPALIVE, &connStatus, sizeof (connStatus), NULL, 0); if (status != STATUS_SUCCESS) { RASAUTO_TRACE1( "StartAutoDialer: NtDeviceIoControlFile(IOCTL_ACD_KEEPALIVE) failed (status=0x%x)", status); goto done; } } if (NULL == pszCmdLine) { // // Construct the command line when there // is not a custom dial DLL. // if (lpEntryName != NULL) { pszCmdLine = LocalAlloc( LPTR, ( lstrlen(RASAUTOUI_DEFAULTDIALENTRY2) + lstrlen(lpAddress) + lstrlen(lpEntryName) + 1) * sizeof(TCHAR)); if(NULL == pszCmdLine) { dwErr = GetLastError(); goto done; } if (fSharedAccess) wsprintf(pszCmdLine, RASAUTOUI_DEFAULTDIALENTRY2, lpAddress, lpEntryName); else wsprintf(pszCmdLine, RASAUTOUI_DEFAULTDIALENTRY, lpAddress, lpEntryName); } else { pszCmdLine = LocalAlloc( LPTR, ( lstrlen(RASAUTOUI_NOENTRY) + lstrlen(lpAddress) + 1) * sizeof(TCHAR)); if(NULL == pszCmdLine) { dwErr = GetLastError(); goto done; } wsprintf(pszCmdLine, RASAUTOUI_NOENTRY, lpAddress); } } RASAUTO_TRACE1("StartAutoDialer: szCmdLine=%S", pszCmdLine); // // Exec the process. // if (!OpenProcessToken( hProcess, TOKEN_ALL_ACCESS, &hToken)) { RASAUTO_TRACE1( "StartAutoDialer: OpenProcessToken failed (dwErr=%d)", GetLastError()); goto done; } if (!CreateEnvironmentBlock( &pEnvBlock, hToken, FALSE)) { TRACE1( "StartAutoDialer: CreateEnvironmentBlock failed (dwErr=%d)", GetLastError()); goto done; } if (!CreateProcessAsUser( hToken, NULL, pszCmdLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS|DETACHED_PROCESS|CREATE_UNICODE_ENVIRONMENT, pEnvBlock, NULL, &StartupInfo, &ProcessInfo)) { RASAUTO_TRACE2( "StartAutoDialer: CreateProcessAsUser(%S) failed (error=0x%x)", pszCmdLine, GetLastError()); CloseHandle(hToken); goto done; } RASAUTO_TRACE1("StartAutoDialer: started pid %d", ProcessInfo.dwProcessId); CloseHandle(hToken); CloseHandle(ProcessInfo.hThread); // // Now that we've started the process, we need to // wait until we think the connection has // been made. // fDialerPresent = TRUE; dwPreConnections = ActiveConnections(TRUE, NULL, NULL); while (dwCount++ < 0xffffffff) { // // Sleep for one second. // status = WaitForSingleObject(hTerminatingG, 1000); if (status == WAIT_OBJECT_0) goto done; // // Ping the driver to let it // know we are working on the // request. // if (pAddr) { connStatus.fSuccess = FALSE; RtlCopyMemory(&connStatus.addr, pAddr, sizeof (ACD_ADDR)); status = NtDeviceIoControlFile( hAcdG, NULL, NULL, NULL, &ioStatusBlock, IOCTL_ACD_KEEPALIVE, &connStatus, sizeof (connStatus), NULL, 0); if (status != STATUS_SUCCESS) { RASAUTO_TRACE1( "StartAutoDialer: NtDeviceIoControlFile(IOCTL_ACD_KEEPALIVE) failed (status=0x%x)", status); // goto done; } } // // Check to see if there are any connections yet. // If there are, then we are done. // dwConnections = ActiveConnections(TRUE, NULL, NULL); if (dwConnections > dwPreConnections) { RASAUTO_TRACE("StartAutoDialer: connection started"); fSuccess = TRUE; goto done; } // // After we have determined there are // no active connections, check to see // if the dialer is still present. This // was calculated on the *previous* iteration // of the loop. We do this to avoid a race // condition of having the dialer go away // after we call ActiveConnections(). // if (!fDialerPresent) { BOOLEAN fFound = FALSE; LPTSTR *lpConnections; RASAUTO_TRACE("StartAutoDialer: dialer went away!"); if (lpEntryName != NULL) { // // Make absolutely sure if an entry was specified, // it is not connected before we return FALSE. // It's possible a connection could have been // in progress before we started the dialer. // dwConnections = ActiveConnections(TRUE, &lpConnections, NULL); if (dwConnections) { for (dwIndex = 0; dwIndex < dwConnections; dwIndex++) { if (!_wcsicmp(lpConnections[dwIndex], lpEntryName)) { fFound = TRUE; break; } } FreeStringArray(lpConnections, dwConnections); if (fFound) { RASAUTO_TRACE1( "StartAutoDialer: found %S on final check!", RASAUTO_TRACESTRW(lpEntryName)); } } } fSuccess = fFound; goto done; } // // After 5 seconds, check to see if // the dialer has terminated. // if (dwCount > 5) { fDialerPresent = GetExitCodeProcess(ProcessInfo.hProcess, &dwExitCode) && dwExitCode == STILL_ACTIVE; RASAUTO_TRACE2( "StartAutoDialer: GetExitCodeProcess returned %d, dwExitCode=%d", fDialerPresent, dwExitCode); if(ERROR_CANCELLED == dwExitCode) { RASAUTO_TRACE("User cancelled the connection attempt"); fDisableAddress = TRUE; } } } done: // // We timed out waiting for a connection. // If the dialer is still running kill it. // if (ProcessInfo.hProcess != NULL) CloseHandle(ProcessInfo.hProcess); // // Complete the connection request // in the driver. // if (pAddr) { connStatus.fSuccess = fSuccess; RtlCopyMemory(&connStatus.addr, pAddr, sizeof (ACD_ADDR)); status = NtDeviceIoControlFile( hAcdG, NULL, NULL, NULL, &ioStatusBlock, IOCTL_ACD_COMPLETION, &connStatus, sizeof (connStatus), NULL, 0); if (status != STATUS_SUCCESS) { RASAUTO_TRACE1( "StartAutoDialer: NtDeviceIoControlFile(IOCTL_ACD_COMPLETION) failed (status=0x%x)", status); } if(fDisableAddress) { DWORD retcode; retcode = DisableAddress(pAddr); RASAUTO_TRACE2("StartAutodialer: Disabled %S. rc=0x%x", RASAUTO_TRACESTRW(lpAddress), retcode); } } if (NULL != pEnvBlock) { DestroyEnvironmentBlock(pEnvBlock); } if(NULL != pszCmdLine) { LocalFree(pszCmdLine); } return fSuccess; } // StartAutoDialer BOOLEAN StartReDialer( IN HANDLE hProcess, IN LPTSTR lpPhonebook, IN LPTSTR lpEntry ) { TCHAR szCmdLine[100]; TCHAR *pszCmdLine = NULL; STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; HANDLE hToken; PVOID pEnvBlock = NULL; // // Initialization of various variables. // memset(&StartupInfo, 0, sizeof (StartupInfo)); memset(&ProcessInfo, 0, sizeof (ProcessInfo)); StartupInfo.cb = sizeof(StartupInfo); // // Construct the command line when there // is not a custom dial DLL. // pszCmdLine = LocalAlloc( LPTR, ( lstrlen(RASAUTOUI_REDIALENTRY) + lstrlen(lpPhonebook) + lstrlen(lpEntry) + 1) * sizeof(TCHAR)); if(NULL == pszCmdLine) { RASAUTO_TRACE1("StartReDialer: failed to allocate pszCmdLine. 0x%x", GetLastError()); return FALSE; } wsprintf(pszCmdLine, RASAUTOUI_REDIALENTRY, lpPhonebook, lpEntry); RASAUTO_TRACE1("StartReDialer: szCmdLine=%S", pszCmdLine); // // Exec the process. // if (!OpenProcessToken( hProcess, TOKEN_ALL_ACCESS, &hToken)) { RASAUTO_TRACE1( "StartReDialer: OpenProcessToken failed (dwErr=%d)", GetLastError()); LocalFree(pszCmdLine); return FALSE; } if (!CreateEnvironmentBlock( &pEnvBlock, hToken, FALSE)) { TRACE1( "StartReDialer: CreateEnvironmentBlock failed (dwErr=%d)", GetLastError()); LocalFree(pszCmdLine); return FALSE; } if (!CreateProcessAsUser( hToken, NULL, pszCmdLine, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS|DETACHED_PROCESS|CREATE_UNICODE_ENVIRONMENT, pEnvBlock, NULL, &StartupInfo, &ProcessInfo)) { RASAUTO_TRACE2( "StartReDialer: CreateProcessAsUser(%S) failed (error=0x%x)", pszCmdLine, GetLastError()); CloseHandle(hToken); LocalFree(pszCmdLine); if (pEnvBlock) { DestroyEnvironmentBlock(pEnvBlock); } return FALSE; } RASAUTO_TRACE1("StartReDialer: started pid %d", ProcessInfo.dwProcessId); CloseHandle(hToken); CloseHandle(ProcessInfo.hThread); LocalFree(pszCmdLine); if (pEnvBlock) { DestroyEnvironmentBlock(pEnvBlock); } return TRUE; } // StartReDialer DWORD GetAddressDialingLocationInfo( IN LPTSTR pszAddress, OUT PADDRESS_LOCATION_INFORMATION *lppDialingInfo, OUT LPDWORD lpdwcDialingInfo ) { DWORD dwErr, dwcb, dwcEntries, i; LPRASAUTODIALENTRY lpAutoDialEntries; PADDRESS_LOCATION_INFORMATION lpDialingInfo; // // Call RAS to find out how many // dialing location entries there are. // dwcb = 0; dwErr = (DWORD)(*lpfnRasGetAutodialAddressG)( pszAddress, NULL, NULL, &dwcb, &dwcEntries); if (dwErr && dwErr != ERROR_BUFFER_TOO_SMALL) return dwErr; if (!dwcEntries) { *lppDialingInfo = NULL; *lpdwcDialingInfo = 0; return 0; } lpAutoDialEntries = LocalAlloc(LPTR, dwcb); if (lpAutoDialEntries == NULL) return ERROR_NOT_ENOUGH_MEMORY; lpAutoDialEntries->dwSize = sizeof (RASAUTODIALENTRY); dwErr = (DWORD)(*lpfnRasGetAutodialAddressG)( pszAddress, NULL, lpAutoDialEntries, &dwcb, &dwcEntries); if (dwErr || (0 == dwcEntries)) { LocalFree(lpAutoDialEntries); if(0 == dwcEntries) { dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY; } return dwErr; } // // Allocate our buffer. // lpDialingInfo = LocalAlloc( LPTR, dwcEntries * sizeof (ADDRESS_LOCATION_INFORMATION)); if (lpDialingInfo == NULL) { LocalFree(lpAutoDialEntries); return ERROR_NOT_ENOUGH_MEMORY; } // // Copy this information over to our // buffer. // for (i = 0; i < dwcEntries; i++) { lpDialingInfo[i].dwLocation = lpAutoDialEntries[i].dwDialingLocation; lpDialingInfo[i].pszEntryName = CopyString(lpAutoDialEntries[i].szEntry); } // // Free the RAS buffer. // LocalFree(lpAutoDialEntries); // // Set return values. // *lppDialingInfo = lpDialingInfo; *lpdwcDialingInfo = dwcEntries; return 0; } // GetAddressDialingLocationInfo DWORD SetAddressDialingLocationInfo( IN LPTSTR pszAddress, IN PADDRESS_LOCATION_INFORMATION lpDialingInfo ) { RASAUTODIALENTRY rasAutoDialEntry; // // Copy the caller's buffer over // to the RAS buffer. // rasAutoDialEntry.dwSize = sizeof (RASAUTODIALENTRY); rasAutoDialEntry.dwDialingLocation = lpDialingInfo->dwLocation; wcscpy(rasAutoDialEntry.szEntry, lpDialingInfo->pszEntryName); return (DWORD)(*lpfnRasSetAutodialAddressG)( pszAddress, 0, &rasAutoDialEntry, sizeof (RASAUTODIALENTRY), 1); } // SetAddressDialingLocationInfo DWORD ClearAddressDialingLocationInfo( IN LPTSTR pszAddress ) { return (DWORD)(*lpfnRasSetAutodialAddressG)(pszAddress, 0, NULL, 0, 0); } // ClearAddressDialingLocationInfo DWORD GetAddressParams( IN LPTSTR pszAddress, IN PADDRESS_PARAMS lpParams ) { HKEY hkey; DWORD dwErr, dwSize, dwType; LPTSTR lpszAddressKey; // // Initialize address map fields. // lpParams->dwTag = ADDRMAP_TAG_NONE; lpParams->dwModifiedTime = 0; // // Read the values from the registry. // lpszAddressKey = LocalAlloc( LPTR, (lstrlen(AUTODIAL_REGADDRESSBASE) + lstrlen(pszAddress) + 2) * sizeof (TCHAR)); if (lpszAddressKey == NULL) return 0; wsprintf(lpszAddressKey, L"%s\\%s", AUTODIAL_REGADDRESSBASE, pszAddress); LockImpersonation(); // // Make sure we have hkcu // dwErr = DwGetHkcu(); if(ERROR_SUCCESS != dwErr) { goto done; } dwErr = RegOpenKeyEx( hkeyCUG, lpszAddressKey, 0, KEY_READ, &hkey); if (dwErr) { LocalFree(lpszAddressKey); goto done; } dwSize = sizeof (DWORD); dwErr = RegQueryValueEx( hkey, AUTODIAL_REGTAGVALUE, NULL, &dwType, (PVOID)&lpParams->dwTag, &dwSize); if (dwErr || dwType != REG_DWORD) lpParams->dwTag = ADDRMAP_TAG_NONE; dwSize = sizeof (DWORD); dwErr = RegQueryValueEx( hkey, AUTODIAL_REGMTIMEVALUE, NULL, &dwType, (PVOID)&lpParams->dwModifiedTime, &dwSize); if (dwErr || dwType != REG_DWORD) lpParams->dwModifiedTime = 0; RegCloseKey(hkey); LocalFree(lpszAddressKey); dwErr = ERROR_SUCCESS; done: UnlockImpersonation(); return dwErr; } // GetAddressParams DWORD SetAddressParams( IN LPTSTR pszAddress, IN PADDRESS_PARAMS lpParams ) { HKEY hkey; DWORD dwErr, dwSize, dwDisp; LPTSTR lpszAddressKey; // // Write the values to the registry. // lpszAddressKey = LocalAlloc( LPTR, (lstrlen(AUTODIAL_REGADDRESSBASE) + lstrlen(pszAddress) + 2) * sizeof (TCHAR)); if (lpszAddressKey == NULL) return 0; wsprintf(lpszAddressKey, L"%s\\%s", AUTODIAL_REGADDRESSBASE, pszAddress); LockImpersonation(); // // Make sure we have hkcu // dwErr = DwGetHkcu(); if(ERROR_SUCCESS != dwErr) { goto done; } dwErr = RegCreateKeyEx( hkeyCUG, lpszAddressKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hkey, &dwDisp); if (dwErr) { LocalFree(lpszAddressKey); goto done; } dwErr = RegSetValueEx( hkey, AUTODIAL_REGTAGVALUE, 0, REG_DWORD, (PVOID)&lpParams->dwTag, sizeof (DWORD)); dwErr = RegSetValueEx( hkey, AUTODIAL_REGMTIMEVALUE, 0, REG_DWORD, (PVOID)&lpParams->dwModifiedTime, sizeof (DWORD)); RegCloseKey(hkey); LocalFree(lpszAddressKey); dwErr = ERROR_SUCCESS; done: UnlockImpersonation(); return dwErr; } // SetAddressParams DWORD EnumAutodialAddresses( IN LPTSTR *ppAddresses, IN LPDWORD lpdwcbAddresses, IN LPDWORD lpdwcAddresses ) { return (DWORD)(*lpfnRasEnumAutodialAddressesG)( ppAddresses, lpdwcbAddresses, lpdwcAddresses); } // EnumAutodialAddresses DWORD GetAutodialParam( IN DWORD dwKey ) { DWORD dwValue, dwcb = sizeof (DWORD); (void)(*lpfnRasGetAutodialParamG)(dwKey, &dwValue, &dwcb); return dwValue; } // GetAutodialParam VOID SetAutodialParam( IN DWORD dwKey, IN DWORD dwValue ) { (void)(*lpfnRasSetAutodialParamG)(dwKey, &dwValue, sizeof (DWORD)); } // SetAutodialParam DWORD NotifyAutoDialChangeEvent( IN HANDLE hEvent ) { DWORD dwErr, dwDisp; // // Make sure we have hkcu // LockImpersonation(); dwErr = DwGetHkcu(); if(ERROR_SUCCESS != dwErr) { goto done; } // // Open the AutoDial registry key. // if (hkeyAutoDialRegChangeG == NULL) { dwErr = RegCreateKeyEx( hkeyCUG, L"Software\\Microsoft\\RAS AutoDial", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_NOTIFY, NULL, &hkeyAutoDialRegChangeG, &dwDisp); if (dwErr) { goto done; } } // // Set the notification change. // dwErr = RegNotifyChangeKeyValue( hkeyAutoDialRegChangeG, TRUE, REG_NOTIFY_CHANGE_NAME|REG_NOTIFY_CHANGE_ATTRIBUTES|REG_NOTIFY_CHANGE_LAST_SET|REG_NOTIFY_CHANGE_SECURITY, hEvent, TRUE); done: UnlockImpersonation(); return dwErr; } // NotifyAutoDialChangeEvent DWORD CreateAutoDialChangeEvent( IN PHANDLE phEvent ) { // // Reset the internal change flag. // fAutoDialRegChangeG = TRUE; // // Create the event. // *phEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (*phEvent == NULL) return GetLastError(); // // Register it. // return NotifyAutoDialChangeEvent(*phEvent); } // CreateAutoDialChangeEvent VOID EnableAutoDialChangeEvent( IN HANDLE hEvent, IN BOOLEAN fEnabled ) { EnterCriticalSection(&csRasG); // // If the event was disabled, and now // it is being enabled, then we reset // the event. // if (!fAutoDialRegChangeG && fEnabled) ResetEvent(hEvent); fAutoDialRegChangeG = fEnabled; LeaveCriticalSection(&csRasG); } BOOLEAN ExternalAutoDialChangeEvent() { BOOLEAN fChanged; EnterCriticalSection(&csRasG); fChanged = fAutoDialRegChangeG; LeaveCriticalSection(&csRasG); return fChanged; } // ExternalAutoDialChangeEvent VOID CloseAutoDialChangeEvent( IN HANDLE hEvent ) { if (hkeyAutoDialRegChangeG != NULL) { RegCloseKey(hkeyAutoDialRegChangeG); hkeyAutoDialRegChangeG = NULL; } CloseHandle(hEvent); } // CloseAutoDialChangeEvent VOID SetHostentCache( IN PCHAR pszDns, IN ULONG ulIpaddr ) { EnterCriticalSection(&csRasG); strcpy((PCHAR)&hostentCacheG[iHostentCacheG].szDns, pszDns); hostentCacheG[iHostentCacheG].ulIpaddr = ulIpaddr; iHostentCacheG = (iHostentCacheG + 1) % HOSTENTCACHESIZ; LeaveCriticalSection(&csRasG); } // SetHostentCache PCHAR GetHostentCache( IN ULONG ulIpaddr ) { PCHAR pszDns = NULL; INT i; EnterCriticalSection(&csRasG); for (i = 0; i < HOSTENTCACHESIZ; i++) { if (hostentCacheG[i].ulIpaddr == ulIpaddr) { pszDns = hostentCacheG[i].szDns; break; } } LeaveCriticalSection(&csRasG); return pszDns; } // GetHostentCache LPTSTR GetNetbiosDevice( IN HRASCONN hrasconn ) { INT i, nProtocols; RAS_PROTOCOLS Protocols; HPORT hPort; RASMAN_ROUTEINFO *pRoute; WCHAR szDevice[MAX_DEVICE_NAME + 1]; nProtocols = 0; hPort = (HPORT) (*lpfnRasGetHportG)(hrasconn); (*lpfnRasPortEnumProtocolsG)(NULL, hPort, &Protocols, &nProtocols); for (i = 0; i < nProtocols; i++) { pRoute = &Protocols.RP_ProtocolInfo[i]; RASAUTO_TRACE3( "GetNetbiosDevice: lana=%d, xport=%S, adapter=%S", pRoute->RI_LanaNum, pRoute->RI_XportName, pRoute->RI_AdapterName); switch (pRoute->RI_Type) { case IPX: return CopyString(L"\\Device\\Nwlnknb"); case IP: wsprintf(szDevice, L"\\Device\\NetBT_Tcpip%s", &pRoute->RI_AdapterName[8]); return CopyString(szDevice); case ASYBEUI: wsprintf(szDevice, L"\\Device\\Nbf_%s", &pRoute->RI_AdapterName[8]); return CopyString(szDevice); } } return NULL; } // GetNetbiosDevice DWORD DwGetDefaultEntryName(LPTSTR *ppszEntryName) { DWORD dwErr = ERROR_SUCCESS; DWORD dwcb = sizeof(RASAUTODIALENTRY); RASAUTODIALENTRY Entry; DWORD dwEntries = 0; LPTSTR pszEntryName = NULL; if(NULL == ppszEntryName) { dwErr = E_INVALIDARG; goto done; } ZeroMemory(&Entry, sizeof(RASAUTODIALENTRY)); Entry.dwSize = sizeof(RASAUTODIALENTRY); dwErr = (DWORD) (*lpfnRasGetAutodialAddressG)( NULL, NULL, &Entry, &dwcb, &dwEntries); if(ERROR_SUCCESS != dwErr) { goto done; } if(0 != dwEntries) { pszEntryName = LocalAlloc(LPTR, sizeof(TCHAR) * (lstrlen(Entry.szEntry) + 1)); if(NULL != pszEntryName) { // // Got a default entry. // lstrcpy(pszEntryName, Entry.szEntry); } else { dwErr = E_OUTOFMEMORY; } } else { RASAUTO_TRACE("No default connection defined"); dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY; } *ppszEntryName = pszEntryName; done: return dwErr; } VOID ProcessLearnedAddress( IN ACD_ADDR_TYPE fType, IN LPTSTR pszAddress, IN PACD_ADAPTER pAdapter ) { BOOLEAN fStatus; DWORD dwConn, dwConnections, dwSize; LPTSTR *pEntryNames, pszEntryName = NULL; HRASCONN *phRasConn; union { RASPPPNBF pppNbf; RASPPPIP pppIp; RASPPPIPX pppIpx; } projBuf; RASPROJECTION fProjection; INT i, nProtocols; RAS_PROTOCOLS Protocols; RASMAN_ROUTEINFO *pRoute; HPORT hPort; PCHAR pszIpAddr, pszMac = NULL; WCHAR szIpAddr[17], *p, *pwszMac; UCHAR cMac[6]; struct in_addr in; LPTSTR pszDefaultEntry = NULL; RASAUTO_TRACE2("ProcessLearnedAddress(%S,%d)", RASAUTO_TRACESTRW(pszAddress), pAdapter->fType); dwConnections = ActiveConnections(TRUE, &pEntryNames, &phRasConn); if (!dwConnections) return; (VOID) DwGetDefaultEntryName(&pszDefaultEntry); if(NULL != pszDefaultEntry) { // // Check to see if we have default entries as one of the // connected entries. If it is we don't learn the address // for(dwConn = 0; dwConn < dwConnections; dwConn++) { if(0 == lstrcmpi(pEntryNames[dwConn], pszDefaultEntry)) { break; } } LocalFree(pszDefaultEntry); if(dwConn != dwConnections) { RASAUTO_TRACE("ProcessLearnedAddress: not processing the address since" " its learned over the default connection"); return; } } // // If this is a DNS-to-IP address mapping, // then simply enter it into the hostent // cache and return. // if (fType == ACD_ADDR_INET && pAdapter->fType == ACD_ADAPTER_IP) { PCHAR pszDns = UnicodeStringToAnsiString(pszAddress, NULL, 0); if (pszDns != NULL) { SetHostentCache(pszDns, pAdapter->ulIpaddr); LocalFree(pszDns); } // return; } // // Set the buffer size according to the // adapter's type. // switch (pAdapter->fType) { case ACD_ADAPTER_LANA: RASAUTO_TRACE1( "ProcessLearnedAddress: ACD_ADAPTER_LANA: bLana=%d", pAdapter->bLana); fProjection = RASP_PppNbf; dwSize = sizeof (RASPPPNBF); break; case ACD_ADAPTER_IP: fProjection = RASP_PppIp; dwSize = sizeof (RASPPPIP); // // Convert the ULONG into a formatted IP address. // in.s_addr = pAdapter->ulIpaddr; pszIpAddr = inet_ntoa(in); RASAUTO_TRACE1( "ProcessLearnedAddress: ACD_ADAPTER_IPADDR: %s", pszIpAddr); AnsiStringToUnicodeString(pszIpAddr, szIpAddr, sizeof (szIpAddr)); break; case ACD_ADAPTER_NAME: RASAUTO_TRACE1( "ProcessLearnedAddress: ACD_ADAPTER_NAME: %S", pAdapter->szName); dwSize = 0; break; case ACD_ADAPTER_MAC: RASAUTO_TRACE6( "ProcessLearnedAddress: ACD_ADAPTER_MAC: %02x:%02x:%02x:%02x:%02x:%02x", pAdapter->cMac[0], pAdapter->cMac[1], pAdapter->cMac[2], pAdapter->cMac[3], pAdapter->cMac[4], pAdapter->cMac[5]); fProjection = RASP_PppIpx; dwSize = sizeof (RASPPPIPX); break; } for (dwConn = 0; dwConn < dwConnections; dwConn++) { // // If we are looking for a device name, // we have to use RasPortEnumProtocols(), // otherwise it's easier to use // RasGetProjectionInfo. // if (pAdapter->fType != ACD_ADAPTER_NAME) { // // Note: the following statement assumes the // dwSize field is at the same offset for // all members of the union. // projBuf.pppNbf.dwSize = dwSize; if ((*lpfnRasGetProjectionInfoG)( phRasConn[dwConn], fProjection, &projBuf, &dwSize)) { RASAUTO_TRACE1( "ProcessLearnedAddress: RasGetProjectionInfo(%S) failed", RASAUTO_TRACESTRW(pEntryNames[dwConn])); continue; } RASAUTO_TRACE3( "ProcessLearnedAddress: RasGetProjectionInfo returned dwSize=%d, dwError=%d, szIpAddress=%S", projBuf.pppIp.dwSize, projBuf.pppIp.dwError, projBuf.pppIp.szIpAddress); // // Note: the following statement assumes the // dwError field is at the same offset for // all members of the union. // if (projBuf.pppNbf.dwError) { RASAUTO_TRACE2( "ProcessLearnedAddress: %S: dwError=0x%x", RASAUTO_TRACESTRW(pEntryNames[dwConn]), projBuf.pppNbf.dwError); continue; } switch (pAdapter->fType) { case ACD_ADAPTER_LANA: RASAUTO_TRACE2( "ProcessLearnedAddress: comparing lanas (%d, %d)", pAdapter->bLana, projBuf.pppNbf.bLana); if (pAdapter->bLana == projBuf.pppNbf.bLana) { pszEntryName = CopyString(pEntryNames[dwConn]); goto done; } break; case ACD_ADAPTER_IP: RASAUTO_TRACE2( "ProcessLearnedAddress: comparing ipaddrs (%S, %S)", szIpAddr, projBuf.pppIp.szIpAddress); // if (!_wcsicmp(szIpAddr, projBuf.pppIp.szIpAddress)) { pszEntryName = CopyString(pEntryNames[dwConn]); goto done; //} break; case ACD_ADAPTER_MAC: // // Terminate IPX address after network number. // pwszMac = wcschr(projBuf.pppIpx.szIpxAddress, '.'); if (pwszMac == NULL) goto done; pszMac = UnicodeStringToAnsiString(pwszMac + 1, NULL, 0); if (pszMac == NULL) goto done; StringToNodeNumber(pszMac, cMac); RASAUTO_TRACE6( "ProcessLearnedAddress: mac addr #1: %02x:%02x:%02x:%02x:%02x:%02x", pAdapter->cMac[0], pAdapter->cMac[1], pAdapter->cMac[2], pAdapter->cMac[3], pAdapter->cMac[4], pAdapter->cMac[5]); RASAUTO_TRACE6( "ProcessLearnedAddress: mac addr #2: %02x:%02x:%02x:%02x:%02x:%02x", cMac[0], cMac[1], cMac[2], cMac[3], cMac[4], cMac[5]); if (RtlEqualMemory(pAdapter->cMac, cMac, sizeof (cMac))) { pszEntryName = CopyString(pEntryNames[dwConn]); goto done; } break; } } else { nProtocols = 0; hPort = (HPORT)(*lpfnRasGetHportG)(phRasConn[dwConn]); (*lpfnRasPortEnumProtocolsG)(NULL, hPort, &Protocols, &nProtocols); for (i = 0; i < nProtocols; i++) { pRoute = &Protocols.RP_ProtocolInfo[i]; RASAUTO_TRACE2( "ProcessLearnedAddress: comparing (%S, %S)", pAdapter->szName, &pRoute->RI_AdapterName[8]); // // Skip the "/Device/" prefix in // RI_AdapterName for the comparison. // if (!_wcsicmp( pAdapter->szName, &pRoute->RI_AdapterName[8])) { pszEntryName = CopyString(pEntryNames[dwConn]); goto done; } } } } done: // // Create a mapping for the original address // if we found one. // if (pszEntryName != NULL) { LPTSTR pszNetbiosName, pszAlias = NULL; CHAR szIpAddress[17], *psz; ULONG inaddr; struct hostent *hp; switch (fType) { case ACD_ADDR_IP: // // Get the Netbios name from the IP address, // if any. // hPort = (HPORT)(*lpfnRasGetHportG)(phRasConn[dwConn]); pszNetbiosName = IpAddressToNetbiosName(pszAddress, hPort); if (pszNetbiosName != NULL) { RASAUTO_TRACE2( "ProcessLearnedAddress: ipaddr %S maps to Netbios name %S", pszAddress, pszNetbiosName); LockAddressMap(); fStatus = SetAddressDialingLocationEntry( pszNetbiosName, pszEntryName); fStatus = SetAddressTag( pszNetbiosName, ADDRMAP_TAG_LEARNED); UnlockAddressMap(); LocalFree(pszNetbiosName); } // // Get the DNS name from the IP address, // if any. // UnicodeStringToAnsiString( pszAddress, szIpAddress, sizeof (szIpAddress)); inaddr = inet_addr(szIpAddress); psz = GetHostentCache(inaddr); if (psz != NULL) pszAlias = AnsiStringToUnicodeString(psz, NULL, 0); if (pszAlias != NULL) { RASAUTO_TRACE2( "ProcessLearnedAddress: ipaddr %S maps to DNS %S", pszAddress, pszAlias); LockAddressMap(); fStatus = SetAddressDialingLocationEntry( pszAlias, pszEntryName); fStatus = SetAddressTag( pszAlias, ADDRMAP_TAG_LEARNED); UnlockAddressMap(); LocalFree(pszAlias); } break; case ACD_ADDR_IPX: // // Get the Netbios name from the IPX address, // if any. // pszNetbiosName = IpxAddressToNetbiosName(pszAddress); if (pszNetbiosName != NULL) { RASAUTO_TRACE2( "ProcessLearnedAddress: ipaddr %S maps to Netbios name %S", pszAddress, pszNetbiosName); LockAddressMap(); fStatus = SetAddressDialingLocationEntry( pszNetbiosName, pszEntryName); fStatus = SetAddressTag( pszNetbiosName, ADDRMAP_TAG_LEARNED); UnlockAddressMap(); LocalFree(pszNetbiosName); } break; } RASAUTO_TRACE2( "ProcessLearnedAddress: learned %S->%S", pszAddress, pszEntryName); LockAddressMap(); fStatus = SetAddressDialingLocationEntry( pszAddress, pszEntryName); fStatus = SetAddressTag( pszAddress, ADDRMAP_TAG_LEARNED); UnlockAddressMap(); LocalFree(pszEntryName); } // // Free resources. // if (dwConnections) { FreeStringArray(pEntryNames, dwConnections); LocalFree(phRasConn); } if(NULL != pszMac) { LocalFree(pszMac); } } // ProcessLearnedAddress VOID SetRedialOnLinkFailureHandler( IN FARPROC lpProc ) { (*lpfnRasRegisterRedialCallbackG)(lpProc); } // SetRedialOnLinkFailureHandler VOID GetPortProtocols( IN HPORT hPort, IN RAS_PROTOCOLS *pProtocols, IN LPDWORD lpdwcProtocols ) { (*lpfnRasPortEnumProtocolsG)(NULL, hPort, pProtocols, lpdwcProtocols); }