OpenVMS Source Code Demos
mod_auth_vms_rms
//================================================================================================================================
// title : mod_auth_vms_rms.c
// author : Neil Rieck (Waterloo, Ontario, Canada) (https://neilrieck.net)
// created: 2015-03-03
// target : CSWS-2.0 (a.k.a. Apache httpd-2.0.63 on OpenVMS)
// notes : 1) this program is based upon my "mod_auth_vms_ext.c" which was based upon "mod_auth_openvms.c" from HP
// : 2) I want to use "application authentication" rather than "SYSUAF authentication" (100% of our current >1400 users are
// web-based so it was easier for us to use store usernames and VMS-created "password hashes" in an application
// database than create VMS accounts for each one; this will allow us to enable self-serve account generation and
// maintenance as is done on Amazon.com and eBay.com; this also allows us to have account names longer than 14
// characters including email addresses)
// : 3) most places using this program will want to employ "domain cookies"
// : 4) VMS convention: exit with 1 = good; UNIX convention: exit with 0 = good; Since Apache was written to follow a UNIX
// convention so most modules here will exit with 0 = good
// ver who when what
// --- --- ------ ----------------------------------------------------------------------------------------------------------------
// 106 NSR 150615 0. copied from MOD_AUTH_VMS_EXT_105.C
// 1. began replacing the lib$spawn section with additional RMS support
// NSR 150616 2. more coding
// NSR 151116 3. straighten out the confussion between VMS exit codes and UNIX exit codes (I can do these repairs now because
// the Itanium cutover has been delayed)
// NSR 151117 4. the saga continues
// NSR 151118 5. started inserting the encryption module we use to generate a new cookie (oops, I must have forgot this)
// NSR 151210 6. mtce tweak to the VMSIFY macro
//================================================================================================================================
// Docs:
// 1) build this program then copy the execuatable to sys$common:[modules]
// be sure to check file ownership and protection bits
// consider using "$SET SECURITY/ACL" to modify/delete access control list params
// add the next line to file: apache$common:[conf]httpd.conf
// LoadModule auth_vms_rms_module modules/mod_auth_rms_ext.exe
// restart CSWS to load the new module
// 2) sample .htaccess
// #---------------------------------------------------------
// # title : apache$common:[neil_private].htaccess
// # author : Neil Rieck
// # created: 2015-03-04
// #---------------------------------------------------------
// AuthType Basic
// AuthVmsRmsUser On off means plugin is disabled
// AuthVmsRmsAuthoritative On off means exit with DECLINED rather than HTTP_UNAUTHORIZED
// AuthVmsRmsCookie ICSIS_SESSION optional test (no value means test is disabled)
// AuthVmsRmsGroupList ATS,BRT,WST,POW, optional test (no value means test is disabled)
// AuthVmsRmsRealmName "OpenVMS RMS-based Authentication" optional, displayed during the password dialog
// require valid-user
// #---------------------------------------------------------
// 3) Simplified Flow Chart:
//
// step-1 does this user have the desired cookie? n goto step-5
// y
// is the cookie in our session database? y goto step-7
// n
// step-5 has this user supplied a username+password n goto step-8
// y
// are user+pass found in the authentication database? n goto step-8
// y
// locate additional information in the profile database
// create a new "domain" session cookie
// save cookie in the session database for the next time
// tell Apache to send the cookie back to the client
// |
// step-7 allow user to access the protected directory or document
// exit with OK (will result in status: 200)
//
// step-8 exit with 401 (put up a username+password dialog)
//================================================================================================================================
#define RMS_SESSION_CACHE 1 // enable support for RMS-based session cache
//
// yep, hardcoded file specs for now (sorry about that but this may be more efficient than defining them in .htaccess)
//
char profile1_fs[] = "csmis$dat:profiledb_authentication_100.dat"; // profile1 (contains usernames + password hashes)
char profile2_fs[] = "csmis$dat:profiledb_employee_120.dat"; // profile2 (contains full employee profile data)
char profile3_fs[] = "csmis$dat:profiledb_22_hist.dat"; // profile3 (contains event history)
char sessions_fs[] = "csmis$dat:icsis_session_5.dat"; // sessions (usernames, cookies, IP addresses, date-time)
char k_key_file$[] = "csmis$dat:web_key_validation.txt"; // a pass phrase used during encryption
//
// Include files (common c stuff)
//
#include <ctype.h>
#include <types.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h> // need this for getenv
#include <time.h> // for time stamps
//
// Include files (VMS and OpenVMS only)
//
#ifdef __VMS // if VMS or OpenVMS
#define __NEW_STARLET 1 // enable new (strict) starlet (OpenVMS Alpha 7.0 and above)
#include <ssdef.h> //
#include <kgbdef.h> //
#include <lgidef.h> //
#include <stsdef.h> //
#include <descrip.h> //
#include <starlet.h> //
#include <builtins.h> //
#include <lib$routines.h> // need this for lib$spawn
#include <rms.h> // OpenVMS Record Management Services
#include <gen64def.h> // required for sys$hash_password
#else //
#define RMS_SESSION_CACHE 0 // no VMS means no RMS
#endif //
//
#ifdef SHADOW
#undef SHADOW
#endif
#ifdef MULTITHREADING
#undef MULTITHREADING
#endif
//
#include "httpd.h"
#include "http_config.h"
#include "http_core.h"
#include "http_log.h"
#include "http_protocol.h"
#include "http_request.h"
#include "apr_strings.h"
#include "protshr.h"
//
// Definitions
//
#ifndef INTERNAL
#define INTERNAL static
#endif
#ifndef NULL
#define NULL (void *) 0
#endif
#ifndef alloca
#define alloca __ALLOCA
#endif
//
// VMSIFY
// a macro for use in the VMS world (VMS strings employ this structure)
// notes: 1. this macro can be used to create VMS strings in c space
// 2. the $DESCRIPTOR macro does something similar employing sizeof-1
// 3. this macro combines two operations
// 4. use str$copy_dx() to copy string data up to the calling program
//
#define VMSIFY(a,b) { \
a.dsc$b_dtype = DSC$K_DTYPE_T; \
a.dsc$b_class = DSC$K_CLASS_S; \
a.dsc$w_length = strlen(b); \
a.dsc$a_pointer = (char *) malloc(strlen(b)); \
strncpy(a.dsc$a_pointer,b,a.dsc$w_length); \
}
//
#define DEBUG 1
#if DEBUG
//dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd Neil's debug code
//
// this block is for development purposes only
//
char spy_stamp[50]; // buffer for time-stamp
char ccyymmdd[10]; // ccyymmdd
char spy_file[99]; //
void build_spy_stamps() {
//----------------------------------------------------------------------
struct timeb timebuffer; // for ftime()
struct tm *time_fields; // for localtime()
char millisecs[5]; //
char my_date_time[20]; //
//----------------------------------------------------------------------
ftime( &timebuffer ); // record current system time
sprintf(millisecs, "%03hu", timebuffer.millitm); // extract milliseconds as three chars
time_fields = localtime( &timebuffer.time ); // breakout other time fields
strftime( my_date_time, // ccyymmdd.hhmmss
sizeof(my_date_time), //
"%Y%m%d.%H%M%S", //
time_fields ); //
sprintf( spy_stamp, // ccyymmdd.hhmmss.xxx
"%s%s%s", //
my_date_time, //
".", //
millisecs); // xxx
strftime( ccyymmdd, //
sizeof(ccyymmdd), //
"%Y%m%d", //
time_fields); //
}
char trc_buf[MAX_STRING_LEN]; //
FILE *trc_file = NULL; //
void TRC1(char *msg) { // trace (one param)
build_spy_stamps(); //
sprintf(spy_file,"%s%s%s", //
"APACHE$COMMON:[000000]aaa_mod_auth_vms_rms_", //
ccyymmdd, //
".trc"); //
// trc_file = fopen("APACHE$COMMON:[000000]aaa_mod_auth_vms_rms.trc", "a"); // open the trace file (old)
trc_file = fopen(spy_file, "a"); // open the trace file (new)
if (trc_file != NULL) { //
fprintf(trc_file, "%s %s\n",spy_stamp,msg); //
fclose (trc_file); //
} //
} //
// trace (two params)
#define TRC2(a,b) { \
sprintf(trc_buf,a,b); \
TRC1 (trc_buf); \
} //
//dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd end of debug
#else
#define TRC2(a,b)
#define TRC1(a)
#endif
//
// Data structures
//
typedef unsigned int VMS_STATUS;
//
typedef struct dsc$descriptor_s DSC_S; // all VMS strings must be passed by descriptor
//
typedef struct { // context block
int fUserEnable; // 0 = false (this module abstains)
int fAuthoritative; // 0 = false (DECLINED, not REJECT)
char *fCookieName; // whatever optional, leave blank to disable
char *fGroupList; // GRP1[,GRP2,GRP3,...] optional, leave blank to disable
char *fRealmName; // authorization name (realm) optional (to override default)
}
CTXBLK;
//
// Function prototypes
//
extern module AP_MODULE_DECLARE_DATA auth_vms_rms_module;
#if RMS_SESSION_CACHE == 1 //
long sessions_lookup(char*, char*, char*); // sessions (usernames, cookies, IP addresses, date-time)
long sessions_write(char*, char*); // sessions (usernames, cookies, IP addresses, date-time)
#include "[.fun]WCSM_TEA_ENCRYPT.C" // need this for cookie encryption (no associated h file)
char ccyymmddhhmmsst[15]; // ccyymmddhhmmsst (stamp for cookie)
char new_data[64] = ""; //
char new_cookie[64] = ""; // same size as variable in wcsm_c_encrypt
#endif //
long profile1_lookup(char*, char*, char*); // usernames + password hashes
long profile2_lookup(char*, char*, char*); // full employee profile data
//
// build cookie date+time stamp
//
void build_cookie_stamp() {
//----------------------------------------------------------------------
struct timeb timebuffer; // for ftime()
struct tm *time_fields; // for localtime()
char millisecs[5]; //
char my_date_time[20]; //
//----------------------------------------------------------------------
ftime( &timebuffer ); // record current system time
sprintf(millisecs, "%03hu", timebuffer.millitm); // extract milliseconds as one char
time_fields = localtime( &timebuffer.time ); // breakout other time fields
strftime( my_date_time, // ccyymmddhhmmss
sizeof(my_date_time), //
"%Y%m%d%H%M%S", //
time_fields ); //
sprintf( ccyymmddhhmmsst, // ccyymmddhhmmsst
"%s%c", //
my_date_time, //
millisecs[0]); //
}
//
void *create_auth_vms_rms_cntxt (apr_pool_t *p, char *d)
{
CTXBLK *sec = (CTXBLK *) apr_pcalloc (p, sizeof(CTXBLK));
sec->fUserEnable = 0;
sec->fAuthoritative = 0;
sec->fCookieName = NULL;
sec->fGroupList = NULL;
sec->fRealmName = NULL;
return (void *) sec;
}
const char* my_first_cmd_func(cmd_parms* cmd, void* cfg, const char* arg);
//
// Directives handled by this module
//
command_rec auth_vms_rms_cmds[] =
{
{ "AuthVmsRmsAuthoritative",
ap_set_flag_slot,
(void *) APR_XtOffsetOf(CTXBLK,fAuthoritative),
OR_AUTHCFG,
FLAG,
"Set to 'no' to allow access control to be passed along "
"to lower modules if the userID is not known to this module" },
{ "AuthVmsRmsUser",
ap_set_flag_slot,
(void *) APR_XtOffsetOf(CTXBLK,fUserEnable),
OR_AUTHCFG,
FLAG,
"OpenVMS user authentication/authorization on/off" },
{ "AuthVmsRmsGroupList",
ap_set_string_slot,
(void*)APR_OFFSETOF(CTXBLK,fGroupList),
OR_AUTHCFG,
TAKE1,
"comma-delimited list of authorized groups (blank=disabled)" },
{ "AuthVmsRmsCookie",
ap_set_string_slot,
(void*)APR_OFFSETOF(CTXBLK,fCookieName),
OR_AUTHCFG,
TAKE1,
"desired cookie (blank=disabled)" },
{ "AuthVmsRmsRealmName",
ap_set_string_slot,
(void*)APR_OFFSETOF(CTXBLK,fRealmName),
OR_AUTHCFG,
TAKE1,
"realm name (eg. \"OpenVMS External Authentication\")" },
{ NULL }
};
//=====================================================================================================================
// a u t h e n t i c a t e _ v m s _ e x t
//
// General Overview:
//
// 1) On our system, users can come here with a valid session cookie (set by another app) but no Authorization string.
// In this case we do not want MOD_AUTH(_BASIC) to prompt for authorization credentials before testing the cookie
// which means the hook for "authenticate_vms_ext" must fire before MOD_AUTH(_BASIC)
// 2) On our system, users might come here with nothing (no cookie or Authorization string) so we will prompt for a
// username + password then create the session cookie
// 3) In order to keep our transaction overhead as low as possible, I do things here which might have been done by a
// combination of the core routines and MOD_AUTH(_BASIC)
// 4) Authorative Off means that authentication failures return DECLINED so other other modules can authenticate
// 5) Authorative On means we never DECLINE to another modules
// 6) Successfull authentication is not enough.
// If a GroupList has been defined then the external authenticator must return a group string.
// If the group string is in the list then we return OK else 403 (HTTP_FORBIDDEN)
//
// Caveats:
//
// 1) Cookie authentication only works properly on our system when we employ DOMAIN cookies
// 2) Never do plain text Basic authentication over port 80; use SSL encryption via port 443
//======================================================================================================================
//
// <<< Local RMS Authentication >>>
//
// pass cookie and remote host to the authenticator
// if the authenticator says the cookie and remote host are valid then that is all we need to move on
// if the cookie is not valid then we will prompt for a username and password (if the authenticator is satisfied
// then it will create a new session cookie which will be passed back to the browser for use on the next
// pass through here)
//======================================================================================================================
INTERNAL int authenticate_vms_ext (request_rec *r)
{
unsigned int st; //
unsigned int rc; //
CTXBLK *sec = (CTXBLK *) ap_get_module_config (r->per_dir_config, &auth_vms_rms_module);
//
// cookie-testing is optional but username is not (we prompt for username+password on a cookie miss)
//
if (!sec->fUserEnable) { // if no enabled username directive
return DECLINED; // then exit with a defer
} //
TRC1("new transaction ==========");
conn_rec *c = r->connection; //
const char *remote_host = ap_get_remote_host ( r->connection, r->per_dir_config, REMOTE_NOLOOKUP, 0 );
const char *cookie_data = apr_table_get( r->headers_in, "Cookie"); //
const char *type = ap_auth_type(r); // Basic, Digest, etc.
const char *auth_line = apr_table_get( r->headers_in, "Authorization");
char cookie_payload[8192] = ""; // max total limit for browser cookies
char username[99] = ""; // big enough for email addresses
char password[33] = ""; //
char errstr[MAX_STRING_LEN]= ""; //
char *temp; //
char groupData[32] = ""; // from sessions or profile2
int score = 0; //
int junk = 0;
char default_realm[] = "OpenVMS External Authentication";
const char *base64_buf = 0;
const char *decode_buf = 0;
const char *cursor = 0;
//--------------------------------------------------------------------------
TRC2("fCookieName: %s",sec->fCookieName);
TRC2("fUserEnable: %d",sec->fUserEnable);
TRC2("fGroupList : %s",sec->fGroupList);
TRC2("fRealmName : %s",sec->fRealmName);
TRC2(" LocalHost : %s",r->server->server_hostname); // needed to prevent cookie spoofing
TRC2(" RemoteHost: %s",remote_host); // needed for domain cookie
TRC2(" CookieData: %s",cookie_data); // inbound cookie string (could be huge)
TRC2(" Authtype : %s",type);
TRC2(" Authorizat: %s",auth_line);
//--------------------------------------------------------------------------
if (auth_line){ // if we have an authorization line
base64_buf = strstr(auth_line,"Basic "); //
if (base64_buf){
base64_buf += 6;
}
decode_buf = ap_pbase64decode(r->pool, base64_buf); //
TRC2("extracted info %s",decode_buf); // user:pass
cursor = decode_buf; //
temp = ap_getword (r->pool, &cursor, ':'); //
strcpy(username,temp);
TRC2("extracted user %s",username); //
temp = ap_getword (r->pool, &cursor, ':'); //
strcpy(password,temp); //
TRC2("extracted pass %s",password); //
}
for (int i=0; i<strlen(username); i++) // on VMS we always upcase: username
username[i] = toupper(username[i]); //
//
// synonyms for the developers
//
if (strcasecmp(username,"NEIL")==0)
sprintf(username,"%s","NS_RIECK");
if (strcasecmp(username,"DAVE")==0)
sprintf(username,"%s","DG_MCNEIL");
if (strcasecmp(username,"STEVE")==0)
sprintf(username,"%s","SM_KENNEL");
if (strcasecmp(username,"KARIM")==0)
sprintf(username,"%s","KA_MACKLAI");
//--------------------------------------------------------------------------
// if a cookie was specified, look for it
//--------------------------------------------------------------------------
if ((sec->fCookieName == NULL) || (cookie_data == NULL)) { // no 'cookie specified' or 'no cookie data'
TRC1("skipping cookie logic"); //
}else{
char *start_cookie, *end_cookie, *payload; //
if (start_cookie = strstr(cookie_data, sec->fCookieName)) { // locate the desired cookie
start_cookie += strlen(sec->fCookieName) + 1; // slide past cookie name (and '=')
end_cookie = (char*) cookie_data + strlen(cookie_data); //
for (char* i=start_cookie;i<=end_cookie;i++) { //
switch(*i) { //
case ';': //
case '\0': //
end_cookie=i; //
break; //
default: //
} //
} //
strncpy(cookie_payload, start_cookie, end_cookie-start_cookie); //
cookie_payload[end_cookie-start_cookie] = '\0'; // ensure string is null terminated
TRC2("Cookie Payload: %s",cookie_payload); //
if (strlen(cookie_payload)>0){ //
score = 1; // indicate we detected the named cookie
} //
} //
} //
//--------------------------------------------------------------------------
// if a username was specified and both username + password are present
//--------------------------------------------------------------------------
if ((!sec->fUserEnable) || // if not enabled
(strlen(password)==0) || // or no password
(strlen(username)==0) ){ // or no username
TRC1("skipping user+pass logic");
}else{
score = score | 2; // indicate we detected user + pass
}
if (score==0)
//--------------------------------------------------------------------------
// if we have no data to send to the authenticator then exit now
//--------------------------------------------------------------------------
if (score==0) { // we have nothing to work with
if (!sec->fUserEnable) { // if username not required
if (sec->fAuthoritative) { // if authoritative
TRC1("no data so HTTP_UNAUTHORIZED"); // the buck stops here
return HTTP_UNAUTHORIZED;
}else{
TRC1("no data so DECLINED");
return DECLINED;
}
}else{ // username required but not provided
//
// this is how we command the client's browser to raise a user+pass dialog
// (he will have a user+pass next time through here)
//
TRC1("no data so throw 401 (to get username+password)");
apr_table_set(r->headers_out, "Cache-Control", "no-cache, no-store");
if (strlen(sec->fRealmName)<10) {
apr_table_setn(r->err_headers_out,
(PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
: "WWW-Authenticate",
apr_pstrcat(r->pool, "Basic realm=\"", default_realm , "\"", NULL));
}else{
apr_table_setn(r->err_headers_out,
(PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
: "WWW-Authenticate",
apr_pstrcat(r->pool, "Basic realm=\"", sec->fRealmName , "\"", NULL));
}
return HTTP_UNAUTHORIZED; //
}
}
#if RMS_SESSION_CACHE==1 //
if (strlen(cookie_payload)>0) { //
junk = sessions_lookup( (char*)&cookie_payload,
(char*)&groupData,
(char*)remote_host); //
TRC2("-i-cache_lookup status: %d",junk); //
if (junk==0) { // 0 means good (unix style)
TRC2("-i-session-group-info : %s",groupData); //
st = 0; // simulate UNIX good
goto skip_user_pass; // don't hate me because I used "goto' :-)
} //
} //
#endif
//
// lookup username + password in our profile database
//
// new_cookie[0] = '\0'; //
junk = profile1_lookup(username, password, (char*)remote_host); // are user+pass valid? (0=good)
TRC2("-i-profile1_lookup: %d",junk); //
if (junk==0) { // if no error
junk = profile2_lookup( username,
(char*)&groupData,
(char*)remote_host); // lookup to create new cookie etc.
TRC2("-i-profile2_lookup: %d",junk); //
}
st = junk; //
//--------------------------------------------------
skip_user_pass:;
TRC2("-i-status: %ld",st);
//
switch(st){ //
case 0: // good
if (strlen(new_cookie)==0){
TRC1("SETCOOKIE data: BLANK");
}else{
TRC2("SETCOOKIE data: %s",new_cookie);
if (sec->fCookieName==NULL) {
TRC1("oops, NO COOKIE NAME defined");
}else{
//
// notes:
// 1) we hope to end up with something like one of these (example two is for a "domain" session cookie)
// ICSIS_SESSION=abcdefghabcdefghabcdefghabcdefgh;
// ICSIS_SESSION=abcdefghabcdefghabcdefghabcdefgh; path=/; HttpOnly; Domain=.kawc09.on.bell.ca
// 2) docs suggest using "apr_table_add()" rather than "apr_table_set()" so I did
// 3) some website say to end with "\n" but that doesn't work here
//
char cookie_hack[128];
sprintf(cookie_hack,"%s%c%s%s%s%s", sec->fCookieName, '=', new_cookie,"; Domain=",
r->server->server_hostname,"; path=/; HttpOnly");
TRC2("SETCOOKIE-HACK: %s",cookie_hack);
apr_table_add(r->headers_out, "Set-Cookie", cookie_hack);
apr_table_set(r->headers_out, "Cache-Control", "no-cache, no-store");
}
}
if (sec->fGroupList) { // if a group list directive is present
if (strlen(groupData)==0) { // if blank...
TRC1("authenticator GROUP data: BLANK"); //
TRC1("forbidden-1"); //
return HTTP_FORBIDDEN; // send back 403
}else{ //
TRC2("authenticator GROUP data: %s",groupData); //
if (!strstr(sec->fGroupList, groupData)) { // if group is not in the defined list
TRC1("forbidden-2"); //
return HTTP_FORBIDDEN; // send back 403
} //
}
}
TRC1("OK"); // yippee!
return OK; // yippee!
default:
//
// this is how we command the client's browser to raise a user+pass dialog
// (he will have a user+pass next time through here)
//
if (strlen(sec->fRealmName)<10){
apr_table_setn(r->err_headers_out,
(PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
: "WWW-Authenticate",
apr_pstrcat(r->pool, "Basic realm=\"", default_realm , "\"", NULL));
}else{
apr_table_setn(r->err_headers_out,
(PROXYREQ_PROXY == r->proxyreq) ? "Proxy-Authenticate"
: "WWW-Authenticate",
apr_pstrcat(r->pool, "Basic realm=\"", sec->fRealmName , "\"", NULL));
}
return HTTP_UNAUTHORIZED; // send back 401
}
}
//=====================================================================================================================
// common apache module stuff
//=====================================================================================================================
static void register_hooks(apr_pool_t *p) {
ap_hook_check_user_id(authenticate_vms_ext,NULL,NULL,APR_HOOK_FIRST); // run before MOD_AUTH(_BASIC)
}
module AP_MODULE_DECLARE_DATA auth_vms_rms_module =
{
STANDARD20_MODULE_STUFF,
create_auth_vms_rms_cntxt, // per dir config creater
NULL, // per dir merger --- default is to override
NULL, // server config
NULL, // merge server config
auth_vms_rms_cmds, // command apr_table_t
register_hooks // register hooks
};
//trek1
//===============================================================================================================================
// support for: profile1
// this file contains usernames + password hashes (no, we are not dumb enough to store raw passwords)
//
// open ( default_node$ + k_fs_pro_auth$ ) as #90 ! profile authentication &
// ,access modify &
// ,allow modify &
// ,organization indexed &
// ,map profile_auth &
// ,primary key d90_username
//===============================================================================================================================
//
// global variables for file 1
//
struct FAB fab1; // file access block (an RMS structure)
struct RAB rab1; // record access block (an RMS structure)
struct XABKEY key10; // extended access block (for each) key
//
#pragma __member_alignment __save
#pragma __nomember_alignment
struct {
char d90_username [99]; // username (space for user=email) key #0 (primary)
GENERIC_64 d90_enc_pwd ; // hashed password (quadword)
unsigned short d90_salt ; // salt
unsigned char d90_enc_type ; // algorithm
char d90_datetime_pwc [14]; // ccyymmddhhmmss
char d90_datetime_login [14]; // ccyymmddhhmmsst
char d90_mixed_case [ 1]; //
char d90_room_to_grow [98]; //
} user_pw_record; //
#pragma __member_alignment __restore
//=======================================================================================
// profile1_lookup
// exit: 0 = good (unix convention)
//=======================================================================================
long profile1_lookup(char *username, char *password, char *remote_address) {
int junk;
int rms_status;
static GENERIC_64 trial_pw_hash; //
struct dsc$descriptor_s user2; //
struct dsc$descriptor_s pass2; //
//
if (strlen(username)==0){
TRC1("profile1_lookup: failed in step 01");
return(-1); // error
}
if (strlen(password)==0){
TRC1("profile1_lookup: failed in step 02");
return(-1); // error
}
TRC2("user: %s",username); //
//-----------------------------------------------------------
// initialize rms (profile1)
//-----------------------------------------------------------
fab1 = cc$rms_fab; // Initialize FAB (be a good citizen)
rab1 = cc$rms_rab; // Initialize RAB (be a good citizen)
key10 = cc$rms_xabkey; // Initialize XAB for our key#0 (primary)
//
// now make changes to the just-initialized fab
//
// fab1.fab$b_bks = 4; // blocksize: 4
fab1.fab$b_fac = FAB$M_GET; // intend to: GET (read)
fab1.fab$l_fna = (char*) &profile1_fs; // file name addr: filename.ext
fab1.fab$b_fns = strlen(profile1_fs); // file name length: whatever
// fab1.fab$l_fop = FAB$M_CIF; // file operation: create if (not found)
fab1.fab$w_mrs = sizeof(user_pw_record); // maximum record size: whatever
fab1.fab$b_org = FAB$C_IDX; // organization: indexed
fab1.fab$b_rat = FAB$M_CR; // record-attribute: <CR>
// fab1.fab$b_rfm = FAB$C_FIX; // format: fixed
// fab1.fab$b_rfm = FAB$C_VAR; // format: variable
fab1.fab$b_shr = FAB$M_NIL; // share: none
fab1.fab$l_xab = &key10; // indicate our primary key
//
rab1.rab$l_fab = &fab1; // now point our rab at our fab
//
// key stuff
//
key10.xab$b_ref = 0; // reference: this is key #0 (primary key)
key10.xab$b_dtp = XAB$C_STG; // key data type: string
key10.xab$b_flg = 0; // key options: clear all flags (nodup, nochange, etc)
key10.xab$w_pos0= (char*) &user_pw_record.d90_username - // start of segment0: compute offset from start of record
(char*) &user_pw_record; //
key10.xab$b_siz0= sizeof(user_pw_record.d90_username); // length of segment0: whatever
//-----------------------------------------------------------
// now open the file
//-----------------------------------------------------------
rms_status = sys$open(&fab1); // use fab to open the file
if (rms_status != RMS$_NORMAL){
TRC2("profile1 open error: %d",rms_status);
return(-1);
}
rms_status = sys$connect(&rab1); // connect rab to fab
if (rms_status != RMS$_NORMAL){ // if some sort of error
TRC2("profile1 connect error: %d",rms_status);
return(-1);
}
//-----------------------------------------------------------
// now use the username to do a primary key lookup
//-----------------------------------------------------------
strcpy(user_pw_record.d90_username, username); // copy desired data into this buffer
for (long i=strlen(username); i<sizeof(user_pw_record.d90_username); i++) {
user_pw_record.d90_username[i] = ' '; // pad with spaces
}
rab1.rab$b_krf = 0; // we want to use key#0 (primary)
rab1.rab$l_kbf = (char *) &user_pw_record.d90_username; // key buf addr: whatever
rab1.rab$b_ksz = sizeof(user_pw_record.d90_username); // key buf size: whatever
rab1.rab$b_rac = RAB$C_KEY; // record access: lookup-by-key
rab1.rab$l_rop = RAB$M_NLK; // record operations: no-lock
rab1.rab$l_ubf = (char *) &user_pw_record; // need for $get (but not $find)
rab1.rab$w_usz = sizeof(user_pw_record); // need for $get (but not $find)
//
rms_status = sys$get(&rab1); // get-by-key
//
switch(rms_status) {
case RMS$_NORMAL:
TRC1("profile1 lookup success");
break; // fall thru to hash generate + compare
case RMS$_RNF:
TRC1("profile1_lookup miss");
junk = sys$close(&fab1); // at this point we will ALWAYS close the file
return(1); //
default:
TRC2("profile1_lookup error: %d",rms_status);
junk = sys$close(&fab1); // at this point we will ALWAYS close the file
return(1);
}
//
// If we get here then the record was found. So use the supplied username + password
// along with the encryption_type and salt to compute a trial_pw_hash
//
junk = sys$close(&fab1); // at this point we will ALWAYS close the file
#define SEE_RECORD 1
#if SEE_RECORD==1
user_pw_record.d90_username[98] = '\0'; // null terminate this mapped string for C
TRC2("d90_username : %s", user_pw_record.d90_username );
TRC2("d90_enc_type : %d", user_pw_record.d90_enc_type );
TRC2("d90_salt : %d", user_pw_record.d90_salt );
TRC2("d90_mixed_case: %c", atoi(user_pw_record.d90_mixed_case) );
TRC2("d90_enc_pwd : %lld", user_pw_record.d90_enc_pwd.gen64$q_quadword); // yep, this line is for real
#endif
// if (d90_mixed_case!='Y') // we DO NOT support mixed case passwords at this time
for (int i=0; i<strlen(password); i++) // upcase the password
password[i] = toupper(password[i]); //
//
// brain damaged moment: be sure to call VMSIFY on password after we upcase it
//
VMSIFY(user2,username); // sys$hash_password requires string descriptors
TRC2("pass: %s",password); // sys$hash_password requires string descriptors
VMSIFY(pass2,password); //
junk = sys$hash_password( &pass2,
user_pw_record.d90_enc_type,
user_pw_record.d90_salt,
&user2,
&trial_pw_hash);
TRC2("rc: %d", junk);
TRC2("d90_enc_pwd : %lld", trial_pw_hash.gen64$q_quadword);// yep, this line is for real
//spock
if (user_pw_record.d90_enc_pwd.gen64$q_quadword ==
trial_pw_hash.gen64$q_quadword )
{
TRC1("password is valid");
junk = sessions_write(username,remote_address); // generate a new COOKIE, etc.
return(0); // zero means "no errors" (unix convention)
}else{
TRC1("password is not valid");
return(2); // two means: vms-e-
}
}
//trek2
//===============================================================================================================================
// support for: profile2
// this file contains user profile data
//
// open ( default_node$ + k_fs_pro_empl$ ) as #92 ! employee-db &
// ,access modify &
// ,allow modify &
// ,organization indexed &
// ,map my_disk &
// ,primary key (d91_last_name ,d91_grp ) duplicates &
// ,alternate key (d91_last_name ,d91_pin ) changes &
// ,alternate key (d91_org_code ,d91_last_name ) duplicates changes &
// ,alternate key (d91_pin ) changes &
// ,alternate key (d91_grp ,d91_init ) changes &
// ,alternate key (d91_cell_phone ) duplicates changes &
// ,alternate key (d91_csmis_id ) duplicates changes
//===============================================================================================================================
//
// global variables for file 2
//
struct FAB fab2; // file access block (an RMS structure)
struct RAB rab2; // record access block (an RMS structure)
struct XABKEY key20, // extended access block (for each) key
key21,
key22,
key23,
key24,
key25,
key26;
//
struct {
char d91_grp [ 3]; // csm group name
char d91_csmis_id [12]; // csmis id
char d91_last_name [20]; // given name
char d91_first_name [15]; // surname
char d91_init [ 3]; // initials
char d91_inactive [ 1]; // inactive flag
char d91_pin [ 7]; // pin
char d91_labour [ 5]; // labour rate (now: S.O.T.)
char d91_job_code [ 3]; // job code from nomas
char d91_pref_prog [ 3]; // what program to run
char d91_alerts [ 5]; // alert option bits
char d91_work_phone [10]; // work phone 10 digits
char d91_home_phone [10]; // home phone 10 digits
char d91_cell_phone [10]; // cell phone 10 digits
char d91_pager_num [10]; // pager 10 digits
char d91_pager_type [ 1]; // type of pager a/n/t
char d91_ardis_num [ 8]; // mobile term num (T.O.D.)
char d91_ardis_type [ 1]; // hand held term (NOMAS Flag)
char d91_org_code [ 8]; // org code
char d91_title [ 3]; // csmis title
char d91_report_centre [12]; // home office
char d91_safety [ 1]; // auto safety check
char d91_printer [ 3]; // default printer
char d91_yada [ 5]; // application privs (20-bits)
char d91_language [ 1]; // default language
char d91_mail_service [ 3]; // service of choice
char d91_mail_id [39]; // service id
char d91_system [20]; // system
char d91_skill [ 1]; // skills
char d91_callout [ 1]; // callout a.....z
char d91_trained [ 8]; // date last trained
char d91_notes [42]; // notes
char d91_region [ 1]; // O/ntario, Q/uebec, A/liant
char d91_tier [ 1]; // level: E/C/D
char d91_reports_to [ 7]; // PIN of manager
char d91_bu [ 3]; // primpary business unit
char d91_priv [ 8]; // common app privs 32-bits
char d91_priv_js [10]; // common app privs 32-bits
char d91_vehicle [10]; // tech's vehicle number
char d91_vehicle_park [30]; // where normally parked
char d91_filler [20]; // room to grow ...
} employee_record; //
//=======================================================================================
// profile2_lookup
// entry: username (used in the primary key lookup)
// remote_address (user when creating the new cookie)
//=======================================================================================
long profile2_lookup(char *username, char *groupData, char *remote_address) {
int junk;
int rms_status;
if (strlen(username)==0){ //
TRC1("profile2_lookup: failed in step 01"); //
return(-1); // error
}
//-----------------------------------------------------------
// initialize rms (profile 2)
//-----------------------------------------------------------
fab2 = cc$rms_fab; // Initialize FAB (be a good citizen)
rab2 = cc$rms_rab; // Initialize RAB (be a good citizen)
key20 = cc$rms_xabkey; // Initialize XAB for our key#0 (primary)
key21 = cc$rms_xabkey; // Initialize XAB for our key#1 (alternate)
key22 = cc$rms_xabkey; // Initialize XAB for our key#2 (alternate)
key23 = cc$rms_xabkey; // Initialize XAB for our key#3 (alternate)
key24 = cc$rms_xabkey; // Initialize XAB for our key#4 (alternate)
key25 = cc$rms_xabkey; // Initialize XAB for our key#5 (alternate)
key26 = cc$rms_xabkey; // Initialize XAB for our key#6 (alternate)
//
// now make changes to the just-initialized fab
//
// fab2.fab$b_bks = 4; // blocksize: 4
fab2.fab$b_fac = FAB$M_GET; // intend to: GET (read)
fab2.fab$l_fna = (char*) &profile2_fs; // file name addr: filename.ext
fab2.fab$b_fns = strlen(profile2_fs); // file name length: whatever
// fab2.fab$l_fop = FAB$M_CIF; xx file operation: create if (not found)
fab2.fab$w_mrs = sizeof(employee_record); // maximum record size: whatever
fab2.fab$b_org = FAB$C_IDX; // organization: indexed
fab2.fab$b_rat = FAB$M_CR; // record-attribute: <CR>
// fab2.fab$b_rfm = FAB$C_FIX; // format: fixed
fab2.fab$b_shr = FAB$M_NIL; // share: none
fab2.fab$l_xab = &key10; // indicate our primary key
//
rab2.rab$l_fab = &fab2; // now point our rab at our fab
//
// key stuff
//
key20.xab$b_ref = 0; // reference: this is key #0 (primary key)
key20.xab$b_dtp = XAB$C_STG; // key data type: string
key20.xab$b_flg = XAB$M_DUP; // key options: dups
key20.xab$w_pos0= (char*) &employee_record.d91_last_name - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key20.xab$b_siz0= sizeof(employee_record.d91_last_name); // length of segment0: whatever
key20.xab$w_pos1= (char*) &employee_record.d91_grp - // start of segmentt1: whatever
(char*) &employee_record; //
key20.xab$b_siz1= sizeof(employee_record.d91_grp); // length of segment1: whatever
key20.xab$l_nxt = &key21; // next xab address
//
key21.xab$b_ref = 1; // reference: this is key #1 (alternate)
key21.xab$b_dtp = XAB$C_STG; // key data type: string
key21.xab$b_flg = XAB$M_CHG; // key options: changes
key21.xab$w_pos0= (char*) &employee_record.d91_last_name - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key21.xab$b_siz0= sizeof(employee_record.d91_last_name); // length of segment0: whatever
key21.xab$w_pos1= (char*) &employee_record.d91_pin - // start of segmentt1: whatever
(char*) &employee_record; //
key21.xab$b_siz1= sizeof(employee_record.d91_pin); // length of segment1: whatever
key21.xab$l_nxt = &key22; // next xab address
//
key22.xab$b_ref = 2; // reference: this is key #2 (alternate)
key22.xab$b_dtp = XAB$C_STG; // key data type: string
key22.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: duplicates + changes
key22.xab$w_pos0= (char*) &employee_record.d91_org_code - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key22.xab$b_siz0= sizeof(employee_record.d91_org_code); // length of segment0: whatever
key22.xab$w_pos1= (char*) &employee_record.d91_last_name - // start of segmentt1: whatever
(char*) &employee_record; //
key22.xab$b_siz1= sizeof(employee_record.d91_last_name); // length of segment1: whatever
key22.xab$l_nxt = &key23; // next xab address
//
key23.xab$b_ref = 3; // reference: this is key #3 (alternate)
key23.xab$b_dtp = XAB$C_STG; // key data type: string
key23.xab$b_flg = XAB$M_CHG; // key options: changes
key23.xab$w_pos0= (char*) &employee_record.d91_pin - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key23.xab$b_siz0= sizeof(employee_record.d91_pin); // length of segment0: whatever
key23.xab$l_nxt = &key24; // next xab address
//
key24.xab$b_ref = 4; // reference: this is key #4 (alternate)
key24.xab$b_dtp = XAB$C_STG; // key data type: string
key24.xab$b_flg = XAB$M_CHG; // key options: changes
key24.xab$w_pos0= (char*) &employee_record.d91_grp - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key24.xab$b_siz0= sizeof(employee_record.d91_grp); // length of segment0: whatever
key24.xab$w_pos1= (char*) &employee_record.d91_init - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key24.xab$b_siz1= sizeof(employee_record.d91_init); // length of segment0: whatever
key24.xab$l_nxt = &key25; // next xab address
//
key25.xab$b_ref = 5; // reference: this is key #5 (alternate)
key25.xab$b_dtp = XAB$C_STG; // key data type: string
key25.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: duplicates + changes
key25.xab$w_pos0= (char*) &employee_record.d91_cell_phone - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key25.xab$b_siz0= sizeof(employee_record.d91_cell_phone); // length of segment0: whatever
key25.xab$l_nxt = &key26; // next xab address
//
key26.xab$b_ref = 6; // reference: this is key #6 (alternate)
key26.xab$b_dtp = XAB$C_STG; // key data type: string
key26.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: duplicates + changes
key26.xab$w_pos0= (char*) &employee_record.d91_csmis_id - // start of segment0: compute offset from start of record
(char*) &employee_record; //
key26.xab$b_siz0= sizeof(employee_record.d91_csmis_id); // length of segment0: whatever
//-----------------------------------------------------------
// now open the file
//-----------------------------------------------------------
rms_status = sys$open(&fab2); // use fab to open the file
if (rms_status != RMS$_NORMAL){
TRC2("profile2 open error: %d",rms_status);
return(-1);
}
rms_status = sys$connect(&rab2); // connect rab to fab
if (rms_status != RMS$_NORMAL){ // if some sort of error
TRC2("profile2 connect error: %d",rms_status);
return(-1);
}
//-----------------------------------------------------------
// now use username to do a key-6 lookup
//-----------------------------------------------------------
strcpy(employee_record.d91_csmis_id,username); // copy desired data into this buffer
for (int i=strlen(username); i<sizeof(employee_record.d91_csmis_id); i++)
employee_record.d91_csmis_id[i] = ' '; // pad with spaces
rab2.rab$b_krf = 6; // we want to use key#6 (alternate)
rab2.rab$l_kbf = (char *) &employee_record.d91_csmis_id; // key buf addr: whatever
rab2.rab$b_ksz = sizeof(employee_record.d91_csmis_id); // key buf size: whatever
rab2.rab$b_rac = RAB$C_KEY; // record access: lookup-by-key
rab2.rab$l_rop = RAB$M_NLK; // record operations: no-lock
rab2.rab$l_ubf = (char *) &employee_record; // need for $get (but not $find)
rab2.rab$w_usz = sizeof(employee_record); // need for $get (but not $find)
//
rms_status = sys$get(&rab2); // get-by-key
//
switch(rms_status) {
case RMS$_NORMAL:
TRC1("profile2 lookup success");
//
// in our system, business unit is used in group restriction
//
strncpy(groupData, employee_record.d91_bu, sizeof(employee_record.d91_bu));
groupData[ sizeof(employee_record.d91_bu) ] = '\0'; //
TRC2("-i-session bu : %s", groupData); //
//
junk = sys$close(&fab2); // at this point we will ALWAYS close the file
return(0); // zero means "no errors" (unix convention)
case RMS$_RNF:
TRC1("profile2_lookup miss");
junk = sys$close(&fab2); // at this point we will ALWAYS close the file
return(1); //
default:
TRC2("profile2_lookup error: %d",rms_status);
junk = sys$close(&fab2); // at this point we will ALWAYS close the file
return(1);
}
}
#if RMS_SESSION_CACHE==1 // enable support for RMS-based session cache
//===============================================================================================================================
// This stuff is for an optional RMS-based session cache
// Note: RMS is an ISAM technology only availble on VMS and OpenVMS
//
// technology: ISAM databases relational databases
// ============== ====================
// terminology: "keys" "indexes"
// "key options" "contraints"
//===============================================================================================================================
//
// global variables for file 0
//
struct FAB fab0; // file access block (an RMS structure)
struct RAB rab0; // record access block (an RMS structure)
struct XABKEY key00, // extended access block (for each) key
key01, // first alternate key
key02; // second alternate key
//
// the is the record layout for our sessions database
//
struct {
char icsis_session_id [32]; // 128-bit session ID (cookie) key #0 (primary)
char icsis_session_pin [ 7]; // employee pin key #1 (alternate,dups,changes)
char icsis_session_priv [ 8]; // copied from d91_priv (cached)
char icsis_session_title [ 3]; // copied from d91_title (cached)
char icsis_session_ip [15]; // ip address where the logon took place
char icsis_session_timestamp[15]; // ccyymmddhhmmsst key #2 (alternate,dups,changes)
char icsis_session_grp [ 3]; // copied from d91_grp (cached)
char icsis_session_ini [ 3]; // copied from d91_ini (cached)
char icsis_session_org [ 8]; // copied from d91_org_code (cached)
char icsis_session_name [35]; // copied from d91_first_name +" "+ d91_last_name
char icsis_session_script [50]; //
char icsis_session_region [ 1]; // copied from d91_region (cached)
char icsis_session_language [ 1]; // copied from d91_language (cached)
char icsis_session_jobcode [ 3]; // copied from schedule at login (cached)
char icsis_session_bu [ 3]; // copied from d91_bu (cached)
char icsis_session_room [13]; // room too grow
} session_record;
//=======================================================================================
// sessions lookup (cookie cache)
// it is assumed that another routine elsewhere is clearing out stale records
//=======================================================================================
long sessions_lookup(char *cookieData, char *groupData, char *remote_address) {
int junk;
int rms_status;
char temp1[32];
if (strlen(cookieData)==0) {
TRC1("sessions_lookup: failed in step 01");
return(-1); // error
}
//-----------------------------------------------------------
// initialize rms (session)
//-----------------------------------------------------------
fab0 = cc$rms_fab; // Initialize FAB (be a good citizen)
rab0 = cc$rms_rab; // Initialize RAB (be a good citizen)
key00 = cc$rms_xabkey; // Initialize XAB for our key#0 (primary)
key01 = cc$rms_xabkey; // Initialize XAB for our key#1 (alternate)
key02 = cc$rms_xabkey; // Initialize XAB for our key#2 (alternate)
//
// now make changes to the just-initialized fab
//
// fab0.fab$b_bks = 4; // blocksize: 4
fab0.fab$b_fac = FAB$M_GET ; // intend to: GET (read)
fab0.fab$l_fna = (char*) &sessions_fs; // file name addr: filename.ext
fab0.fab$b_fns = strlen(sessions_fs); // file name length: whatever
fab0.fab$l_fop = FAB$M_CIF; // file operation: create if (not found)
fab0.fab$w_mrs = sizeof(session_record); // maximum record size: whatever
fab0.fab$b_org = FAB$C_IDX; // organization: indexed
fab0.fab$b_rat = FAB$M_CR; // record-attribute: <CR>
// fab0.fab$b_rfm = FAB$C_FIX; // format: fixed
fab0.fab$b_shr = FAB$M_NIL; // share: none
fab0.fab$l_xab = &key00; // indicate our primary key
//
rab0.rab$l_fab = &fab0; // now point our rab at our fab
//
// key stuff
//
key00.xab$b_ref = 0; // reference: this is key #0 (primary key)
key00.xab$b_dtp = XAB$C_STG; // key data type: string
key00.xab$b_flg = 0; // key options: clear all flags (nodup, nochange, etc)
key00.xab$w_pos0= (char*) &session_record.icsis_session_id - // start of segment0: compute offset from start of record
(char*) &session_record; //
key00.xab$b_siz0= sizeof(session_record.icsis_session_id); // length of segment0: whatever
key00.xab$l_nxt = &key01; // next xab address:
//
// now make changes to the just initialized xab (this one is chained to the previous xab)
//
key01.xab$b_ref = 1; // reference: this is key #1
key01.xab$b_dtp = XAB$C_STG; // key data type: string
key01.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: DUP + CHANGE
key01.xab$w_pos0 = (char*) &session_record.icsis_session_pin- // start of segment0: offset from start of record
(char*) &session_record; //
key01.xab$b_siz0= sizeof(session_record.icsis_session_pin); // length of segment0: whatever
key01.xab$l_nxt = &key02; // next xab address:
//
// now make changes to the just initialized xab (this one is chained to the previous xab)
//
key02.xab$b_ref = 2; // reference: this is key #2
key02.xab$b_dtp = XAB$C_STG; // key data type: string
key02.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: DUP + CHANGE
key02.xab$w_pos0 = // start of segment0: offset from start of record
(char*) &session_record.icsis_session_timestamp - //
(char*) &session_record; //
key02.xab$b_siz0= // length of segment0: whatever
sizeof(session_record.icsis_session_timestamp);
//-----------------------------------------------------------
// now open the file
//-----------------------------------------------------------
rms_status = sys$open(&fab0); // use fab to open the file
if (rms_status != RMS$_NORMAL){
TRC2("sessions_lookup open error: %d",rms_status);
return(-1);
}
rms_status = sys$connect(&rab0); // connect rab to fab
if (rms_status != RMS$_NORMAL){ // if some sort of error
TRC2("sessions_lookup connect error: %d",rms_status);
return(-1);
}
//-----------------------------------------------------------
// now use the cookie to do a primary key lookup
//-----------------------------------------------------------
rab0.rab$b_krf = 0; // we want to use key#0 (primary)
rab0.rab$l_kbf = cookieData; // key buf addr: whatever
rab0.rab$b_ksz = sizeof(session_record.icsis_session_id); // key buf size: whatever
rab0.rab$b_rac = RAB$C_KEY; // record access: lookup-by-key
rab0.rab$l_rop = RAB$M_NLK; // record operations: no-lock
rab0.rab$l_ubf = (char *) &session_record; // need for $get (but not $find)
rab0.rab$w_usz = sizeof(session_record); // need for $get (but not $find)
//
rms_status = sys$get(&rab0); // get-by-key
//
switch(rms_status) {
case RMS$_NORMAL:
TRC1("sessions_lookup success (cookie found)");
//
strncpy(temp1, session_record.icsis_session_pin, sizeof(session_record.icsis_session_pin));
temp1[ sizeof(session_record.icsis_session_pin) ] = '\0';
TRC2("-i-session pin: %s", temp1);
//
// in our system, "business unit" is used in group restriction
//
strncpy(temp1, session_record.icsis_session_bu, sizeof(session_record.icsis_session_bu));
temp1[ sizeof(session_record.icsis_session_bu) ] = '\0';
TRC2("-i-session bu : %s", temp1);
//
// now save BU + GRP as comma-delimited data in the global variable "group"
//
strcpy(groupData,temp1);
TRC2("-i-groupData : %s",groupData);
//
junk = sys$close(&fab0); // at this point we will ALWAYS close the file
return(0); // zero means "no errors"; OKAY TO SERVE REQUEST
case RMS$_RNF:
TRC1("sessions_lookup failed");
junk = sys$close(&fab0); // at this point we will ALWAYS close the file
return(1); //
default:
TRC2("sessions_lookup error: %d",rms_status);
junk = sys$close(&fab0); // at this point we will ALWAYS close the file
return(1);
}
}
//=======================================================================================
// sessions write (create a cookie then save it in the sessions database
//=======================================================================================
long sessions_write(char *uname, char *remote_address) {
char *p1,*p2, *p3;
int junk;
int rms_status;
char temp1[99]; // large enough for various things
//
if (strlen(uname)==0) {
TRC1("sessions_write: failed in step 01");
return(-1); // error
}
//-----------------------------------------------------------
// initialize rms
//-----------------------------------------------------------
fab0 = cc$rms_fab; // Initialize FAB (be a good citizen)
rab0 = cc$rms_rab; // Initialize RAB (be a good citizen)
key00 = cc$rms_xabkey; // Initialize XAB for our key#0 (primary)
key01 = cc$rms_xabkey; // Initialize XAB for our key#1 (alternate)
key02 = cc$rms_xabkey; // Initialize XAB for our key#2 (alternate)
//
// now make changes to the just-initialized fab
//
// fab0.fab$b_bks = 4; // blocksize: 4
fab0.fab$b_fac = FAB$M_PUT ; // intend to: PUT (write)
fab0.fab$l_fna = (char*) &sessions_fs; // file name addr: filename.ext
fab0.fab$b_fns = strlen(sessions_fs); // file name length: whatever
// fab0.fab$l_fop = FAB$M_CIF; xx file operation: create if (not found)
fab0.fab$w_mrs = sizeof(session_record); // maximum record size: whatever
fab0.fab$b_org = FAB$C_IDX; // organization: indexed
fab0.fab$b_rat = FAB$M_CR; // record-attribute: <CR>
// fab0.fab$b_rfm = FAB$C_FIX; // format: fixed
fab0.fab$b_shr = FAB$M_NIL; // share: none
fab0.fab$l_xab = &key00; // indicate our primary key
//
rab0.rab$l_fab = &fab0; // now point our rab at our fab
//
// key stuff
//
key00.xab$b_ref = 0; // reference: this is key #0 (primary key)
key00.xab$b_dtp = XAB$C_STG; // key data type: string
key00.xab$b_flg = 0; // key options: clear all flags (nodup, nochange, etc)
key00.xab$w_pos0= (char*) &session_record.icsis_session_id - // start of segment0: compute offset from start of record
(char*) &session_record; //
key00.xab$b_siz0= sizeof(session_record.icsis_session_id); // length of segment0: whatever
key00.xab$l_nxt = &key01; // next xab address:
//
// now make changes to the just initialized xab (this one is chained to the previous xab)
//
key01.xab$b_ref = 1; // reference: this is key #1
key01.xab$b_dtp = XAB$C_STG; // key data type: string
key01.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: DUP + CHANGE
key01.xab$w_pos0 = (char*) &session_record.icsis_session_pin- // start of segment0: offset from start of record
(char*) &session_record; //
key01.xab$b_siz0= sizeof(session_record.icsis_session_pin); // length of segment0: whatever
key01.xab$l_nxt = &key02; // next xab address:
//
// now make changes to the just initialized xab (this one is chained to the previous xab)
//
key02.xab$b_ref = 2; // reference: this is key #2
key02.xab$b_dtp = XAB$C_STG; // key data type: string
key02.xab$b_flg = XAB$M_DUP | XAB$M_CHG; // key options: DUP + CHANGE
key02.xab$w_pos0 = // start of segment0: offset from start of record
(char*) &session_record.icsis_session_timestamp - //
(char*) &session_record; //
key02.xab$b_siz0= // length of segment0: whatever
sizeof(session_record.icsis_session_timestamp);
//-----------------------------------------------------------
// now open the file
//-----------------------------------------------------------
rms_status = sys$open(&fab0); // use fab to open the file
if (rms_status != RMS$_NORMAL){
TRC2("sessions_write open error: %d",rms_status);
return(-1);
}
rms_status = sys$connect(&rab0); // connect rab to fab
if (rms_status != RMS$_NORMAL){ // if some sort of error
TRC2("sessions_write connect error: %d",rms_status);
return(-1);
}
//-----------------------------------------------------------
// now prepare to write a record
//-----------------------------------------------------------
//
// setup data for presentation to TEA encrypt (must be 16 bytes for now)
// note: the encoded data string is currently 16 bytes long; the first bytes consist of the username
// whilst the remainder consist of the last chunk of a 15-byte time stamp
//
build_cookie_stamp(); // populate ccyymmddhhmmsst
junk = strlen(uname); // this could be any length up to 15 bytes
strcpy(temp1,ccyymmddhhmmsst+junk-1); // middle to the end
sprintf(new_data,"%s%s",uname,temp1); //
TRC2("hack-1 %s",uname);
TRC2("hack-2 %s",ccyymmddhhmmsst);
TRC2("hack-3 %s",temp1);
TRC2("hack-4 %s",new_data);
junk = wcsm_c_encrypt(new_data,new_cookie,k_key_file$); //
if (junk!=1){
TRC2("wcsm_c_encrypt status: %d",junk);
TRC2("wcsm_c_encrypt msg: %s",new_cookie);
}else{
TRC2("new_cookie: %s",new_cookie);
}
//
// now data-fill the record
//
for (int i=0; i<sizeof(session_record); i++) //
session_record.icsis_session_id[i]=' '; // blank this record with spaces (BASIC-style map)
memcpy(session_record.icsis_session_id ,new_cookie ,sizeof(new_cookie) );
memcpy(session_record.icsis_session_pin ,employee_record.d91_pin ,sizeof(employee_record.d91_pin) );
memcpy(session_record.icsis_session_priv ,employee_record.d91_priv ,sizeof(employee_record.d91_priv) );
memcpy(session_record.icsis_session_title ,employee_record.d91_title ,sizeof(employee_record.d91_title) );
memcpy(session_record.icsis_session_ip ,remote_address ,strlen(remote_address) );
memcpy(session_record.icsis_session_timestamp,ccyymmddhhmmsst ,sizeof(ccyymmddhhmmsst) );
memcpy(session_record.icsis_session_grp ,employee_record.d91_grp ,sizeof(employee_record.d91_grp) );
memcpy(session_record.icsis_session_ini ,employee_record.d91_init ,sizeof(employee_record.d91_init) );
memcpy(session_record.icsis_session_org ,employee_record.d91_org_code ,sizeof(employee_record.d91_org_code) );
//
// now copy space-padded FIRST NAME and space-padded LAST NAME
//
temp1[0] = '\0'; // init
p1 = (char*) &temp1; // init
p2 = (char*) &employee_record.d91_first_name; // init
p3 = strstr(employee_record.d91_first_name," "); // locate the first <space>
if (p3!=NULL){ // if found
p3--;
while (p1<p3) {
*p1++ = *p2++;
}
}
*p1++ = ' ';
p2 = (char*) &employee_record.d91_last_name; //
p3 = strstr(employee_record.d91_last_name," "); //
if (p3!=NULL){ // if found
p3--;
while (p1<p3) {
*p1++ = *p2++;
}
}
*p1++ = '\0';
memcpy(session_record.icsis_session_name ,temp1 ,strlen(temp1) );
memcpy(session_record.icsis_session_script ,"mod_auth_vms_rms.c" ,18 );
memcpy(session_record.icsis_session_region ,employee_record.d91_region ,sizeof(employee_record.d91_region) );
memcpy(session_record.icsis_session_language ,employee_record.d91_language ,sizeof(employee_record.d91_language) );
memcpy(session_record.icsis_session_jobcode ,employee_record.d91_job_code ,sizeof(employee_record.d91_job_code) );
memcpy(session_record.icsis_session_bu ,employee_record.d91_bu ,sizeof(employee_record.d91_bu) );
// memcpy(session_record.icsis_session_room room to grow
//
rab0.rab$l_rbf = (char *) &session_record;
rab0.rab$w_rsz = sizeof(session_record);
//
rms_status = sys$put(&rab0); // get-by-key
//
switch(rms_status) {
case RMS$_NORMAL: // no issues
case RMS$_OK_DUP: // one key was a duplicate but this is not an error
TRC1("sessions_write success (cookie stored)");
junk = sys$close(&fab0); // at this point we will ALWAYS close the file
return(0); // zero means "no errors"; OKAY TO SERVE REQUEST
default:
TRC2("session_write error: %d",rms_status);
junk = sys$close(&fab0); // at this point we will ALWAYS close the file
return(1);
}
}
#endif
Back to
Home
Neil Rieck
Waterloo, Ontario, Canada.