Los journals de auditoría son bastante útiles a la hora de dar seguimiento a actividad de los usuarios. Para poder activar la auditoría del IBM i es necesario :
1) Crear un journal receiver y el journal, que es el que permitirá guardar la información. Es aconsejable respaldar los journals con cierta frecuencia para poder depurarlos. Lo ideal es respaldarlos de forma separada a los datos del equipo, por lo que recomienda crear una biblioteca especialmente para ellos
CRTLIB JRNLIB
RTJRNRCV JRNRCV(JRNLIB/AUD)
CRTJRN JRN(QSYS/QAUDJRN) JRNRCV(JRNLIB/AUD)
2) Cambiar los valores del sistema para que se active la recogida de información
WRKSYSVAL y cambiar los siguientes valores
QAUDCTL
*AUDLVL
*OBJAUD
*NOQTEMP
QAUDLVL
*AUTFAIL
*CREATE
*DELETE
*SECURITY
*SAVRST
3) Marcar los usuarios que deseemos como auditables. Lo mismo podemos hacer con los objetos
La información se irá recogiendo en los receivers, pero no será muy util si no la podemos leer de forma cómoda.
Para tal fin, y pensando en poder armar reportes de auditoría, creé un par de programas en PHP que permiten listar estos informes.
Armé un pequeño CL que diariamente lista los incidentes de seguridad de AF (Fallas de autorización) y PW (Fallas de usuario y/o password) y guarda la información en una tabla
PGM
DCL VAR(&FECHA1) TYPE(*CHAR) LEN(6)
DCL VAR(&FECHA2) TYPE(*CHAR) LEN(8)
RTVSYSVAL SYSVAL(QDATE) RTNVAR(&FECHA1)
CVTDAT DATE(&FECHA1) TOVAR(&FECHA2) FROMFMT(*sysval) +
TOFMT(*DMY) TOSEP(*NONE)
chgvar (&FECHA2) Value(%SST(&FECHA2 1 4) *TCAT +
'20' *TCAT %SST(&FECHA2 5 2))
SNDMSG MSG(&FECHA2) TOUSR(BOMIAUD)
CPYAUDJRNE ENTTYP(AF PW CD) OUTFILE(MYLIB/QAUDIT) +
OUTMBR(*FIRST *ADD) JRNRCV(*CURCHAIN) +
FROMTIME(&FECHA2 000000)
MONMSG MSGID(CPF0000)
ENDPGM
Este pequeño CL lo agregué en el JOB SCHEDULLER para que diariamente ejecute en las noches y vaya poblando mis tablas de trabajo, que luego listaré en los reportes.
Luego,armé 2 programas en PHP, cada uno lista un tipo de entrada
AUDAF.php
<html>
<head>
<title>Journal de auditoria - Fallas de Autorizacion</title>
</head>
<p align="center"><b>Journal de auditoria - Fallas de Autorizacion</b></p>
<p>
<i><b>
<?php
include 'Connection.php';
$date = new DateTime();
$cdate = $date->format('Y-m-d');
$fdd = $date;
$fht = $date;
$cdd = $cdate . ' 00:00:00';
$cht = $cdate . ' 23:59:59';
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
} else {
$fdesde=$cdate;
$fhasta=$cdate;
}
echo "<form name='form1'' method='post'' action='audaf.php'>";
echo "<td>";
echo "<table width='100%'' border='0'' cellpadding='3'' cellspacing='1'' bgcolor='#FFFFFF'>";
echo "<tr>";
echo "<td colspan='3'><strong>Parametros del reporte</strong></td>";
echo "</tr>";
echo "<tr>";
echo "<td width='78'>Desde</td>";
echo "<td width='6'>:</td>";
echo "<td width='294'><input name='fdesde' type='text' id='fdesde' value='$fdesde'</td> </tr>";
echo "<tr> <td>Hasta</td><td>:</td>";
echo "<td><input name='fhasta'' type='text' id='fhasta' value='$fhasta' </td></tr>";
echo "<tr>";
echo "<td> </td>";
echo "<td> </td>";
echo "<td><input type='submit'' name='Submit'' value='Aceptar'></td>";
echo "</tr>";
echo "</table>";
echo "</td>";
echo "</form>";
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
$cdd = $fdesde . ' 00:00:00';
$cht = $fhasta . ' 23:59:59';
}
#Consulta de registros PW
$sqlaf = "SELECT date(a.AFTSTP) as Fecha, Time(a.AFTSTP) as Hora,a.AFUSER as Usuario, a.AFJOB as Trabajo,a.AFNBR as Nro_Trabajo,a.AFPGM as Programa, a.AFPGMLIB as Biblioteca,trim(a.AFRADR) as Direccion_IP, a.AFVIOL as Tipo, b.AFVIOLDS as Descripcion
From MYLIB.QAUDITAF a left outer join MYLIB.AUDAFTYPE b
on a.AFVIOL = b.AFVIOL
where a.AFTSTP >= '$cdd' and a.AFTSTP <= '$cht'
order by a.AFTSTP" ;
#echo $sqlaf;
$result=odbc_exec($conn,$sqlaf);
echo '<table border=1 cellspacing=0 cellpadding=2 ><tr>';
$fila = 1;
while (odbc_fetch_row($result)) {
$FieldQ = odbc_num_fields($result);
if ($fila==1) {
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
echo "<th bgcolor=#AFAFAF>$fn</th>";
}
echo "</tr>";
}
$fila++;
echo "<tr>";
$td = "<td bgcolor=#DCEBF9>";
if (($fila/2)==intval($fila/2)) {
$td = "<td bgcolor=#FFFFFF>";
}
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
$Campo = odbc_result($result,$fn);
echo $td . $Campo . "</td>";
}
echo "</tr>";
}
echo "</table>";
$clo = odbc_close($conn);
?></b></i>
//-------------------------------------------------------------//
Luego tengo otro programa que lista las entradas de fallas de usuario y password
AUDPW.php
<html>
<head>
<title>Journal de auditoria - Fallas de Password</title>
</head>
<p align="center"><b>Journal de auditoria - Fallas de Password</b></p>
<p>
<i><b>
<?php
include 'Connection.php';
$date = new DateTime();
$cdate = $date->format('Y-m-d');
$fdd = $date;
$fht = $date;
$cdd = $cdate . ' 00:00:00';
$cht = $cdate . ' 23:59:59';
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
} else {
$fdesde=$cdate;
$fhasta=$cdate;
}
echo "<form name='form1'' method='post'' action='audpw.php'>";
echo "<td>";
echo "<table width='100%'' border='0'' cellpadding='3'' cellspacing='1'' bgcolor='#FFFFFF'>";
echo "<tr>";
echo "<td colspan='3'><strong>Parametros del reporte</strong></td>";
echo "</tr>";
echo "<tr>";
echo "<td width='78'>Desde</td>";
echo "<td width='6'>:</td>";
echo "<td width='294'><input name='fdesde' type='text' id='fdesde' value='$fdesde'</td> </tr>";
echo "<tr> <td>Hasta</td><td>:</td>";
echo "<td><input name='fhasta'' type='text' id='fhasta' value='$fhasta' </td></tr>";
echo "<tr>";
echo "<td> </td>";
echo "<td> </td>";
echo "<td><input type='submit'' name='Submit'' value='Aceptar'></td>";
echo "</tr>";
echo "</table>";
echo "</td>";
echo "</form>";
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
$cdd = $fdesde . ' 00:00:00';
$cht = $fhasta . ' 23:59:59';
##$fdd = strtotime($cdd);
##$fht = strtotime($cht);
}
#Consulta de registros PW
$sqlpw = "SELECT date(a.PWTSTP) as Fecha, time(a.PWTSTP) as Hora,a.PWUSRN as Usuario, a.PWJOB as Trabajo,a.PWNBR as Nro_Trabajo, a.PWPGM as Programa, a.PWPGMLIB as Biblioteca,trim(a.PWRADR) as Direccion_IP, a.PWTYPE as Tipo_de_Intento, b.PWTYPEDS as Detalle_del_Intento
from MYLIB.QAUDITPW a left join MYLIB.AUDPWTYPE b
on a.PWTYPE = b.PWTYPE
where a.PWTSTP >= '$cdd' and a.PWTSTP <= '$cht'
order by a.PWTSTP" ;
##echo $sqlpw;
$result=odbc_exec($conn,$sqlpw);
echo '<table border=1 cellspacing=0 cellpadding=2 ><tr>';
$fila = 1;
while (odbc_fetch_row($result)) {
$FieldQ = odbc_num_fields($result);
if ($fila==1) {
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
echo "<th bgcolor=#AFAFAF>$fn</th>";
}
echo "</tr>";
}
$fila++;
echo "<tr>";
$td = "<td bgcolor=#DCEBF9>";
if (($fila/2)==intval($fila/2)) {
$td = "<td bgcolor=#FFFFFF>";
}
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
$Campo = odbc_result($result,$fn);
echo $td . $Campo . "</td>";
}
echo "</tr>";
}
echo "</table>";
$clo = odbc_close($conn);
?></b></i>
//---------------------------------------//
El programa Connection.php es común en ambos reportes
<?php
$user="usuario"; #a valid username that will connect to the DB
$pass="password"; #a password for the username
$dsn = "Driver={Client Access ODBC Driver (32-bit)};System=IP_SERVIDOR;BLOCKSIZE=256;BLOCKFETCH=0;
DateFormat=6;DSP=0;COMPRESSION=1;PREFETCH=1;TRANSLATE=1;ExtendedDynamic=1;";
#Connect to the Database with ODBC
# $conn is defined and loaded using the odbc_connect PHP directive.
$conn=odbc_connect($dsn,$user,$pass);
#Check Connection
if ($conn == false) {
echo "<br>";
echo "Not able to connect to database<br>";
echo "<br>";
}
?>
//---------------------------------------//
Hay que preparar un par de tablas con descripciones, para que los reportes tengan algo de sentido
MYLIB.AUDPWTYPE
PWTYPE PWTYPEDS
A APPC bind failure
C User authentication with the CHKPWD command failed
D Service tools user ID name not valid
E Service tools user ID password not valid
P Password not valid
Q Attempted signon (user authentication) failed because user profile is d
R Attempted signon failed because password was expired. This audit record
S SQL Decryption password is not valid
U User name not valid
X Service tools user ID is disabled
Y Service tools user ID not valid
Z Service tools user ID password not valid
MYLIB.AUDAFTYPE
AFVIOL AFVIOLDS
A Not authorized to object
B Restricted instruction
C Validation failure (see J5 offset 639)
D Validation failure (see J5 offset 639)
E Hardware storage protection error, program constant space violation
S Default sign-on attempt
T Not authorized to TCP/IP port
F ICAPI authorization error
G ICAPI authentication error
H Scan exit program action (see J5 offset 639)
I System Java inheritance not allowed
J Submit job profile error
K Special authority violation
N Profile token not a regenerable token
O Optical Object Authority Failure
P Profile swap error
R Hardware protection error
U User permission request not valid
V Profile token not valid for generating new profile token
W Profile token not valid for swap
X System violation
Y Not authorized to the current JUID field during a clear JUID operation
Z Not authorized to the current JUID field during a set JUID operation.
Esto se probó corriendo en Windows con WAMPSERVER y System i Access V6R1 sin problema alguno.
1) Crear un journal receiver y el journal, que es el que permitirá guardar la información. Es aconsejable respaldar los journals con cierta frecuencia para poder depurarlos. Lo ideal es respaldarlos de forma separada a los datos del equipo, por lo que recomienda crear una biblioteca especialmente para ellos
CRTLIB JRNLIB
RTJRNRCV JRNRCV(JRNLIB/AUD)
CRTJRN JRN(QSYS/QAUDJRN) JRNRCV(JRNLIB/AUD)
2) Cambiar los valores del sistema para que se active la recogida de información
WRKSYSVAL y cambiar los siguientes valores
QAUDCTL
*AUDLVL
*OBJAUD
*NOQTEMP
QAUDLVL
*AUTFAIL
*CREATE
*DELETE
*SECURITY
*SAVRST
3) Marcar los usuarios que deseemos como auditables. Lo mismo podemos hacer con los objetos
La información se irá recogiendo en los receivers, pero no será muy util si no la podemos leer de forma cómoda.
Para tal fin, y pensando en poder armar reportes de auditoría, creé un par de programas en PHP que permiten listar estos informes.
Armé un pequeño CL que diariamente lista los incidentes de seguridad de AF (Fallas de autorización) y PW (Fallas de usuario y/o password) y guarda la información en una tabla
PGM
DCL VAR(&FECHA1) TYPE(*CHAR) LEN(6)
DCL VAR(&FECHA2) TYPE(*CHAR) LEN(8)
RTVSYSVAL SYSVAL(QDATE) RTNVAR(&FECHA1)
CVTDAT DATE(&FECHA1) TOVAR(&FECHA2) FROMFMT(*sysval) +
TOFMT(*DMY) TOSEP(*NONE)
chgvar (&FECHA2) Value(%SST(&FECHA2 1 4) *TCAT +
'20' *TCAT %SST(&FECHA2 5 2))
SNDMSG MSG(&FECHA2) TOUSR(BOMIAUD)
CPYAUDJRNE ENTTYP(AF PW CD) OUTFILE(MYLIB/QAUDIT) +
OUTMBR(*FIRST *ADD) JRNRCV(*CURCHAIN) +
FROMTIME(&FECHA2 000000)
MONMSG MSGID(CPF0000)
ENDPGM
Este pequeño CL lo agregué en el JOB SCHEDULLER para que diariamente ejecute en las noches y vaya poblando mis tablas de trabajo, que luego listaré en los reportes.
Luego,armé 2 programas en PHP, cada uno lista un tipo de entrada
AUDAF.php
<html>
<head>
<title>Journal de auditoria - Fallas de Autorizacion</title>
</head>
<p align="center"><b>Journal de auditoria - Fallas de Autorizacion</b></p>
<p>
<i><b>
<?php
include 'Connection.php';
$date = new DateTime();
$cdate = $date->format('Y-m-d');
$fdd = $date;
$fht = $date;
$cdd = $cdate . ' 00:00:00';
$cht = $cdate . ' 23:59:59';
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
} else {
$fdesde=$cdate;
$fhasta=$cdate;
}
echo "<form name='form1'' method='post'' action='audaf.php'>";
echo "<td>";
echo "<table width='100%'' border='0'' cellpadding='3'' cellspacing='1'' bgcolor='#FFFFFF'>";
echo "<tr>";
echo "<td colspan='3'><strong>Parametros del reporte</strong></td>";
echo "</tr>";
echo "<tr>";
echo "<td width='78'>Desde</td>";
echo "<td width='6'>:</td>";
echo "<td width='294'><input name='fdesde' type='text' id='fdesde' value='$fdesde'</td> </tr>";
echo "<tr> <td>Hasta</td><td>:</td>";
echo "<td><input name='fhasta'' type='text' id='fhasta' value='$fhasta' </td></tr>";
echo "<tr>";
echo "<td> </td>";
echo "<td> </td>";
echo "<td><input type='submit'' name='Submit'' value='Aceptar'></td>";
echo "</tr>";
echo "</table>";
echo "</td>";
echo "</form>";
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
$cdd = $fdesde . ' 00:00:00';
$cht = $fhasta . ' 23:59:59';
}
#Consulta de registros PW
$sqlaf = "SELECT date(a.AFTSTP) as Fecha, Time(a.AFTSTP) as Hora,a.AFUSER as Usuario, a.AFJOB as Trabajo,a.AFNBR as Nro_Trabajo,a.AFPGM as Programa, a.AFPGMLIB as Biblioteca,trim(a.AFRADR) as Direccion_IP, a.AFVIOL as Tipo, b.AFVIOLDS as Descripcion
From MYLIB.QAUDITAF a left outer join MYLIB.AUDAFTYPE b
on a.AFVIOL = b.AFVIOL
where a.AFTSTP >= '$cdd' and a.AFTSTP <= '$cht'
order by a.AFTSTP" ;
#echo $sqlaf;
$result=odbc_exec($conn,$sqlaf);
echo '<table border=1 cellspacing=0 cellpadding=2 ><tr>';
$fila = 1;
while (odbc_fetch_row($result)) {
$FieldQ = odbc_num_fields($result);
if ($fila==1) {
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
echo "<th bgcolor=#AFAFAF>$fn</th>";
}
echo "</tr>";
}
$fila++;
echo "<tr>";
$td = "<td bgcolor=#DCEBF9>";
if (($fila/2)==intval($fila/2)) {
$td = "<td bgcolor=#FFFFFF>";
}
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
$Campo = odbc_result($result,$fn);
echo $td . $Campo . "</td>";
}
echo "</tr>";
}
echo "</table>";
$clo = odbc_close($conn);
?></b></i>
//-------------------------------------------------------------//
Luego tengo otro programa que lista las entradas de fallas de usuario y password
AUDPW.php
<html>
<head>
<title>Journal de auditoria - Fallas de Password</title>
</head>
<p align="center"><b>Journal de auditoria - Fallas de Password</b></p>
<p>
<i><b>
<?php
include 'Connection.php';
$date = new DateTime();
$cdate = $date->format('Y-m-d');
$fdd = $date;
$fht = $date;
$cdd = $cdate . ' 00:00:00';
$cht = $cdate . ' 23:59:59';
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
} else {
$fdesde=$cdate;
$fhasta=$cdate;
}
echo "<form name='form1'' method='post'' action='audpw.php'>";
echo "<td>";
echo "<table width='100%'' border='0'' cellpadding='3'' cellspacing='1'' bgcolor='#FFFFFF'>";
echo "<tr>";
echo "<td colspan='3'><strong>Parametros del reporte</strong></td>";
echo "</tr>";
echo "<tr>";
echo "<td width='78'>Desde</td>";
echo "<td width='6'>:</td>";
echo "<td width='294'><input name='fdesde' type='text' id='fdesde' value='$fdesde'</td> </tr>";
echo "<tr> <td>Hasta</td><td>:</td>";
echo "<td><input name='fhasta'' type='text' id='fhasta' value='$fhasta' </td></tr>";
echo "<tr>";
echo "<td> </td>";
echo "<td> </td>";
echo "<td><input type='submit'' name='Submit'' value='Aceptar'></td>";
echo "</tr>";
echo "</table>";
echo "</td>";
echo "</form>";
if (!empty($_POST)){
$fdesde=$_POST['fdesde'];
$fhasta=$_POST['fhasta'];
$cdd = $fdesde . ' 00:00:00';
$cht = $fhasta . ' 23:59:59';
##$fdd = strtotime($cdd);
##$fht = strtotime($cht);
}
#Consulta de registros PW
$sqlpw = "SELECT date(a.PWTSTP) as Fecha, time(a.PWTSTP) as Hora,a.PWUSRN as Usuario, a.PWJOB as Trabajo,a.PWNBR as Nro_Trabajo, a.PWPGM as Programa, a.PWPGMLIB as Biblioteca,trim(a.PWRADR) as Direccion_IP, a.PWTYPE as Tipo_de_Intento, b.PWTYPEDS as Detalle_del_Intento
from MYLIB.QAUDITPW a left join MYLIB.AUDPWTYPE b
on a.PWTYPE = b.PWTYPE
where a.PWTSTP >= '$cdd' and a.PWTSTP <= '$cht'
order by a.PWTSTP" ;
##echo $sqlpw;
$result=odbc_exec($conn,$sqlpw);
echo '<table border=1 cellspacing=0 cellpadding=2 ><tr>';
$fila = 1;
while (odbc_fetch_row($result)) {
$FieldQ = odbc_num_fields($result);
if ($fila==1) {
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
echo "<th bgcolor=#AFAFAF>$fn</th>";
}
echo "</tr>";
}
$fila++;
echo "<tr>";
$td = "<td bgcolor=#DCEBF9>";
if (($fila/2)==intval($fila/2)) {
$td = "<td bgcolor=#FFFFFF>";
}
for ($i = 1; $i <= $FieldQ ; $i++)
{
$fn = odbc_field_name($result,$i);
$Campo = odbc_result($result,$fn);
echo $td . $Campo . "</td>";
}
echo "</tr>";
}
echo "</table>";
$clo = odbc_close($conn);
?></b></i>
//---------------------------------------//
El programa Connection.php es común en ambos reportes
<?php
$user="usuario"; #a valid username that will connect to the DB
$pass="password"; #a password for the username
$dsn = "Driver={Client Access ODBC Driver (32-bit)};System=IP_SERVIDOR;BLOCKSIZE=256;BLOCKFETCH=0;
DateFormat=6;DSP=0;COMPRESSION=1;PREFETCH=1;TRANSLATE=1;ExtendedDynamic=1;";
#Connect to the Database with ODBC
# $conn is defined and loaded using the odbc_connect PHP directive.
$conn=odbc_connect($dsn,$user,$pass);
#Check Connection
if ($conn == false) {
echo "<br>";
echo "Not able to connect to database<br>";
echo "<br>";
}
?>
//---------------------------------------//
Hay que preparar un par de tablas con descripciones, para que los reportes tengan algo de sentido
MYLIB.AUDPWTYPE
PWTYPE PWTYPEDS
A APPC bind failure
C User authentication with the CHKPWD command failed
D Service tools user ID name not valid
E Service tools user ID password not valid
P Password not valid
Q Attempted signon (user authentication) failed because user profile is d
R Attempted signon failed because password was expired. This audit record
S SQL Decryption password is not valid
U User name not valid
X Service tools user ID is disabled
Y Service tools user ID not valid
Z Service tools user ID password not valid
MYLIB.AUDAFTYPE
AFVIOL AFVIOLDS
A Not authorized to object
B Restricted instruction
C Validation failure (see J5 offset 639)
D Validation failure (see J5 offset 639)
E Hardware storage protection error, program constant space violation
S Default sign-on attempt
T Not authorized to TCP/IP port
F ICAPI authorization error
G ICAPI authentication error
H Scan exit program action (see J5 offset 639)
I System Java inheritance not allowed
J Submit job profile error
K Special authority violation
N Profile token not a regenerable token
O Optical Object Authority Failure
P Profile swap error
R Hardware protection error
U User permission request not valid
V Profile token not valid for generating new profile token
W Profile token not valid for swap
X System violation
Y Not authorized to the current JUID field during a clear JUID operation
Z Not authorized to the current JUID field during a set JUID operation.
Esto se probó corriendo en Windows con WAMPSERVER y System i Access V6R1 sin problema alguno.