/*REXX*/
/*trace r?*/
Signal On NoValue
Call On Error
Signal On Failure
Signal On Syntax
Parse source opsys . exec_name .
/*****************************************/
/*                                       */
/* AUTHOR: Charles Fenton                */
/*                                       */
/**************************************************************/
/*       ITEM: CNTL(CACC0010)                                 */
/*   FUNCTION: REXX for OS/390 UNIX System Services           */
/*             data collection                                */
/*                                                            */
/*      NOTES: - This member contains UNIX file names.        */
/*                - It MUST stay in mixed case.               */
/*                - It MUST NOT be numbered.                  */
/*********************************************************************/
/* Change summary:                                                   */
/* 07/07/2000 DCM Start                                              */
/* 11/19/2009 CL Fenton Changes to allow for use of BPXWUNIX.        */
/* 04/24/2012 CL Fenton initial creation of script copied from       */
/*            USSICOL1, CSD-AR003400262.                             */
/* 05/21/2015 CL Fenton Changed includes test for CSFTP, CSTCP,      */
/*            and WAS to stream line process, STS-008182.            */
/* 08/11/2016 CL Fenton Cleaned up several unneccessary entries.     */
/* 05/04/2018 CL Fenton Changed process to work from users HOME      */
/*            directory.  If blank will use /tmp/(username) as       */
/*            directory, STS-019498.                                 */
/* 02/31/2019 CL Fenton Changes to initialize CWD variable,          */
/*            STS-021618.                                            */
/* 09/25/2019 CL Fenton Changes to check the value of CWD and the    */
/*            RETVAL from the getcwd commands to determine if the    */
/*            /tmp directory is to be used, STS-023237 and           */
/*            STS-023242.                                            */
/* 11/08/2019 CL Fenton Added automation for IUTN0010 and IUTN0020,  */
/*            STS-023415 and STS-023417.                             */
/* 03/29/2021 CL Fenton Added evaluation for sntpd PDI ZUSS0037 for  */
/*            ACF2-OS-000150, RACF-OS-000190, and TSS0-OS-000280,    */
/*            STS-026250.                                            */
/* 11/08/2022 CL Fenton Added automation for PDI ZUSS0015 for        */
/*            ACF2-US-000020, RACF-US-000050, and TSS0-US-000150,    */
/*            STS-029124.                                            */
/* 11/10/2022 CL Fenton Added automation for PDI ZUSS0038 for        */
/*            ACF2-OS-000160, RACF-OS-000180, and TSS0-OS-000270,    */
/*            STS-029112.                                            */
/* 02/22/2023 CL Fenton Added automation for PDIs ZSSH0010,          */
/*            ZSSH0020, ZSSH0030, ZSSH0040, and ZSSH0050 for         */
/*            ACF2-SH-000010, RACF-SH-000010, TSS0-SS-000010,        */
/*            ACF2-SH-000030, RACF-SH-000040, TSS0-SS-000040,        */
/*            ACF2-SH-000040, RACF-SH-000050, TSS0-SH-000030,        */
/*            ACF2-SH-000050, RACF-SH-000020, TSS0-SH-000020,        */
/*            ACF2-OS-000330, RACF-SH-000060, and TSS0-ES-000100,    */
/*            STS-029286, STS-029287, STS-029288, STS-029289, and    */
/*            STS-029334.                                            */
/* 01/22/2024 CL Fenton Added automation for IUTN0020 for            */
/*            ACF2-UT-000050, RACF-UT-000050, and TSS0-UT-000050,    */
/*            SCTASK0074636.                                         */
/* 01/22/2024 CL Fenton Added automation for IUTN0021 for            */
/*            ACF2-UT-000040, RACF-UT-000040, and TSS0-UT-000040,    */
/*            SCTASK0074631.                                         */
/* 06/05/2024 CL Fenton Added automation for ZUSS0014 for            */
/*            ACF2-US-000180, RACF-US-000180, and TSS0-US-000180,    */
/*            SCTASK0133769.                                         */
/* 06/05/2024 CL Fenton Added automation for ZUSS0013 for            */
/*            ACF2-US-000150, RACF-US-000170, and TSS0-US-000010,    */
/*            SCTASK0133761.                                         */
/* 09/27/2024 CL Fenton Created to evaluate existance of programs    */
/*            for IFTP0040 for STIG IDs ACF2-US-000170,              */
/*            RACF-FT-000090, and TSS0-FT-000060.                    */
/*            Script to be executed in CACJ0005 in CACC0010 for      */
/*            FTP, SCTASKU0221468.                                   */
/* 03/31/2025 CL Fenton Created to evaluate text banners for the     */
/*            following:                                             */
/*            ACF2-SH-000030, RACF-SH-000040, and TSS0-SS-000040 as  */
/*            ZSSH0030, SCTASKU0330749.                              */
/* 04/01/2025 CL Fenton Added Error and Exit code.                   */
/*                                                                   */
/*                                                                   */
/*                                                                   */
/*********************************************************************/
/* Setup variables for copying report files                          */
/*                                                                   */
/* PARSE UPPER ARG VDSNNODE .                                        */
/*********************************************************************/
PGMNAME = 'CACC0010 04/01/25'
CONSLIST  = "OFF"                 /* DEFAULT IS OFF                  */
COMLIST   = "OFF"                 /* DEFAULT IS OFF                  */
SYMLIST   = "OFF"                 /* DEFAULT IS OFF                  */
TERMMSGS  = "OFF"                 /* DEFAULT IS OFF                  */
sysprompt = "OFF"                 /* CONTROL NOPROMPT                */
sysflush  = "OFF"                 /* CONTROL NOFLUSH                 */
sysasis   = "ON"                  /* CONTROL ASIS - caps off         */
TRACE     = "OFF"                 /* TRACE ACTIONS AND ERRORS        */
Numeric digits 10                 /* default of 9 not enough         */
return_code = 0
maxcc = 0
lminit_dialog  = "N/A"
lminit_pdidd   = "N/A"
lmopen_dialog  = "N/A"
lmopen_pdidd   = "N/A"
lmclose_dialog = "N/A"
lmclose_pdidd  = "N/A"
lmfree_dialog  = "N/A"
lmfree_pdidd   = "N/A"
lc = 'abcdefghijklmnopqrstuvwxyz'
uc = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
username = translate(userid(),lc,uc)
Arg OPTION
do until OPTION = ""
  parse var OPTION key"("val")" OPTION
  val = strip(val,"b","'")
  val = strip(val,"b",'"')
  optcmd = key '= "'val'"'
  interpret optcmd
  end
 
