/*****************************************************************************/ /* util.c Module name says it all. VERSION HISTORY --------------- 23-APR-2017 MGD initial */ /*****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "certman.h" #include "util.h" #include "acmeport/config.h" #define FI_LI "UTIL", __LINE__ /* from [.acme-client-portable..]main.c */ extern char *AcmePortDomainPtr, *AcmePortEsPtr; char* doasprintf (char*, ...); #ifdef WCMEDBGVMS int doddbg(char*, ...); #endif /*****************************************************************************/ /* Disable all privleges except NETMBX and TMPMBX in the calling process. */ void UtilMereMortal () { static ulong GroundMask [2] = { ~(PRV$M_NETMBX | PRV$M_TMPMBX), -1 }; int status; /*********/ /* begin */ /*********/ status = sys$setprv (0, &GroundMask, 0, 0); if (!(status & 1)) EXIT_FI_LI (status); } /*****************************************************************************/ /* Enable SYSPRV in the calling process. */ void UtilSysPrv () { static ulong SysPrvMask [2] = { PRV$M_SYSPRV, 0 }; int status; ulong PrevPrvMask [2] = { 0, 0 }; /*********/ /* begin */ /*********/ status = sys$setprv (1, &SysPrvMask, 0, &PrevPrvMask); if ((status & 1) == 0) EXIT_FI_LI (status); /* if already enabled then consider that a programming error */ if (PrevPrvMask[0] & PRV$M_SYSPRV) EXIT_FI_LI (SS$_BUGCHECK); } /*****************************************************************************/ /* Enable IMPERSONATE in the calling process. */ void UtilImpersonate () { static ulong ImpersonateMask [2] = { PRV$M_IMPERSONATE, 0 }; int status; ulong PrevPrvMask [2] = { 0, 0 }; /*********/ /* begin */ /*********/ status = sys$setprv (1, &ImpersonateMask, 0, &PrevPrvMask); if ((status & 1) == 0) EXIT_FI_LI (status); /* if already enabled then consider that a programming error */ if (PrevPrvMask[0] & PRV$M_IMPERSONATE) EXIT_FI_LI (SS$_BUGCHECK); } /*****************************************************************************/ /* Return a pointer to an equivalent VMS name. Calling code must cast return value using (char*) and type as -1. Also acts as its own callback routine. */ int UtilVmsName ( char *name, int type ) { static char *vname; /*********/ /* begin */ /*********/ if (type == -1) { if (decc$to_vms (name, UtilVmsName, 0, 0) != 1) { if (vname) free (vname); vname = NULL; } return ((int)vname); } if (vname) free (vname); if (type == DECC$K_DIRECTORY || type == DECC$K_FOREIGN) { vname = NULL; return (0); } vname = strdup(name); return (1); } /*****************************************************************************/ /* Allowed to use the application? */ int UtilHaveSysPrv () { static ulong SysPrvMask[2] = { PRV$M_SYSPRV, 0 }; return (UtilHavePriv(SysPrvMask)); } /*****************************************************************************/ /* Check privilege mask. Return true or false. */ int UtilHavePriv (ulong *PrivMask) { static ulong JpiImagPriv [2], JpiProcPriv [2]; static struct { short int buf_len; short int item; void *buf_addr; ushort *ret_len; } JpiItemList[] = { { sizeof(JpiImagPriv), JPI$_IMAGPRIV, &JpiImagPriv, 0 }, { sizeof(JpiProcPriv), JPI$_PROCPRIV, &JpiProcPriv, 0 }, {0,0,0,0} }; int status; /*********/ /* begin */ /*********/ status = sys$getjpiw (0, 0, 0, &JpiItemList, 0, 0, 0); if ((status & 1) == 0) exit(status); return ((((JpiImagPriv[0] & PrivMask[0]) == PrivMask[0]) && ((JpiImagPriv[1] & PrivMask[1]) == PrivMask[1])) || (((JpiProcPriv[0] & PrivMask[0]) == PrivMask[0]) && ((JpiProcPriv[1] & PrivMask[1]) == PrivMask[1]))); } /*****************************************************************************/ /* Return true if interactive process. */ int UtilInteractive () { static ulong JpiMode; static struct { short int buf_len; short int item; void *buf_addr; ushort *ret_len; } JpiItemList[] = { { sizeof(JpiMode), JPI$_MODE, &JpiMode, 0 }, {0,0,0,0} }; int status; /*********/ /* begin */ /*********/ status = sys$getjpiw (0, 0, 0, &JpiItemList, 0, 0, 0); if (!(status & 1)) exit(status); return (JpiMode == JPI$K_INTERACTIVE); } /*****************************************************************************/ /* ODS-2-ify (39.39) the supplied file name. Returns allocated string which must be freed by caller. */ char* UtilOds2FileName ( char* root, char* fname ) { char *cptr, *sptr, *zptr, *name, *type; char buf [256]; /*********/ /* begin */ /*********/ zptr = (sptr = buf) + sizeof(buf)-1; if (root) { for (cptr = root; *cptr && sptr < zptr; *sptr++ = *cptr++); if (root[0] && sptr < zptr) *sptr++ = '/'; } name = sptr; cptr = fname; while (*cptr && sptr < zptr && sptr - name < 39) { if (isalnum(*cptr) || *cptr == '-') *sptr++ = *cptr; else *sptr++ = '_'; cptr++; } if (sptr < zptr) *sptr++ = '.'; type = sptr; while (*cptr && sptr < zptr && sptr - type < 39) { if (isalnum(*cptr) || *cptr == '-') *sptr++ = *cptr; else *sptr++ = '_'; cptr++; } if (sptr >= zptr) exit(SS$_RESULTOVF); *sptr = '\0'; #ifdef WCMEDBGVMS doddbg("ODS-2: %s", buf); #endif return (strdup(buf)); } /*****************************************************************************/ /* Generate a ODS-2 compliant certificate name. Returns allocated string which must be freed by caller. */ char* UtilOds2CertName ( char* root, char* fname ) { char *cptr, *sptr, *zptr, *name, *type; char buf [256]; /*********/ /* begin */ /*********/ zptr = (sptr = buf) + sizeof(buf)-1; if (root) { for (cptr = root; *cptr && sptr < zptr; *sptr++ = *cptr++); if (root[0] && sptr < zptr) *sptr++ = '/'; } name = sptr; /* name element of file name */ cptr = fname; while (*cptr && sptr < zptr && sptr - name < 39) { if (*cptr == '.' && !strncasecmp(cptr,".pem",4)) break; if (isalnum(*cptr) || *cptr == '-') *sptr++ = *cptr; else *sptr++ = '_'; cptr++; } if (strncasecmp(cptr,".pem",4)) exit (SS$_BUGCHECK); type = cptr; if (sptr < zptr) *sptr++ = '_'; /* host name element */ cptr = AcmePortDomainPtr; while (*cptr && sptr < zptr && sptr - name < 39) { if (isalnum(*cptr) || *cptr == '-') *sptr++ = *cptr; else *sptr++ = '_'; cptr++; } /* type element of file name */ cptr = type; if (sptr < zptr) *sptr++ = *cptr++; type = sptr; while (*cptr && sptr < zptr && sptr - type < 39) { if (isalnum(*cptr) || *cptr == '-') *sptr++ = *cptr; else *sptr++ = '_'; cptr++; } if (sptr >= zptr) exit(SS$_RESULTOVF); *sptr = '\0'; #ifdef WCMEDBGVMS doddbg("ODS-2: %s", buf); #endif return (strdup(buf)); } /*****************************************************************************/ /* Set the process name. */ void UtilSetPrn (char *name) { char *cptr, *sptr, *zptr; char prcnam [16]; $DESCRIPTOR (NameDsc, (char*)prcnam); /*********/ /* begin */ /*********/ zptr = (sptr = prcnam) + sizeof(prcnam)-1; for (cptr = "WCME-"; *cptr && sptr < zptr; *sptr++ = *cptr++); for (cptr = (char*)name; *cptr && sptr < zptr; *sptr++ = *cptr++); NameDsc.dsc$w_length = sptr - prcnam; sys$setprn (&NameDsc); } /*****************************************************************************/ /* Divine our image name. */ char* UtilImageName () { static char JpiImagName [256]; static struct { ushort buf_len; ushort item; uchar *buf_addr; ushort *short_ret_len; } JpiItems [] = { { sizeof(JpiImagName), JPI$_IMAGNAME, (uchar*)&JpiImagName, 0 }, { 0,0,0,0 } }; int status; char *cptr; /*********/ /* begin */ /*********/ if (JpiImagName[0]) return (JpiImagName); status = sys$getjpiw (0, 0, 0, &JpiItems, 0, 0, 0); if ((status & 1) == 0) exit(status); /* when fork()ing ensure we're not using a specific version */ for (cptr = JpiImagName; *cptr && *cptr != ';'; cptr++); if (*cptr == ';') *cptr = '\0'; return (JpiImagName); } /*****************************************************************************/ /* Return a pointer to a static buffer containing the string equivalent of the supplied VMS status value. */ char* UtilGetMsg (int status) { static char buf [256]; unsigned short slen; $DESCRIPTOR (bufDsc, buf); /*********/ /* begin */ /*********/ sys$getmsg (status, &slen, &bufDsc, 1, 0); buf[slen] = '\0'; buf[0] = toupper(buf[0]); return (buf); } /*****************************************************************************/ /* Create a detached process executing under the optional username, the supplied command procedure, with output to the optional file name. Return a VMS status value. */ int UtilCrePrcDetach ( char *UserName, char *SysCommand, char *SysOutput, char *ProcessName, ulong *pidptr ) { #define ISS$C_ID_NATURAL 1 #define PRC$M_DETACH 0x200 static ulong CrePrcFlags = PRC$M_DETACH; static ulong PersonaFlags = 0; static $DESCRIPTOR (LoginOutDsc, "SYS$SYSTEM:LOGINOUT.EXE"); static $DESCRIPTOR (SysCommandDsc, ""); static $DESCRIPTOR (SysOutputDsc, ""); static $DESCRIPTOR (PrcNamDsc, ""); static $DESCRIPTOR (UserNameDsc, ""); int handle, status; ulong pid; /*********/ /* begin */ /*********/ if (!SysCommand || !SysCommand[0]) return (SS$_ABORT); SysCommandDsc.dsc$a_pointer = SysCommand; SysCommandDsc.dsc$w_length = strlen(SysCommand); if (!SysOutput || !SysOutput[0]) SysOutput = "NL:"; SysOutputDsc.dsc$a_pointer = SysOutput; SysOutputDsc.dsc$w_length = strlen(SysOutput); if (ProcessName) { if (ProcessName[0]) { PrcNamDsc.dsc$a_pointer = ProcessName; PrcNamDsc.dsc$w_length = strlen(ProcessName); } else ProcessName = NULL; } UtilSysPrv(); if (UserName && UserName[0]) { UserNameDsc.dsc$a_pointer = UserName; UserNameDsc.dsc$w_length = strlen(UserName); UtilImpersonate(); status = sys$persona_create (&handle, &UserNameDsc, PersonaFlags, 0, 0); if (!(status & 1)) return (status); status = sys$persona_assume (&handle, 0, 0, 0); if (!(status & 1)) return (status); } status = sys$creprc (pidptr, &LoginOutDsc, &SysCommandDsc, &SysOutputDsc, &SysOutputDsc, 0, 0, ProcessName ? &PrcNamDsc : 0, 0, 0, 0, CrePrcFlags, 0, 0); UtilMereMortal(); if (UserName && UserName[0]) { handle = ISS$C_ID_NATURAL; sys$persona_assume (&handle, 0, 0, 0); } /* the sys$creprc() status */ return (status); } /*****************************************************************************/ /* Translate a logical name using LNM$FILE_DEV by default or the specified name table. Returns a pointer to the value string, or NULL if the name does not exist. 'IndexValue' should be zero for a 'flat' logical name, or 0..127 for interative translations. Returns pointer to non-reentrant static buffer which must be strdup()ed if retained. */ char* UtilTrnLnm ( char *LogName, char *LogTable, int IndexValue ) { static ushort ValueLength; static ulong LnmAttributes, LnmIndex; static char LogValue [256]; static $DESCRIPTOR (LogNameDsc, ""); static $DESCRIPTOR (LogTableDsc, ""); static struct { short int buf_len; short int item; void *buf_addr; ushort *ret_len; } LnmItems [] = { { sizeof(LnmIndex), LNM$_INDEX, &LnmIndex, 0 }, { sizeof(LnmAttributes), LNM$_ATTRIBUTES, &LnmAttributes, 0 }, { sizeof(LogValue), LNM$_STRING, LogValue, &ValueLength }, { 0,0,0,0 } }; int status; /*********/ /* begin */ /*********/ LnmIndex = IndexValue; if (LogTable) { LogTableDsc.dsc$a_pointer = LogTable; LogTableDsc.dsc$w_length = strlen(LogTable); } else { LogTableDsc.dsc$a_pointer = "LNM$FILE_DEV"; LogTableDsc.dsc$w_length = sizeof("LNM$FILE_DEV")-1; } LogNameDsc.dsc$a_pointer = LogName; LogNameDsc.dsc$w_length = strlen(LogName); status = sys$trnlnm (0, &LogTableDsc, &LogNameDsc, 0, &LnmItems); if (!(status & 1) || !(LnmAttributes & LNM$M_EXISTS)) { if (LogValue) LogValue[0] = '\0'; return (NULL); } LogValue[ValueLength] = '\0'; return (LogValue); } /*****************************************************************************/