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]