mirror of https://github.com/lianthony/NT4.0
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.
377 lines
9.9 KiB
377 lines
9.9 KiB
/* basic.c -- Security Protocol Module for Basic Authentication. */
|
|
/* Jeff Hostetler, Spyglass, Inc., 1994. */
|
|
/* Copyright (C) 1994, Spyglass, Inc. All rights reserved. */
|
|
|
|
#include <win32.h>
|
|
#include <basic.h>
|
|
|
|
#define MAXFIELD 64
|
|
|
|
|
|
/*****************************************************************/
|
|
static unsigned char * x_FindRealmName(HTHeaderList * hlProtocol)
|
|
{
|
|
/* return pointer to buffer containing realm name. */
|
|
|
|
HTHeaderSVList * svl;
|
|
|
|
svl=hlProtocol->sub_value;
|
|
while (svl)
|
|
{
|
|
if (spm_strcasecomp(svl->name,"Realm")==0)
|
|
return svl->value;
|
|
svl=svl->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
static HTSPMStatusCode x_QueryUserForInfo(F_UserInterface fpUI,
|
|
void * pvOpaqueOS,
|
|
HTHeader * hRequest,
|
|
HTHeaderList * hlProtocol,
|
|
unsigned char * szRealm,
|
|
unsigned char * szUserInfo)
|
|
{
|
|
HTSPMStatusCode hsc;
|
|
unsigned char szUsername[MAXFIELD];
|
|
unsigned char szPassword[MAXFIELD];
|
|
|
|
szUsername[0] = szPassword[0] = 0;
|
|
|
|
hsc = (Dialog_QueryUserForInfo(fpUI,pvOpaqueOS,hRequest,szRealm,szUsername,szPassword,MAXFIELD,szUserInfo));
|
|
if (hsc != HTSPM_STATUS_OK)
|
|
return hsc;
|
|
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
unsigned char buf[3*MAXFIELD];
|
|
sprintf(buf,"Received username:password [%s]",szUserInfo);
|
|
(*fpUI)(pvOpaqueOS,UI_SERVICE_DEBUG_MESSAGE,buf,NULL);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
return hsc;
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
|
|
static HTSPMStatusCode module__ProcessResponse(F_UserInterface fpUI,
|
|
void * pvOpaqueOS,
|
|
HTSPM * htspm,
|
|
HTHeaderList * hlProtocol,
|
|
HTHeader * hRequest,
|
|
HTHeader * hResponse,
|
|
HTHeader ** phNewRequest,
|
|
unsigned int bNonBlock)
|
|
{
|
|
HTSPMStatusCode htsc;
|
|
HTHeaderList * hlCur;
|
|
unsigned char buf[256];
|
|
unsigned char buf_uuencoded[256];
|
|
unsigned long bResult;
|
|
unsigned char * szCache;
|
|
unsigned long bModelessDialogs = 0;
|
|
unsigned char * szRealm = NULL;
|
|
char szMsg[256];
|
|
|
|
szRealm = x_FindRealmName(hlProtocol);
|
|
|
|
/* see if there is already an Auth header in the request. */
|
|
|
|
hlCur = HL_FindHeader(hRequest, "Authorization");
|
|
|
|
#ifdef UNIX
|
|
{
|
|
/* see if we already have a modeless dialog up for this request */
|
|
extern void * Dialog_IsActive(HTHeader *);
|
|
|
|
bModelessDialogs = (Dialog_IsActive(hRequest) != NULL);
|
|
}
|
|
#endif /* UNIX */
|
|
|
|
if (bModelessDialogs)
|
|
goto QueryUser;
|
|
|
|
/* see if we have a cache entry for this destination. */
|
|
|
|
szCache = pwc_Lookup(fpUI,pvOpaqueOS,htspm->pvOpaque,
|
|
hRequest->host,hRequest->uri,szRealm);
|
|
|
|
/* see if cache is valid and if we can satisfy the request
|
|
* without bothering the user.
|
|
*/
|
|
|
|
if (szCache)
|
|
{
|
|
HTUU_encode(szCache,strlen(szCache),buf_uuencoded);
|
|
|
|
if (!hlCur)
|
|
{
|
|
/* we have a cache value and there was no auth in the
|
|
* previous request, so we must assume that the cache
|
|
* entry is OK. so let's use it.
|
|
*/
|
|
wsprintf(buf,"%s %s",htspm->szProtocolName,buf_uuencoded);
|
|
#ifdef DEBUG
|
|
{
|
|
unsigned char msg[200];
|
|
sprintf(msg,"Basic_ProcessResponse: Using cache value [%s]",szCache);
|
|
(*fpUI)(pvOpaqueOS,UI_SERVICE_DEBUG_MESSAGE,msg,NULL);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
/* create new header for the auth */
|
|
|
|
hlCur = HL_AppendNewNameValue(fpUI,pvOpaqueOS,hRequest,"Authorization",buf);
|
|
bResult = (hlCur != NULL);
|
|
goto Finish;
|
|
}
|
|
|
|
/* we have a cache value, but there was an auth header
|
|
* in the request (that bounced). since we're the only
|
|
* ones that could have put in an auth header, we assume
|
|
* that we did so in a previous call using the current
|
|
* cache entry. let's ignore the cache entry.
|
|
*/
|
|
#ifdef DEBUG
|
|
{
|
|
unsigned char msg[200];
|
|
sprintf(msg,"Basic_ProcessResponse: Assuming cache stale [%s]",szCache);
|
|
(*fpUI)(pvOpaqueOS,UI_SERVICE_DEBUG_MESSAGE,msg,NULL);
|
|
}
|
|
#endif /* DEBUG */
|
|
}
|
|
|
|
#ifndef UNIX /* unix dialog start returns immediately */
|
|
/* fall-thru, we must ask user for information */
|
|
|
|
if (bNonBlock)
|
|
return HTSPM_STATUS_WOULD_BLOCK;
|
|
#endif /* not UNIX */
|
|
|
|
QueryUser:
|
|
|
|
htsc = x_QueryUserForInfo(fpUI,pvOpaqueOS,hRequest,hlProtocol,szRealm,buf);
|
|
if (htsc != HTSPM_STATUS_OK)
|
|
return htsc;
|
|
|
|
/* update the cache */
|
|
|
|
pwc_Store(fpUI,pvOpaqueOS,htspm->pvOpaque,
|
|
hRequest->host,hRequest->uri,buf,szRealm);
|
|
|
|
HTUU_encode(buf,strlen(buf),buf_uuencoded);
|
|
wsprintf(buf,"%s %s",htspm->szProtocolName,buf_uuencoded);
|
|
|
|
if (hlCur)
|
|
{
|
|
/* update existing auth header */
|
|
|
|
bResult = spm_CloneString(fpUI,pvOpaqueOS,&hlCur->value,buf);
|
|
}
|
|
else
|
|
{
|
|
/* create new header for the auth */
|
|
|
|
hlCur = HL_AppendNewNameValue(fpUI,pvOpaqueOS,hRequest,"Authorization",buf);
|
|
bResult = (hlCur != NULL);
|
|
}
|
|
|
|
Finish:
|
|
|
|
/* For this SPM, we always just update the original header
|
|
* and return. Other SPM's may need to create a new one.
|
|
*/
|
|
|
|
if (bResult)
|
|
return HTSPM_STATUS_RESUBMIT_OLD;
|
|
|
|
SEC_formatmsg(RES_STRING_BASIC1,szMsg,sizeof(szMsg));
|
|
(void)(*fpUI)(pvOpaqueOS,UI_SERVICE_ERROR_MESSAGE,szMsg,NULL);
|
|
|
|
return HTSPM_ERROR;
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************/
|
|
/*****************************************************************/
|
|
|
|
static HTSPMStatusCode module__PreProcessRequest(F_UserInterface fpUI,
|
|
void * pvOpaqueOS,
|
|
HTSPM * htspm,
|
|
HTHeader * hRequest,
|
|
HTHeader ** phNewRequest)
|
|
{
|
|
/* Take a guess at whether we can prevent a 401/402
|
|
* server response, by pre-loading the request with
|
|
* the necessary security information.
|
|
*/
|
|
|
|
HTHeaderList * hlCur;
|
|
unsigned char * szCache;
|
|
unsigned long bResult;
|
|
unsigned char buf[256];
|
|
unsigned char buf_uuencoded[256];
|
|
|
|
/* see if we have a cache entry for this destination. */
|
|
|
|
szCache= pwc_Lookup(fpUI,pvOpaqueOS,htspm->pvOpaque,
|
|
hRequest->host,hRequest->uri,NULL);
|
|
|
|
if (!szCache) /* no matching item in the cache, we could */
|
|
return HTSPM_ERROR; /* not help, let someone else try. */
|
|
|
|
/* let's make a guess and update the existing request */
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
unsigned char msg[200];
|
|
sprintf(msg,"Basic_PreProcessRequest: Using cache value [%s]",szCache);
|
|
(*fpUI)(pvOpaqueOS,UI_SERVICE_DEBUG_MESSAGE,msg,NULL);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
HTUU_encode(szCache,strlen(szCache),buf_uuencoded);
|
|
wsprintf(buf,"%s %s",htspm->szProtocolName,buf_uuencoded);
|
|
|
|
/* see if there is already an Auth header in the request. */
|
|
|
|
hlCur = HL_FindHeader(hRequest, "Authorization");
|
|
|
|
if (hlCur)
|
|
{
|
|
/* update existing auth header */
|
|
|
|
bResult = spm_CloneString(fpUI,pvOpaqueOS,&hlCur->value,buf);
|
|
}
|
|
else
|
|
{
|
|
/* create new header for the auth */
|
|
|
|
hlCur = HL_AppendNewNameValue(fpUI,pvOpaqueOS,hRequest,"Authorization",buf);
|
|
bResult = (hlCur != NULL);
|
|
}
|
|
|
|
/* we updated the original request, so tell the client to send it. */
|
|
|
|
return HTSPM_STATUS_RESUBMIT_OLD;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/*****************************************************************/
|
|
|
|
static HTSPMStatusCode module__Unload(F_UserInterface fpUI,
|
|
void * pvOpaqueOS,
|
|
HTSPM * htspm)
|
|
{
|
|
pwc_Destroy(fpUI,pvOpaqueOS,htspm->pvOpaque);
|
|
htspm->pvOpaque = NULL;
|
|
|
|
return HTSPM_STATUS_OK;
|
|
}
|
|
|
|
/*****************************************************************/
|
|
/*****************************************************************/
|
|
|
|
static HTSPMStatusCode module__DownCall(HTSPM_ServiceId sid, /* down-call service id */
|
|
F_UserInterface fpUI, /* common arg to all down calls */
|
|
void * pvOpaqueOS, /* common arg to all down calls */
|
|
HTSPM * htspm, /* common arg to all down calls */
|
|
void * pvMethodData) /* per-method data */
|
|
{
|
|
#ifdef DEBUG
|
|
{
|
|
unsigned char msg[200];
|
|
sprintf(msg,"Basic_DownCall: ServiceId [0x%x]\n",sid);
|
|
(*fpUI)(pvOpaqueOS,UI_SERVICE_DEBUG_MESSAGE,msg,NULL);
|
|
}
|
|
#endif /* DEBUG */
|
|
|
|
switch (sid)
|
|
{
|
|
case HTSPM_SERVICE_UNLOAD:
|
|
{
|
|
return module__Unload(fpUI,pvOpaqueOS,htspm);
|
|
}
|
|
case HTSPM_SERVICE_MENUCOMMAND:
|
|
{
|
|
/* REMOVE About/Config dialogs
|
|
D_MenuCommand * pmc = pvMethodData;
|
|
return Dialog_MenuCommand(fpUI,pvOpaqueOS,htspm,
|
|
pmc->pszMoreInfo);
|
|
*/
|
|
return HTSPM_ERROR_UNIMPLEMENTED;
|
|
|
|
}
|
|
|
|
case HTSPM_SERVICE_PROCESSRESPONSE:
|
|
{
|
|
D_ProcessResponse * ppr = pvMethodData;
|
|
return module__ProcessResponse(fpUI,pvOpaqueOS,htspm,
|
|
ppr->hlProtocol,
|
|
ppr->hRequest,
|
|
ppr->hResponse,
|
|
ppr->phNewRequest,
|
|
ppr->bNonBlock);
|
|
}
|
|
|
|
case HTSPM_SERVICE_PREPROCESSREQUEST:
|
|
{
|
|
D_PreProcessRequest * pppr = pvMethodData;
|
|
return module__PreProcessRequest(fpUI,pvOpaqueOS,htspm,
|
|
pppr->hRequest,
|
|
pppr->phNewRequest);
|
|
}
|
|
|
|
default:
|
|
return HTSPM_ERROR_UNIMPLEMENTED;
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
|
|
/*****************************************************************/
|
|
/*****************************************************************/
|
|
|
|
/* WARNING: the name of this function is exported and used in the
|
|
* WARNING: mosaic .ini file
|
|
*/
|
|
|
|
#ifdef WIN32
|
|
__declspec(dllexport)
|
|
#endif
|
|
HTSPMStatusCode Basic_Load(F_UserInterface fpUI,
|
|
void * pvOpaqueOS,
|
|
HTSPM * htspm)
|
|
{
|
|
if (htspm->ulStructureVersion != HTSPM_STRUCTURE_VERSION)
|
|
return HTSPM_ERROR_WRONG_VERSION;
|
|
|
|
/* we use the opaque field provided to us to store our password cache. */
|
|
|
|
htspm->pvOpaque = pwc_Create(fpUI,pvOpaqueOS);
|
|
|
|
htspm->f_downcall = (F_DownCall)module__DownCall;
|
|
|
|
SEC_formatmsg(RES_STRING_BASIC2,htspm->szMenuName,sizeof(htspm->szMenuName));
|
|
// SEC_formatmsg(RES_STRING_BASIC3,htspm->szStatusText,sizeof(htspm->szStatusText));
|
|
htspm->szStatusText[0] = 0;
|
|
|
|
{
|
|
UI_ProtocolId uid;
|
|
|
|
uid.htspm = htspm;
|
|
uid.szIdentHeader = "WWW-Authenticate"; /* note: no colon */
|
|
uid.szIdentValue = "Basic";
|
|
uid.szIdentSubValue = NULL;
|
|
(*fpUI)(pvOpaqueOS,UI_SERVICE_REGISTER_PROTOCOL,&uid,NULL);
|
|
}
|
|
|
|
return HTSPM_STATUS_OK;
|
|
}
|