/*****************************************************************************/ #ifdef COMMENTS_WITH_COMMENTS /* script.c This is strictly for a CGI and NOT a CGIplus environment. COPYRIGHT --------- Copyright (C) 2017-2019 Mark G.Daniel This program comes with ABSOLUTELY NO WARRANTY. This is free software, and you are welcome to redistribute it under the conditions of the GNU GENERAL PUBLIC LICENSE, version 3, or any later version. http://www.gnu.org/licenses/gpl.txt VERSION HISTORY --------------- 06-JAN-2019 MGD minor changes at v2.0 23-APR-2017 MGD initial */ #endif /* COMMENTS_WITH_COMMENTS */ /*****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include "certman.h" #include "overseer.h" #include "report.h" #include "script.h" #include "util.h" #include "acme-client/wcme_config.h" #include "wcme_tls_internal.h" #define FI_LI "SCRIPT", __LINE__ int WcmeVeryVerbose; extern int verbose; extern char SoftwareId []; char stream200 [] = "Status: 200\r\n\ Content-Type: text/plain\r\n\ Script-Control: X-stream-mode\r\n\ Cache-Control: no-cache, no-store, must-revalidate\r\n\ Pragma: no-cache\r\n\ Expires: 0\r\n\ \r\n"; char record200 [] = "Status: 200\r\n\ Content-Type: text/plain\r\n\ Script-Control: X-record-mode\r\n\ Cache-Control: no-cache, no-store, must-revalidate\r\n\ Pragma: no-cache\r\n\ Expires: 0\r\n\ \r\n"; char zero2c [] = "Status: 404\r\n\ Content-Type: text/plain\r\n\ Script-Control: X-stream-mode\r\n\ Cache-Control: no-cache, no-store, must-revalidate\r\n\ Pragma: no-cache\r\n\ Expires: 0\r\n\ \r\n\ Nothing to see here ... move along.\n"; char plain502 [] = "Status: 502\r\n\ Script-Control: X-stream-mode\r\n\ Content-Type: text/plain\r\n\ Cache-Control: no-cache, no-store, must-revalidate\r\n\ Pragma: no-cache\r\n\ Expires: 0\r\n\ \r\n"; char* doasprintf (char*, ...); char* tstamp (ulong*); int vasprintf (char**, const char*, va_list); /*****************************************************************************/ /* Executing as a CGI script. */ void ScriptProcess (int argc, char* argv[]) { char *cptr, *image, *piptr; /*********/ /* begin */ /*********/ /* only for development purposes */ WcmeVeryVerbose = (UtilTrnLnm ("WCME_VERBOSE", "LNM$SYSTEM", 0) != NULL); if (WcmeVeryVerbose) verbose = 2; /* this is also a sanity check */ if ((piptr = getenv ("WWW_PATH_INFO")) == NULL && (piptr = getenv ("PATH_INFO")) == NULL) EXIT_FI_LI (SS$_ABORT); if ((cptr = getenv ("WWW_SERVER_SOFTWARE")) == NULL && (cptr = getenv ("SERVER_SOFTWARE")) == NULL) EXIT_FI_LI (SS$_ABORT); if (strstr (cptr, "Apache/") == NULL) { /* do not allow the CRTL to interfere with carriage-control */ if ((stdout = freopen ("SYS$OUTPUT:", "w", stdout, "ctx=bin")) == NULL) EXIT_FI_LI (vaxc$errno); } /* ensure and don't dance on each others' toes */ dup2 (fileno(stdout), fileno(stderr)); /* ensure we're not using a specific version */ for (cptr = image = strdup (argv[0]); *cptr; cptr++); while (cptr > image && *cptr != ';' && *cptr != ']') cptr--; if (*cptr == ';') *cptr = '\0'; if (!strncmp (piptr, "/admin/", 7)) ScriptAdmin (image, piptr+7); else if (!strncmp (piptr, "/.well-known/acme-challenge/", 28)) ScriptChallenge (piptr+28); else fputs (zero2c, stdout); exit (SS$_NORMAL); } /*****************************************************************************/ /* HTTP request for an administration URI. Must be subject to authorisation. The test functions here perform the activity under the scripting account (and of course using the INSTALLed image). */ void ScriptAdmin ( char *image, char *what ) { int status, target; char *cptr; /*********/ /* begin */ /*********/ /* admin functions must be subject to authorisation */ if (getenv ("WWW_REMOTE_USER") == NULL && getenv ("REMOTE_USER") == NULL) fputs (zero2c, stdout); else if (!strcmp (what, "list") || /* and for backward compatibility */ !strcmp (what, "cert")) CertManAdminCert (); else if (!strcmp (what, "log")) ScriptAdminLog (); else if (!strncmp (what, "check/", 6)) { /* rest just for development/debugging purposes */ what += 6; if (!strcmp (what, "ca")) { fputs (record200, stdout); fflush (stdout); CertManCertify (NULL); } else if (!strcmp (what, "certmanbegin")) { fputs (record200, stdout); fflush (stdout); vmsdbg ("%s", OverseerVersion()); CertManBegin (image); } else if (!strcmp (what, "load")) { fputs (record200, stdout); fflush (stdout); CertManLoad (); } else if (!strcmp (what, "mail")) { if (cptr = UtilTrnLnm ("WCME_MAIL", "LNM$SYSTEM", 0)) { cptr = strdup(cptr); fprintf (stdout, "%sTest of MAIL report: %s\n", stream200, cptr); ReportMail (MAIL_PERSONAL, cptr, "wCME test only!", "wCME test of MAIL report..."); } else fprintf (stdout, "%sWCME_MAIL not defined!\n", plain502); } else if (!strcmp (what, "opcom")) { if (cptr = UtilTrnLnm ("WCME_OPCOM", "LNM$SYSTEM", 0)) { cptr = strdup(cptr); target = ReportOpcomTargetOf(cptr); } else target = ReportOpcomTargetOf(cptr = "CENTRAL"); fprintf (stdout, "%sTest of OPCOM report: %s\n", stream200, cptr); ReportOpcom (target, "wCME test of OPCOM report..."); } else fputs (zero2c, stdout); } else fputs (zero2c, stdout); exit (SS$_NORMAL); } /*****************************************************************************/ /* Return an HTTP response containing the current overseer process log. */ void ScriptAdminLog () { char line [4096]; char *cptr, *dname, *fname; FILE *fp; DIR *dirptr; struct dirent *dentptr; /*********/ /* begin */ /*********/ UtilSysPrv(); dirptr = opendir (dname = "wcme_root:[log]"); if (!dirptr) { vmsdbg ("opendir() %s:%d %%X%08.08X", FI_LI, vaxc$errno); EXIT_FI_LI (vaxc$errno); } /* search for the latest log file */ fname = NULL; for (dentptr = readdir(dirptr); dentptr; dentptr = readdir(dirptr)) { if (strncasecmp (dentptr->d_name, "overseer_", 9)) continue; for (cptr = dentptr->d_name; *cptr; cptr++); while (cptr > dentptr->d_name && *cptr != '.') cptr--; if (strncasecmp (cptr, ".log;", 5)) continue; fname = doasprintf ("%s%s", dname, dentptr->d_name); } if (!fname) fname = doasprintf ("%s%s", dname, "__.log"); #undef fopen fp = fopen (fname, "r", "shr=put"); UtilMereMortal(); if (!fp) { fprintf (stdout, "%sOverseer log: %s.\n", plain502, strerror(errno)); return; } fputs (stream200, stderr); while (fgets (line, sizeof(line), fp)) fputs (line, stdout); fprintf (stdout, "%s ^Z\n", tstamp(NULL)); fclose (fp); } /*****************************************************************************/ /* This function returns the content of the "challenge" file name. */ void ScriptChallenge (char *challenge) { char *cptr; char token [256]; FILE *fp; /*********/ /* begin */ /*********/ UtilSysPrv(); fp = fopen (UtilOds2FileName(WWW_DIR,challenge,NULL), "r"); if (!fp) { fprintf (stdout, "%sChallenge received but %s.\n", plain502, strerror(errno)); return; } if (!fgets (token, sizeof(token), fp)) { fprintf (stdout, "%sChallenge received but %s.\n", plain502, strerror(errno)); return; } fclose (fp); UtilMereMortal(); fprintf (stdout, "Status: 200 OK\r\n\ Content-Length: %d\r\n\ Cache-Control: no-cache, no-store, must-revalidate\r\n\ Pragma: no-cache\r\n\ Expires: 0\r\n\ \r\n\ %s", strlen(token), token); } /*****************************************************************************/