445 lines
9.1 KiB
C
445 lines
9.1 KiB
C
/*++
|
||
|
||
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 <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
|
||
#include <stdlib.h>
|
||
#include <windows.h>
|
||
#include <acd.h>
|
||
#include <debug.h>
|
||
#include <winsock2.h>
|
||
#include <dnsapi.h>
|
||
|
||
#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;
|
||
}
|