CGIplus-enabled Run-time Environment Example
--------------------------------------------
***** FIRST, EVIDENCE OF PERSISTANCE *****
Usage Count: 1
***** SECOND, THE CGI ENVIRONMENT AVAILABLE *****
WWW_AUTH_TYPE=
WWW_CONTENT_LENGTH=0
WWW_CONTENT_TYPE=
WWW_DOCUMENT_ROOT=
WWW_GATEWAY_BG=BG2315:
WWW_GATEWAY_INTERFACE=CGI/1.1
WWW_GATEWAY_EOF=$Z-970FB1A4753A94556DC61912-
WWW_GATEWAY_EOT=$D-0FF9FD6B7A795DB09AA1F5F1-
WWW_GATEWAY_ESC=$E-03202EFE522687674521A87C-
WWW_GATEWAY_MRS=4492
WWW_HTTP_ACCEPT=*/*
WWW_HTTP_ACCEPT_ENCODING=gzip, br, zstd, deflate
WWW_HTTP_HOST=polarhome.com:703
WWW_HTTP_USER_AGENT=Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com)
WWW_PATH_INFO=
WWW_PATH_TRANSLATED=
WWW_QUERY_STRING=
WWW_REMOTE_ADDR=18.118.208.127
WWW_REMOTE_HOST=18.118.208.127
WWW_REMOTE_PORT=16145
WWW_REMOTE_USER=
WWW_REQUEST_METHOD=GET
WWW_REQUEST_SCHEME=http:
WWW_REQUEST_TIME_GMT=Thu, 23 Jan 2025 03:15:57 GMT
WWW_REQUEST_TIME_LOCAL=Thu, 23 Jan 2025 05:15:57
WWW_REQUEST_URI=/rtbin/track.c
WWW_SCRIPT_FILENAME=WASD_ROOT:[SRC.HTTPD]TRACK.C
WWW_SCRIPT_NAME=/rtbin/track.c
WWW_SCRIPT_RTE=cgi-bin:[000000]rte_example.exe
WWW_SERVER_ADDR=192.168.10.2
WWW_SERVER_CHARSET=ISO-8859-1
WWW_SERVER_GMT=+02:00
WWW_SERVER_NAME=vax.polarhome.com
WWW_SERVER_PROTOCOL=HTTP/1.1
WWW_SERVER_PORT=80
WWW_SERVER_SIGNATURE=
WASD/10.3.0 Server at vax.polarhome.com Port 80
WWW_SERVER_SOFTWARE=HTTPd-WASD/10.3.0 OpenVMS/VAX
WWW_UNIQUE_ID=Z5HQjQAAAAQAAAIeLQ4
WWW_SECURITY_STATUS=NONE
WWW_KEY_COUNT=0
***** THIRD, AN "INTERPRETED" FILE (WWW_SCRIPT_NAME/WWW_SCRIPT_FILENAME) *****
[0001] /*****************************************************************************/
[0002] /*
[0003] track.c
[0004]
[0005] Track site usage by individual browser sessions. This parallels the
[0006] functionality of the Apache "mod_usertrack" module in that it provides the
[0007] capability to track a user's path through a site or domain of sites using
[0008] cookie technology.
[0009]
[0010] The track is accomplished by creating a unique ID for an initial request. This
[0011] is a globally and temporally unique string (see GenerateUniqueId() in SUPPORT.C
[0012] module). This string is then placed into the site's access logs (either as the
[0013] common format remote ID field, or in a custom log position) and can then be
[0014] tracked through the site or across multiple WASD sites in an organisation (if a
[0015] domain is specified).
[0016]
[0017] By default the track is confined to the single (virtual) server and to a single
[0018] browser session (terminated by the browser being closed). If the configuration
[0019] specifies multiple sessions a cookie expiry date well in the future is added to
[0020] "encourage" the browser to keep the cookie between sessions. Also, if the
[0021] configuration specifies a domain the cookie will also include a domain
[0022] specification, ensuring the same cookie (and unique ID) is sent with all
[0023] requests to servers within that domain.
[0024]
[0025] As it is not possible to insert response header fields (i.e. the cookie) into
[0026] non-parsed header script responses (those that supply a full HTTP response)
[0027] this approach cannot be used to *set* track cookies from such responses, but if
[0028] already set in the browser these responses will be tracked like any other.
[0029] Note also that this is a Netscape-compatible (non RFC) cookie format.
[0030]
[0031] For administrative/experimental/investigative purposes a track cookie may
[0032] cancelled (expired) by accessesing the path "/httpd/-/track/cancel".
[0033]
[0034]
[0035] CONFIGURATION DIRECTIVES
[0036] ------------------------
[0037] [Track] enables/disables per-server tracking
[0038] [TrackMultiSession] enables/enables tracking across multiple sessions
[0039] [TrackDomain] in the form ".org.domain" (two periods) for the major
[0040] top-level domains (e.g. ".com", ".edu", etc.), or
[0041] ".org.group.domain" (three periods) for others
[0042]
[0043] By default non-proxy services are enabled, proxy services disabled.
[0044] The per-service ";track"/";notrack" parameters further allow the
[0045] enabling/disabling of tracking on a per-service basis.
[0046]
[0047]
[0048] VERSION HISTORY
[0049] ---------------
[0050] 04-AUG-2001 MGD support module WATCHing
[0051] 07-MAY-2000 MGD initial (I really just wanted to fool around with cookies ;^)
[0052] */
[0053] /*****************************************************************************/
[0054]
[0055] #ifdef WASD_VMS_V7
[0056] #undef _VMS__V6__SOURCE
[0057] #define _VMS__V6__SOURCE
[0058] #undef __VMS_VER
[0059] #define __VMS_VER 70000000
[0060] #undef __CRTL_VER
[0061] #define __CRTL_VER 70000000
[0062] #endif
[0063]
[0064] #include
[0065] #include
[0066]
[0067] #include "wasd.h"
[0068]
[0069] #define WASD_MODULE "TRACK"
[0070]
[0071] /******************/
[0072] /* global storage */
[0073] /******************/
[0074]
[0075] char TrackCookieName [] = TRACK_COOKIE_NAME;
[0076] int TrackCookieNameLength = sizeof(TrackCookieName)-1;
[0077]
[0078] /********************/
[0079] /* external storage */
[0080] /********************/
[0081]
[0082] extern CONFIG_STRUCT Config;
[0083] extern WATCH_STRUCT Watch;
[0084]
[0085] /*****************************************************************************/
[0086] /*
[0087] Generate a globally unique ID for this request and create a "WASDtrack" cookie
[0088] to contain it.
[0089] */
[0090]
[0091] TrackSetCookie (REQUEST_STRUCT *rqptr)
[0092]
[0093] {
[0094] int idx;
[0095] unsigned short Length;
[0096] char *cptr;
[0097] char Buffer [256];
[0098]
[0099] /*********/
[0100] /* begin */
[0101] /*********/
[0102]
[0103] if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD__OTHER))
[0104] WatchThis (rqptr, FI_LI, WATCH_MOD__OTHER, "TrackSetCookie()");
[0105]
[0106] /* this fits, they're both based on UNIQUE_ID_SIZE */
[0107] strcpy (rqptr->TrackId, GenerateUniqueId(rqptr));
[0108] FaoToBuffer (Buffer, sizeof(Buffer), &Length, "!AZ=!AZ; path=/;!&@!&@",
[0109] TrackCookieName, rqptr->TrackId,
[0110] Config.cfTrack.Domain[0] ?
[0111] " domain=!AZ;" : "!+", Config.cfTrack.Domain,
[0112] Config.cfTrack.MultiSession ?
[0113] " expires=Wed, 13 Jan 2038 14:00:00 GMT;" : "");
[0114]
[0115] cptr = VmGetHeap (rqptr, Length+1);
[0116] for (idx = 0; idx < RESPONSE_COOKIE_MAX; idx++)
[0117] {
[0118] if (!rqptr->rqResponse.CookiePtr[idx])
[0119] {
[0120] memcpy (rqptr->rqResponse.CookiePtr[idx] = cptr, Buffer, Length+1);
[0121] break;
[0122] }
[0123] }
[0124]
[0125] if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST))
[0126] WatchThis (rqptr, FI_LI, WATCH_REQUEST,
[0127] "TRACK set \"!AZ\"", rqptr->TrackId);
[0128] }
[0129]
[0130] /*****************************************************************************/
[0131] /*
[0132] Search the request cookie header field for the "WASDtrack" name-value pair. If
[0133] found copy the value into the request structures track ID field after some
[0134] simple integrity checking.
[0135] */
[0136]
[0137] BOOL TrackGetCookie (REQUEST_STRUCT *rqptr)
[0138]
[0139] {
[0140] char *cptr, *mptr, *sptr, *zptr;
[0141]
[0142] /*********/
[0143] /* begin */
[0144] /*********/
[0145]
[0146] if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD__OTHER))
[0147] WatchThis (rqptr, FI_LI, WATCH_MOD__OTHER, "TrackGetCookie()");
[0148]
[0149] if (!(cptr = rqptr->rqHeader.CookiePtr))
[0150] {
[0151] if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST))
[0152] WatchThis (rqptr, FI_LI, WATCH_REQUEST, "TRACK no cookie(s)");
[0153] return (false);
[0154] }
[0155]
[0156] while (*cptr)
[0157] {
[0158] while (*cptr && *cptr != TrackCookieName[0]) cptr++;
[0159] if (!*cptr) break;
[0160] if (MATCH0 (cptr, TrackCookieName, TrackCookieNameLength))
[0161] {
[0162] cptr += TrackCookieNameLength;
[0163] if (*cptr == '=')
[0164] {
[0165] mptr = ++cptr;
[0166] zptr = (sptr = rqptr->TrackId) + sizeof(rqptr->TrackId)-1;
[0167] while (*cptr && *cptr != ';' && !isspace(*cptr) && sptr < zptr)
[0168] *sptr++ = *cptr++;
[0169] /* scan to end of cookie value (just checking) */
[0170] while (*cptr && *cptr != ';' && !isspace(*cptr)) cptr++;
[0171] /* if it wasn't the correct size for some reason then flag that */
[0172] if (cptr - mptr != sizeof(rqptr->TrackId)-1)
[0173] {
[0174] *sptr = '\0';
[0175] if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST))
[0176] {
[0177] WatchThis (rqptr, FI_LI, WATCH_REQUEST,
[0178] "TRACK cookie problem", rqptr->TrackId);
[0179] WatchData (rqptr->rqHeader.CookiePtr,
[0180] strlen(rqptr->rqHeader.CookiePtr));
[0181] }
[0182] return (false);
[0183] }
[0184] else
[0185] {
[0186] if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST))
[0187] WatchThis (rqptr, FI_LI, WATCH_REQUEST,
[0188] "TRACK found \"!AZ\"", rqptr->TrackId);
[0189] *sptr = '\0';
[0190] return (true);
[0191] }
[0192] }
[0193] }
[0194] if (*cptr) cptr++;
[0195] }
[0196]
[0197] if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST))
[0198] WatchThis (rqptr, FI_LI, WATCH_REQUEST, "TRACK not found");
[0199]
[0200] return (false);
[0201] }
[0202]
[0203] /*****************************************************************************/
[0204] /*
[0205] Cancel (expire) the request's current track cookie.
[0206] */
[0207]
[0208] TrackCancelCookie
[0209] (
[0210] REQUEST_STRUCT *rqptr,
[0211] REQUEST_AST NextTaskFunction
[0212] )
[0213] {
[0214] int idx;
[0215] unsigned short Length;
[0216] char *cptr;
[0217] char Buffer [256];
[0218]
[0219] /*********/
[0220] /* begin */
[0221] /*********/
[0222]
[0223] if (WATCHING(rqptr) && WATCH_MODULE(WATCH_MOD__OTHER))
[0224] WatchThis (rqptr, FI_LI, WATCH_MOD__OTHER,
[0225] "TrackCancelCookie() !&A", NextTaskFunction);
[0226]
[0227] if (!Config.cfTrack.Enabled)
[0228] {
[0229] rqptr->rqResponse.HttpStatus = 403;
[0230] ErrorGeneral (rqptr, MsgFor(rqptr,MSG_GENERAL_DISABLED), FI_LI);
[0231] SysDclAst (NextTaskFunction, rqptr);
[0232] return;
[0233] }
[0234]
[0235] FaoToBuffer (Buffer, sizeof(Buffer), &Length,
[0236] "!AZ=; path=/;!&@ expires=Fri, 13 Jan 1978 14:00:00 GMT;",
[0237] TrackCookieName,
[0238] Config.cfTrack.Domain[0] ?
[0239] " domain=!AZ;" : "!+", Config.cfTrack.Domain);
[0240]
[0241] cptr = VmGetHeap (rqptr, Length+1);
[0242] for (idx = 0; idx < RESPONSE_COOKIE_MAX; idx++)
[0243] {
[0244] if (!rqptr->rqResponse.CookiePtr[idx])
[0245] {
[0246] memcpy (rqptr->rqResponse.CookiePtr[idx] = cptr, Buffer, Length+1);
[0247] break;
[0248] }
[0249] }
[0250]
[0251] if (WATCHING(rqptr) && WATCH_CATEGORY(WATCH_REQUEST))
[0252] WatchThis (rqptr, FI_LI, WATCH_REQUEST,
[0253] "TRACK cancel \"!AZ\"", rqptr->TrackId);
[0254]
[0255] ReportSuccess (rqptr, "Track cookie \"!AZ\" cancelled.", rqptr->TrackId);
[0256]
[0257] SysDclAst (NextTaskFunction, rqptr);
[0258] }
[0259]
[0260] /*****************************************************************************/
[0261]