/*****************************************************************************/ /* AuthHTL.c THE GNU GENERAL PUBLIC LICENSE APPLIES DOUBLY TO ANYTHING TO DO WITH AUTHENTICATION AND AUTHORIZATION! This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License, or any later version. > This package is distributed in the hope that it will be useful, > but WITHOUT ANY WARRANTY; without even the implied warranty of > MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. This module provides functions related to the authentication of case-insensitive usernames via simple lists of names (and optional case-insensitive passwords and user detail). See AUTH.C for overall detail on the WASD authorization environment. VERSION HISTORY --------------- 26-JUN-2012 MGD bugfix; AuthReadSimpleList() parameter /DIRECTORY= processing 26-AUG-2003 MGD service directory located authorization databases 12-AUG-2003 MGD allow the database directory location to be specified using an authorization rule 'param="/directory=device:[directory]"' 27-APR-2002 MGD use sys$setprv() 04-AUG-2001 MGD support module WATCHing 05-FEB-2000 MGD change HTL database type from ".HTL" to ".$HTL" (keep the nomenclature in line with ".$HTA", see AUTHHTA.C) 01-JAN-2000 MGD no significant modifications for ODS-5 (no NAM block) 28-AUG-1999 MGD unbundled from AUTH.C for v6.1 */ /*****************************************************************************/ #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 #include /* VMS related header files */ #include #include #include #include #include /* application related header files */ #include "wasd.h" #define WASD_MODULE "AUTHHTL" #if WATCH_MOD #define FI_NOLI WASD_MODULE, __LINE__ #else /* in production let's keep the exact line to ourselves! */ #define FI_NOLI WASD_MODULE, 0 #endif /********************/ /* external storage */ /********************/ extern int ToLowerCase[], ToUpperCase[]; extern unsigned long SysPrvMask[]; extern char *AuthConfigHtaDirectory; extern char ErrorSanityCheck[]; extern ACCOUNTING_STRUCT *AccountingPtr; extern MSG_STRUCT Msgs; extern WATCH_STRUCT Watch; /****************************************************************************/ /* */ int AuthReadSimpleList ( REQUEST_STRUCT* rqptr, char *DatabaseName, BOOL AuthenticatePassword ) { int status, AuthFileNameLength; char *cptr, *sptr, *zptr, *cptrBuffer; char AuthFileName [256], Line [1024]; struct FAB AuthFileFab; struct RAB AuthFileRab; /*********/ /* begin */ /*********/ if (WATCHMOD (rqptr, WATCH_MOD_AUTH)) WatchThis (WATCHITM(rqptr), WATCH_MOD_AUTH, "AuthReadSimpleList() !&Z !&Z !&B", DatabaseName, rqptr->RemoteUser, AuthenticatePassword); /* flag that case-less username and password checks were performed */ rqptr->rqAuth.CaseLess = true; /* must supply a user name and database name */ if (!rqptr->RemoteUser[0] || !DatabaseName[0]) return (AUTH_DENIED_BY_LOGIN); if (rqptr->rqAuth.PathParameterPtr && rqptr->rqAuth.PathParameterPtr[0]) { if ((cptr = strstr (rqptr->rqAuth.PathParameterPtr, "/directory=")) || (cptr = strstr (rqptr->rqAuth.PathParameterPtr, "/DIRECTORY="))) cptr += 11; else cptr = NULL; } else cptr = NULL; if (!cptr) { if (rqptr->rqAuth.DirectoryPtr) cptr = rqptr->rqAuth.DirectoryPtr; else if (rqptr->ConfigDirectory[0]) cptr = rqptr->ConfigDirectory; else cptr = AuthConfigHtaDirectory; } /* just a safeguard against the service directory not being configured */ if (!*cptr) cptr = AUTH_DIR_NOT_CONFIGURED; zptr = (sptr = AuthFileName) + sizeof(AuthFileName)-1; while (*cptr && sptr < zptr) *sptr++ = *cptr++; for (cptr = DatabaseName; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = HTL_FILE_TYPE; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; AuthFileNameLength = sptr - AuthFileName; if (WATCHING (rqptr, WATCH_AUTH)) WatchThis (WATCHITM(rqptr), WATCH_AUTH, "FILE !AZ", AuthFileName); AuthFileFab = cc$rms_fab; AuthFileFab.fab$b_fac = FAB$M_GET; AuthFileFab.fab$l_fna = AuthFileName; AuthFileFab.fab$b_fns = AuthFileNameLength; AuthFileFab.fab$b_shr = FAB$M_SHRGET; /* turn on SYSPRV to allow access to authentication database file */ sys$setprv (1, &SysPrvMask, 0, 0); status = sys$open (&AuthFileFab, 0, 0); sys$setprv (0, &SysPrvMask, 0, 0); /* status from sys$open() */ if (VMSnok (status)) { rqptr->rqResponse.HttpStatus = 500; rqptr->rqResponse.ErrorTextPtr = MsgFor(rqptr,MSG_AUTH_DATABASE); rqptr->rqResponse.ErrorOtherTextPtr = DatabaseName; ErrorVmsStatus (rqptr, status, FI_LI); return (status); } AuthFileRab = cc$rms_rab; AuthFileRab.rab$l_fab = &AuthFileFab; AuthFileRab.rab$b_mbf = 2; AuthFileRab.rab$l_rop = RAB$M_RAH; if (VMSnok (status = sys$connect (&AuthFileRab, 0, 0))) { sys$close (&AuthFileFab, 0, 0); rqptr->rqResponse.HttpStatus = 500; rqptr->rqResponse.ErrorTextPtr = MsgFor(rqptr,MSG_AUTH_DATABASE); rqptr->rqResponse.ErrorOtherTextPtr = DatabaseName; ErrorVmsStatus (rqptr, status, FI_LI); return (status); } /*****************/ /* locate record */ /*****************/ AuthFileRab.rab$l_ubf = Line; AuthFileRab.rab$w_usz = sizeof(Line)-1; while (VMSok (status = sys$get (&AuthFileRab, 0, 0))) { AuthFileRab.rab$l_rbf[AuthFileRab.rab$w_rsz] = '\0'; if (AuthFileRab.rab$w_rsz) { if (AuthFileRab.rab$l_ubf[AuthFileRab.rab$w_rsz-1] == '\\') { /* directive is continued on next line */ AuthFileRab.rab$l_ubf[AuthFileRab.rab$w_rsz-1] = ' '; AuthFileRab.rab$l_ubf += AuthFileRab.rab$w_rsz; AuthFileRab.rab$w_usz -= AuthFileRab.rab$w_rsz; continue; } } for (cptr = Line; *cptr && ISLWS(*cptr); cptr++) if (*cptr == '#' || *cptr == '!') continue; sptr = rqptr->RemoteUser; while (*cptr && !ISLWS(*cptr) && *cptr != '=' && *sptr && TOLO(*cptr) == TOLO(*sptr)) { cptr++; sptr++; } if ((*cptr && !ISLWS(*cptr) && *cptr != '=') || *sptr) continue; break; } sys$close (&AuthFileFab); if (status == RMS$_EOF) { /* user record not found */ if (WATCHING (rqptr, WATCH_AUTH)) WatchThis (WATCHITM(rqptr), WATCH_AUTH, "FAIL !AZ!AZ username", DatabaseName, AuthSourceString (DatabaseName, AUTH_SOURCE_LIST)); if (AuthenticatePassword) return (AUTH_DENIED_BY_LOGIN); else return (AUTH_DENIED_BY_GROUP); } /* if just checking if the user name is an entry in the list file */ if (!AuthenticatePassword) return (SS$_NORMAL); sptr = cptr; if (*sptr == '=') while (*sptr && !ISLWS(*sptr)) sptr++; while (*sptr && ISLWS(*sptr)) sptr++; if (*sptr) { cptrBuffer = cptr; for (cptr = sptr; *cptr; cptr++); if (cptr > sptr) cptr--; while (cptr > sptr && ISLWS(*cptr)) cptr--; if (!ISLWS(*cptr)) cptr++; *cptr = '\0'; rqptr->rqAuth.UserDetailsLength = cptr - sptr; rqptr->rqAuth.UserDetailsPtr = cptr = VmGetHeap (rqptr, rqptr->rqAuth.UserDetailsLength+1); strcpy (cptr, sptr); cptr = cptrBuffer; } /* if just checking if the user name is an entry in the list file */ if (!AuthenticatePassword) return (status); /* simple, clear-text password comparison */ if (*cptr != '=') { if (WATCHING (rqptr, WATCH_AUTH)) WatchThis (WATCHITM(rqptr), WATCH_AUTH, "FAIL !AZ!AZ no password", DatabaseName, AuthSourceString (DatabaseName, AUTH_SOURCE_LIST)); return (AUTH_DENIED_BY_LOGIN); } while (*cptr && *cptr == '=') cptr++; sptr = rqptr->RemoteUserPassword; while (*cptr && !ISLWS(*cptr) && *sptr && TOLO(*cptr) == TOLO(*sptr)) { cptr++; sptr++; } if ((*cptr && !ISLWS(*cptr)) || *sptr) { /* passwords do not match */ if (WATCHING (rqptr, WATCH_AUTH)) WatchThis (WATCHITM(rqptr), WATCH_AUTH, "FAIL !AZ!AZ password", DatabaseName, AuthSourceString (DatabaseName, AUTH_SOURCE_LIST)); return (AUTH_DENIED_BY_LOGIN); } /* passwords match */ return (SS$_NORMAL); } /****************************************************************************/