/*****************************************************************************/ /* util.c Module name says it all. 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 */ /*****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "asprintf.h" #include "certman.h" #include "util.h" #include "acme-client/wcme_config.h" #define FI_LI "UTIL", __LINE__ #ifdef WCME_DBG_VMS 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); } /*****************************************************************************/ /* * Wrap around asprintf(3), which sometimes nullifies the input values, * sometimes not, but always returns <0 on error. * Returns NULL on failure or the pointer on success. */ char * doasprintf(char *fmt, ...) { int c; char *cp; va_list ap; va_start(ap, fmt); c = vasprintf(&cp, fmt, ap); va_end(ap); return(c < 0 ? NULL : cp); } /*****************************************************************************/ /* 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 int status; 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} }; /*********/ /* begin */ /*********/ if (!status) { 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. If a file type is supplied a 39+ name is truncated. If not it is continued as the type up to 39 length. Expects file specification to be in U*x format. Returns allocated string which must be freed by caller. */ char* UtilOds2FileName ( char* fddir, char* fname, char* ftype ) { char *aptr, *cptr, *sptr, *zptr, *name, *type; char buf [256]; /*********/ /* begin */ /*********/ zptr = (sptr = buf) + sizeof(buf)-1; if (fddir) { for (cptr = fddir; *cptr && sptr < zptr; *sptr++ = *cptr++); if (*(sptr-1) != '/' && sptr < zptr) *sptr++ = '/'; } cptr = fname; name = sptr; while (*cptr && sptr < zptr && sptr - name < 39) { if (isalnum(*cptr) || *cptr == '-') *sptr++ = *cptr; else if (*cptr == '.' && !ftype) { for (aptr = cptr + 1; *aptr && *aptr != '.'; aptr++); if (*aptr == '.') *sptr++ = '_'; else *sptr++ = '.'; } else *sptr++ = '_'; cptr++; } if (cptr = ftype) { if (*cptr == '.') 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 WCME_DBG_VMS doddbg("ODS-2: %s", buf); #endif return (strdup(buf)); } /*****************************************************************************/ /* If |name| no NULL sets the process name. Always returns a pointer to the significant portion of the process name. */ char* UtilSetPrn (char *name) { static char *NamePtr = ""; static char prcnam [16]; char *cptr, *sptr, *zptr; $DESCRIPTOR (NameDsc, (char*)prcnam); /*********/ /* begin */ /*********/ if (!name) return (NamePtr); zptr = (sptr = prcnam) + sizeof(prcnam)-1; for (cptr = "WCME-"; *cptr && sptr < zptr; *sptr++ = *cptr++); NamePtr = sptr; for (cptr = name; *cptr && sptr < zptr; *sptr++ = *cptr++); *sptr = '\0'; NameDsc.dsc$w_length = sptr - prcnam; if (*name) sys$setprn (&NameDsc); return (NamePtr); } /*****************************************************************************/ /* 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); } /*****************************************************************************/ /* What's my user name? */ char* UtilUserName () { static char JpiUserName [12+1]; static struct { ushort buf_len; ushort item; uchar *buf_addr; ushort *short_ret_len; } JpiItems [] = { { sizeof(JpiUserName)-1, JPI$_USERNAME, (uchar*)&JpiUserName, 0 }, { 0,0,0,0 } }; int status; char *cptr; /*********/ /* begin */ /*********/ if (JpiUserName[0]) return (JpiUserName); status = sys$getjpiw (0, 0, 0, &JpiItems, 0, 0, 0); if ((status & 1) == 0) exit(status); for (cptr = JpiUserName; *cptr && *cptr != ' '; cptr++); *cptr = '\0'; return (JpiUserName); } /*****************************************************************************/ /* 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); } /*****************************************************************************/