2025-11-28 00:35:46 +09:00

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