return_code = 0
If trace = "ON" then do           /* TURN messages on                */
  termmsgs = "ON"                 /* CONTROL MSG                     */
  comlist = "ON"                  /* CONTROL LIST                    */
  conslist = "ON"                 /* CONTROL CONLIST                 */
  symlist = "ON"                  /* CONTROL SYMLIST                 */
  end
 
If CONSLIST = "ON" | COMLIST = "ON" | SYMLIST = "ON" | TRACE = "ON",
  then Trace ?r
 
syssymlist = symlist           /* CONTROL SYMLIST/NOSYMLIST */
sysconlist = conslist          /* CONTROL CONLIST/NOCONLIST */
syslist    = comlist           /* CONTROL LIST/NOLIST       */
sysmsg     = termmsgs          /* CONTROL MSG/NOMSG         */
Address ISPEXEC
"CONTROL NONDISPL ENTER"
"CONTROL ERRORS RETURN"
zispfrc = 0
"VPUT (ZISPFRC) SHARED"
return_code = 0
"VPUT (CONSLIST COMLIST SYMLIST TERMMSGS)"
"SELECT CMD(CACC1000 ACP)"
Address TSO
pdi = ''
cwd = ''
cwdrc = 0
return_code = 0
call syscalls 'ON'
say PGMNAME "syscalls" return_code
return_code = 0
address syscall "getlogin lid"
say PGMNAME "getlogin" lid return_code RETVAL ERRNO ERRNOJR
return_code = 0
address syscall "getcwd cwd"
say PGMNAME "getcwd" cwd return_code RETVAL ERRNO ERRNOJR
if RETVAL = -1 | cwd = "/" then do
  say PGMNAME "Either" lid "has a HOME of Root (/) or the",
    "/u/"username "directory is not defined to Unix."
  set cwdrc = -1
  end
return_code = 0
address syscall "getuid"
say PGMNAME "getuid" return_code RETVAL ERRNO ERRNOJR
uid = RETVAL
return_code = 0
address syscall "getgid"
say PGMNAME "getgid" return_code RETVAL ERRNO ERRNOJR
gid = RETVAL
return_code = 0
address syscall "geteuid"
say PGMNAME "geteuid" return_code RETVAL ERRNO ERRNOJR
euid = RETVAL
return_code = 0
address syscall "getegid"
say PGMNAME "getegid" return_code RETVAL ERRNO ERRNOJR
egid = RETVAL
uidsu = ""
gidsu = ""
if uid <> 0 then do
  return_code = 0
  address syscall "setuid 0"
  say PGMNAME "setuid" return_code RETVAL ERRNO ERRNOJR
  if retval <> -1 then do
    return_code = 0
    address syscall "getuid"
    say PGMNAME "getuid" return_code RETVAL ERRNO ERRNOJR
    uidsu = RETVAL
    return_code = 0
    address syscall "getgid"
    say PGMNAME "getgid" return_code RETVAL ERRNO ERRNOJR
    gidsu = RETVAL
    cwdsu = ""
    return_code = 0
    address syscall "getcwd cwdsu"
    say PGMNAME "getcwd" cwdsu return_code RETVAL ERRNO ERRNOJR
    if RETVAL = -1 | cwdsu = "/" then do
      say PGMNAME "Either" lid "has a HOME of Root (/) or the",
        "u/"username "directory is not defined to Unix."
      set cwdrc = -1
      end
    end
  end
