AUTHFILT.C

/*++ 

Copyright (c) 1996 Microsoft Corporation

This program is released into the public domain for any purpose.


Module Name:

authfilt.c

Abstract:

This module is an example of an ISAPI Authentication Filter.

It demonstrates how to do an authentication filter based on an external
datasource. Though this sample uses a flat file, access to a database
could easily be plugged in.

--*/

#include <windows.h>
#include <httpfilt.h>
#include "authfilt.h"

//
// Functions
//

BOOL
WINAPI
DllMain(
IN HINSTANCE hinstDll,
IN DWORD fdwReason,
IN LPVOID lpvContext OPTIONAL
)
/*++

Routine Description:

This function DllLibMain() is the main initialization function for
this DLL. It initializes local variables and prepares it to be invoked
subsequently.

Arguments:

hinstDll Instance Handle of the DLL
fdwReason Reason why NT called this DLL
lpvReserved Reserved parameter for future use.

Return Value:

Returns TRUE is successful; otherwise FALSE is returned.
--*/
{
BOOL fReturn = TRUE;

switch (fdwReason )
{
case DLL_PROCESS_ATTACH:

if ( !InitializeUserDatabase() ||
!InitializeCache() )
{
DbgWrite(( DEST,
"[GetFilterVersion] Database or cache failed, error %d\n",
GetLastError() ))

return FALSE;
}

//
// We don't care about thread attach/detach notifications
//

DisableThreadLibraryCalls( hinstDll );

break;

case DLL_PROCESS_DETACH:
{

if ( lpvContext != NULL)
{
TerminateCache();
TerminateUserDatabase();
}

break;
} /* case DLL_PROCESS_DETACH */

default:
break;
} /* switch */

return ( fReturn);
} /* DllLibMain() */



BOOL
WINAPI
GetFilterVersion(
HTTP_FILTER_VERSION * pVer
)
{
DbgWrite(( DEST,
"[GetFilterVersion] Server filter version is %d.%d\n",
HIWORD( pVer->dwServerFilterVersion ),
LOWORD( pVer->dwServerFilterVersion ) ));

pVer->dwFilterVersion = HTTP_FILTER_REVISION;

//
// Specify the types and order of notification
//

pVer->dwFlags = (SF_NOTIFY_SECURE_PORT |
SF_NOTIFY_NONSECURE_PORT |

SF_NOTIFY_AUTHENTICATION |
SF_NOTIFY_LOG |

SF_NOTIFY_ORDER_DEFAULT);

strcpy( pVer->lpszFilterDesc, "Sample Authentication Filter, version 1.0" );

return TRUE;
}

DWORD
WINAPI
HttpFilterProc(
HTTP_FILTER_CONTEXT * pfc,
DWORD NotificationType,
VOID * pvData
)
/*++

Routine Description:

Filter notification entry point

Arguments:

pfc - Filter context
NotificationType - Type of notification
pvData - Notification specific data

Return Value:

One of the SF_STATUS response codes

--*/
{
BOOL fAllowed;
CHAR achUser[SF_MAX_USERNAME];
HTTP_FILTER_AUTHENT * pAuth;
HTTP_FILTER_LOG * pLog;
CHAR * pch;

//
// Handle this notification
//

switch ( NotificationType )
{
case SF_NOTIFY_AUTHENTICATION:

pAuth = (HTTP_FILTER_AUTHENT *) pvData;

//
// Ignore the anonymous user
//

if ( !*pAuth->pszUser )
{
//
// Tell the server to notify any subsequent notifications in the
// chain
//

return SF_STATUS_REQ_NEXT_NOTIFICATION;
}

//
// Save the unmapped username so we can log it later
//

strcpy( achUser, pAuth->pszUser );

//
// Make sure this user is a valid user and map to the appropriate
// Windows NT user
//

if ( !ValidateUser( pAuth->pszUser,
pAuth->pszPassword,
&fAllowed ))
{
DbgWrite(( DEST,
"[OnAuthentication] Error %d validating user %s\n",
GetLastError(),
pAuth->pszUser ));

return SF_STATUS_REQ_ERROR;
}

if ( !fAllowed )
{
//
// This user isn't allowed access. Indicate this to the server
//

SetLastError( ERROR_ACCESS_DENIED );

return SF_STATUS_REQ_ERROR;
}

//
// Save the unmapped user name so we can log it later on. We allocate
// enough space for two usernames so we can use this memory block
// for logging. Note we may have already allocated it from a previous
// request on this TCP session
//

if ( !pfc->pFilterContext )
{
pfc->pFilterContext = pfc->AllocMem( pfc, 2 * SF_MAX_USERNAME + 4, 0 );

if ( !pfc->pFilterContext )
{
SetLastError( ERROR_NOT_ENOUGH_MEMORY );
return SF_STATUS_REQ_ERROR;
}
}

strcpy( (CHAR *) pfc->pFilterContext, achUser );

return SF_STATUS_REQ_HANDLED_NOTIFICATION;

case SF_NOTIFY_LOG:

//
// The unmapped username is in pFilterContext if this filter
// authenticated this user
//

if ( pfc->pFilterContext )
{
pch = pfc->pFilterContext;
pLog = (HTTP_FILTER_LOG *) pvData;

//
// Put both the original username and the NT mapped username
// into the log in the form "Original User (NT User)"
//

strcat( pch, " (" );
strcat( pch, pLog->pszClientUserName );
strcat( pch, ")" );

pLog->pszClientUserName = pch;
}

return SF_STATUS_REQ_NEXT_NOTIFICATION;

default:
DbgWrite(( DEST,
"[HttpFilterProc] Unknown notification type, %d\n",
NotificationType ));

break;
}

return SF_STATUS_REQ_NEXT_NOTIFICATION;
}