420 lines
13 KiB
C
420 lines
13 KiB
C
//---------------------------------------------------------------------
|
|
// This file is part of the Microsoft .NET Framework SDK Code Samples.
|
|
//
|
|
// Copyright (C) Microsoft Corporation. All rights reserved.
|
|
//
|
|
//This source code is intended only as a supplement to Microsoft
|
|
//Development Tools and/or on-line documentation. See these other
|
|
//materials for detailed information regarding Microsoft code samples.
|
|
//
|
|
//THIS CODE AND INFORMATION ARE PROVIDED AS IS WITHOUT WARRANTY OF ANY
|
|
//KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|
//IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
//PARTICULAR PURPOSE.
|
|
//
|
|
// RasNapAdmin.c
|
|
// Implements a RAS administration DLL which implements the callback functions
|
|
// to decide if the reauthentication attempt can be allowed or not. It also logs the
|
|
// user and port information whenever a new connection/link is accepted. This
|
|
// creates a file with the name log.txt under %windir%\system32.
|
|
//
|
|
// The RAS administration DLL registry setup need to be performed as mentioned
|
|
// in MSDN before running this application.
|
|
//
|
|
//---------------------------------------------------------------------
|
|
|
|
#ifndef UNICODE
|
|
#define UNICODE
|
|
#endif
|
|
|
|
|
|
// INCLUDES
|
|
#include "RasNapAdmin.h"
|
|
|
|
// The log file to which we will log the information
|
|
// when each callback function is called
|
|
|
|
|
|
FILE *g_fpFile = NULL;
|
|
|
|
//
|
|
// Function which decides id reauthentication can take place
|
|
//
|
|
// Parameters: Username for this connection
|
|
//
|
|
|
|
BOOL IsReAuthAllowedForUser(WCHAR *User)
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Converts an IPv6 address in IN6_ADDR to a readable host string format
|
|
//
|
|
//Arguments:
|
|
// ipv6addr - Pointer to IN6_ADDR structure having the IPv6 address.
|
|
// hoststring - The buffer to be returned with the address in host string format.
|
|
//
|
|
DWORD ConvertAddressToString(IN6_ADDR *ipv6addr,WCHAR * hoststring)
|
|
{
|
|
struct sockaddr_in6 sin6;
|
|
int RetVal = 0;
|
|
DWORD dwRet = ERROR_SUCCESS;
|
|
WSADATA WsaData;
|
|
|
|
if(WSAStartup(0x202,&WsaData))
|
|
{
|
|
dwRet = GetLastError();
|
|
wprintf(L"Error in WSAStartup[Error:%d]\n",dwRet);
|
|
goto Cleanup;
|
|
}
|
|
|
|
sin6.sin6_family = AF_INET6;
|
|
sin6.sin6_port = 0;
|
|
sin6.sin6_flowinfo = 0;
|
|
sin6.sin6_scope_id = 0;
|
|
sin6.sin6_addr = *ipv6addr;
|
|
|
|
RetVal = GetNameInfoW((SOCKADDR *)&sin6,
|
|
sizeof(struct sockaddr_in6),
|
|
hoststring,
|
|
MAX_IPV6_STRING,
|
|
NULL,
|
|
0,
|
|
NI_NUMERICHOST);
|
|
if (RetVal != 0)
|
|
{
|
|
dwRet = WSAGetLastError();
|
|
wprintf(L"Could not convert IPv6 address to address string format![Error:%d]",dwRet);
|
|
|
|
}
|
|
Cleanup:
|
|
WSACleanup();
|
|
return dwRet;
|
|
}
|
|
|
|
// Copy an address prefix of the given length
|
|
//
|
|
//Parameters:
|
|
// Address - Supplies the address buffer to fill in.
|
|
// Prefix - Supplies the initial prefix.
|
|
// PrefixLength - Supplies the initial prefix length in bits.
|
|
// AddressBytes- Prefix length in bytes (ceiling)
|
|
//
|
|
VOID
|
|
CopyPrefixBytes(
|
|
BYTE *Address,
|
|
BYTE* Prefix,
|
|
ULONG PrefixLength,
|
|
ULONG AddressBytes
|
|
)
|
|
{
|
|
ULONG PLBytes, PLRemainderBits, Loop;
|
|
|
|
PLBytes = PrefixLength / 8;
|
|
PLRemainderBits = PrefixLength % 8;
|
|
if (AddressBytes != (PLBytes+ (PLRemainderBits?1:0))) return;
|
|
for (Loop = 0; Loop < PLBytes; Loop++) {
|
|
Address[Loop] = Prefix[Loop];
|
|
}
|
|
if (PLRemainderBits ) {
|
|
Address[PLBytes] = (UCHAR)(Prefix[PLBytes] &
|
|
(0xff << (8 - PLRemainderBits)));
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Function is called whenever PPP reauthentication happens due to change in
|
|
// quarantine state of the client
|
|
//
|
|
// Parameters: pointer to a RAS_CONNECTION_0 structure
|
|
// pointer to a RAS_CONNECTION_1 structure
|
|
// pointer to a RAS_CONNECTION_2 structure
|
|
// pointer to a RAS_CONNECTION_3 structure
|
|
//
|
|
BOOL WINAPI MprAdminAcceptReauthentication(RAS_CONNECTION_0 *pRasCon0,
|
|
RAS_CONNECTION_1 *pRasCon1,
|
|
RAS_CONNECTION_2 *pRasCon2,
|
|
RAS_CONNECTION_3 *pRasCon3)
|
|
{
|
|
BOOL fReAuthAllowed = TRUE;
|
|
fwprintf(g_fpFile,L"============MprAdminAcceptReauthentication callback============\n");
|
|
fwprintf(g_fpFile,L"User = %s: quarstate=%d: probationtimer=%d \n",pRasCon3->wszUserName,pRasCon3->rasQuarState,pRasCon3->timer.dwLowDateTime);
|
|
|
|
//
|
|
// Here we have a function based on the username whether the reauthentication
|
|
// attempt is allowed or not. This function can be implemented according to
|
|
// the administrator's requirements. In this sample, the function just returns
|
|
// true always.
|
|
//
|
|
fReAuthAllowed = IsReAuthAllowedForUser(pRasCon3->wszUserName);
|
|
|
|
if(fReAuthAllowed)
|
|
{
|
|
fwprintf(g_fpFile,L"Reauth allowed\n");
|
|
}
|
|
else
|
|
{
|
|
fwprintf(g_fpFile,L"Reauth not allowed\n");
|
|
}
|
|
|
|
fwprintf(g_fpFile,L"Exiting MprAdminReauthentication");
|
|
fflush(g_fpFile);
|
|
return fReAuthAllowed == 0? FALSE : TRUE;
|
|
|
|
}
|
|
|
|
//
|
|
// Function is called whenever a link is disconnected.
|
|
//
|
|
// Parameters: pointer to a RAS_PORT_0 structure
|
|
// pointer to a RAS_PORT_1 structure
|
|
//
|
|
VOID WINAPI
|
|
MprAdminLinkHangupNotification(RAS_PORT_0 * pRasPort0,
|
|
RAS_PORT_1 * pRasPort1)
|
|
{
|
|
fwprintf(g_fpFile,L"============MprAdminLinkHangupNotification callback============\n");
|
|
fflush(g_fpFile);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Function is called whenever a call is disconnected.
|
|
//
|
|
// Parameters: pointer to a RAS_CONNECTION_0 structure
|
|
// pointer to a RAS_CONNECTION_1 structure
|
|
// pointer to a RAS_CONNECTION_2 structure
|
|
//
|
|
VOID WINAPI
|
|
MprAdminConnectionHangupNotification3(RAS_CONNECTION_0 * pRasConnection0,
|
|
RAS_CONNECTION_1 * pRasConnection1,
|
|
RAS_CONNECTION_2 * pRasConnection2,
|
|
RAS_CONNECTION_3* pRasConnection3)
|
|
{
|
|
SYSTEMTIME systime;
|
|
IN6_ADDR ipv6Address = {0}; // Variable to hold IPv6 address of the client connection
|
|
WCHAR szIpv6AddrString[MAX_IPV6_STRING] = {0}; //Variable to hold the IPv6 address string of the client connection
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
|
|
fwprintf(g_fpFile,L"============MprAdminConnectionHangupNotification3 callback============\n");
|
|
|
|
// We log the time the user has disconnected alongwith the username, IPv4 address
|
|
// and the IPv6 address. This information can be used for billing
|
|
// purposes.
|
|
|
|
GetSystemTime(&systime);
|
|
|
|
fwprintf(g_fpFile,L"Time(HR:MIN:SEC): %d:%d:%d \n",systime.wHour,systime.wMinute,systime.wSecond);
|
|
fwprintf(g_fpFile,L"Username: %s\n",pRasConnection3->wszUserName);
|
|
fwprintf(g_fpFile,L"IPv4 address of client: %s\n",pRasConnection3->PppInfo3.ip.wszRemoteAddress);
|
|
|
|
// For the IPv6 address of the client, we get the interface ID, the prefix and the prefix length
|
|
// from the RAS_CONNECTION_3 structure. Here we copy the prefix and the 64-bit interface
|
|
// ID to a IN6_ADDR structure and use GetNameInfoW with the flag NI_NUMERICHOST to convert it to
|
|
// IPv6 address string in the readable form
|
|
// As the prefix length we get from the structure is in bits we need the 'CopyPrefixBytes'
|
|
// module to convert the length into bytes and copy the prefix accordingly.
|
|
|
|
|
|
CopyPrefixBytes(ipv6Address.u.Byte,
|
|
pRasConnection3->PppInfo3.ipv6.bPrefix,
|
|
pRasConnection3->PppInfo3.ipv6.dwPrefixLength,
|
|
sizeof(ipv6Address)-IPV6_INTERFACE_ID_LENGTH_IN_BYTES);
|
|
|
|
// Copy the RemoteInterfaceIdentifier to the last 8 bytes of ipv6Address.u.Byte
|
|
memcpy(&ipv6Address.u.Byte[IPV6_INTERFACE_ID_LENGTH_IN_BYTES],
|
|
pRasConnection3->PppInfo3.ipv6.bRemoteInterfaceIdentifier,
|
|
IPV6_INTERFACE_ID_LENGTH_IN_BYTES);
|
|
|
|
// Convert the IPv6 address in IN6_ADDR format to readable host string format
|
|
dwStatus = ConvertAddressToString(&ipv6Address,szIpv6AddrString);
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
fwprintf(g_fpFile,L"IPv6 address of the client: %s\n",szIpv6AddrString);
|
|
|
|
fflush(g_fpFile);
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Function is called whenever a call is connected.
|
|
//
|
|
// Parameters: pointer to a RAS_CONNECTION_0 structure
|
|
// pointer to a RAS_CONNECTION_1 structure
|
|
// pointer to a RAS_CONNECTION_2 structure
|
|
//
|
|
BOOL WINAPI
|
|
MprAdminAcceptNewConnection3(RAS_CONNECTION_0 * pRasConnection0,
|
|
RAS_CONNECTION_1 * pRasConnection1,
|
|
RAS_CONNECTION_2 * pRasConnection2,
|
|
RAS_CONNECTION_3* pRasConnection3)
|
|
{
|
|
SYSTEMTIME systime;
|
|
DWORD dwStatus = ERROR_SUCCESS;
|
|
IN6_ADDR ipv6Address = {0}; // Variable to hold IPv6 address of the client connection
|
|
WCHAR szIpv6AddrString[MAX_IPV6_STRING] = {0}; //Variable to hold the IPv6 address string of the client connection
|
|
fwprintf(g_fpFile,L"============MprAdminAcceptNewConnection3 callback============\n");
|
|
|
|
// We log the username, the IPv4 and IPv6 address of the client
|
|
// which can be used to see how much time the user was connected
|
|
|
|
|
|
GetSystemTime(&systime);
|
|
|
|
fwprintf(g_fpFile,L"Time(HR:MIN:SEC): %d:%d:%d \n",systime.wHour,systime.wMinute,systime.wSecond);
|
|
fwprintf(g_fpFile,L"Username: %s\n",pRasConnection3->wszUserName);
|
|
fwprintf(g_fpFile,L"IPv4 address of client: %s\n",pRasConnection3->PppInfo3.ip.wszRemoteAddress);
|
|
|
|
// For the IPv6 address of the client, we get the interface ID, the prefix and the prefix length
|
|
// from the RAS_CONNECTION_3 structure. Here we copy the prefix and the 64-bit interface
|
|
// ID to a IN6_ADDR structure and use GetNameInfoW with the flag NI_NUMERICHOST to convert it to
|
|
// IPv6 address string in the readable form
|
|
// As the prefix length we get from the structure is in bits we need the 'CopyPrefixBytes'
|
|
// module to convert the length into bytes and copy the prefix accordingly.
|
|
|
|
|
|
CopyPrefixBytes(ipv6Address.u.Byte,
|
|
pRasConnection3->PppInfo3.ipv6.bPrefix,
|
|
pRasConnection3->PppInfo3.ipv6.dwPrefixLength,
|
|
sizeof(ipv6Address)-IPV6_INTERFACE_ID_LENGTH_IN_BYTES);
|
|
|
|
// Copy the RemoteInterfaceIdentifier to the last 8 bytes of ipv6Address.u.Byte
|
|
memcpy(&ipv6Address.u.Byte[IPV6_INTERFACE_ID_LENGTH_IN_BYTES],
|
|
pRasConnection3->PppInfo3.ipv6.bRemoteInterfaceIdentifier,
|
|
IPV6_INTERFACE_ID_LENGTH_IN_BYTES);
|
|
|
|
// Convert the IPv6 address in IN6_ADDR format to readable host string format
|
|
dwStatus = ConvertAddressToString(&ipv6Address,szIpv6AddrString);
|
|
|
|
if (dwStatus == ERROR_SUCCESS)
|
|
fwprintf(g_fpFile,L"IPv6 address of the client: %s\n",szIpv6AddrString);
|
|
|
|
fflush(g_fpFile);
|
|
return TRUE;
|
|
}
|
|
|
|
//
|
|
// Function is called whenever a new link is made.
|
|
//
|
|
// Parameters: pointer to a RAS_PORT_0 structure
|
|
// pointer to a RAS_PORT_1 structure
|
|
//
|
|
BOOL WINAPI
|
|
MprAdminAcceptNewLink(RAS_PORT_0 * pRasPort0,
|
|
RAS_PORT_1 * pRasPort1)
|
|
{
|
|
fwprintf(g_fpFile,L"============MprAdminAcceptNewLink callback============\n");
|
|
|
|
// We log the port to which the user connected
|
|
fwprintf(g_fpFile,L"Link accepted on port : %s\n",pRasPort0->wszPortName);
|
|
fflush(g_fpFile);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// Function used for DLL specific initialization.
|
|
//
|
|
// Returns: NO_ERROR if successful
|
|
// The last error number if an error is encountered
|
|
//
|
|
DWORD WINAPI
|
|
MprAdminInitializeDll(void)
|
|
{
|
|
DWORD dwRetVal = ERROR_SUCCESS;
|
|
dwRetVal = InitializeDll();
|
|
if ( ERROR_SUCCESS != dwRetVal )
|
|
fwprintf(g_fpFile, L"Initialization function failed with error %d\n", dwRetVal);
|
|
else
|
|
fwprintf(g_fpFile,L"RAS Admin DLL initialized.\n");
|
|
|
|
fflush(g_fpFile);
|
|
return dwRetVal;
|
|
}
|
|
|
|
//
|
|
// Function used to form DLL specific cleanup.
|
|
//
|
|
DWORD WINAPI
|
|
MprAdminTerminateDll(void)
|
|
{
|
|
|
|
fwprintf(g_fpFile,L"Terminating RAS Admin DLL ...\n");
|
|
CleanUp();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Function initializes everything needed
|
|
//
|
|
// Returns: TRUE if all is well
|
|
// FALSE otherwise
|
|
DWORD
|
|
InitializeDll()
|
|
{
|
|
HKEY hKey = NULL;
|
|
WCHAR DLLName[MAX_PATH];
|
|
DWORD dwBufferLength = MAX_PATH;
|
|
DWORD dwRetval = ERROR_SUCCESS;
|
|
|
|
|
|
//
|
|
// Open the log file.
|
|
//
|
|
if ((dwRetval = _wfopen_s(&g_fpFile,LOG_FILE,L"w")) != 0)
|
|
{
|
|
goto CleanUp;
|
|
}
|
|
|
|
|
|
dwRetval = RegOpenKeyEx(HKEY_LOCAL_MACHINE,ADMINDLL_KEY,0,KEY_QUERY_VALUE,&hKey);
|
|
if ( ERROR_SUCCESS != dwRetval )
|
|
{
|
|
fwprintf(g_fpFile,L"Could not open registry key required for Admin DLL!\n");
|
|
goto CleanUp;
|
|
}
|
|
|
|
dwRetval = RegQueryValueEx(hKey,DISPLAYNAME_VALUE,NULL,NULL,(LPBYTE)DLLName,&dwBufferLength);
|
|
if ( ERROR_SUCCESS != dwRetval)
|
|
{
|
|
fwprintf(g_fpFile,L"Display Name of Admin DLL not found in registry!\n");
|
|
goto CleanUp;
|
|
}
|
|
|
|
CleanUp:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
if (dwRetval== ERROR_SUCCESS)
|
|
{
|
|
fwprintf(g_fpFile,L"Display Name of Admin DLL: %s\n",DLLName);
|
|
fflush(g_fpFile);
|
|
}
|
|
else
|
|
{
|
|
fflush(g_fpFile);
|
|
CleanUp();
|
|
}
|
|
|
|
return dwRetval;
|
|
}
|
|
|
|
//
|
|
// Function cleans up all threads, handles, memory, etc.
|
|
//
|
|
void
|
|
CleanUp()
|
|
{
|
|
|
|
//
|
|
// Close the log file
|
|
//
|
|
_fcloseall();
|
|
}
|
|
|