X = LISTDSI("USSCMDS" "FILE")
VDSNFULL = SYSDSNAME
Address ISPEXEC
return_code = 0
"lminit dataid(dialog) ddname(dialog)"
lminit_dialog = return_code
return_code = 0
"lminit dataid(pdidd) ddname(pdidd)"
lminit_pdidd = return_code
return_code = 0
"lmopen dataid("dialog")"
lmopen_dialog = return_code
return_code = 0
"lmopen dataid("pdidd") option(output)"
lmopen_pdidd = return_code
/*VHFSFULL = "/tmp/fso_srrmvs/usscmds_rpt/"
  return_code = 0
  address syscall "lstat (VHFSFULL) dir."
  say pgmname "lstat" dir.0 return_code RETVAL ERRNO ERRNOJR
  say pgmname "lstat st_uid" dir.st_uid
  say pgmname "lstat st_type" dir.st_type
  if uid <> 0 & uidsu <> 0 & uid <> dir.st_uid then ,
    VHFSPART = cwd
  else ,
    VHFSPART = "/tmp"*/
if cwdrc = 0 then,
  VHFSPART = cwd
else ,
  VHFSPART = "/tmp/"username
return_code = 0
address syscall "opendir "VHFSPART
say pgmname "opendir" return_code RETVAL ERRNO ERRNOJR
if RETVAL = -1 then ,
  address syscall "mkdir (VHFSPART) 0750"
return_code = 0
address syscall "closedir "RETVAL
say pgmname "closedir" return_code RETVAL ERRNO ERRNOJR
return_code = 0
address syscall "lstat (VHFSPART) dir."
/*say pgmname "lstat" dir.0 return_code RETVAL ERRNO ERRNOJR
  say pgmname "lstat st_uid" dir.st_uid
  say pgmname "lstat st_type" dir.st_type*/
VHFSFULL = VHFSPART"/fso_srrmvs/usscmds_rpt"
 
say pgmname "Home directory set to" VHFSPART"."
say pgmname "Work information can be found in directory" VHFSFULL"."
/* obtain information from VHFSFULL */
return_code = 0
address syscall "opendir "VHFSFULL
if RETVAL = 0 then do
  address syscall 'readdir (VHFSFULL) dir. stem.'
  do a = 3 to dir.0
    file = VHFSFULL"/"dir.a
    address syscall "unlink (file)"
    end
  address syscall "closedir "RETVAL
  end
 
x = outtrap("out.")
test = cacc1010('d omvs,p')
x = outtrap("OFF")
auto = ""
line = ""
do a = 1 to out.0
  if word(out.a,1) = "AUTOMNT" then do
    auto = word(out.a,2)
    line = out.a
    leave
    end
  end
 
Signal OFF NoValue
urc = BPXWUNIX("df -P",,df.,"DD:SYSERR")
AUTOMNT = "NONE"
do x = 1 to df.0
/*say pgmname df.x*/
  if substr(df.x,1,1) = "*" then ,
    AUTOMNT = word(df.x,6)
  end
/*                                                            */
/* Allocate HFS file; copy script to it                       */
/*                                                            */
Address TSO
cmd=VHFSPART'/fso_srrmvs_usscmds_ksh'
/*"OCOPY INDD(MVSENV) OUTDD(STDENV) TEXT CONVERT((BPXFX111))"*/
env.0 = 0
x = outtrap("out.")
listalc status
x = outtrap("OFF")
do x = 1 to out.0
  if pos("MVSENV",out.x) <> 0 then do
    y = x - 1
    DSN="'"strip(out.y)"'"
    leave
    end
end
if SYSDSN(DSN) = "OK" then ,
  "execio * diskr MVSENV (FINIS STEM env."
x = env.0 + 1
env.x = "HOME="VHFSPART
say pgmname "HOME="VHFSPART
 
env.0 = x
x = env.0 + 1
env.x = "AUTOMNT="AUTOMNT
say pgmname "AUTOMNT="AUTOMNT
env.0 = x
 
typeruns = "CSFTP CSTCP WAS"
y = "Y"
n = "N"
 
do until typeruns = ""
  parse var typeruns TYPERUN typeruns
  TYPERUN = left(TYPERUN,8)
  rectype = "0"
  Call collect_rec
  OPTION = strip(TYPERUN)||'='||ind
  x = env.0 + 1
  env.x = OPTION
  say pgmname OPTION
  env.0 = x
  interpret OPTION
  end
/*say pgmname "CSFTP:"csftp "CSTCP:"cstcp "WAS:"was*/
 
DO x = 1 to env.0
  env.x = strip(env.x)
/*say pgmname 'env' x env.x*/
  end
