/*****************************************************************************/ /* Basic.c This module implements the BASIC authentication functionality. VERSION HISTORY --------------- 04-AUG-2001 MGD support module WATCHing 29-APR-2000 MGD proxy authorization 18-SEP-1999 MGD to support authentication agents username/password are no longer forced to upper case (in true VMS fashion :^) 30-OCT-1997 MGD a little maintenance 01-JUL-1996 MGD own module with development of "Digest" authentication */ /*****************************************************************************/ #ifdef WASD_VMS_V7 #undef _VMS__V6__SOURCE #define _VMS__V6__SOURCE #undef __VMS_VER #define __VMS_VER 70000000 #undef __CRTL_VER #define __CRTL_VER 70000000 #endif /* standard C header files */ #include #include #include /* VMS related header files */ #include #include /* application related header files */ #include "wasd.h" #define WASD_MODULE "BASIC" /********************/ /* external storage */ /********************/ extern char SoftwareID[]; extern MSG_STRUCT Msgs; extern WATCH_STRUCT Watch; /*****************************************************************************/ /* */ int BasicAuthorization (REQUEST_STRUCT *rqptr) { int status; char *cptr, *sptr, *zptr; char EncodedString [256], UserNamePassword [256]; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "BasicAuthorization() !&Z", rqptr->rqAuth.RequestAuthorizationPtr); rqptr->rqAuth.Scheme = rqptr->rqAuth.ChallengeScheme = AUTH_SCHEME_BASIC; cptr = rqptr->rqAuth.RequestAuthorizationPtr; /* skip across the authorization scheme name ("basic") */ while (*cptr && !ISLWS(*cptr)) cptr++; /* skip over white-space between scheme and encoded string */ while (*cptr && ISLWS(*cptr)) cptr++; /* get the RFC1421-encoded "username:password" string */ zptr = (sptr = EncodedString) + sizeof(EncodedString); while (*cptr && !ISLWS(*cptr) && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { rqptr->rqResponse.HttpStatus = 401; ErrorGeneralOverflow (rqptr, FI_LI); return (STS$K_ERROR); } *sptr = '\0'; /************************************************/ /* decode and extract the username and password */ /************************************************/ sptr = BasicPrintableDecode (EncodedString, UserNamePassword, sizeof(UserNamePassword)); if (sptr[0]) { /* an error report string has been returned by the decode function */ rqptr->rqResponse.HttpStatus = 401; ErrorGeneral (rqptr, sptr, FI_LI); return (STS$K_ERROR); } cptr = UserNamePassword; /* get the remote username from the decoded "username:password" string */ zptr = (sptr = rqptr->RemoteUser) + sizeof(rqptr->RemoteUser); while (*cptr && *cptr != ':' && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { rqptr->rqResponse.HttpStatus = 401; ErrorGeneralOverflow (rqptr, FI_LI); return (STS$K_ERROR); } *sptr = '\0'; rqptr->RemoteUserLength = sptr - rqptr->RemoteUser; /* get the password from the decoded "username:password" string */ if (*cptr == ':') cptr++; zptr = (sptr = rqptr->RemoteUserPassword) + sizeof(rqptr->RemoteUserPassword); while (*cptr && sptr < zptr) *sptr++ = *cptr++; if (sptr >= zptr) { rqptr->rqResponse.HttpStatus = 401; ErrorGeneralOverflow (rqptr, FI_LI); return (STS$K_ERROR); } *sptr = '\0'; return (SS$_NORMAL); } /*****************************************************************************/ /* Generate a BASIC challenge string, comprising the authentication realm. Store this null-terminated string in dynamically allocated memory pointed to by 'rqptr->rqAuth.BasicChallengePtr'. */ int BasicChallenge (REQUEST_STRUCT *rqptr) { static $DESCRIPTOR (StringDsc, ""); static $DESCRIPTOR (BasicChallengeFaoDsc, "!AZ: Basic realm=\"!AZ\""); int status; unsigned short slen; char String [256]; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "BasicChallenge()"); StringDsc.dsc$a_pointer = String; StringDsc.dsc$w_length = sizeof(String)-1; sys$fao (&BasicChallengeFaoDsc, &slen, &StringDsc, rqptr->ServicePtr->ProxyAuthRequired ? "Proxy-Authenticate" : "WWW-Authenticate", rqptr->rqAuth.RealmDescrPtr); String[slen] = '\0'; /* allocate heap memory */ rqptr->rqAuth.BasicChallengePtr = VmGetHeap (rqptr, slen+1); memcpy (rqptr->rqAuth.BasicChallengePtr, String, slen+1); return (SS$_NORMAL); } /*****************************************************************************/ /* Decodes a string encoded using "Printable Encoding" as described in RFC1421. */ char* BasicPrintableDecode ( char *Encoded, char *Plain, int SizeOfPlain ) { static char ErrorIncorrect [] = "Incorrect character in quantum."; static char ErrorIncomplete [] = "Incomplete quantum."; static char ErrorOverflow [] = "Plain text string too small."; static unsigned char ValueTable [128] = { 255, 255, 255, 255, 255, 255, 255, 255, /* 7 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 15 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 23 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 31 */ 255, 255, 255, 255, 255, 255, 255, 255, /* 39 */ 255, 255, 255, 62, 255, 255, 255, 63, /* 47 */ 52, 53, 54, 55, 56, 57, 58, 59, /* 55 */ 60, 61, 255, 255, 255, 255, 255, 255, /* 63 */ 255, 0, 1, 2, 3, 4, 5, 6, /* 71 */ 7, 8, 9, 10, 11, 12, 13, 14, /* 79 */ 15, 16, 17, 18, 19, 20, 21, 22, /* 87 */ 23, 24, 25, 255, 255, 255, 255, 255, /* 95 */ 255, 26, 27, 28, 29, 30, 31, 32, /* 103 */ 33, 34, 35, 36, 37, 38, 39, 40, /* 111 */ 41, 42, 43, 44, 45, 46, 47, 48, /* 119 */ 49, 50, 51, 255, 255, 255, 255, 255 /* 127 */ }; int ccnt, pcnt; unsigned long reg; char val; char *eptr, *pptr; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "BasicPrintableDecode()"); eptr = Encoded; pptr = Plain; pcnt = SizeOfPlain-1; while (*eptr) { reg = 0; if (*eptr) { if (*eptr == '=') return (ErrorIncorrect); if ((val = ValueTable [*eptr++ & 0x7f]) == 255) return (ErrorIncorrect); reg |= val << 18; } if (*eptr) { if (*eptr == '=') return (ErrorIncorrect); ccnt = 1; if ((val = ValueTable [*eptr++ & 0x7f]) == 255) return (ErrorIncorrect); reg |= val << 12; } if (*eptr) { if (*eptr == '=') eptr++; else { ccnt++; if ((val = ValueTable [*eptr++ & 0x7f]) == 255) return (ErrorIncorrect); reg |= val << 6; } } if (*eptr) { if (*eptr == '=') eptr++; else { ccnt++; if ((val = ValueTable [*eptr++ & 0x7f]) == 255) return (ErrorIncorrect); reg |= val; } } else return (ErrorIncomplete); if (!pcnt--) return (ErrorOverflow); if (ccnt--) *pptr++ = (reg >> 16) & 0xff; if (!pcnt--) return (ErrorOverflow); if (ccnt--) *pptr++ = (reg >> 8) & 0xff; if (!pcnt--) return (ErrorOverflow); if (ccnt--) *pptr++ = reg & 0xff; } *pptr = '\0'; return (""); } /*****************************************************************************/ /* Encodes a plain-text string using "Printable Encoding" as described in RFC1421. This function is not actually used at all in this daemon! It is included here as a tutorial on how the string is encoded at the browser end! */ char* BasicPrintableEncode ( unsigned char *Plain, unsigned char *Encoded, int SizeOfEncoded ) { static char ErrorOverflow [] = "Encoded text string too small."; static unsigned char ValueTable [] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int ccnt, ecnt; unsigned long reg; unsigned char *eptr, *pptr; /*********/ /* begin */ /*********/ if (WATCH_MODULE(WATCH_MOD__OTHER)) WatchThis (WATCHALL, WATCH_MOD__OTHER, "BasicPrintableEncode()"); pptr = Plain; eptr = Encoded; ecnt = SizeOfEncoded-1; while (*pptr) { ccnt = reg = 0; if (*pptr) { reg |= *pptr++ << 16; ccnt++; } if (*pptr) { reg |= *pptr++ << 8; ccnt++; } if (*pptr) { reg |= *pptr++; ccnt++; } *eptr++ = ValueTable[(reg>>18)&0x3f]; if (!ecnt--) return (ErrorOverflow); *eptr++ = ValueTable[(reg>>12)&0x3f]; if (!ecnt--) return (ErrorOverflow); if (ccnt == 1) { if (!ecnt--) return (ErrorOverflow); *eptr++ = '='; if (!ecnt--) return (ErrorOverflow); *eptr++ = '='; } else { *eptr++ = ValueTable[(reg>>6)&0x3f]; if (ccnt == 2) { if (!ecnt--) return (ErrorOverflow); *eptr++ = '='; } else { if (!ecnt--) return (ErrorOverflow); *eptr++ = ValueTable[reg&0x3f]; } } } *eptr = '\0'; return (""); } /****************************************************************************/