/*++ Copyright (c) 1996 Microsoft Corporation MODULE NAME autodial.c ABSTRACT This module contains support for RAS AutoDial system service. AUTHOR Anthony Discolo (adiscolo) 22-Apr-1996 REVISION HISTORY --*/ #define UNICODE #define _UNICODE #include #include #include #include #include #include #include #include #include #define NEW_TRANSPORT_INTERVAL 0 BOOLEAN AcsHlpSendCommand( IN PACD_NOTIFICATION pRequest ) /*++ DESCRIPTION Take an automatic connection driver command block and send it to the driver. ARGUMENTS pRequest: a pointer to the command block RETURN VALUE TRUE if successful; FALSE otherwise. --*/ { NTSTATUS status; HANDLE hAcd; HANDLE hNotif = NULL; UNICODE_STRING nameString; OBJECT_ATTRIBUTES objectAttributes; IO_STATUS_BLOCK ioStatusBlock; // // Initialize the name of the automatic // connection device. // RtlInitUnicodeString(&nameString, ACD_DEVICE_NAME); // // Initialize the object attributes. // InitializeObjectAttributes( &objectAttributes, &nameString, OBJ_CASE_INSENSITIVE, (HANDLE)NULL, (PSECURITY_DESCRIPTOR)NULL); // // Open the automatic connection device. // status = NtCreateFile( &hAcd, FILE_READ_DATA|FILE_WRITE_DATA, &objectAttributes, &ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ|FILE_SHARE_WRITE, FILE_OPEN_IF, 0, NULL, 0); if (status != STATUS_SUCCESS) return FALSE; // // Create an event to wait on. // hNotif = CreateEvent(NULL, FALSE, FALSE, NULL); if (hNotif == NULL) { CloseHandle(hAcd); return FALSE; } status = NtDeviceIoControlFile( hAcd, hNotif, NULL, NULL, &ioStatusBlock, IOCTL_ACD_CONNECT_ADDRESS, pRequest, sizeof (ACD_NOTIFICATION), NULL, 0); if (status == STATUS_PENDING) { status = WaitForSingleObject(hNotif, INFINITE); // // If WaitForSingleObject() returns successfully, // return the status from the status block, // otherwise return the wait status. // if (status == WAIT_OBJECT_0) status = ioStatusBlock.Status; } // // Free resources. // CloseHandle(hNotif); CloseHandle(hAcd); return (status == STATUS_SUCCESS); } // AcsHlpSendCommand BOOLEAN AcsHlpAttemptConnection( IN PACD_ADDR pAddr ) /*++ DESCRIPTION Construct an automatic connection driver command block to attempt to create an autodial connection for the specified address. ARGUMENTS pAddr: a pointer to the address RETURN VALUE TRUE if successful; FALSE otherwise. --*/ { ACD_NOTIFICATION request; // // Initialize the request with // the address. // RtlCopyMemory(&request.addr, pAddr, sizeof (ACD_ADDR)); request.ulFlags = 0; RtlZeroMemory(&request.adapter, sizeof (ACD_ADAPTER)); // // Give this request to the automatic // connection driver. // return AcsHlpSendCommand(&request); } // AcsHlpAttemptConnection BOOLEAN AcsHlpNoteNewConnection( IN PACD_ADDR pAddr, IN PACD_ADAPTER pAdapter ) /*++ DESCRIPTION Construct an automatic connection driver command block to notify the automatic connection service of a new connection. ARGUMENTS pAddr: a pointer to the address pAdapter: a pointer to the adapter over which the new connection was made RETURN VALUE TRUE if successful; FALSE otherwise. --*/ { ULONG cbAddress; ACD_NOTIFICATION request; // // Initialize the request with // the address. // RtlCopyMemory(&request.addr, pAddr, sizeof (ACD_ADDR)); request.ulFlags = ACD_NOTIFICATION_SUCCESS; RtlCopyMemory(&request.adapter, pAdapter, sizeof (ACD_ADAPTER)); // // Give this request to the automatic // connection driver. // return AcsHlpSendCommand(&request); } // AcsHlpNoteNewConnection CHAR * pszDupWtoA( IN LPCWSTR psz ) { CHAR* pszNew = NULL; if (NULL != psz) { DWORD cb; cb = WideCharToMultiByte(CP_ACP, 0, psz, -1, NULL, 0, NULL, NULL); pszNew = (CHAR*) LocalAlloc(LPTR, cb); if (NULL == pszNew) { goto done; } cb = WideCharToMultiByte(CP_ACP, 0, psz, -1, pszNew, cb, NULL, NULL); if (!cb) { LocalFree(pszNew); pszNew = NULL; goto done; } } done: return pszNew; } BOOL fIsDnsName(LPCWSTR pszName) { HINSTANCE hInst = NULL; BOOL fRet = FALSE; FARPROC pfnDnsValidateName = NULL; if( (NULL == (hInst = LoadLibrary(TEXT("dnsapi.dll")))) || (NULL == (pfnDnsValidateName = GetProcAddress( hInst, "DnsValidateName_W") ))) { DWORD retcode = GetLastError(); goto done; } fRet = (ERROR_SUCCESS == pfnDnsValidateName(pszName, DnsNameDomain)); done: if(NULL != hInst) { FreeLibrary(hInst); } return fRet; } ULONG ulGetAutodialSleepInterval() { DWORD dwSleepInterval = NEW_TRANSPORT_INTERVAL; HKEY hkey = NULL; DWORD dwType; DWORD dwSize = sizeof(DWORD); TCHAR *pszAutodialParam = TEXT("SYSTEM\\CurrentControlSet\\Services\\RasAuto\\Parameters"); if (ERROR_SUCCESS != RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszAutodialParam, 0, KEY_READ, &hkey)) { goto done; } if(ERROR_SUCCESS != RegQueryValueEx( hkey, TEXT("NewTransportWaitInterval"), NULL, &dwType, (LPBYTE) &dwSleepInterval, &dwSize)) { goto done; } done: if(NULL != hkey) { RegCloseKey(hkey); } return (ULONG) dwSleepInterval; } DWORD DwGetAcdAddr(ACD_ADDR *paddr, LPCWSTR pszName) { CHAR *pszNameA = NULL; CHAR *pszNameAt = NULL; DWORD retcode = ERROR_SUCCESS; ULONG ulIpAddr = 0; if( (NULL == pszName) || (NULL == paddr)) { retcode = E_INVALIDARG; goto done; } pszNameA = pszDupWtoA(pszName); if(NULL == pszNameA) { retcode = E_FAIL; goto done; } if(INADDR_NONE != (ulIpAddr = inet_addr(pszNameA))) { paddr->fType = ACD_ADDR_IP; paddr->ulIpaddr = ulIpAddr; goto done; } if(fIsDnsName(pszName)) { paddr->fType = ACD_ADDR_INET; RtlCopyMemory((PBYTE) paddr->szInet, (PBYTE) pszNameA, strlen(pszNameA) + 1); goto done; } pszNameAt = pszNameA; // // Skip '\\' if required // if( (TEXT('\0') != pszName[0]) && (TEXT('\\') == pszName[0]) && (TEXT('\\') == pszName[1])) { pszNameA += 2; } // // Default to a netbios name if its neither an ip address // or a dns name // paddr->fType = ACD_ADDR_NB; RtlCopyMemory((PBYTE) paddr->cNetbios, (PBYTE) pszNameA, strlen(pszNameA) + 1); done: if(NULL != pszNameAt) { LocalFree(pszNameAt); } return retcode; } BOOL AcsHlpNbConnection(LPCWSTR pszName) { ACD_ADDR addr = {0}; BOOL fRet; if(!(fRet = (ERROR_SUCCESS == DwGetAcdAddr(&addr, pszName)))) { goto done; } fRet = AcsHlpAttemptConnection(&addr); // // Temporary solution for beta2. We may need to wait till redir gets // a new transport notification. Currently There is no way to // guarantee that redir is bound to some transport before returning // from this api. // if(fRet) { ULONG ulSleepInterval = ulGetAutodialSleepInterval(); if(ulSleepInterval > 0) { Sleep(ulSleepInterval); } } done: return fRet; }