/*                                                            */
return_code = 0
"ALLOCATE FILE(HFS01) PATH('"VHFSPART"/fso_srrmvs_usscmds_ksh') ",
  "PATHDISP(KEEP,DELETE) ",
  "PATHOPTS(OWRONLY,OCREAT) ",
  "PATHMODE(SIRWXU)"
say pgmname "ALLOCATE HFS01" return_code
return_code = 0
"OCOPY INDD(MVS01) OUTDD(HFS01) TEXT CONVERT((BPXFX111))"
say pgmname "OCOPY MVS01 to HFS01" return_code
"FREE FILE(HFS01)"
/*                                                            */
/* Allocate Shell STDIN, STDOUT; execute script; free files   */
/*                                                            */
return_code = 0
"ALLOCATE FILE(STDIN) PATH('"VHFSPART"/fso_srrmvs_usscmds_ksh') ",
  "PATHDISP(DELETE,DELETE) ",
  "PATHOPTS(ORDONLY)"
urc = BPXWUNIX('sh -L' cmd,,'DD:SYSMSG','DD:SYSERR',env.)
say pgmname "BPXWUNIX" return_code urc
"FREE FILE(STDIN)"
/*                                                            */
/* Copy HFS report files to PDS                               */
/*                                                            */
x = outtrap('err.')
VRPT = "zssh0050"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "ps"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call process_ps
VRPT = "eautom"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call process_eautom
VRPT = "einetd"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call process_inetd
VRPT = "eprof"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call Process_eprof
VRPT = "erc"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "eserv"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "estepll"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "owdir"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "sdperm"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
pdi = "zuss0034"
call process_permission_pdi
VRPT = "sfperm"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
pdi = "zuss0035"
call process_permission_pdi
if CSTCP = "Y" then do
  VRPT = "itcp0040"
  "OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
  call process_permission_pdi
  end
VRPT = "iutn0030"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "iutn0040"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call process_permission_pdi
if CSFTP = "Y" then do
  VRPT = "iftp0050"
  "OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
  VRPT = "iftp0070"
  "OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
  call process_permission_pdi
  Address ISPEXEC "lmclose dataid("pdidd")"
  pdi = "IFTP0040"
  Address ISPEXEC "EDIT DATAID("pdidd") MACRO("cacm0007")",
    "MEMBER("pdi")"
  Address ISPEXEC "lmopen dataid("pdidd") option(output)"
  end
pdi = ""
VRPT = "islg0030"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call process_permission_pdi
VRPT = "zuss0037"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
call process_permission_pdi
/*                                                            */
/* Allocate HFS file; copy script to it                       */
/*                                                            */
if WAS = "N" then signal bypass_was
"ALLOCATE FILE(HFS01) PATH('"VHFSPART"/fso_srrmvs_usscmds_ksh') ",
  "PATHDISP(KEEP,DELETE) ",
  "PATHOPTS(OWRONLY,OCREAT) ",
  "PATHMODE(SIRWXU)"
"OCOPY INDD(MVS02) OUTDD(HFS01) TEXT CONVERT((BPXFX111))"
"FREE FILE(HFS01)"
/*                                                            */
/* Allocate Shell STDIN, STDOUT; execute script; free files   */
/*                                                            */
return_code = 0
"ALLOCATE FILE(STDIN) PATH('"VHFSPART"/fso_srrmvs_usscmds_ksh') ",
  "PATHDISP(DELETE,DELETE) ",
  "PATHOPTS(ORDONLY)"
urc = BPXWUNIX('sh -L' cmd,,'DD:SYSMSG','DD:SYSERR',env.)
say pgmname "BPXWUNIX" return_code urc
"FREE FILE(STDIN)"
/*                                                            */
/* Copy HFS report files to PDS                               */
/*                                                            */
VRPT = "ihshfsob"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "washfsob"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
VRPT = "ahttpd"
"OGET '"VHFSFULL'/'VRPT"' '"VDSNFULL"("VRPT")' TEXT CONVERT((BPXFX111))"
 
 
ERR_EXIT:
bypass_was:
call syscalls 'OFF'
Address ISPEXEC
return_code = 0
"lmclose dataid("dialog")"
lmclose_dialog = return_code
return_code = 0
"lmclose dataid("pdidd")"
lmclose_pdidd = return_code
return_code = 0
"lmfree dataid("dialog")"
lmfree_dialog = return_code
return_code = 0
"lmfree dataid("pdidd")"
lmfree_pdidd = return_code
/*                                                            */
If TERMMSGS = 'ON' then do
  say
  say '==============================================================='
  say PGMNAME 'LMINIT_DIALOG                 ' lminit_dialog
  say PGMNAME 'LMINIT_PDIDD                  ' lminit_pdidd
  say PGMNAME 'LMOPEN_DIALOG                 ' lmopen_dialog
  say PGMNAME 'LMOPEN_PDIDD                  ' lmopen_pdidd
  say PGMNAME 'LMCLOSE_DIALOG                ' lmclose_dialog
  say PGMNAME 'LMCLOSE_PDIDD                 ' lmclose_pdidd
  say PGMNAME 'LMFREE_DIALOG                 ' lmfree_dialog
  say PGMNAME 'LMFREE_PDIDD                  ' lmfree_pdidd
  say '==============================================================='
  end
 
