/*
* Copyright 2000, International Business Machines Corporation and others.
* All Rights Reserved.
- *
+ *
* This software has been released under the terms of the IBM Public
* License. For details, see the LICENSE file in the top-level source
* directory or online at http://www.openafs.org/dl/license10.html
#include <afsconfig.h>
#include <afs/param.h>
-RCSID
- ("$Header$");
+#include <roken.h>
-#include <fcntl.h>
-#include <stdarg.h>
#ifdef AFS_AIX32_ENV
#include <sys/audit.h>
+#else
+#define AUDIT_OK 0
+#define AUDIT_FAIL 1
+#define AUDIT_FAIL_AUTH 2
+#define AUDIT_FAIL_ACCESS 3
+#define AUDIT_FAIL_PRIV 4
#endif /* AFS_AIX32_ENV */
-#include <errno.h>
+#include <afs/opr.h>
#include "afs/afsint.h"
+#include "afs/butc.h"
#include <rx/rx.h>
#include <rx/rxkad.h>
#include "audit.h"
+#include "audit-api.h"
#include "lock.h"
-#ifdef AFS_AIX32_ENV
-#include <sys/audit.h>
-#endif
+
#include <afs/afsutil.h>
-char *bufferPtr;
-int bufferLen;
-int osi_audit_all = (-1); /* Not determined yet */
-int osi_echo_trail = (-1);
+extern struct osi_audit_ops audit_file_ops;
+#ifdef HAVE_SYS_IPC_H
+extern struct osi_audit_ops audit_sysvmq_ops;
+#endif
+
+static struct {
+ void *rock;
+ int (*islocal)(void *rock, char *name, char *inst, char *cell);
+} audit_user_check = { NULL, NULL };
+
+static struct {
+ const char *name;
+ const struct osi_audit_ops *ops;
+} audit_interfaces[] = {
+
+ { "file", &audit_file_ops },
+#ifdef HAVE_SYS_IPC_H
+ { "sysvmq", &audit_sysvmq_ops },
+#endif
+};
+/* default_interface indexes into the audit_interfaces list. */
+static int default_interface = 0; /* Set default to the file interface */
-#ifdef AFS_AIX_ENV /** all these functions are only defined for AIX */
+#define N_INTERFACES (sizeof(audit_interfaces) / sizeof(audit_interfaces[0]))
-#ifndef AFS_OSF_ENV
/*
- * These variadic functions work under AIX, and not all systems (osf1)
+ * Audit interface calling sequence:
+ * osi_audit_interface - sets the default audit interface
+ * osi_audit_file
+ * create_instance - Called during command arg processing (-auditlog)
+ * open_file - Called during command arg processing (-auditlog)
+ * osi_audit_open_interface
+ * open_interface - Called after thread environment has been established
+ * osi_audit_close_interface
+ * close_interface - Called during main process shutdown
+ * osi_audit
+ * send_msg - Called during audit events
*/
-/* ************************************************************************** */
-/* AIX requires a buffer filled with values to record with each audit event.
- * aixmakebuf creates that buffer from the variable list of values we are given.
- * ************************************************************************** */
-static
-aixmakebuf(audEvent, vaList)
- char *audEvent;
- char *vaList;
+struct audit_log {
+ struct opr_queue link;
+ const struct osi_audit_ops *audit_ops;
+ int auditout_open;
+ void *context;
+};
+
+struct audit_msg {
+ char buf[OSI_AUDIT_MAXMSG];
+ size_t len; /* length of the string in 'buf' (not including the trailing '\0') */
+ int truncated; /* was this message truncated during formatting? */
+};
+
+#ifdef AFS_PTHREAD_ENV
+static pthread_mutex_t audit_lock;
+static pthread_once_t audit_lock_once = PTHREAD_ONCE_INIT;
+#endif
+
+/* Chain of active interfaces */
+static struct opr_queue audit_logs = {&audit_logs, &audit_logs};
+
+static int osi_audit_all = (-1); /* Not determined yet */
+static int osi_echo_trail = (-1);
+
+static int auditout_open = 0; /* True if any interface is open */
+
+static int osi_audit_check(void);
+
+/*
+ * Send the message to all the interfaces
+ * @pre audit_lock held
+ */
+static void
+multi_send_msg(struct audit_msg *msg)
+{
+ struct opr_queue *cursor;
+
+ if (msg->len < 1) /* Don't send empty strings */
+ return;
+
+ for (opr_queue_Scan(&audit_logs, cursor)) {
+ struct audit_log *alog;
+ alog = opr_queue_Entry(cursor, struct audit_log, link);
+ if (alog->auditout_open) {
+ alog->audit_ops->send_msg(alog->context, msg->buf, msg->len,
+ msg->truncated);
+ }
+ }
+}
+static void
+append_msg(struct audit_msg *msg, const char *format, ...)
+{
+ va_list ap;
+ int remaining, printed;
+
+ if (msg->truncated) {
+ return;
+ }
+
+ if (msg->len >= OSI_AUDIT_MAXMSG - 1) {
+ /* Make sure we have at least some space left */
+ msg->truncated = 1;
+ return;
+ }
+
+ remaining = OSI_AUDIT_MAXMSG - msg->len;
+
+ va_start(ap, format);
+
+ printed = vsnprintf(&msg->buf[msg->len], remaining, format, ap);
+
+ if (printed < 0) {
+ /* Error during formatting. */
+ msg->truncated = 1;
+ printed = 0;
+
+ } else if (printed >= remaining) {
+ /* We tried to write more characters than we had space for. */
+ msg->truncated = 1;
+ printed = remaining - 1;
+
+ /* Make sure we're still terminated. */
+ msg->buf[OSI_AUDIT_MAXMSG - 1] = '\0';
+ }
+
+ msg->len += printed;
+ opr_Assert(msg->len < OSI_AUDIT_MAXMSG);
+
+ va_end(ap);
+}
+#ifdef AFS_AIX32_ENV
+static char *bufferPtr;
+static int bufferLen;
+
+static void
+audmakebuf(char *audEvent, va_list vaList)
{
int code;
int vaEntry;
int vaInt;
afs_int32 vaLong;
char *vaStr;
- char *vaLst;
- char hname[20];
struct AFSFid *vaFid;
vaEntry = va_arg(vaList, int);
while (vaEntry != AUD_END) {
switch (vaEntry) {
case AUD_STR: /* String */
- vaStr = (char *)va_arg(vaList, int);
+ case AUD_NAME: /* Name */
+ case AUD_ACL: /* ACL */
+ vaStr = (char *)va_arg(vaList, char *);
if (vaStr) {
strcpy(bufferPtr, vaStr);
bufferPtr += strlen(vaStr) + 1;
}
break;
case AUD_INT: /* Integer */
+ case AUD_ID: /* ViceId */
vaInt = va_arg(vaList, int);
*(int *)bufferPtr = vaInt;
bufferPtr += sizeof(vaInt);
*(afs_int32 *) bufferPtr = vaLong;
bufferPtr += sizeof(vaLong);
break;
- case AUD_LST: /* Ptr to another list */
- vaLst = (char *)va_arg(vaList, int);
- aixmakebuf(audEvent, vaLst);
- break;
case AUD_FID: /* AFSFid - contains 3 entries */
- vaFid = (struct AFSFid *)va_arg(vaList, int);
+ vaFid = (struct AFSFid *)va_arg(vaList, struct AFSFid *);
if (vaFid) {
memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
} else {
{
struct AFSCBFids *Fids;
- Fids = (struct AFSCBFids *)va_arg(vaList, int);
+ Fids = (struct AFSCBFids *)va_arg(vaList, struct AFSCBFids *);
if (Fids && Fids->AFSCBFids_len) {
*((u_int *) bufferPtr) = Fids->AFSCBFids_len;
bufferPtr += sizeof(u_int);
memcpy(bufferPtr, Fids->AFSCBFids_val,
sizeof(struct AFSFid));
} else {
- struct AFSFid dummy;
*((u_int *) bufferPtr) = 0;
bufferPtr += sizeof(u_int);
memset(bufferPtr, 0, sizeof(struct AFSFid));
bufferPtr += sizeof(struct AFSFid);
break;
}
+ /* butc tape label */
+ case AUD_TLBL:
+ {
+ struct tc_tapeLabel *label;
+
+ label = (struct tc_tapeLabel *)va_arg(vaList,
+ struct tc_tapeLabel *);
+ if (label)
+ memcpy(bufferPtr, label, sizeof(*label));
+ else
+ memset(bufferPtr, 0, sizeof(*label));
+ bufferPtr += sizeof(label);
+ break;
+ }
+ /* butc dump interface */
+ case AUD_TDI:
+ {
+ struct tc_dumpInterface *di;
+
+ di = (struct tc_dumpInterface *)
+ va_arg(vaList, struct tc_dumpInterface *);
+ if (di)
+ memcpy(bufferPtr, di, sizeof(*di));
+ else
+ memset(bufferPtr, 0, sizeof(*di));
+ bufferPtr += sizeof(*di);
+ break;
+ }
+ /*
+ * butc dump array
+ * An array of dump descriptions, but the AIX audit package assumes fixed
+ * length, so we can only do the first one for now.
+ */
+ case AUD_TDA:
+ {
+ struct tc_dumpArray *da;
+
+ da = (struct tc_dumpArray *)
+ va_arg(vaList, struct tc_dumpArray *);
+ if (da && da->tc_dumpArray_len) {
+ memcpy(bufferPtr, &da->tc_dumpArray_len, sizeof(u_int));
+ bufferPtr += sizeof(u_int);
+ memcpy(bufferPtr, da->tc_dumpArray_val,
+ sizeof(da->tc_dumpArray_val[0]));
+ } else {
+ memset(bufferPtr, 0, sizeof(u_int));
+ bufferPtr += sizeof(u_int);
+ memset(bufferPtr, 0, sizeof(da->tc_dumpArray_val[0]));
+ }
+ bufferPtr += sizeof(da->tc_dumpArray_val[0]);
+ break;
+ }
+ /*
+ * butc restore array
+ * An array of restore descriptions, but the AIX audit package assumes
+ * fixed length, so we can only do the first one for now.
+ */
+ case AUD_TRA:
+ {
+ struct tc_restoreArray *ra;
+
+ ra = (struct tc_restoreArray *)
+ va_arg(vaList, struct tc_restoreArray *);
+ if (ra && ra->tc_restoreArray_len) {
+ memcpy(bufferPtr, &ra->tc_restoreArray_len, sizeof(u_int));
+ bufferPtr += sizeof(u_int);
+ memcpy(bufferPtr, ra->tc_restoreArray_val,
+ sizeof(ra->tc_restoreArray_val[0]));
+ } else {
+ memset(bufferPtr, 0, sizeof(u_int));
+ bufferPtr += sizeof(u_int);
+ memset(bufferPtr, 0, sizeof(ra->tc_restoreArray_val[0]));
+ }
+ bufferPtr += sizeof(ra->tc_restoreArray_val[0]);
+ break;
+ }
+ /* butc tape controller status */
+ {
+ struct tciStatusS *status;
+
+ status = (struct tciStatusS *)va_arg(vaList,
+ struct tciStatusS *);
+ if (status)
+ memcpy(bufferPtr, status, sizeof(*status));
+ else
+ memset(bufferPtr, 0, sizeof(*status));
+ bufferPtr += sizeof(*status);
+ break;
+ }
default:
#ifdef AFS_AIX32_ENV
code =
vaEntry = va_arg(vaList, int);
} /* end while */
}
+#endif
-static
-printbuf(audEvent, errCode, vaList)
- char *audEvent;
- afs_int32 errCode;
- char *vaList;
+static void
+printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
+ afs_int32 errCode, va_list vaList)
{
int vaEntry;
int vaInt;
afs_int32 vaLong;
char *vaStr;
- char *vaLst;
- char hname[20];
struct AFSFid *vaFid;
struct AFSCBFids *vaFids;
+ struct tc_tapeLabel *vaLabel;
+ struct tc_dumpInterface *vaDI;
+ struct tc_dumpArray *vaDA;
+ struct tc_restoreArray *vaRA;
+ struct tciStatusS *vaTCstatus;
+ int num = LogThreadNum();
+ struct in_addr hostAddr;
+ time_t currenttime;
+ char tbuffer[26];
+ struct tm tm;
+ struct audit_msg *msg = calloc(1, sizeof(*msg));
- if (osi_echo_trail < 0)
- osi_audit_check();
- if (!osi_echo_trail)
+ if (!msg) {
return;
+ }
+
+ /* Don't print the timestamp or thread id if we recursed */
+ if (rec == 0) {
+ currenttime = time(0);
+ if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y ",
+ localtime_r(¤ttime, &tm)) !=0)
+ append_msg(msg, tbuffer);
- if (strcmp(audEvent, "VALST") != 0)
- printf("%s %d ", audEvent, errCode);
+ if (num > -1)
+ append_msg(msg, "[%d] ", num);
+ }
+
+ append_msg(msg, "EVENT %s CODE %d ", audEvent, errCode);
+
+ if (afsName) {
+ hostAddr.s_addr = hostId;
+ append_msg(msg, "NAME %s HOST %s ", afsName, inet_ntoa(hostAddr));
+ }
vaEntry = va_arg(vaList, int);
while (vaEntry != AUD_END) {
switch (vaEntry) {
case AUD_STR: /* String */
- vaStr = (char *)va_arg(vaList, int);
+ vaStr = (char *)va_arg(vaList, char *);
if (vaStr)
- printf("%s ", vaStr);
+ append_msg(msg, "STR %s ", vaStr);
else
- printf("<null>", vaStr);
+ append_msg(msg, "STR <null>");
+ break;
+ case AUD_NAME: /* Name */
+ vaStr = (char *)va_arg(vaList, char *);
+ if (vaStr)
+ append_msg(msg, "NAME %s ", vaStr);
+ else
+ append_msg(msg, "NAME <null>");
+ break;
+ case AUD_ACL: /* ACL */
+ vaStr = (char *)va_arg(vaList, char *);
+ if (vaStr)
+ append_msg(msg, "ACL %s ", vaStr);
+ else
+ append_msg(msg, "ACL <null>");
break;
case AUD_INT: /* Integer */
vaInt = va_arg(vaList, int);
- printf("%d ", vaInt);
+ append_msg(msg, "INT %d ", vaInt);
+ break;
+ case AUD_ID: /* ViceId */
+ vaInt = va_arg(vaList, int);
+ append_msg(msg, "ID %d ", vaInt);
break;
case AUD_DATE: /* Date */
+ vaLong = va_arg(vaList, afs_int32);
+ append_msg(msg, "DATE %u ", vaLong);
+ break;
case AUD_HOST: /* Host ID */
vaLong = va_arg(vaList, afs_int32);
- printf("%u ", vaLong);
+ hostAddr.s_addr = vaLong;
+ append_msg(msg, "HOST %s ", inet_ntoa(hostAddr));
break;
case AUD_LONG: /* afs_int32 */
vaLong = va_arg(vaList, afs_int32);
- printf("%d ", vaLong);
- break;
- case AUD_LST: /* Ptr to another list */
- vaLst = (char *)va_arg(vaList, int);
- printbuf("VALST", 0, vaLst);
+ append_msg(msg, "LONG %d ", vaLong);
break;
case AUD_FID: /* AFSFid - contains 3 entries */
- vaFid = (struct AFSFid *)va_arg(vaList, int);
+ vaFid = va_arg(vaList, struct AFSFid *);
if (vaFid)
- printf("%u:%u:%u ", vaFid->Volume, vaFid->Vnode,
- vaFid->Unique);
+ append_msg(msg, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
+ vaFid->Unique);
else
- printf("%u:%u:%u ", 0, 0, 0);
+ append_msg(msg, "FID %u:%u:%u ", 0, 0, 0);
break;
case AUD_FIDS: /* array of Fids */
- vaFids = (struct AFSCBFids *)va_arg(vaList, int);
- vaFid = NULL;
+ vaFids = va_arg(vaList, struct AFSCBFids *);
- if (vaFids)
- vaFid = vaFids->AFSCBFids_val;
- if (vaFid)
- printf("%u %u:%u:%u ", vaFids->AFSCBFids_len, vaFid->Volume,
- vaFid->Vnode, vaFid->Unique);
+ if (vaFids) {
+ unsigned int i;
+
+ vaFid = vaFids->AFSCBFids_val;
+
+ if (vaFid) {
+ append_msg(msg, "FIDS %u ", vaFids->AFSCBFids_len);
+ for ( i = 1; i <= vaFids->AFSCBFids_len; i++, vaFid++ )
+ append_msg(msg, "FID %u:%u:%u ", vaFid->Volume,
+ vaFid->Vnode, vaFid->Unique);
+ } else
+ append_msg(msg, "FIDS 0 FID 0:0:0 ");
+
+ }
+ break;
+ case AUD_TLBL: /* butc tape label */
+ vaLabel = va_arg(vaList, struct tc_tapeLabel *);
+
+ if (vaLabel) {
+ append_msg(msg, "TAPELABEL %d:%.*s:%.*s:%u ",
+ vaLabel->size,
+ TC_MAXTAPELEN, vaLabel->afsname,
+ TC_MAXTAPELEN, vaLabel->pname,
+ vaLabel->tapeId);
+ } else {
+ append_msg(msg, "TAPELABEL <null>");
+ }
+ break;
+ case AUD_TDI:
+ vaDI = va_arg(vaList, struct tc_dumpInterface *);
+
+ if (vaDI) {
+ append_msg(msg,
+ "TCDUMPINTERFACE %.*s:%.*s:%.*s:%d:%d:%d:%d:%.*s:%.*s:%d:%d:%d:%d:%d ",
+ TC_MAXDUMPPATH, vaDI->dumpPath, TC_MAXNAMELEN, vaDI->volumeSetName,
+ TC_MAXNAMELEN, vaDI->dumpName, vaDI->parentDumpId, vaDI->dumpLevel,
+ vaDI->doAppend,
+ vaDI->tapeSet.id, TC_MAXHOSTLEN, vaDI->tapeSet.tapeServer,
+ TC_MAXFORMATLEN, vaDI->tapeSet.format, vaDI->tapeSet.maxTapes,
+ vaDI->tapeSet.a, vaDI->tapeSet.b, vaDI->tapeSet.expDate,
+ vaDI->tapeSet.expType);
+ } else {
+ append_msg(msg, "TCDUMPINTERFACE <null>");
+ }
+ break;
+ case AUD_TDA:
+ vaDA = va_arg(vaList, struct tc_dumpArray *);
+
+ if (vaDA) {
+ u_int i;
+ struct tc_dumpDesc *desc;
+ struct in_addr hostAddr;
+
+ desc = vaDA->tc_dumpArray_val;
+ if (desc) {
+ append_msg(msg, "DUMPS %d ", vaDA->tc_dumpArray_len);
+ for (i = 0; i < vaDA->tc_dumpArray_len; i++, desc++) {
+ hostAddr.s_addr = desc->hostAddr;
+ append_msg(msg, "DUMP %d:%d:%.*s:%d:%d:%d:%s ",
+ desc->vid, desc->vtype, TC_MAXNAMELEN, desc->name,
+ desc->partition, desc->date, desc->cloneDate,
+ inet_ntoa(hostAddr));
+ }
+ } else {
+ append_msg(msg, "DUMPS 0 DUMP 0:0::0:0:0:0.0.0.0");
+ }
+ }
+ break;
+ case AUD_TRA:
+ vaRA = va_arg(vaList, struct tc_restoreArray *);
+
+ if (vaRA) {
+ u_int i;
+ struct tc_restoreDesc *desc;
+ struct in_addr hostAddr;
+
+ desc = vaRA->tc_restoreArray_val;
+ if (desc) {
+ append_msg(msg, "RESTORES %d ",
+ vaRA->tc_restoreArray_len);
+ for(i = 0; i < vaRA->tc_restoreArray_len; i++, desc++) {
+ hostAddr.s_addr = desc->hostAddr;
+ append_msg(msg,
+ "RESTORE %d:%.*s:%d:%d:%d:%d:%d:%d:%d:%s:%.*s:%.*s ",
+ desc->flags, TC_MAXTAPELEN, desc->tapeName,
+ desc->dbDumpId, desc->initialDumpId,
+ desc->position, desc->origVid, desc->vid,
+ desc->partition, desc->dumpLevel,
+ inet_ntoa(hostAddr), TC_MAXNAMELEN,
+ desc->oldName, TC_MAXNAMELEN, desc->newName);
+ }
+ } else {
+ append_msg(msg,
+ "RESTORES 0 RESTORE 0::0:0:0:0:0:0:0:0.0.0.0::: ");
+ }
+ }
+ break;
+ case AUD_TSTT:
+ vaTCstatus = va_arg(vaList, struct tciStatusS *);
+
+ if (vaTCstatus)
+ append_msg(msg, "TCSTATUS %.*s:%d:%d:%d:%d:%.*s:%d:%d ",
+ TC_MAXNAMELEN, vaTCstatus->taskName,
+ vaTCstatus->taskId, vaTCstatus->flags,
+ vaTCstatus->dbDumpId, vaTCstatus->nKBytes,
+ TC_MAXNAMELEN, vaTCstatus->volumeName,
+ vaTCstatus->volsFailed,
+ vaTCstatus->lastPolled);
else
- printf("0 0:0:0 ");
+ append_msg(msg, "TCSTATUS <null>");
break;
default:
- printf("--badval-- ");
+ append_msg(msg, "--badval-- ");
break;
} /* end switch */
vaEntry = va_arg(vaList, int);
} /* end while */
- if (strcmp(audEvent, "VALST") != 0)
- printf("\n");
-}
-#else
-static
-aixmakebuf(audEvent, vaList)
- char *audEvent;
- va_list vaList;
-{
- return;
+ MUTEX_ENTER(&audit_lock);
+ multi_send_msg(msg);
+ MUTEX_EXIT(&audit_lock);
+
+ free(msg);
}
-static
-printbuf(audEvent, errCode, vaList)
- char *audEvent;
- long errCode;
- va_list vaList;
+#ifdef AFS_PTHREAD_ENV
+static void
+osi_audit_init_lock(void)
{
- return;
+ MUTEX_INIT(&audit_lock, "audit", MUTEX_DEFAULT, 0);
}
-
#endif
+void
+osi_audit_init(void)
+{
+#ifdef AFS_PTHREAD_ENV
+ pthread_once(&audit_lock_once, osi_audit_init_lock);
+#endif /* AFS_PTHREAD_ENV */
+}
/* ************************************************************************** */
/* The routine that acually does the audit call.
* ************************************************************************** */
-int
-osi_audit(char *audEvent, /* Event name (15 chars or less) */
- afs_int32 errCode, /* The error code */
- ...)
+static int
+osi_audit_internal(char *audEvent, /* Event name (15 chars or less) */
+ afs_int32 errCode, /* The error code */
+ char *afsName,
+ afs_int32 hostId,
+ va_list vaList)
{
#ifdef AFS_AIX32_ENV
afs_int32 code;
afs_int32 err;
+ static char BUFFER[32768];
int result;
+#endif
- va_list vaList;
- static struct Lock audbuflock = { 0, 0, 0, 0,
#ifdef AFS_PTHREAD_ENV
- PTHREAD_MUTEX_INITIALIZER,
- PTHREAD_COND_INITIALIZER,
- PTHREAD_COND_INITIALIZER
+ /* i'm pretty sure all the server apps now call osi_audit_init(),
+ * but to be extra careful we'll leave this in here for a
+ * while to make sure */
+ pthread_once(&audit_lock_once, osi_audit_init_lock);
#endif /* AFS_PTHREAD_ENV */
- };
- static char BUFFER[32768];
- if (osi_audit_all < 0)
+ if ((osi_audit_all < 0) || (osi_echo_trail < 0))
osi_audit_check();
- if (!osi_audit_all)
- return;
+ if (!osi_audit_all && !auditout_open)
+ return 0;
+#ifdef AFS_AIX32_ENV
switch (errCode) {
case 0:
result = AUDIT_OK;
break;
case VL_PERM: /* vlserver.h */
case BUDB_NOTPERMITTED: /* budb_errs.h */
-/* case KRB_RD_AP_UNAUTHOR : */
case BZACCESS: /* bnode.h */
case VOLSERBAD_ACCESS: /* volser.h */
result = AUDIT_FAIL_PRIV;
result = AUDIT_FAIL;
break;
}
+#endif
- ObtainWriteLock(&audbuflock);
+#ifdef AFS_AIX32_ENV
+ MUTEX_ENTER(&audit_lock);
bufferPtr = BUFFER;
/* Put the error code into the buffer list */
*(int *)bufferPtr = errCode;
bufferPtr += sizeof(errCode);
- va_start(vaList, errCode);
- aixmakebuf(audEvent, vaList);
-
- va_start(vaList, errCode);
- printbuf(audEvent, errCode, vaList);
+ audmakebuf(audEvent, vaList);
bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
code = auditlog(audEvent, result, BUFFER, bufferLen);
-#ifdef notdef
- if (code) {
- err = errno;
- code = auditlog("AFS_Aud_Fail", result, &err, sizeof(err));
- if (code)
- printf("Error while writing audit entry: %d.\n", errno);
+ MUTEX_EXIT(&audit_lock);
+#else
+ if (auditout_open) {
+ printbuf(0, audEvent, afsName, hostId, errCode, vaList);
}
-#endif /* notdef */
- ReleaseWriteLock(&audbuflock);
#endif
+
+ return 0;
+}
+int
+osi_audit(char *audEvent, /* Event name (15 chars or less) */
+ afs_int32 errCode, /* The error code */
+ ...)
+{
+ va_list vaList;
+
+ if ((osi_audit_all < 0) || (osi_echo_trail < 0))
+ osi_audit_check();
+ if (!osi_audit_all && !auditout_open)
+ return 0;
+
+ va_start(vaList, errCode);
+ osi_audit_internal(audEvent, errCode, NULL, 0, vaList);
+ va_end(vaList);
+
+ return 0;
}
/* ************************************************************************** */
-/* Given a RPC call structure, this routine extracts the name and host id from the
+/* Given a RPC call structure, this routine extracts the name and host id from the
* call and includes it within the audit information.
* ************************************************************************** */
int
struct rx_peer *peer;
afs_int32 secClass;
afs_int32 code;
- char afsName[MAXKTCNAMELEN];
+ char afsName[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
afs_int32 hostId;
va_list vaList;
-
if (osi_audit_all < 0)
osi_audit_check();
- if (!osi_audit_all)
- return;
+ if (!osi_audit_all && !auditout_open)
+ return 0;
strcpy(afsName, "--Unknown--");
hostId = 0;
if (call) {
conn = rx_ConnectionOf(call); /* call -> conn) */
if (conn) {
- secClass = rx_SecurityClassOf(conn); /* conn -> securityIndex */
- if (secClass == 0) { /* unauthenticated */
+ secClass = rx_SecurityClassOf(conn); /* conn -> securityIndex */
+ if (secClass == RX_SECIDX_NULL) { /* unauthenticated */
osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
strcpy(afsName, "--UnAuth--");
- } else if (secClass == 2) { /* authenticated */
- code =
- rxkad_GetServerInfo(conn, NULL, NULL, afsName, NULL, NULL,
+ } else if (secClass == RX_SECIDX_KAD || secClass == RX_SECIDX_KAE) {
+ /* authenticated with rxkad */
+ char tcell[MAXKTCREALMLEN];
+ char name[MAXKTCNAMELEN];
+ char inst[MAXKTCNAMELEN];
+
+ code =
+ rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
NULL);
if (code) {
- osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent,
- AUD_END);
+ osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
strcpy(afsName, "--NoName--");
+ } else {
+ afs_int32 islocal = 0;
+ if (audit_user_check.islocal) {
+ islocal =
+ audit_user_check.islocal(audit_user_check.rock,
+ name, inst, tcell);
+ }
+ strlcpy(afsName, name, sizeof(afsName));
+ if (inst[0]) {
+ strlcat(afsName, ".", sizeof(afsName));
+ strlcat(afsName, inst, sizeof(afsName));
+ }
+ if (tcell[0] && !islocal) {
+ strlcat(afsName, "@", sizeof(afsName));
+ strlcat(afsName, tcell, sizeof(afsName));
+ }
}
- } else { /* Unauthenticated & unknown */
-
- osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent,
- AUD_END);
+ } else { /* Unauthenticated and/or unknown */
+ osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
+ strcpy(afsName, "--Unknown--");
}
-
peer = rx_PeerOf(conn); /* conn -> peer */
if (peer)
hostId = rx_HostOf(peer); /* peer -> host */
else
osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
} else { /* null conn */
-
osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
}
} else { /* null call */
-
osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
}
-
va_start(vaList, errCode);
- osi_audit(audEvent, errCode, AUD_STR, afsName, AUD_HOST, hostId, AUD_LST,
- vaList, AUD_END);
+ osi_audit_internal(audEvent, errCode, afsName, hostId, vaList);
+ va_end(vaList);
+ return 0;
}
/* ************************************************************************** */
/* Determines whether auditing is on or off by looking at the Audit file.
- * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
+ * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
* enabled.
* ************************************************************************** */
int
-osi_audit_check()
+osi_audit_check(void)
{
FILE *fds;
int onoff;
/* Now set whether we audit all events from here on out */
osi_audit_all = onoff;
+
+ return 0;
+}
+
+/*
+ * Handle parsing a string: [interface_name:]filespec[:options]
+ * The string a:b will parse 'a' as the interface name and 'b' as the filespec.
+ * Note that the string pointed by optionstr will be modified
+ * by strtok_r by inserting '\0' between the tokens.
+ * The values returned in interface_name, filespec and options
+ * are pointers to the 'sub-strings' within optionstr.
+ */
+static int
+parse_file_options(char *optionstr,
+ const char **interface_name,
+ char **filespec,
+ char **options)
+{
+ int code = 0;
+ char *opt_cursor = optionstr;
+ char *tok1 = NULL, *tok2 = NULL, *tok3 = NULL, *tokptrsave = NULL;
+
+ /*
+ * Handle the fact that strtok doesn't handle empty fields e.g. a::b
+ * and will return tok1-> a tok2-> b
+ */
+
+ /* 1st field */
+ if (*opt_cursor != ':') {
+ tok1 = strtok_r(opt_cursor, ":", &tokptrsave);
+ opt_cursor = strtok_r(NULL, "", &tokptrsave);
+ } else {
+ /* Skip the ':' */
+ opt_cursor++;
+ }
+
+ /* 2nd field */
+ if (opt_cursor != NULL) {
+ if (*opt_cursor != ':') {
+ tok2 = strtok_r(opt_cursor, ":", &tokptrsave);
+ opt_cursor = strtok_r(NULL, "", &tokptrsave);
+ } else {
+ /* Skip the ':' */
+ opt_cursor++;
+ }
+ }
+
+ /* 3rd field is just the remainder if any */
+ tok3 = opt_cursor;
+
+ if (tok1 == NULL || strlen(tok1) == 0) {
+ fprintf(stderr, "Missing -auditlog parameter\n");
+ code = EINVAL;
+ goto done;
+ }
+
+ /* If only one token, then it's the filespec */
+ if (tok2 == NULL && tok3 == NULL) {
+ *filespec = tok1;
+ } else {
+ *interface_name = tok1;
+ *filespec = tok2;
+ *options = tok3;
+ }
+
+ done:
+ return code;
}
+/*
+ * Parse the options looking for comma-seperated values.
+ */
+static int
+parse_option_string(const struct osi_audit_ops *ops, void *rock, char *options)
+{
+ int code = 0;
+ char *tok1, *tokptrsave = NULL;
+
+ tok1 = strtok_r(options, ",", &tokptrsave);
+ while (tok1) {
+ /* Handle opt=val or just opt */
+ char *opt, *val;
+ char *optvalsave;
+
+ opt = strtok_r(tok1, "=", &optvalsave);
+ val = strtok_r(NULL, "", &optvalsave);
+
+ code = ops->set_option(rock, opt, val);
-#else /* ! AFS_AIX_ENV */
+ if (code) {
+ /* Bad option */
+ goto done;
+ }
+ tok1 = strtok_r(NULL, ",", &tokptrsave);
+ }
+
+ done:
+ return code;
+}
+
+/*
+ * Process -auditlog
+ * [interface]:filespec[:options]
+ * interface - interface name (optional - defaults to default_interface)
+ * filespec - depends on the interface (required)
+ * options - optional string passed to interface
+ * Returns 0 - success
+ * EINVAL - option error
+ * ENOMEM - error allocating memory
+ */
int
-osi_audit(char *audEvent, afs_int32 errCode, ...)
+osi_audit_file(const char *fileplusoptions)
{
- return 0;
+
+ int idx;
+ int code;
+
+ char *optionstr = NULL;
+
+ const char *interface_name = NULL;
+ char *filespec = NULL;
+ char *options = NULL;
+
+ const struct osi_audit_ops *ops = NULL;
+ struct audit_log *new_alog = NULL;
+
+ /* Use the default unless specified */
+ interface_name = audit_interfaces[default_interface].name;
+
+ /* dup of the input string so the parsing can safely modify it */
+ optionstr = strdup(fileplusoptions);
+ if (!optionstr) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ code = parse_file_options(optionstr, &interface_name, &filespec, &options);
+ if (code)
+ goto done;
+
+ if (interface_name && strlen(interface_name) != 0) {
+ for (idx = 0; idx < N_INTERFACES; idx++) {
+ if (strcmp(interface_name, audit_interfaces[idx].name) == 0) {
+ ops = audit_interfaces[idx].ops;
+ break;
+ }
+ }
+ if (ops == NULL) {
+ /* Couldn't find the interface name */
+ fprintf(stderr, "Could not find the specified audit interface %s\n", interface_name);
+ code = EINVAL;
+ goto done;
+ }
+ } else {
+ fprintf(stderr, "Missing interface name\n");
+ code = EINVAL;
+ goto done;
+ }
+
+ if (filespec == NULL || strlen(filespec) == 0) {
+ fprintf(stderr, "Missing auditlog path for %s interface\n", interface_name);
+ code = EINVAL;
+ goto done;
+ }
+
+ opr_Assert(ops->create_interface != NULL);
+ opr_Assert(ops->close_interface != NULL);
+ opr_Assert(ops->open_file != NULL);
+ opr_Assert(ops->send_msg != NULL);
+ opr_Assert(ops->print_interface_stats != NULL);
+ /* open_interface, set_option and close_interface are optional */
+
+ new_alog = calloc(1, sizeof(*new_alog));
+ if (!new_alog) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ new_alog->audit_ops = ops;
+ new_alog->auditout_open = 0;
+
+ new_alog->context = ops->create_interface();
+ if (new_alog->context == NULL) {
+ code = ENOMEM;
+ goto done;
+ }
+
+ if (options != NULL && ops->set_option != NULL) {
+ /* Split the option string at commas */
+ code = parse_option_string(ops, new_alog->context, options);
+ if (code)
+ goto done;
+ }
+
+ code = ops->open_file(new_alog->context, filespec);
+ if (code) {
+ /* Error opening file */
+ goto done;
+ }
+
+ new_alog->auditout_open = 1;
+ auditout_open = 1;
+
+ /* Add to chain of active interfaces */
+ opr_queue_Append(&audit_logs, &new_alog->link);
+ new_alog = NULL;
+
+ code = 0;
+
+ done:
+ if (code) {
+ /* Error condition present.. */
+ if (new_alog) {
+ ops->close_interface(&new_alog->context);
+ free(new_alog);
+ }
+ }
+
+ if (optionstr)
+ free(optionstr);
+ return code;
}
+/*
+ * Set the default interface
+ * return 0 for success
+ * EINVAL missing or invalid interface name
+ */
int
-osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
+osi_audit_interface(const char *interface)
{
- return 0;
+ int idx;
+
+ if (interface == NULL || strlen(interface) == 0)
+ return EINVAL;
+
+ for (idx = 0; idx < N_INTERFACES; idx++) {
+ if (strcmp(interface, audit_interfaces[idx].name) == 0) {
+ default_interface = idx;
+ return 0;
+ }
+ }
+ return EINVAL;
}
-#endif
+/*
+ * Let the interfaces finish initialization
+ */
+void
+osi_audit_open(void)
+{
+ struct opr_queue *cursor;
+
+ for (opr_queue_Scan(&audit_logs, cursor)) {
+ struct audit_log *alog;
+ alog = opr_queue_Entry(cursor, struct audit_log, link);
+ if (alog->auditout_open && alog->audit_ops->open_interface != NULL)
+ alog->audit_ops->open_interface(alog->context);
+ }
+}
+
+/*
+ * Shutdown the interfaces
+ */
+void
+osi_audit_close(void)
+{
+ struct opr_queue *cursor, *cursorsave;
+
+ for (opr_queue_ScanSafe(&audit_logs, cursor, cursorsave)) {
+ struct audit_log *alog;
+ alog = opr_queue_Entry(cursor, struct audit_log, link);
+ alog->audit_ops->close_interface(&alog->context);
+ opr_queue_Remove(&alog->link);
+ free(alog);
+ }
+}
+
+void
+osi_audit_set_user_check(void *rock,
+ int (*islocal) (void *rock, char *name, char *inst,
+ char *cell))
+{
+ audit_user_check.rock = rock;
+ audit_user_check.islocal = islocal;
+}
+
+void
+audit_PrintStats(FILE *out)
+{
+ struct opr_queue *cursor;
+
+ for (opr_queue_Scan(&audit_logs, cursor)) {
+ struct audit_log *alog;
+ alog = opr_queue_Entry(cursor, struct audit_log, link);
+ if (alog->auditout_open)
+ alog->audit_ops->print_interface_stats(alog->context, out);
+ }
+}