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;
|
|||
|
}
|