Exit 0
/*********************************************************************/
/*  Start of sub-routines                                            */
/*********************************************************************/
process_permission_pdi:
Address ISPEXEC
if pdi = "" then pdi = VRPT
upper pdi
pb = 0
uab = 0
f1 = "Permission bits and user audit bits is (are) inappropriate:"
f2 = "Permission bits allow inappropriate access."
f3 = "User audit bits provide inadequate logging."
address tso "alloc fi(input) da('"VDSNFULL"("VRPT")') shr reuse"
address tso "execio * diskr input (finis stem out."
do a = 1 to out.0
  parse var out.a ind 2 sp 5 data
/*say pgmname "ind="ind "sp="sp "data="data*/
  if ind = "" then iterate
  if ind = "0" then iterate
  if ind = "1" then pb = pb + 1
  if ind = "2" then uab = uab + 1
  if ind = "3" then do
    pb = pb + 1
    uab = uab + 1
    end
  end
/*say PGMNAME 'Processing PDI' pdi'.  pb='pb 'uab='uab*/
Address TSO "newstack"
if pb = 0 & uab = 0 then queue 'Not a Finding'
if pb > 0 | uab > 0 then do
  queue f1
  queue " "
  end
if pb > 0 & uab > 0 then do
  nr = 1
  lp = ") "
  end
else do
  nr = ""
  lp = ""
  end
if pb > 0 then do
  queue nr""lp""f2
  queue " "
  if nr > 0 then nr = nr + 1
  do a = 1 to out.0
    parse var out.a ind 2 sp 5 data
    if ind = "1" | ind = "3" then ,
      queue "     "data
    end
  queue " "
  end
if uab > 0 then do
  queue nr""lp""f3
  queue " "
  do a = 1 to out.0
    parse var out.a ind 2 sp 5 data
    if ind = "2" | ind = "3" then ,
      queue "     "data
    end
  queue " "
  end
call process_queued_pdi
pdi = ""
Address TSO "free fi(input)"
return
 
 
process_eautom:
pdi = "ZUSS0013"
/*say PGMNAME 'Processing PDI' pdi'.'*/
eprof_data = ""
Address ISPEXEC
return_code = 0
address tso "alloc fi(input) da('"VDSNFULL"("VRPT")') shr reuse"
if return_code > 0 | auto = "" then do
  Address TSO "newstack"
  queue "Not Applicable"
  call process_queued_pdi
  return
  end
address tso "execio * diskr input (finis stem out."
maps. = ""
mc = 0
mapdata =
finding_rc = 0
do a = 1 to out.0
  parse var out.a out.a "#" .
  if word(out.a,1) = "name" &,
    mapdata <> "" then do
    mc = mc + 1
    maps.mc = mapdata
    end
  if word(out.a,1) = "name" then,
    mapdata = strip(out.a,"B")" @"
  if wordpos("type",out.a) = 1 |,
     wordpos("filesystem",out.a) = 1 |,
     wordpos("mode",out.a) = 1 |,
     wordpos("duration",out.a) = 1 |,
     wordpos("delay",out.a) = 1 |,
     wordpos("setuid",out.a) = 1 |,
     wordpos("security",out.a) = 1 then,
    mapdata = mapdata""strip(out.a,"B")" @"
  end
if mapdata <> "" then do
  mc = mc + 1
  maps.mc = mapdata
  end
 
Address TSO "newstack"
if mc = 0 then,
  queue "Not Applicable"
else do x = 1 to mc
  parse upper var maps.x . "SECURITY" security .
  parse upper var maps.x . "SETUID" setuid .
  if security <> "YES" | ,
     setuid <> "NO" then do
    if finding_rc = 0 then do
      queue "The following MapName files security parameters are not",
        "properly defined."
      queue " "
      finding_rc = 1
      end
    mapdata = maps.x
    do until mapdata = ""
      parse var mapdata line "@" mapdata
      queue "     "line
      end
    queue " "
    end
  end
if finding_rc = 0 then,
  queue "Not a Finding"
call process_queued_pdi
return
 
 
process_eprof:
eprof_data = ""
Address ISPEXEC
address tso "alloc fi(input) da('"VDSNFULL"("VRPT")') shr reuse"
address tso "execio * diskr input (finis stem out."
do a = 1 to out.0
  parse var out.a out.a "#" .
  if out.a = "" then iterate
  if wordpos("umask",out.a) > 0 then do
    eprof_data = eprof_data""out.a"@"
    iterate
    end
  if wordpos("LOGNAME",out.a) > 0 then do
    eprof_data = eprof_data""out.a"@"
    iterate
    end
  end
