You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1567 lines
48 KiB
1567 lines
48 KiB
/*++
|
|
|
|
Copyright(c) 1995 Microsoft Corporation
|
|
|
|
MODULE NAME
|
|
connect.c
|
|
|
|
ABSTRACT
|
|
Connection routines for the automatic connection service.
|
|
|
|
AUTHOR
|
|
Anthony Discolo (adiscolo) 23-Feb-1995
|
|
|
|
REVISION HISTORY
|
|
Original version from Gurdeep
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <npapi.h>
|
|
#include <ras.h>
|
|
#include <rasman.h>
|
|
#include <raserror.h>
|
|
#include <rasuip.h>
|
|
#include <acd.h>
|
|
#include <debug.h>
|
|
#include <nouiutil.h>
|
|
#include <pbk.h>
|
|
|
|
#include "table.h"
|
|
#include "addrmap.h"
|
|
#include "netmap.h"
|
|
#include "rasprocs.h"
|
|
#include "reg.h"
|
|
#include "misc.h"
|
|
#include "imperson.h"
|
|
#include "init.h"
|
|
#include "process.h"
|
|
|
|
extern LONG g_lRasAutoRunning;
|
|
|
|
extern DWORD g_dwCritSecFlags;
|
|
|
|
//
|
|
// A request from the driver.
|
|
//
|
|
typedef struct _REQUEST_ENTRY {
|
|
LIST_ENTRY listEntry; // link to other requests
|
|
ACD_NOTIFICATION notif; // the driver request
|
|
} REQUEST_ENTRY, *PREQUEST_ENTRY;
|
|
|
|
//
|
|
// The list of requests from the driver.
|
|
//
|
|
typedef struct _REQUEST_LIST {
|
|
CRITICAL_SECTION csLock; // list lock
|
|
HANDLE hEvent; // non-empty transistion event
|
|
LIST_ENTRY listHead; // list head
|
|
} REQUEST_LIST, *PREQUEST_LIST;
|
|
|
|
//
|
|
// Arguments we pass to AcsCreateConnectionThread().
|
|
//
|
|
typedef struct _CREATION_ARGS {
|
|
HANDLE hProcess; // process handle to impersonate
|
|
ACD_ADDR addr; // original type/address from driver
|
|
LPTSTR pszAddress; // canonicalized address
|
|
DWORD dwTimeout; // RASADP_FailedConnectionTimeout
|
|
} CREATION_ARGS, *PCREATION_ARGS;
|
|
|
|
//
|
|
// Arguments we pass to AcsProcessLearnedAddressThread().
|
|
//
|
|
typedef struct _PROCESS_ADDR_ARGS {
|
|
ACD_ADDR_TYPE fType; // address type
|
|
LPTSTR pszAddress; // canonicalized address
|
|
ACD_ADAPTER adapter; // adapter structure
|
|
} PROCESS_ADDR_ARGS, *PPROCESS_ADDR_ARGS;
|
|
|
|
//
|
|
// Information we need to pass to ResetEntryName()
|
|
// to reset an invalid address map entry name.
|
|
//
|
|
typedef struct _RESET_ENTRY_INFO {
|
|
LPTSTR pszOldEntryName;
|
|
LPTSTR pszNewEntryName;
|
|
} RESET_ENTRY_INFO, *PRESET_ENTRY_INFO;
|
|
|
|
//
|
|
// Arguments we pass to AcsRedialOnLinkFailureThread().
|
|
//
|
|
typedef struct _REDIAL_ARGS {
|
|
LPTSTR pszPhonebook; // the phonebook
|
|
LPTSTR pszEntry; // the phonebook entry
|
|
} REDIAL_ARGS, *PREDIAL_ARGS;
|
|
|
|
//
|
|
// Global variables
|
|
//
|
|
HANDLE hAcdG;
|
|
REQUEST_LIST RequestListG;
|
|
|
|
//
|
|
// External variables
|
|
//
|
|
extern HANDLE hTerminatingG;
|
|
extern HANDLE hSharedConnectionG;
|
|
extern PHASH_TABLE pDisabledAddressesG;
|
|
extern FARPROC lpfnRasDialG;
|
|
extern FARPROC lpfnRasQuerySharedAutoDialG;
|
|
extern FARPROC lpfnRasQuerySharedConnectionG;
|
|
extern FARPROC lpfnRasQueryRedialOnLinkFailureG;
|
|
extern FARPROC lpfnRasGetCredentialsG;
|
|
extern FARPROC lpfnRasHangUpG;
|
|
extern FARPROC lpfnRasGetEntryPropertiesG;
|
|
|
|
//
|
|
// Forward declarations
|
|
//
|
|
BOOLEAN
|
|
CreateConnection(
|
|
IN HANDLE hToken,
|
|
IN PACD_ADDR pAddr,
|
|
IN LPTSTR lpRemoteName,
|
|
IN DWORD dwTimeout
|
|
);
|
|
|
|
DWORD
|
|
AcsRedialOnLinkFailureThread(
|
|
LPVOID lpArg
|
|
);
|
|
|
|
VOID
|
|
AcsRedialOnLinkFailure(
|
|
IN LPSTR lpszPhonebook,
|
|
IN LPSTR lpszEntry
|
|
);
|
|
|
|
VOID
|
|
AcsDialSharedConnection(
|
|
HANDLE *phProcess
|
|
);
|
|
|
|
DWORD WINAPI
|
|
AcsDialSharedConnectionNoUser(
|
|
PVOID Parameter
|
|
);
|
|
|
|
|
|
DWORD
|
|
AcsRequestWorkerThread(
|
|
LPVOID pArgs
|
|
)
|
|
{
|
|
HANDLE hProcess = NULL, hEvents[3];
|
|
NTSTATUS status;
|
|
PLIST_ENTRY pEntry;
|
|
PREQUEST_ENTRY pRequest = NULL;
|
|
LPTSTR pszAddress = NULL;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
|
|
hEvents[0] = hTerminatingG;
|
|
hEvents[1] = RequestListG.hEvent;
|
|
hEvents[2] = hSharedConnectionG;
|
|
for (;;) {
|
|
//
|
|
// Unload any user-based resources before
|
|
// a potentially long-term wait.
|
|
//
|
|
// PrepareForLongWait();
|
|
//
|
|
// Wait for something to do.
|
|
//
|
|
RASAUTO_TRACE("AcsRequestWorkerThread: waiting...");
|
|
status = WaitForMultipleObjects(3, hEvents, FALSE, INFINITE);
|
|
if (status == WAIT_OBJECT_0 || status == WAIT_FAILED) {
|
|
RASAUTO_TRACE1("AcsRequestWorkerThread: status=%d: shutting down", status);
|
|
break;
|
|
}
|
|
if (status == WAIT_OBJECT_0 + 2) {
|
|
//
|
|
// Check to see if connections are disabled
|
|
// for this dialing location.
|
|
//
|
|
BOOL fEnabled;
|
|
if ((*lpfnRasQuerySharedAutoDialG)(&fEnabled) || !fEnabled) {
|
|
RASAUTO_TRACE("AcsRequestWorkerThread: shared-autodial disabled!");
|
|
continue;
|
|
}
|
|
//
|
|
// Dial the shared connection
|
|
//
|
|
if ((hProcess = RefreshImpersonation(hProcess)) == NULL) {
|
|
RASAUTO_TRACE("AcsRequestWorkerThread: no currently logged-on user!");
|
|
QueueUserWorkItem(AcsDialSharedConnectionNoUser, NULL, 0);
|
|
continue;
|
|
}
|
|
AcsDialSharedConnection(&hProcess);
|
|
continue;
|
|
}
|
|
//
|
|
// RASAUTO_TRACE() who we think the current user is.
|
|
//
|
|
TraceCurrentUser();
|
|
//
|
|
// Process all requests in the list.
|
|
//
|
|
for (;;) {
|
|
//
|
|
// Make sure we aren't shutting down
|
|
// before processing the next request.
|
|
//
|
|
if (WaitForSingleObject(hTerminatingG, 0) != WAIT_TIMEOUT) {
|
|
RASAUTO_TRACE("AcsRequestWorkerThread: shutting down");
|
|
return 0;
|
|
}
|
|
//
|
|
// Get the next request.
|
|
//
|
|
EnterCriticalSection(&RequestListG.csLock);
|
|
if (IsListEmpty(&RequestListG.listHead)) {
|
|
LeaveCriticalSection(&RequestListG.csLock);
|
|
break;
|
|
}
|
|
pEntry = RemoveHeadList(&RequestListG.listHead);
|
|
LeaveCriticalSection(&RequestListG.csLock);
|
|
pRequest = CONTAINING_RECORD(pEntry, REQUEST_ENTRY, listEntry);
|
|
//
|
|
// Make sure the current thread is impersonating
|
|
// the currently logged-on user.
|
|
//
|
|
if ((hProcess = RefreshImpersonation(hProcess)) == NULL) {
|
|
RASAUTO_TRACE("AcsRequestWorkerThread: no currently logged-on user!");
|
|
goto done;
|
|
}
|
|
//
|
|
// Handle the request.
|
|
//
|
|
pszAddress = AddressToUnicodeString(&pRequest->notif.addr);
|
|
if (pszAddress == NULL) {
|
|
RASAUTO_TRACE("AcsRequestWorkerThread: AddressToUnicodeString failed");
|
|
goto done;
|
|
}
|
|
RASAUTO_TRACE2(
|
|
"AcsRequestWorkerThread: pszAddress=%S, ulFlags=0x%x",
|
|
pszAddress,
|
|
pRequest->notif.ulFlags);
|
|
if (pRequest->notif.ulFlags & ACD_NOTIFICATION_SUCCESS) {
|
|
//
|
|
// Process a learned address.
|
|
//
|
|
ProcessLearnedAddress(
|
|
pRequest->notif.addr.fType,
|
|
pszAddress,
|
|
&pRequest->notif.adapter);
|
|
}
|
|
else {
|
|
ACD_STATUS connStatus;
|
|
DWORD dwTimeout;
|
|
|
|
//
|
|
// Get the connection timeout value.
|
|
//
|
|
dwTimeout = GetAutodialParam(RASADP_FailedConnectionTimeout);
|
|
//
|
|
// Create the new connection.
|
|
//
|
|
connStatus.fSuccess = CreateConnection(
|
|
hProcess,
|
|
&pRequest->notif.addr,
|
|
pszAddress,
|
|
dwTimeout);
|
|
RASAUTO_TRACE1(
|
|
"AcsRequestWorkerThread: CreateConnection returned %d",
|
|
connStatus.fSuccess);
|
|
//
|
|
// Complete the connection by issuing
|
|
// the completion ioctl to the driver.
|
|
//
|
|
RtlCopyMemory(
|
|
&connStatus.addr,
|
|
&pRequest->notif.addr,
|
|
sizeof (ACD_ADDR));
|
|
status = NtDeviceIoControlFile(
|
|
hAcdG,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
IOCTL_ACD_COMPLETION,
|
|
&connStatus,
|
|
sizeof (connStatus),
|
|
NULL,
|
|
0);
|
|
if (status != STATUS_SUCCESS) {
|
|
RASAUTO_TRACE1(
|
|
"AcsRequestWorkerThread: NtDeviceIoControlFile(IOCTL_ACD_COMPLETION) failed (status=0x%x)",
|
|
status);
|
|
}
|
|
}
|
|
done:
|
|
if (pszAddress != NULL) {
|
|
LocalFree(pszAddress);
|
|
pszAddress = NULL;
|
|
}
|
|
if (pRequest != NULL) {
|
|
LocalFree(pRequest);
|
|
pRequest = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
} // AcsRequestWorkerThread
|
|
|
|
BOOL
|
|
fProcessDisabled(HANDLE hPid)
|
|
{
|
|
PSYSTEM_PROCESS_INFORMATION pProcessInfo;
|
|
ULONG ulTotalOffset = 0;
|
|
PUCHAR pLargeBuffer = NULL;
|
|
BOOL fProcessDisabled = FALSE;
|
|
|
|
pProcessInfo = GetSystemProcessInfo();
|
|
|
|
if(NULL == pProcessInfo)
|
|
{
|
|
goto done;
|
|
}
|
|
|
|
pLargeBuffer = (PUCHAR)pProcessInfo;
|
|
|
|
//
|
|
// Look in the process list for svchost.exe and services.exe
|
|
//
|
|
for (;;)
|
|
{
|
|
if ( (pProcessInfo->ImageName.Buffer != NULL)
|
|
&& (hPid == pProcessInfo->UniqueProcessId))
|
|
{
|
|
if( (0 == _wcsicmp(
|
|
pProcessInfo->ImageName.Buffer,
|
|
L"svchost.exe"))
|
|
|| (0 == _wcsicmp(
|
|
pProcessInfo->ImageName.Buffer,
|
|
L"services.exe"))
|
|
|| (0 == _wcsicmp(
|
|
pProcessInfo->ImageName.Buffer,
|
|
L"llssrv.exe")))
|
|
{
|
|
fProcessDisabled = TRUE;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Increment offset to next process information block.
|
|
//
|
|
if (!pProcessInfo->NextEntryOffset)
|
|
{
|
|
break;
|
|
}
|
|
|
|
ulTotalOffset += pProcessInfo->NextEntryOffset;
|
|
pProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&pLargeBuffer[ulTotalOffset];
|
|
}
|
|
|
|
|
|
done:
|
|
|
|
if(NULL != pLargeBuffer)
|
|
{
|
|
FreeSystemProcessInfo((PSYSTEM_PROCESS_INFORMATION)pLargeBuffer);
|
|
}
|
|
|
|
return fProcessDisabled;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VOID
|
|
AcsDoService()
|
|
{
|
|
HANDLE hProcess = NULL, hNotif, hObjects[2];
|
|
HANDLE hWorkerThread;
|
|
PWCHAR pszAddr;
|
|
LONG cbAddr;
|
|
NTSTATUS status;
|
|
BOOLEAN fDisabled, fStatus, fEnabled;
|
|
BOOLEAN fAsynchronousRequest;
|
|
IO_STATUS_BLOCK ioStatusBlock;
|
|
PREQUEST_ENTRY pRequest;
|
|
ACD_NOTIFICATION connInfo;
|
|
DWORD dwErr, dwThreadId, dwfDisableLoginSession;
|
|
ULONG ulAttributes;
|
|
|
|
{
|
|
LONG l;
|
|
l = InterlockedIncrement(&g_lRasAutoRunning);
|
|
|
|
// DbgPrint("RASAUTO: AcsDoService: lrasautorunning=%d\n",
|
|
// l);
|
|
}
|
|
|
|
//
|
|
// Initialize the request list.
|
|
//
|
|
RasInitializeCriticalSection(&RequestListG.csLock, &dwErr);
|
|
|
|
if(dwErr != ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_dwCritSecFlags |= RASAUTO_CRITSEC_REQUESTLIST;
|
|
|
|
RequestListG.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (RequestListG.hEvent == NULL) {
|
|
RASAUTO_TRACE1(
|
|
"AcsDoService: CreateEvent failed (error=0x%x)",
|
|
GetLastError());
|
|
DeleteCriticalSection(&RequestListG.csLock);
|
|
g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_REQUESTLIST);
|
|
return;
|
|
}
|
|
InitializeListHead(&RequestListG.listHead);
|
|
//
|
|
// Start the asynchronous request worker
|
|
// thread.
|
|
//
|
|
hWorkerThread = CreateThread(
|
|
NULL,
|
|
10000L,
|
|
(LPTHREAD_START_ROUTINE)AcsRequestWorkerThread,
|
|
NULL,
|
|
0,
|
|
&dwThreadId);
|
|
if (hWorkerThread == NULL) {
|
|
RASAUTO_TRACE1(
|
|
"AcsDoService: CreateThread failed (error=0x%x)",
|
|
GetLastError());
|
|
//
|
|
// .NET bug# 514423 new verbose RASAUTO/RASAUTOU prefast warnings
|
|
//
|
|
CloseHandle(RequestListG.hEvent);
|
|
RequestListG.hEvent = NULL;
|
|
DeleteCriticalSection(&RequestListG.csLock);
|
|
g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_REQUESTLIST);
|
|
return;
|
|
}
|
|
//
|
|
// Create an event to wait for
|
|
// the ioctl completion.
|
|
//
|
|
hNotif = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
if (hNotif == NULL) {
|
|
RASAUTO_TRACE1(
|
|
"AcsDoService: CreateEvent failed (error=0x%x)",
|
|
GetLastError());
|
|
//
|
|
// .NET bug# 514423 new verbose RASAUTO/RASAUTOU prefast warnings
|
|
//
|
|
CloseHandle(hWorkerThread);
|
|
CloseHandle(RequestListG.hEvent);
|
|
RequestListG.hEvent = NULL;
|
|
DeleteCriticalSection(&RequestListG.csLock);
|
|
g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_REQUESTLIST);
|
|
return;
|
|
}
|
|
//
|
|
// Initialize the array of events
|
|
// we need to wait for with WaitForMultipleObjects()
|
|
// below.
|
|
//
|
|
hObjects[0] = hNotif;
|
|
hObjects[1] = hTerminatingG;
|
|
for (;;) {
|
|
//
|
|
// Unload any user-based resources before
|
|
// a potentially long-term wait.
|
|
//
|
|
// PrepareForLongWait();
|
|
//
|
|
// Initialize the connection information.
|
|
//
|
|
pszAddr = NULL;
|
|
RtlZeroMemory(&connInfo, sizeof (connInfo));
|
|
//
|
|
// Wait for a connection notification.
|
|
//
|
|
status = NtDeviceIoControlFile(
|
|
hAcdG,
|
|
hNotif,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
IOCTL_ACD_NOTIFICATION,
|
|
NULL,
|
|
0,
|
|
&connInfo,
|
|
sizeof (connInfo));
|
|
if (status == STATUS_PENDING) {
|
|
RASAUTO_TRACE("AcsDoService: waiting for notification");
|
|
status = WaitForMultipleObjects(2, hObjects, FALSE, INFINITE);
|
|
RASAUTO_TRACE1(
|
|
"AcsDoService: WaitForMultipleObjects returned 0x%x",
|
|
status);
|
|
if (status == WAIT_OBJECT_0 + 1)
|
|
break;
|
|
status = ioStatusBlock.Status;
|
|
}
|
|
if (status != STATUS_SUCCESS) {
|
|
RASAUTO_TRACE1(
|
|
"AcsDoService: NtDeviceIoControlFile(IOCTL_ACD_NOTIFICATION) failed (status=0x%x)",
|
|
status);
|
|
//
|
|
// .NET bug# 514423 new verbose RASAUTO/RASAUTOU prefast warnings
|
|
//
|
|
CloseHandle(hNotif);
|
|
CloseHandle(hWorkerThread);
|
|
CloseHandle(RequestListG.hEvent);
|
|
RequestListG.hEvent = NULL;
|
|
DeleteCriticalSection(&RequestListG.csLock);
|
|
g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_REQUESTLIST);
|
|
return;
|
|
}
|
|
//
|
|
// Initialize the flag that notes whether
|
|
// the request is added to the list of
|
|
// asynchronous requests.
|
|
//
|
|
fAsynchronousRequest = FALSE;
|
|
//
|
|
// RASAUTO_TRACE() who we think the currently
|
|
// impersonated user is.
|
|
//
|
|
TraceCurrentUser();
|
|
//
|
|
// Convert the address structure to a Unicode string.
|
|
//
|
|
pszAddr = AddressToUnicodeString(&connInfo.addr);
|
|
if (pszAddr == NULL) {
|
|
RASAUTO_TRACE("AcsDoService: AddressToUnicodeString failed");
|
|
continue;
|
|
}
|
|
//
|
|
// If we get a bogus address from
|
|
// the driver, ignore it.
|
|
//
|
|
if (!wcslen(pszAddr)) {
|
|
RASAUTO_TRACE("AcsDoService: ignoring null address");
|
|
LocalFree(pszAddr);
|
|
continue;
|
|
}
|
|
RASAUTO_TRACE2(
|
|
"AcsDoService: got notification: address: %S, ulFlags=0x%x",
|
|
pszAddr,
|
|
connInfo.ulFlags);
|
|
//
|
|
// Make sure the current thread is impersonating
|
|
// the currently logged-on user. We need this
|
|
// so the RAS utilities run with the user's credentials.
|
|
//
|
|
if ((hProcess = RefreshImpersonation(hProcess)) == NULL) {
|
|
RASAUTO_TRACE("AcsDoService: no currently logged-on user!");
|
|
goto done;
|
|
}
|
|
//
|
|
// Check to see if this address is in the list
|
|
// of disabled addresses.
|
|
//
|
|
LockDisabledAddresses();
|
|
if (GetTableEntry(pDisabledAddressesG, pszAddr, NULL)) {
|
|
RASAUTO_TRACE1("AcsDoService: %S: is disabled", pszAddr);
|
|
UnlockDisabledAddresses();
|
|
goto done;
|
|
}
|
|
UnlockDisabledAddresses();
|
|
|
|
//
|
|
// Check to see if connections are disabled
|
|
// for this login session.
|
|
//
|
|
dwfDisableLoginSession = GetAutodialParam(RASADP_LoginSessionDisable);
|
|
if (dwfDisableLoginSession) {
|
|
RASAUTO_TRACE("AcsDoService: connections disabled for this login session");
|
|
goto done;
|
|
}
|
|
//
|
|
// Check to see if connections are disabled
|
|
// for this dialing location.
|
|
//
|
|
dwErr = AutoDialEnabled(&fEnabled);
|
|
if (!dwErr && !fEnabled) {
|
|
RASAUTO_TRACE("AcsDoService: connections disabled for this dialing location");
|
|
goto done;
|
|
}
|
|
//
|
|
// If the address we're trying to connect
|
|
// to is on the disabled list, then fail
|
|
// this connection attempt.
|
|
//
|
|
LockAddressMap();
|
|
GetAddressDisabled(pszAddr, &fDisabled);
|
|
UnlockAddressMap();
|
|
if (fDisabled) {
|
|
RASAUTO_TRACE1("AcsDoService: %S: address disabled", RASAUTO_TRACESTRW(pszAddr));
|
|
goto done;
|
|
}
|
|
|
|
RASAUTO_TRACE1("AcsDoService: notif.ulFlags=0x%x", connInfo.ulFlags);
|
|
|
|
//
|
|
// If autodial is disabled for this pid, don't start autodial and bail
|
|
//
|
|
if( (0 == (connInfo.ulFlags & ACD_NOTIFICATION_SUCCESS))
|
|
&& fProcessDisabled(connInfo.Pid))
|
|
{
|
|
RASAUTO_TRACE1("AcsDoService: Autodial is disabled for process 0x%lx",
|
|
connInfo.Pid);
|
|
|
|
goto done;
|
|
}
|
|
else
|
|
{
|
|
RASAUTO_TRACE1("AcsDoService: process 0x%lx is not disabled",
|
|
connInfo.Pid);
|
|
}
|
|
|
|
//
|
|
// We need to process this request
|
|
// asynchronously. Create and initialize
|
|
// a request entry.
|
|
//
|
|
pRequest = LocalAlloc(LPTR, sizeof (REQUEST_ENTRY));
|
|
if (pRequest == NULL) {
|
|
RASAUTO_TRACE("AcsDoService: LocalAlloc failed");
|
|
goto done;
|
|
}
|
|
RtlCopyMemory(&pRequest->notif, &connInfo, sizeof (ACD_NOTIFICATION));
|
|
//
|
|
// Add this request to the list of
|
|
// requests to be processed asynchronously.
|
|
//
|
|
EnterCriticalSection(&RequestListG.csLock);
|
|
InsertTailList(&RequestListG.listHead, &pRequest->listEntry);
|
|
SetEvent(RequestListG.hEvent);
|
|
LeaveCriticalSection(&RequestListG.csLock);
|
|
fAsynchronousRequest = TRUE;
|
|
|
|
done:
|
|
if (pszAddr != NULL)
|
|
LocalFree(pszAddr);
|
|
//
|
|
// If we aren't going to process this request
|
|
// asynchronously, then we need to signal the
|
|
// (unsuccessful) completion of the connection
|
|
// attempt. Only signal completion of
|
|
// non-ACD_NOTIFICATION_SUCCESS requests.
|
|
//
|
|
if (!fAsynchronousRequest) {
|
|
if (!(connInfo.ulFlags & ACD_NOTIFICATION_SUCCESS)) {
|
|
ACD_STATUS connStatus;
|
|
|
|
connStatus.fSuccess = FALSE;
|
|
RtlCopyMemory(&connStatus.addr, &connInfo.addr, sizeof (ACD_ADDR));
|
|
status = NtDeviceIoControlFile(
|
|
hAcdG,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&ioStatusBlock,
|
|
IOCTL_ACD_COMPLETION,
|
|
&connStatus,
|
|
sizeof (connStatus),
|
|
NULL,
|
|
0);
|
|
if (status != STATUS_SUCCESS) {
|
|
RASAUTO_TRACE1(
|
|
"AcsDoService: NtDeviceIoControlFile(IOCTL_ACD_COMPLETION) failed (status=0x%x)",
|
|
status);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Clean up the worker thread.
|
|
//
|
|
RASAUTO_TRACE("AcsDoService: signaling worker thread to shutdown");
|
|
WaitForSingleObject(hWorkerThread, INFINITE);
|
|
if(RequestListG.hEvent != NULL)
|
|
{
|
|
CloseHandle(RequestListG.hEvent);
|
|
RequestListG.hEvent = NULL;
|
|
}
|
|
|
|
DeleteCriticalSection(&RequestListG.csLock);
|
|
g_dwCritSecFlags &= ~(RASAUTO_CRITSEC_REQUESTLIST);
|
|
CloseHandle(hWorkerThread);
|
|
RASAUTO_TRACE("AcsDoService: worker thread shutdown done");
|
|
//
|
|
// Clean up all resources associated
|
|
// with the service.
|
|
//
|
|
CloseHandle(hNotif);
|
|
AcsCleanup();
|
|
RASAUTO_TRACE("AcsDoService: exiting");
|
|
} // AcsDoService
|
|
|
|
|
|
VOID
|
|
AcsDialSharedConnection(
|
|
HANDLE *phProcess
|
|
)
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Looks for a shared connection and initiates a connection for it.
|
|
|
|
ARGUMENTS
|
|
phProcess: pointer to the handle to the process token that we inherit the
|
|
security attributes from when we exec the dialer
|
|
|
|
RETURN VALUE
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwErr;
|
|
BOOLEAN fEntryInvalid;
|
|
BOOLEAN fRasLoaded;
|
|
RASSHARECONN rsc;
|
|
TCHAR* pszEntryName;
|
|
TCHAR szEntryName[RAS_MaxEntryName + 1];
|
|
RASAUTO_TRACE("AcsDialSharedConnection");
|
|
//
|
|
// Load RAS entrypoints
|
|
//
|
|
fRasLoaded = LoadRasDlls();
|
|
if (!fRasLoaded) {
|
|
RASAUTO_TRACE("AcsDialSharedConnection: Could not load RAS DLLs.");
|
|
return;
|
|
}
|
|
//
|
|
// A guest isn't able to dial a RAS connection, so if we're currently
|
|
// impersonating a guest we need to perform a no-user autodial
|
|
//
|
|
if (ImpersonatingGuest()) {
|
|
QueueUserWorkItem(AcsDialSharedConnectionNoUser, NULL, 0);
|
|
return;
|
|
}
|
|
//
|
|
// Get the shared connection, if any. We can't do this in an impersonated
|
|
// context, as the user we're impersonating may not have sufficient access
|
|
// to retrieve the current shared connection.
|
|
//
|
|
RevertImpersonation();
|
|
*phProcess = NULL;
|
|
dwErr = (DWORD)(*lpfnRasQuerySharedConnectionG)(&rsc);
|
|
if ((*phProcess = RefreshImpersonation(NULL)) == NULL) {
|
|
RASAUTO_TRACE("AcsDialSharedConnection: unable to refresh impersonation!");
|
|
if (NO_ERROR == dwErr && !rsc.fIsLanConnection) {
|
|
//
|
|
// Attempt to do no-user autodial
|
|
//
|
|
QueueUserWorkItem(AcsDialSharedConnectionNoUser, NULL, 0);
|
|
return;
|
|
}
|
|
}
|
|
if (dwErr) {
|
|
RASAUTO_TRACE1("AcsDialSharedConnection: RasQuerySharedConnection=%d", dwErr);
|
|
return;
|
|
} else if (rsc.fIsLanConnection) {
|
|
RASAUTO_TRACE("AcsDialSharedConnection: shared connection is LAN adapter");
|
|
return;
|
|
}
|
|
#ifdef UNICODE
|
|
pszEntryName = rsc.name.szEntryName;
|
|
#else
|
|
//
|
|
// Convert to ANSI
|
|
//
|
|
pszEntryName = szEntryName;
|
|
wcstombs(pszEntryName, rsc.name.szEntryName, RAS_MaxEntryName);
|
|
#endif
|
|
//
|
|
// Initiate a dial-attempt
|
|
//
|
|
StartAutoDialer(
|
|
*phProcess,
|
|
NULL,
|
|
pszEntryName,
|
|
pszEntryName,
|
|
TRUE,
|
|
&fEntryInvalid);
|
|
}
|
|
|
|
|
|
DWORD WINAPI
|
|
AcsDialSharedConnectionNoUser(
|
|
PVOID Parameter
|
|
)
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Looks for a shared connection and initiates a connection for it
|
|
using RasDial and the cached credentials for the connection.
|
|
|
|
ARGUMENTS
|
|
none
|
|
|
|
RETURN VALUE
|
|
none
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwErr;
|
|
BOOLEAN fRasLoaded;
|
|
HRASCONN hrasconn;
|
|
RASCREDENTIALSW rc;
|
|
RASDIALEXTENSIONS rde;
|
|
RASDIALPARAMSW rdp;
|
|
RASSHARECONN rsc;
|
|
RASAUTO_TRACE("AcsDialSharedConnectionNoUser");
|
|
//
|
|
// Load RAS entrypoints
|
|
//
|
|
fRasLoaded = LoadRasDlls();
|
|
if (!fRasLoaded) {
|
|
RASAUTO_TRACE("AcsDialSharedConnectionNoUser: Could not load RAS DLLs.");
|
|
return NO_ERROR;
|
|
}
|
|
//
|
|
// Get the shared connection, if any
|
|
//
|
|
dwErr = (DWORD)(*lpfnRasQuerySharedConnectionG)(&rsc);
|
|
if (dwErr) {
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: RasQuerySharedConnection=%d",
|
|
dwErr);
|
|
return NO_ERROR;
|
|
} else if (rsc.fIsLanConnection) {
|
|
RASAUTO_TRACE("AcsDialSharedConnectionNoUser: shared connection is LAN");
|
|
return NO_ERROR;
|
|
}
|
|
//
|
|
// Retrieve the credentials for the shared connection.
|
|
//
|
|
rc.dwSize = sizeof(rc);
|
|
rc.dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain | RASCM_DefaultCreds;
|
|
dwErr = (DWORD)(*lpfnRasGetCredentialsG)(
|
|
rsc.name.szPhonebookPath, rsc.name.szEntryName, &rc
|
|
);
|
|
if (dwErr) {
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: "
|
|
"RasGetCredentials=%d", dwErr);
|
|
return NO_ERROR;
|
|
}
|
|
//
|
|
// Prepare to initiate the connection, setting up the dial-extensions
|
|
// and the dial-parameters.
|
|
//
|
|
ZeroMemory(&rde, sizeof(rde));
|
|
rde.dwSize = sizeof(rde);
|
|
rde.dwfOptions = RDEOPT_NoUser;
|
|
|
|
ZeroMemory(&rdp, sizeof(rdp));
|
|
rdp.dwSize = sizeof(rdp);
|
|
lstrcpyW(rdp.szEntryName, rsc.name.szEntryName);
|
|
lstrcpyW(rdp.szUserName, rc.szUserName);
|
|
lstrcpyW(rdp.szDomain, rc.szDomain);
|
|
lstrcpyW(rdp.szPassword, rc.szPassword);
|
|
//
|
|
// Clear the credentials from memory, and dial the connection.
|
|
//
|
|
RASAUTO_TRACE("AcsDialSharedConnectionNoUser: RasDial");
|
|
hrasconn = NULL;
|
|
ZeroMemory(&rc, sizeof(rc));
|
|
dwErr = (DWORD)(*lpfnRasDialG)(
|
|
&rde, rsc.name.szPhonebookPath, &rdp, 0, NULL, &hrasconn
|
|
);
|
|
ZeroMemory(&rdp, sizeof(rdp));
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: RasDial=%d", dwErr);
|
|
|
|
if (E_NOTIMPL == dwErr)
|
|
{
|
|
//
|
|
// This is possibly a Connection Manager connection since it's returning E_NOTIMPL,
|
|
// we should check the phonebook entry for the type and then call the RasDialDlg
|
|
// with the RASDDFLAG_NoPrompt flag.
|
|
//
|
|
RASDIALDLG info;
|
|
BOOL fRetVal = FALSE;
|
|
HINSTANCE hRasDlgDll = NULL;
|
|
RASENTRY re;
|
|
DWORD dwRasEntrySize;
|
|
DWORD dwIgnore;
|
|
typedef BOOL (*lpfnRasDialDlgFunc)(LPWSTR, LPWSTR, LPWSTR, LPRASDIALDLG);
|
|
|
|
ZeroMemory(&info, sizeof(info));
|
|
info.dwSize = sizeof(info);
|
|
|
|
ZeroMemory(&re, sizeof(re));
|
|
dwRasEntrySize = sizeof(re);
|
|
re.dwSize = dwRasEntrySize;
|
|
|
|
dwErr = (DWORD)(*lpfnRasGetEntryPropertiesG)(
|
|
rsc.name.szPhonebookPath,
|
|
rsc.name.szEntryName,
|
|
&re,
|
|
&dwRasEntrySize,
|
|
NULL,
|
|
&dwIgnore);
|
|
|
|
if (ERROR_SUCCESS == dwErr)
|
|
{
|
|
dwErr = ERROR_NOT_SUPPORTED;
|
|
//
|
|
// Check if this is a Connection Manager entry
|
|
//
|
|
if (RASET_Internet == re.dwType)
|
|
{
|
|
//
|
|
// Prevent the DialerDialog
|
|
//
|
|
info.dwFlags |= RASDDFLAG_NoPrompt;
|
|
|
|
hRasDlgDll = LoadLibrary(L"RASDLG.DLL");
|
|
if (hRasDlgDll)
|
|
{
|
|
lpfnRasDialDlgFunc lpfnRasDialDlg = (lpfnRasDialDlgFunc)GetProcAddress(hRasDlgDll, "RasDialDlgW");
|
|
|
|
if (lpfnRasDialDlg)
|
|
{
|
|
fRetVal = (BOOL)(lpfnRasDialDlg)(rsc.name.szPhonebookPath, rsc.name.szEntryName, NULL, &info );
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: lpfnRasDialDlg returns %d", (DWORD)fRetVal);
|
|
if (fRetVal)
|
|
{
|
|
dwErr = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RASAUTO_TRACE("AcsDialSharedConnectionNoUser: Failed to get procaddress for RasDialDlgW");
|
|
|
|
}
|
|
FreeLibrary(hRasDlgDll);
|
|
hRasDlgDll = NULL;
|
|
}
|
|
else
|
|
{
|
|
RASAUTO_TRACE("AcsDialSharedConnectionNoUser: Failed to load RASDLG.dll");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: Wrong type. RASENTRY.dwType=%d", re.dwType);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: lpfnRasGetEntryPropertiesG=%d", dwErr);
|
|
}
|
|
}
|
|
|
|
//
|
|
// If RasDial returned an error and passed back a valid connection
|
|
// handle we need to call RasHangUp on that handle.
|
|
//
|
|
if (ERROR_SUCCESS != dwErr && NULL != hrasconn) {
|
|
dwErr = (DWORD)(*lpfnRasHangUpG)(hrasconn);
|
|
RASAUTO_TRACE1("AcsDialSharedConnectionNoUser: RasHangUp=%d", dwErr);
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
ResetEntryName(
|
|
IN PVOID pArg,
|
|
IN LPTSTR pszAddress,
|
|
IN PVOID pData
|
|
)
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
A table enumerator procedure to reset all
|
|
address map entries referencing an old RAS
|
|
phonebook entry to a new one.
|
|
|
|
ARGUMENTS
|
|
pArg: a pointer to a RESET_ENTRY_INFO structure
|
|
|
|
pszAddress: a pointer to the address string
|
|
|
|
pData: ignored
|
|
|
|
RETURN VALUE
|
|
Always TRUE to continue the enumeration.
|
|
|
|
--*/
|
|
|
|
{
|
|
PRESET_ENTRY_INFO pResetEntryInfo = (PRESET_ENTRY_INFO)pArg;
|
|
LPTSTR pszEntryName;
|
|
|
|
if (GetAddressDialingLocationEntry(pszAddress, &pszEntryName)) {
|
|
if (!_wcsicmp(pszEntryName, pResetEntryInfo->pszOldEntryName)) {
|
|
if (!SetAddressDialingLocationEntry(
|
|
pszAddress,
|
|
pResetEntryInfo->pszNewEntryName))
|
|
{
|
|
RASAUTO_TRACE("ResetEntryName: SetAddressEntryName failed");
|
|
}
|
|
}
|
|
LocalFree(pszEntryName);
|
|
}
|
|
|
|
return TRUE;
|
|
} // ResetEntryName
|
|
|
|
BOOL
|
|
fRequestToSelf(LPTSTR lpRemoteName)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
|
|
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
|
|
DWORD dwSize;
|
|
|
|
RASAUTO_TRACE1("fRequestToSelf. lpRemoteName=%S", lpRemoteName);
|
|
|
|
dwSize = MAX_COMPUTERNAME_LENGTH;
|
|
|
|
if(GetComputerName(szComputerName, &dwSize))
|
|
{
|
|
if(0 == lstrcmpi(lpRemoteName, szComputerName))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return fRet;
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CreateConnection(
|
|
IN HANDLE hProcess,
|
|
IN PACD_ADDR pAddr,
|
|
IN LPTSTR lpRemoteName,
|
|
IN DWORD dwTimeout
|
|
)
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
Take a notification and figure out what to do with it.
|
|
|
|
ARGUMENTS
|
|
hToken: the handle to the process token that we inherit the
|
|
security attributes from when we exec the dialer
|
|
|
|
pAddr: a pointer to the original address from the driver
|
|
|
|
lpRemoteName: a pointer to the address of the connection attempt
|
|
|
|
dwTimeout: number of seconds to disable the address between
|
|
failed connections
|
|
|
|
RETURN VALUE
|
|
Returns TRUE if the net attempt should be retried, FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD dwStatus = WN_SUCCESS;
|
|
RASENTRYNAME entry;
|
|
DWORD dwErr, dwSize, dwEntries;
|
|
DWORD dwPreConnections, dwPostConnections, i;
|
|
DWORD dwTicks;
|
|
BOOLEAN fRasLoaded;
|
|
BOOLEAN fMappingExists, fRasConnectSuccess = FALSE;
|
|
BOOLEAN fStatus, fEntryInvalid;
|
|
BOOLEAN fFailedConnection = FALSE;
|
|
LPTSTR lpEntryName = NULL;
|
|
LPTSTR *lpPreActiveEntries = NULL, *lpPostActiveEntries = NULL;
|
|
LPTSTR lpNewConnection, lpNetworkName = NULL;
|
|
BOOL fDefault = FALSE;
|
|
|
|
RASAUTO_TRACE1("CreateConnection: lpRemoteName=%S", RASAUTO_TRACESTRW(lpRemoteName));
|
|
//
|
|
// Load the RAS DLLs.
|
|
//
|
|
fRasLoaded = LoadRasDlls();
|
|
if (!fRasLoaded) {
|
|
RASAUTO_TRACE("CreateConnection: Could not load RAS DLLs.");
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Check to see if the request is for the same machine. Bail if so.
|
|
// we don't want autodial to kick in if the connection request is
|
|
// to the same machine.
|
|
//
|
|
if(fRequestToSelf(lpRemoteName))
|
|
{
|
|
RASAUTO_TRACE("CreateConnetion: Request to self. Bailing.");
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// Get a list of the active RAS connections before
|
|
// we attempt to create a new one.
|
|
//
|
|
dwPreConnections = ActiveConnections(TRUE, &lpPreActiveEntries, NULL);
|
|
RASAUTO_TRACE1("CreateConnection: dwPreConnections=%d", dwPreConnections);
|
|
//
|
|
// If we reach this point, we have an unsuccessful
|
|
// network connection without any active RAS
|
|
// connections. Try to start the implicit connection
|
|
// machinery. See if there already exists a mapping
|
|
// for the address.
|
|
//
|
|
LockAddressMap();
|
|
//
|
|
// Make sure we have the current information
|
|
// about this address from the registry.
|
|
//
|
|
ResetAddressMapAddress(lpRemoteName);
|
|
fMappingExists = GetAddressDialingLocationEntry(lpRemoteName, &lpEntryName);
|
|
//
|
|
// If the entry doesn't exist, and this is a
|
|
// Internet hostname, then see if we can find
|
|
// an address with the same organization name.
|
|
//
|
|
if (!fMappingExists && pAddr->fType == ACD_ADDR_INET)
|
|
fMappingExists = GetSimilarDialingLocationEntry(lpRemoteName, &lpEntryName);
|
|
fFailedConnection = GetAddressLastFailedConnectTime(
|
|
lpRemoteName,
|
|
&dwTicks);
|
|
UnlockAddressMap();
|
|
RASAUTO_TRACE2(
|
|
"CreateConnection: lookup of %S returned %S",
|
|
RASAUTO_TRACESTRW(lpRemoteName),
|
|
RASAUTO_TRACESTRW(lpEntryName));
|
|
//
|
|
// If we know nothing about the address, and
|
|
// we are connected to some network, then ignore
|
|
// the request.
|
|
//
|
|
if (!fMappingExists && IsNetworkConnected()) {
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: no mapping for lpRemoteName=%S and connected to a network",
|
|
lpRemoteName);
|
|
goto done;
|
|
}
|
|
|
|
//
|
|
// If no mapping exists and not connected to network,
|
|
// check to see if theres a default internet connection.
|
|
//
|
|
if(!fMappingExists && !IsNetworkConnected())
|
|
{
|
|
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: no mapping for lpRemoteName=%S and"
|
|
" not connected to a network", lpRemoteName);
|
|
|
|
dwErr = DwGetDefaultEntryName(&lpEntryName);
|
|
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: found default entry %S",
|
|
(NULL == lpEntryName)?TEXT("NULL"):lpEntryName);
|
|
|
|
if(NULL != lpEntryName)
|
|
{
|
|
fMappingExists = TRUE;
|
|
fDefault = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// If there is a mapping, but the phonebook
|
|
// entry is missing from the mapping, then
|
|
// ignore the request. Also check to make
|
|
// sure the phonebook entry isn't already
|
|
// connected.
|
|
//
|
|
//
|
|
// Perform various checks on the mapping.
|
|
//
|
|
if (fMappingExists) {
|
|
BOOLEAN bStatus, bConnected = FALSE;
|
|
|
|
//
|
|
// Make sure it's not NULL.
|
|
//
|
|
if (!wcslen(lpEntryName)) {
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: lpRemoteName=%S is permanently disabled",
|
|
RASAUTO_TRACESTRW(lpRemoteName));
|
|
goto done;
|
|
}
|
|
//
|
|
// If the network associated with this
|
|
// entry is connected, then ignore the
|
|
// request.
|
|
//
|
|
lpNetworkName = EntryToNetwork(lpEntryName);
|
|
RASAUTO_TRACE2(
|
|
"CreateConnection: network for entry %S is %S",
|
|
lpEntryName,
|
|
RASAUTO_TRACESTRW(lpNetworkName));
|
|
if (lpNetworkName != NULL) {
|
|
LockNetworkMap();
|
|
bStatus = GetNetworkConnected(lpNetworkName, &bConnected);
|
|
UnlockNetworkMap();
|
|
if (bStatus && bConnected) {
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: %S is already connected!",
|
|
RASAUTO_TRACESTRW(lpEntryName));
|
|
fRasConnectSuccess = TRUE;
|
|
goto done;
|
|
}
|
|
}
|
|
//
|
|
// If the entry itself is connected,
|
|
// then ignore the request. We need
|
|
// to do this check as well as the one
|
|
// above, because the mapping may not
|
|
// have a network assigned to it yet.
|
|
//
|
|
for (i = 0; i < dwPreConnections; i++) {
|
|
if (!_wcsicmp(lpEntryName, lpPreActiveEntries[i])) {
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: lpEntryName=%S is already connected!", lpEntryName);
|
|
goto done;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// Check for a recent failed connection
|
|
// attempt.
|
|
//
|
|
if (fFailedConnection) {
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: RASADP_FailedConnectionTimeout=%d",
|
|
dwTimeout);
|
|
if (GetTickCount() - dwTicks < dwTimeout * 1000) {
|
|
RASAUTO_TRACE2(
|
|
"CreateConnection: lpRemoteName=%S is temporarily disabled (failed connection %d ticks ago)",
|
|
RASAUTO_TRACESTRW(lpRemoteName),
|
|
GetTickCount() - dwTicks);
|
|
goto done;
|
|
}
|
|
else {
|
|
//
|
|
// Reset last failed tick count.
|
|
//
|
|
fFailedConnection = FALSE;
|
|
}
|
|
}
|
|
//
|
|
// If a mapping already exists for the address, then
|
|
// start rasphone with the address. Otherwise, simply
|
|
// have rasphone show the entire phonebook.
|
|
//
|
|
fEntryInvalid = FALSE;
|
|
fRasConnectSuccess = StartAutoDialer(
|
|
hProcess,
|
|
pAddr,
|
|
lpRemoteName,
|
|
fMappingExists ? lpEntryName : NULL,
|
|
FALSE,
|
|
&fEntryInvalid);
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: StartDialer returned %d",
|
|
fRasConnectSuccess);
|
|
if (fRasConnectSuccess) {
|
|
//
|
|
// Get the list of active connections again. We will
|
|
// compare the lists to determine which is the new
|
|
// entry.
|
|
//
|
|
dwPostConnections = ActiveConnections(
|
|
TRUE,
|
|
&lpPostActiveEntries,
|
|
NULL);
|
|
//
|
|
// If the number of active connections before and after
|
|
// the newly created connection differs by more than 1,
|
|
// then we have to skip saving the mapping in the registry,
|
|
// since we cannot determine which is the right one!
|
|
//
|
|
if (dwPostConnections - dwPreConnections == 1) {
|
|
lpNewConnection = CompareConnectionLists(
|
|
lpPreActiveEntries,
|
|
dwPreConnections,
|
|
lpPostActiveEntries,
|
|
dwPostConnections);
|
|
RASAUTO_TRACE2(
|
|
"CreateConnection: mapped %S->%S",
|
|
RASAUTO_TRACESTRW(lpRemoteName),
|
|
RASAUTO_TRACESTRW(lpNewConnection));
|
|
LockAddressMap();
|
|
if (!fEntryInvalid) {
|
|
//
|
|
// Store the new RAS phonebook entry, since
|
|
// it could be different from the one we
|
|
// retrieved in the mapping.
|
|
//
|
|
// #ifdef notdef
|
|
if(!fDefault)
|
|
{
|
|
//
|
|
// We do not want to do this because the
|
|
// user may have selected the wrong phonebook
|
|
// entry. We will let a successful connection
|
|
// notification map it for us.
|
|
//
|
|
fStatus = SetAddressDialingLocationEntry(lpRemoteName, lpNewConnection);
|
|
// #endif
|
|
fStatus = SetAddressTag(lpRemoteName, ADDRMAP_TAG_USED);
|
|
}
|
|
}
|
|
else {
|
|
RESET_ENTRY_INFO resetEntryInfo;
|
|
|
|
//
|
|
// If the RAS phonebook entry in the mapping
|
|
// was invalid, then automatically
|
|
// remap all other mappings referencing that
|
|
// entry to the newly selected phonebook entry.
|
|
//
|
|
resetEntryInfo.pszOldEntryName = lpEntryName;
|
|
resetEntryInfo.pszNewEntryName = lpNewConnection;
|
|
EnumAddressMap(ResetEntryName, &resetEntryInfo);
|
|
}
|
|
//
|
|
// Flush this mapping to the registry now
|
|
// and reload the address info. We do this to
|
|
// get the network name for a new address/network
|
|
// pair.
|
|
//
|
|
FlushAddressMap();
|
|
ResetAddressMapAddress(lpRemoteName);
|
|
if (lpNetworkName == NULL &&
|
|
GetAddressNetwork(lpRemoteName, &lpNetworkName))
|
|
{
|
|
LockNetworkMap();
|
|
SetNetworkConnected(lpNetworkName, TRUE);
|
|
UnlockNetworkMap();
|
|
}
|
|
UnlockAddressMap();
|
|
if (!fStatus)
|
|
RASAUTO_TRACE("CreateConnection: SetAddressEntryName failed");
|
|
}
|
|
else {
|
|
RASAUTO_TRACE1(
|
|
"CreateConnection: %d (> 1) new RAS connections! (can't write registry)",
|
|
dwPostConnections - dwPreConnections);
|
|
}
|
|
}
|
|
|
|
done:
|
|
#ifdef notdef
|
|
// we only unload rasman.dll if we are going to exit
|
|
if (fRasLoaded)
|
|
UnloadRasDlls();
|
|
#endif
|
|
if (!fFailedConnection && !fRasConnectSuccess) {
|
|
//
|
|
// If the connection attempt wasn't successful,
|
|
// then we disable future connections to that
|
|
// address for a while.
|
|
//
|
|
RASAUTO_TRACE1("CreateConnection: disabling %S", RASAUTO_TRACESTRW(lpRemoteName));
|
|
LockAddressMap();
|
|
fStatus = SetAddressLastFailedConnectTime(lpRemoteName);
|
|
UnlockAddressMap();
|
|
if (!fStatus)
|
|
RASAUTO_TRACE("CreateConnection: SetAddressAttribute failed");
|
|
}
|
|
//
|
|
// Free resources.
|
|
//
|
|
if (lpEntryName != NULL)
|
|
LocalFree(lpEntryName);
|
|
if (lpNetworkName != NULL)
|
|
LocalFree(lpNetworkName);
|
|
if (lpPreActiveEntries != NULL)
|
|
FreeStringArray(lpPreActiveEntries, dwPreConnections);
|
|
if (lpPostActiveEntries != NULL)
|
|
FreeStringArray(lpPostActiveEntries, dwPostConnections);
|
|
|
|
return fRasConnectSuccess;
|
|
} // CreateConnection
|
|
|
|
|
|
|
|
DWORD
|
|
AcsRedialOnLinkFailureThread(
|
|
LPVOID lpArg
|
|
)
|
|
{
|
|
DWORD dwErr;
|
|
PREDIAL_ARGS pRedial = (PREDIAL_ARGS)lpArg;
|
|
HANDLE hProcess = NULL;
|
|
|
|
RASAUTO_TRACE2(
|
|
"AcsRedialOnLinkFailureThread: lpszPhonebook=%s, lpszEntry=%s",
|
|
RASAUTO_TRACESTRW(pRedial->pszPhonebook),
|
|
RASAUTO_TRACESTRW(pRedial->pszEntry));
|
|
|
|
//
|
|
// Make sure the current thread is impersonating
|
|
// the currently logged-on user. We need this
|
|
// so the RAS utilities run with the user's credentials.
|
|
//
|
|
if ((hProcess = RefreshImpersonation(hProcess)) == NULL) {
|
|
RASAUTO_TRACE("AcsRedialOnLinkFailureThread: no currently logged-on user!");
|
|
return 0;
|
|
}
|
|
//
|
|
// Reset HKEY_CURRENT_USER to get the
|
|
// correct value with the new impersonation
|
|
// token.
|
|
//
|
|
// RegCloseKey(HKEY_CURRENT_USER);
|
|
|
|
/* Check that user has enabled redial on link failure.
|
|
*/
|
|
{
|
|
BOOL fRedial = FALSE;
|
|
|
|
dwErr = (DWORD)(lpfnRasQueryRedialOnLinkFailureG)(
|
|
pRedial->pszPhonebook,
|
|
pRedial->pszEntry,
|
|
&fRedial);
|
|
|
|
if(!fRedial)
|
|
{
|
|
PBUSER user;
|
|
|
|
dwErr = GetUserPreferences( NULL, &user, FALSE );
|
|
if (dwErr == 0)
|
|
{
|
|
fRedial = user.fRedialOnLinkFailure;
|
|
DestroyUserPreferences( &user );
|
|
}
|
|
}
|
|
|
|
if (!fRedial)
|
|
{
|
|
RASAUTO_TRACE1("Skip redial,e=%d",dwErr);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Redial the entry.
|
|
//
|
|
dwErr = StartReDialer(hProcess, pRedial->pszPhonebook, pRedial->pszEntry);
|
|
//
|
|
// Free the parameter block we were passed.
|
|
//
|
|
if (pRedial->pszPhonebook != NULL)
|
|
LocalFree(pRedial->pszPhonebook);
|
|
if (pRedial->pszEntry != NULL)
|
|
LocalFree(pRedial->pszEntry);
|
|
LocalFree(pRedial);
|
|
|
|
return dwErr;
|
|
} // AcsRedialOnLinkFailureThread
|
|
|
|
|
|
|
|
VOID
|
|
AcsRedialOnLinkFailure(
|
|
IN LPSTR lpszPhonebook,
|
|
IN LPSTR lpszEntry
|
|
)
|
|
|
|
/*++
|
|
|
|
DESCRIPTION
|
|
This is the redial-on-link-failure handler we give to rasman
|
|
via RasRegisterRedialCallback. It gets called when the final
|
|
port of a connection is disconnected due to a hardware failure.
|
|
We package up the parameters rasman gives us an create a thread
|
|
because the callback is made within rasman's worker thread
|
|
context.
|
|
|
|
ARGUMENTS
|
|
lpszPhonebook: the phonebook string of the connection
|
|
|
|
lpszEntry: the entry name of the connection
|
|
|
|
RETURN VALUE
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PREDIAL_ARGS lpRedial = LocalAlloc(LPTR, sizeof (REDIAL_ARGS));
|
|
HANDLE hThread;
|
|
DWORD dwThreadId;
|
|
|
|
if (lpRedial == NULL)
|
|
return;
|
|
lpRedial->pszPhonebook = AnsiStringToUnicodeString(
|
|
lpszPhonebook,
|
|
NULL,
|
|
0);
|
|
if (lpszPhonebook != NULL && lpRedial->pszPhonebook == NULL) {
|
|
RASAUTO_TRACE("AcsRedialOnLinkFailure: LocalAlloc failed");
|
|
LocalFree(lpRedial);
|
|
return;
|
|
}
|
|
lpRedial->pszEntry = AnsiStringToUnicodeString(
|
|
lpszEntry,
|
|
NULL,
|
|
0);
|
|
if (lpszEntry != NULL && lpRedial->pszEntry == NULL) {
|
|
RASAUTO_TRACE("AcsRedialOnLinkFailure: LocalAlloc failed");
|
|
LocalFree(lpRedial->pszPhonebook);
|
|
LocalFree(lpRedial);
|
|
return;
|
|
}
|
|
//
|
|
// Start the connection.
|
|
//
|
|
hThread = CreateThread(
|
|
NULL,
|
|
10000L,
|
|
(LPTHREAD_START_ROUTINE)AcsRedialOnLinkFailureThread,
|
|
(LPVOID)lpRedial,
|
|
0,
|
|
&dwThreadId);
|
|
if (hThread == NULL) {
|
|
RASAUTO_TRACE1(
|
|
"AcsRedialOnLinkFailure: CreateThread failed (error=0x%x)",
|
|
GetLastError());
|
|
LocalFree(lpRedial->pszEntry);
|
|
LocalFree(lpRedial->pszPhonebook);
|
|
LocalFree(lpRedial);
|
|
return;
|
|
}
|
|
CloseHandle(hThread);
|
|
} // AcsRedialOnLinkFailure
|
|
|