/*****************************************************************************/ /* AuthHTL.c Licensed under the Apache License, Version 2.0 (the License); you may not use this software except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an AS IS BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 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 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 && to_lower(*cptr) == to_lower(*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); strzcpy (cptr, sptr, rqptr->rqAuth.UserDetailsLength+1); 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 && to_lower(*cptr) == to_lower(*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); } /****************************************************************************/