pdi = "ZUSS0015"
/*say PGMNAME 'Processing PDI' pdi'.'*/
Address TSO "newstack"
if eprof_data = "" then,
  queue "UMASK and LOGNAME are not specified in /etc/profile."
else do
  umask = ""
  logname = ""
  do until eprof_data = ""
    parse var eprof_data data "@" eprof_data
    if pos("umask",data) > 0 then,
      parse var data . "umask" umask .
    if pos("LOGNAME",data) > 0 then,
      parse var data logname "LOGNAME" .
    end
  if umask = "077" &,
     logname = "readonly" then,
    queue "Not a Finding"
  else do
    queue "The /etc/profile file does not specify the following",
      "parameters."
    queue " "
    if umask = "" then,
      queue "     umask 077 is not specified."
    else,
      if umask <> "077" then,
        queue "     umask" umask "is specified."
    if logname = "" then,
      queue "     readonly LOGNAME is not specified."
    else,
      if logname <> "readonly" then,
        queue "     "logname "LOGNAME is specified."
    end
  end
call process_queued_pdi
return
 
 
process_ps:
sntpd_data = ""
sshd_data = ""
Address ISPEXEC
address tso "alloc fi(input) da('"VDSNFULL"("VRPT")') shr reuse"
address tso "execio * diskr input (finis stem out."
do a = 1 to out.0
  parse var out.a out.a "#" .
  if out.a = "" then iterate
  if pos("sntp",out.a) > 0 |,
     pos("SNTP",out.a) > 0 then do
    sntpd_data = sntpd_data""strip(out.a,"B")"@"
    end
  if pos("sshd",out.a) > 0 |,
     pos("SSHD",out.a) > 0 then do
    sshd_data = sshd_data""strip(out.a,"B")"@"
    end
  end
pdi = "ZUSS0038"
/*say PGMNAME 'Processing PDI' pdi'.'*/
Address TSO "newstack"
if sntpd_data = "" then,
  queue "SNTPD daemon is not active on the system."
else do
  queue "Not a Finding"
  queue " "
  do until sntpd_data = ""
    parse var sntpd_data data "@" sntpd_data
    queue "    " data
    end
  end
call process_queued_pdi
Address TSO "delstack"
 
if sshd_data = "" then do
  pdilist = "ZSSH0010 ZSSH0020 ZSSH0030 ZSSH0040"
  do x = 1 to words(pdilist)
    queue "Not a Finding"
    queue " "
    queue "The SSHD daemon is not active."
    queue " "
    pdi = word(pdilist,x)
    call process_queued_pdi
    end
  end
Else do
  call process_sshd_pdis
  end
Address TSO "delstack"
pdi = "ZSSH0050"
address tso "alloc fi(input) da('"VDSNFULL"("pdi")') shr reuse"
address tso "execio * diskr input (finis stem out."
if out.0 = 0 then do
  queue "Not a Finding"
  queue " "
  end
Else do
  queue "There are keys or certificates identified in Unix files."
  queue " "
  do x = 1 to out.0
    queue "    " out.x
    end
  queue " "
  end
call process_queued_pdi
return
 
 
process_sshd_pdis:
zssh0010_protocol = "Protocol statement is not specified."
zssh0020_ciphers = "Ciphers statement is not specified."
zssh0020_macs = "Macs statement is not specified."
zssh0020_fips = "FIPSMODE statement is not specified."
zssh0020_cipherssrc = "CiphersSource statement is not specified."
zssh0020_macssrc = "MACsSource statement is not specified."
zssh0030_banner = "Banner statement is not specified."
zssh0040_srvrsmf = "ServerSMF statement is not specified."
testdata = sshd_data
do until testdata = ""
  parse var testdata data "@" testdata
  ufile = word(data,words(data))
  address syscall "readfile (ufile) test."
  say
  say pgmname ufile "usable contents:"
  do xx = 1 to test.0
    parse var test.xx test.xx "#" .
    test.xx = strip(test.xx,"B")
    if test.xx = "" then iterate
    parse upper var test.xx key .
    say pgmname test.xx
    if key = "PROTOCOL" then,
      zssh0010_protocol = test.xx
    if key = "CIPHERS" then do
      zssh0020_ciphers = test.xx
      if right(zssh0020_ciphers,1) = "," then,
        do until right(zssh0020_ciphers,1) <> ","
          xx = xx + 1
          zssh0020_ciphers = zssh0020_ciphers""test.xx
          end
      end
    if key = "MACS" then do
      zssh0020_macs = test.xx
      if right(zssh0020_macs,1) = "," then,
        do until right(zssh0020_macs,1) <> ","
          xx = xx + 1
          zssh0020_macs = zssh0020_macs""test.xx
          end
      end
    if key = "BANNER" then,
      zssh0030_banner = test.xx
    end
  end
 
ufile = "/etc/ssh/zos_sshd_config"
address syscall "readfile (ufile) test."
say
say pgmname ufile "usable contents:"
do xx = 1 to test.0
  parse var test.xx test.xx "#" .
  test.xx = strip(test.xx,"B")
  if test.xx = "" then iterate
  if pos("=",test.xx) > 0 then,
    parse upper var test.xx key "=" .
  else,
    parse upper var test.xx key .
  say pgmname test.xx
  if key = "FIPSMODE" then,
    zssh0020_fips = test.xx
  if key = "CIPHERSSOURCE" then,
    zssh0020_cipherssrc = test.xx
  if key = "MACSSOURCE" then,
    zssh0020_macssrc = test.xx
  if key = "SERVERSMF" then,
    zssh0040_srvrsmf = test.xx
  end
say
 
if word(zssh0010_protocol,2) = 2 then do
  queue "Not a Finding"
  queue " "
  queue "    " zssh0010_protocol
  queue " "
  end
Else do
  queue "SSH daemon must be configured to only use the SSHv2 protocol."
  queue " "
  queue "    " zssh0010_protocol
  queue " "
  end
 
pdi = "ZSSH0010"
call process_queued_pdi
 
if word(zssh0020_ciphers,1) = "Ciphers" then do
  ciphers_data = word(zssh0020_ciphers,2)
  do until ciphers_data = ""
    parse var ciphers_data tdata "," ciphers_data
    if pos("aes",tdata) = 1 |,
       pos("3des",tdata) = 1 then nop
    else do
      queue "    " zssh0020_ciphers
      queue " "
      ciphers_data = ""
      end
    end
  end
Else do
  queue "    " zssh0020_ciphers
  queue " "
  end
 
if word(zssh0020_macs,1) = "Macs" then do
  macs_data = word(zssh0020_macs,2)
  do until macs_data = ""
    parse var macs_data tdata "," macs_data
    if pos("hmac-sha",tdata) <> 1 then do
      queue "    " zssh0020_macs
      queue " "
      macs_data = ""
      end
    end
  end
Else do
  queue "    " zssh0020_macs
  queue " "
  end
 
if pos("yes",zssh0020_fips) = 0 then do
  queue "    " zssh0020_fips
  queue " "
  end
 
if pos("ICSF",zssh0020_cipherssrc) = 0 then do
  queue "    " zssh0020_cipherssrc
  queue " "
  end
 
if pos("ICSF",zssh0020_macssrc) = 0 then do
  queue "    " zssh0020_macssrc
  queue " "
  end
 
if queued() = 0 then do
  queue "Not a Finding"
  queue " "
  queue "    " zssh0020_ciphers
  queue "    " zssh0020_macs
  queue "    " zssh0020_fips
  queue "    " zssh0020_cipherssrc
  queue "    " zssh0020_macssrc
  queue " "
  end
else do
  push " "
  push "SSH daemon must be configured to only use a FIPS 140-2",
    "compliant cryptographic algorithm."
  end
 
pdi = "ZSSH0020"
call process_queued_pdi
 
pdi = "ZSSH0030"
parse upper var zssh0030_banner banner
if wordpos("BANNER",banner) > 0 then do
  ufile = word(zssh0030_banner,words(zssh0030_banner))
  fdetail = "The" ufile "file does not contain the required",
    "notification and consent information."
  Address ISPEXEC "VPUT (PDIDD PDI FDETAIL)"
  if left(ufile,1) = "/" then,
    Address ISPEXEC "EDIT FILE(UFILE) MACRO(CACM0002)"
  Else,
    Address ISPEXEC "EDIT DATASET('"ufile"') MACRO(CACM0002)"
/*address syscall "readfile (ufile) test."
  say pgmname "Processing" ufile"."
  queue "Not Reviewed"
  queue "The" ufile "file does not contain the required notification",
    "and consent information."
  queue " "
  queue "     Contents of" ufile "are as follows:"
  queue " "
  do xx = 1 to test.0
    queue "         " test.xx
    end
  queue " "*/
  end
Else do
  queue zssh0030_banner
  queue " "
  call process_queued_pdi
  end
 
if word(zssh0040_srvrsmf,2) = "TYPE119_U83" then do
  queue "Not a Finding"
  queue " "
  queue "    " zssh0040_srvrsmf
  queue " "
  end
Else do
  queue "SSH daemon must be configured to write SMF records for all",
    "eligible events."
  queue " "
  queue "    " zssh0040_srvrsmf
  queue " "
  end
pdi = "ZSSH0040"
call process_queued_pdi
 
return
 
 
process_queued_pdi:
say pgmname right(queued(),4) 'records written for' pdi'.'
do xx = 1 to queued()
  parse pull ac
  "LMPUT DATAID("pdidd") MODE(INVAR) DATALOC(ac)",
    "DATALEN("length(ac)") MEMBER("pdi")"
  end
return_code = 0
"LMMADD DATAID("pdidd") MEMBER("pdi")"
if return_code = 4 then do
  return_code = 0
  "LMMREP DATAID("pdidd") MEMBER("pdi")"
  if return_code <> 0 then,
    say PGMNAME 'LMMREP_PDIDD =' return_code PDI ZERRSM
  end
return
 
 
process_inetd:
inetd_data = ""
Address ISPEXEC
address tso "alloc fi(input) da('"VDSNFULL"("VRPT")') shr reuse"
address tso "execio * diskr input (finis stem out."
do a = 1 to out.0
  parse var out.a out.a "#" .
  if out.a = "" then iterate
  if word(out.a,1) = "otelnet" then do
    inetd_data = out.a
    leave
    end
  end
pdi = "IUTN0010"
/*say PGMNAME 'Processing PDI' pdi'.'*/
Address TSO "newstack"
if inetd_data = "" then,
  queue "Not Applicable"
else do
  if word(inetd_data,5) = "OMVS" |,
     word(inetd_data,5) = "OMVSKERN" then do
    queue "Not a Finding"
    queue " "
    queue "     "word(inetd_data,5) "is specified."
    end
  else do
    queue "The startup user account for the z/OS UNIX Telnet Server",
      "does not specify OMVS or OMVSKERN."
    queue " "
    queue "     "word(inetd_data,5) "is specified."
    end
  end
call process_queued_pdi
pdi = "IUTN0020"
/*say PGMNAME 'Processing PDI' pdi'.'*/
Address TSO "newstack"
if inetd_data = "" then,
  queue "Not Applicable"
else do
  login = ""
  timeout = ""
  x = wordindex(inetd_data,7)
  parse var inetd_data . =(x) inetd_parm
  if pos("-h",inetd_parm) = 0 then do
    queue "Not a Finding"
    queue " "
    queue "     "inetd_parm
    end
  else do
    queue "Startup parameters for the z/OS UNIX Telnet Server are",
      "improperly specified."
    queue " "
    queue "     "inetd_parm
    end
  end
call process_queued_pdi
pdi = "IUTN0021"
/*say PGMNAME 'Processing PDI' pdi'.'*/
Address TSO "newstack"
if inetd_data = "" then,
  queue "Not Applicable"
else do
  login = ""
  timeout = ""
  x = wordindex(inetd_data,7)
  parse var inetd_data . =(x) inetd_parm
  parse var inetd_parm . "-D" login .
  parse var inetd_parm . "-c" timeout .
  if login = "login" &,
     timeout <= 900 then do
    queue "Not a Finding"
    queue " "
    queue "     "inetd_parm
    end
  else do
    queue "Startup parameters for the z/OS UNIX Telnet Server are",
      "improperly specified."
    queue " "
    queue "     "inetd_parm
    end
  end
call process_queued_pdi
pdi = "ZUSS0014"
services = "chargen daytime discard echo exec finger shell time",
  "login smtp timed nameserver systat uucp netstat talk qotd tftp"
inetd_data = ""
/*say PGMNAME 'Processing PDI' pdi'.'*/
do a = 1 to out.0
  parse var out.a out.a "#" .
  if out.a = "" then iterate
  service = word(out.a,1)
  if wordpos(service,services) > 0 then do
    inetd_data = inetd_data""out.a"#"
    leave
    end
  end
Address TSO "newstack"
if inetd_data = "" then,
  queue "Not a Finding"
else do
  queue "The following restricted network service(s) are specified",
    "in /etc/inetd.conf."
  queue " "
  do until inetd_data = ""
    parse var inetd_data service "#" inetd_data
    queue "     "service
    end
  end
call process_queued_pdi
pdi = ""
Address TSO "free fi(input)"
return
 
 
collect_rec:
Address ISPEXEC
return_code = 0
"lmmfind dataid("dialog") member(products)"
lmmfind_dialog = return_code
TYPERUN = left(TYPERUN,8)
recs =
return_code = 0
do until return_code > 0
  "lmget dataid("dialog") mode(invar) dataloc(data) datalen(lrecl)",
    "maxlen(80)"
  if return_code = 0 & ,
     pos(TYPERUN' 'rectype,data) = 1 then do
    parse var data . "0" ind
    ind = strip(ind)
    return 0
    end /* if return_code = 0 & */
end /* until return_code > 0 */
return 0
 
 
NoValue:
Failure:
Syntax:
say pgmname 'REXX error' rc 'in line' sigl':' strip(ERRORTEXT(rc))
say SOURCELINE(sigl)
SIGNAL ERR_EXIT
 
 
Error:
return_code = RC
if RC > 4 & RC <> 8 then do
  say pgmname "LASTCC =" RC strip(zerrlm)
  say pgmname 'REXX error' rc 'in line' sigl':' ERRORTEXT(rc)
  say SOURCELINE(sigl)
  end
if return_code > maxcc then
  maxcc = return_code
return
 
 
