2 * Copyright 2000, International Business Machines Corporation and others.
5 * This software has been released under the terms of the IBM Public
6 * License. For details, see the LICENSE file in the top-level source
7 * directory or online at http://www.openafs.org/dl/license10.html
10 #include <afsconfig.h>
11 #include <afs/param.h>
16 #include <sys/audit.h>
20 #define AUDIT_FAIL_AUTH 2
21 #define AUDIT_FAIL_ACCESS 3
22 #define AUDIT_FAIL_PRIV 4
23 #endif /* AFS_AIX32_ENV */
26 #include "afs/afsint.h"
31 #include "audit-api.h"
34 #include <afs/afsutil.h>
36 extern struct osi_audit_ops audit_file_ops;
38 extern struct osi_audit_ops audit_sysvmq_ops;
43 int (*islocal)(void *rock, char *name, char *inst, char *cell);
44 } audit_user_check = { NULL, NULL };
48 const struct osi_audit_ops *ops;
49 } audit_interfaces[] = {
51 { "file", &audit_file_ops },
53 { "sysvmq", &audit_sysvmq_ops },
56 /* default_interface indexes into the audit_interfaces list. */
57 static int default_interface = 0; /* Set default to the file interface */
59 #define N_INTERFACES (sizeof(audit_interfaces) / sizeof(audit_interfaces[0]))
62 * Audit interface calling sequence:
63 * osi_audit_interface - sets the default audit interface
65 * create_instance - Called during command arg processing (-auditlog)
66 * open_file - Called during command arg processing (-auditlog)
67 * osi_audit_open_interface
68 * open_interface - Called after thread environment has been established
69 * osi_audit_close_interface
70 * close_interface - Called during main process shutdown
72 * send_msg - Called during audit events
75 struct opr_queue link;
76 const struct osi_audit_ops *audit_ops;
82 char buf[OSI_AUDIT_MAXMSG];
83 size_t len; /* length of the string in 'buf' (not including the trailing '\0') */
84 int truncated; /* was this message truncated during formatting? */
87 #ifdef AFS_PTHREAD_ENV
88 static pthread_mutex_t audit_lock;
89 static pthread_once_t audit_lock_once = PTHREAD_ONCE_INIT;
92 /* Chain of active interfaces */
93 static struct opr_queue audit_logs = {&audit_logs, &audit_logs};
95 static int osi_audit_all = (-1); /* Not determined yet */
96 static int osi_echo_trail = (-1);
98 static int auditout_open = 0; /* True if any interface is open */
100 static int osi_audit_check(void);
103 * Send the message to all the interfaces
104 * @pre audit_lock held
107 multi_send_msg(struct audit_msg *msg)
109 struct opr_queue *cursor;
111 if (msg->len < 1) /* Don't send empty strings */
114 for (opr_queue_Scan(&audit_logs, cursor)) {
115 struct audit_log *alog;
116 alog = opr_queue_Entry(cursor, struct audit_log, link);
117 if (alog->auditout_open) {
118 alog->audit_ops->send_msg(alog->context, msg->buf, msg->len,
124 append_msg(struct audit_msg *msg, const char *format, ...)
127 int remaining, printed;
129 if (msg->truncated) {
133 if (msg->len >= OSI_AUDIT_MAXMSG - 1) {
134 /* Make sure we have at least some space left */
139 remaining = OSI_AUDIT_MAXMSG - msg->len;
141 va_start(ap, format);
143 printed = vsnprintf(&msg->buf[msg->len], remaining, format, ap);
146 /* Error during formatting. */
150 } else if (printed >= remaining) {
151 /* We tried to write more characters than we had space for. */
153 printed = remaining - 1;
155 /* Make sure we're still terminated. */
156 msg->buf[OSI_AUDIT_MAXMSG - 1] = '\0';
160 opr_Assert(msg->len < OSI_AUDIT_MAXMSG);
165 static char *bufferPtr;
166 static int bufferLen;
169 audmakebuf(char *audEvent, va_list vaList)
176 struct AFSFid *vaFid;
178 vaEntry = va_arg(vaList, int);
179 while (vaEntry != AUD_END) {
181 case AUD_STR: /* String */
182 case AUD_NAME: /* Name */
183 case AUD_ACL: /* ACL */
184 vaStr = (char *)va_arg(vaList, char *);
186 strcpy(bufferPtr, vaStr);
187 bufferPtr += strlen(vaStr) + 1;
189 strcpy(bufferPtr, "");
193 case AUD_INT: /* Integer */
194 case AUD_ID: /* ViceId */
195 vaInt = va_arg(vaList, int);
196 *(int *)bufferPtr = vaInt;
197 bufferPtr += sizeof(vaInt);
199 case AUD_DATE: /* Date */
200 case AUD_HOST: /* Host ID */
201 case AUD_LONG: /* long */
202 vaLong = va_arg(vaList, afs_int32);
203 *(afs_int32 *) bufferPtr = vaLong;
204 bufferPtr += sizeof(vaLong);
206 case AUD_FID: /* AFSFid - contains 3 entries */
207 vaFid = (struct AFSFid *)va_arg(vaList, struct AFSFid *);
209 memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
211 memset(bufferPtr, 0, sizeof(struct AFSFid));
213 bufferPtr += sizeof(struct AFSFid);
216 /* Whole array of fids-- don't know how to handle variable length audit
217 * data with AIX audit package, so for now we just store the first fid.
218 * Better one than none. */
221 struct AFSCBFids *Fids;
223 Fids = (struct AFSCBFids *)va_arg(vaList, struct AFSCBFids *);
224 if (Fids && Fids->AFSCBFids_len) {
225 *((u_int *) bufferPtr) = Fids->AFSCBFids_len;
226 bufferPtr += sizeof(u_int);
227 memcpy(bufferPtr, Fids->AFSCBFids_val,
228 sizeof(struct AFSFid));
230 *((u_int *) bufferPtr) = 0;
231 bufferPtr += sizeof(u_int);
232 memset(bufferPtr, 0, sizeof(struct AFSFid));
234 bufferPtr += sizeof(struct AFSFid);
237 /* butc tape label */
240 struct tc_tapeLabel *label;
242 label = (struct tc_tapeLabel *)va_arg(vaList,
243 struct tc_tapeLabel *);
245 memcpy(bufferPtr, label, sizeof(*label));
247 memset(bufferPtr, 0, sizeof(*label));
248 bufferPtr += sizeof(label);
251 /* butc dump interface */
254 struct tc_dumpInterface *di;
256 di = (struct tc_dumpInterface *)
257 va_arg(vaList, struct tc_dumpInterface *);
259 memcpy(bufferPtr, di, sizeof(*di));
261 memset(bufferPtr, 0, sizeof(*di));
262 bufferPtr += sizeof(*di);
267 * An array of dump descriptions, but the AIX audit package assumes fixed
268 * length, so we can only do the first one for now.
272 struct tc_dumpArray *da;
274 da = (struct tc_dumpArray *)
275 va_arg(vaList, struct tc_dumpArray *);
276 if (da && da->tc_dumpArray_len) {
277 memcpy(bufferPtr, &da->tc_dumpArray_len, sizeof(u_int));
278 bufferPtr += sizeof(u_int);
279 memcpy(bufferPtr, da->tc_dumpArray_val,
280 sizeof(da->tc_dumpArray_val[0]));
282 memset(bufferPtr, 0, sizeof(u_int));
283 bufferPtr += sizeof(u_int);
284 memset(bufferPtr, 0, sizeof(da->tc_dumpArray_val[0]));
286 bufferPtr += sizeof(da->tc_dumpArray_val[0]);
291 * An array of restore descriptions, but the AIX audit package assumes
292 * fixed length, so we can only do the first one for now.
296 struct tc_restoreArray *ra;
298 ra = (struct tc_restoreArray *)
299 va_arg(vaList, struct tc_restoreArray *);
300 if (ra && ra->tc_restoreArray_len) {
301 memcpy(bufferPtr, &ra->tc_restoreArray_len, sizeof(u_int));
302 bufferPtr += sizeof(u_int);
303 memcpy(bufferPtr, ra->tc_restoreArray_val,
304 sizeof(ra->tc_restoreArray_val[0]));
306 memset(bufferPtr, 0, sizeof(u_int));
307 bufferPtr += sizeof(u_int);
308 memset(bufferPtr, 0, sizeof(ra->tc_restoreArray_val[0]));
310 bufferPtr += sizeof(ra->tc_restoreArray_val[0]);
313 /* butc tape controller status */
315 struct tciStatusS *status;
317 status = (struct tciStatusS *)va_arg(vaList,
318 struct tciStatusS *);
320 memcpy(bufferPtr, status, sizeof(*status));
322 memset(bufferPtr, 0, sizeof(*status));
323 bufferPtr += sizeof(*status);
329 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
330 (strlen(audEvent) + 1));
336 vaEntry = va_arg(vaList, int);
342 printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
343 afs_int32 errCode, va_list vaList)
349 struct AFSFid *vaFid;
350 struct AFSCBFids *vaFids;
351 struct tc_tapeLabel *vaLabel;
352 struct tc_dumpInterface *vaDI;
353 struct tc_dumpArray *vaDA;
354 struct tc_restoreArray *vaRA;
355 struct tciStatusS *vaTCstatus;
356 int num = LogThreadNum();
357 struct in_addr hostAddr;
361 struct audit_msg *msg = calloc(1, sizeof(*msg));
367 /* Don't print the timestamp or thread id if we recursed */
369 currenttime = time(0);
370 if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y ",
371 localtime_r(¤ttime, &tm)) !=0)
372 append_msg(msg, tbuffer);
375 append_msg(msg, "[%d] ", num);
378 append_msg(msg, "EVENT %s CODE %d ", audEvent, errCode);
381 hostAddr.s_addr = hostId;
382 append_msg(msg, "NAME %s HOST %s ", afsName, inet_ntoa(hostAddr));
385 vaEntry = va_arg(vaList, int);
386 while (vaEntry != AUD_END) {
388 case AUD_STR: /* String */
389 vaStr = (char *)va_arg(vaList, char *);
391 append_msg(msg, "STR %s ", vaStr);
393 append_msg(msg, "STR <null>");
395 case AUD_NAME: /* Name */
396 vaStr = (char *)va_arg(vaList, char *);
398 append_msg(msg, "NAME %s ", vaStr);
400 append_msg(msg, "NAME <null>");
402 case AUD_ACL: /* ACL */
403 vaStr = (char *)va_arg(vaList, char *);
405 append_msg(msg, "ACL %s ", vaStr);
407 append_msg(msg, "ACL <null>");
409 case AUD_INT: /* Integer */
410 vaInt = va_arg(vaList, int);
411 append_msg(msg, "INT %d ", vaInt);
413 case AUD_ID: /* ViceId */
414 vaInt = va_arg(vaList, int);
415 append_msg(msg, "ID %d ", vaInt);
417 case AUD_DATE: /* Date */
418 vaLong = va_arg(vaList, afs_int32);
419 append_msg(msg, "DATE %u ", vaLong);
421 case AUD_HOST: /* Host ID */
422 vaLong = va_arg(vaList, afs_int32);
423 hostAddr.s_addr = vaLong;
424 append_msg(msg, "HOST %s ", inet_ntoa(hostAddr));
426 case AUD_LONG: /* afs_int32 */
427 vaLong = va_arg(vaList, afs_int32);
428 append_msg(msg, "LONG %d ", vaLong);
430 case AUD_FID: /* AFSFid - contains 3 entries */
431 vaFid = va_arg(vaList, struct AFSFid *);
433 append_msg(msg, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
436 append_msg(msg, "FID %u:%u:%u ", 0, 0, 0);
438 case AUD_FIDS: /* array of Fids */
439 vaFids = va_arg(vaList, struct AFSCBFids *);
444 vaFid = vaFids->AFSCBFids_val;
447 append_msg(msg, "FIDS %u ", vaFids->AFSCBFids_len);
448 for ( i = 1; i <= vaFids->AFSCBFids_len; i++, vaFid++ )
449 append_msg(msg, "FID %u:%u:%u ", vaFid->Volume,
450 vaFid->Vnode, vaFid->Unique);
452 append_msg(msg, "FIDS 0 FID 0:0:0 ");
456 case AUD_TLBL: /* butc tape label */
457 vaLabel = va_arg(vaList, struct tc_tapeLabel *);
460 append_msg(msg, "TAPELABEL %d:%.*s:%.*s:%u ",
462 TC_MAXTAPELEN, vaLabel->afsname,
463 TC_MAXTAPELEN, vaLabel->pname,
466 append_msg(msg, "TAPELABEL <null>");
470 vaDI = va_arg(vaList, struct tc_dumpInterface *);
474 "TCDUMPINTERFACE %.*s:%.*s:%.*s:%d:%d:%d:%d:%.*s:%.*s:%d:%d:%d:%d:%d ",
475 TC_MAXDUMPPATH, vaDI->dumpPath, TC_MAXNAMELEN, vaDI->volumeSetName,
476 TC_MAXNAMELEN, vaDI->dumpName, vaDI->parentDumpId, vaDI->dumpLevel,
478 vaDI->tapeSet.id, TC_MAXHOSTLEN, vaDI->tapeSet.tapeServer,
479 TC_MAXFORMATLEN, vaDI->tapeSet.format, vaDI->tapeSet.maxTapes,
480 vaDI->tapeSet.a, vaDI->tapeSet.b, vaDI->tapeSet.expDate,
481 vaDI->tapeSet.expType);
483 append_msg(msg, "TCDUMPINTERFACE <null>");
487 vaDA = va_arg(vaList, struct tc_dumpArray *);
491 struct tc_dumpDesc *desc;
492 struct in_addr hostAddr;
494 desc = vaDA->tc_dumpArray_val;
496 append_msg(msg, "DUMPS %d ", vaDA->tc_dumpArray_len);
497 for (i = 0; i < vaDA->tc_dumpArray_len; i++, desc++) {
498 hostAddr.s_addr = desc->hostAddr;
499 append_msg(msg, "DUMP %d:%d:%.*s:%d:%d:%d:%s ",
500 desc->vid, desc->vtype, TC_MAXNAMELEN, desc->name,
501 desc->partition, desc->date, desc->cloneDate,
502 inet_ntoa(hostAddr));
505 append_msg(msg, "DUMPS 0 DUMP 0:0::0:0:0:0.0.0.0");
510 vaRA = va_arg(vaList, struct tc_restoreArray *);
514 struct tc_restoreDesc *desc;
515 struct in_addr hostAddr;
517 desc = vaRA->tc_restoreArray_val;
519 append_msg(msg, "RESTORES %d ",
520 vaRA->tc_restoreArray_len);
521 for(i = 0; i < vaRA->tc_restoreArray_len; i++, desc++) {
522 hostAddr.s_addr = desc->hostAddr;
524 "RESTORE %d:%.*s:%d:%d:%d:%d:%d:%d:%d:%s:%.*s:%.*s ",
525 desc->flags, TC_MAXTAPELEN, desc->tapeName,
526 desc->dbDumpId, desc->initialDumpId,
527 desc->position, desc->origVid, desc->vid,
528 desc->partition, desc->dumpLevel,
529 inet_ntoa(hostAddr), TC_MAXNAMELEN,
530 desc->oldName, TC_MAXNAMELEN, desc->newName);
534 "RESTORES 0 RESTORE 0::0:0:0:0:0:0:0:0.0.0.0::: ");
539 vaTCstatus = va_arg(vaList, struct tciStatusS *);
542 append_msg(msg, "TCSTATUS %.*s:%d:%d:%d:%d:%.*s:%d:%d ",
543 TC_MAXNAMELEN, vaTCstatus->taskName,
544 vaTCstatus->taskId, vaTCstatus->flags,
545 vaTCstatus->dbDumpId, vaTCstatus->nKBytes,
546 TC_MAXNAMELEN, vaTCstatus->volumeName,
547 vaTCstatus->volsFailed,
548 vaTCstatus->lastPolled);
550 append_msg(msg, "TCSTATUS <null>");
553 append_msg(msg, "--badval-- ");
556 vaEntry = va_arg(vaList, int);
559 MUTEX_ENTER(&audit_lock);
561 MUTEX_EXIT(&audit_lock);
566 #ifdef AFS_PTHREAD_ENV
568 osi_audit_init_lock(void)
570 MUTEX_INIT(&audit_lock, "audit", MUTEX_DEFAULT, 0);
577 #ifdef AFS_PTHREAD_ENV
578 pthread_once(&audit_lock_once, osi_audit_init_lock);
579 #endif /* AFS_PTHREAD_ENV */
582 /* ************************************************************************** */
583 /* The routine that acually does the audit call.
584 * ************************************************************************** */
586 osi_audit_internal(char *audEvent, /* Event name (15 chars or less) */
587 afs_int32 errCode, /* The error code */
595 static char BUFFER[32768];
599 #ifdef AFS_PTHREAD_ENV
600 /* i'm pretty sure all the server apps now call osi_audit_init(),
601 * but to be extra careful we'll leave this in here for a
602 * while to make sure */
603 pthread_once(&audit_lock_once, osi_audit_init_lock);
604 #endif /* AFS_PTHREAD_ENV */
606 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
608 if (!osi_audit_all && !auditout_open)
616 case KANOAUTH: /* kautils.h */
617 case RXKADNOAUTH: /* rxkad.h */
618 result = AUDIT_FAIL_AUTH;
620 case EPERM: /* errno.h */
621 case EACCES: /* errno.h */
622 case PRPERM: /* pterror.h */
623 result = AUDIT_FAIL_ACCESS;
625 case VL_PERM: /* vlserver.h */
626 case BUDB_NOTPERMITTED: /* budb_errs.h */
627 case BZACCESS: /* bnode.h */
628 case VOLSERBAD_ACCESS: /* volser.h */
629 result = AUDIT_FAIL_PRIV;
638 MUTEX_ENTER(&audit_lock);
641 /* Put the error code into the buffer list */
642 *(int *)bufferPtr = errCode;
643 bufferPtr += sizeof(errCode);
645 audmakebuf(audEvent, vaList);
647 bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
648 code = auditlog(audEvent, result, BUFFER, bufferLen);
649 MUTEX_EXIT(&audit_lock);
652 printbuf(0, audEvent, afsName, hostId, errCode, vaList);
659 osi_audit(char *audEvent, /* Event name (15 chars or less) */
660 afs_int32 errCode, /* The error code */
665 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
667 if (!osi_audit_all && !auditout_open)
670 va_start(vaList, errCode);
671 osi_audit_internal(audEvent, errCode, NULL, 0, vaList);
677 /* ************************************************************************** */
678 /* Given a RPC call structure, this routine extracts the name and host id from the
679 * call and includes it within the audit information.
680 * ************************************************************************** */
682 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
684 struct rx_connection *conn;
685 struct rx_peer *peer;
688 char afsName[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
692 if (osi_audit_all < 0)
694 if (!osi_audit_all && !auditout_open)
697 strcpy(afsName, "--Unknown--");
701 conn = rx_ConnectionOf(call); /* call -> conn) */
703 secClass = rx_SecurityClassOf(conn); /* conn -> securityIndex */
704 if (secClass == RX_SECIDX_NULL) { /* unauthenticated */
705 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
706 strcpy(afsName, "--UnAuth--");
707 } else if (secClass == RX_SECIDX_KAD || secClass == RX_SECIDX_KAE) {
708 /* authenticated with rxkad */
709 char tcell[MAXKTCREALMLEN];
710 char name[MAXKTCNAMELEN];
711 char inst[MAXKTCNAMELEN];
714 rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
717 osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
718 strcpy(afsName, "--NoName--");
720 afs_int32 islocal = 0;
721 if (audit_user_check.islocal) {
723 audit_user_check.islocal(audit_user_check.rock,
726 strlcpy(afsName, name, sizeof(afsName));
728 strlcat(afsName, ".", sizeof(afsName));
729 strlcat(afsName, inst, sizeof(afsName));
731 if (tcell[0] && !islocal) {
732 strlcat(afsName, "@", sizeof(afsName));
733 strlcat(afsName, tcell, sizeof(afsName));
736 } else { /* Unauthenticated and/or unknown */
737 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
738 strcpy(afsName, "--Unknown--");
740 peer = rx_PeerOf(conn); /* conn -> peer */
742 hostId = rx_HostOf(peer); /* peer -> host */
744 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
745 } else { /* null conn */
746 osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
748 } else { /* null call */
749 osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
751 va_start(vaList, errCode);
752 osi_audit_internal(audEvent, errCode, afsName, hostId, vaList);
757 /* ************************************************************************** */
758 /* Determines whether auditing is on or off by looking at the Audit file.
759 * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
761 * ************************************************************************** */
764 osi_audit_check(void)
770 osi_audit_all = 1; /* say we made check (>= 0) */
771 /* and assume audit all events (for now) */
772 onoff = 0; /* assume we will turn auditing off */
773 osi_echo_trail = 0; /* assume no echoing */
775 fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
777 while (fscanf(fds, "%256s", event) > 0) {
778 if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
781 if (strcmp(event, "Echo_Trail") == 0)
787 /* Audit this event all of the time */
789 osi_audit("AFS_Aud_On", 0, AUD_END);
791 osi_audit("AFS_Aud_Off", 0, AUD_END);
793 /* Now set whether we audit all events from here on out */
794 osi_audit_all = onoff;
800 * Handle parsing a string: [interface_name:]filespec[:options]
801 * The string a:b will parse 'a' as the interface name and 'b' as the filespec.
802 * Note that the string pointed by optionstr will be modified
803 * by strtok_r by inserting '\0' between the tokens.
804 * The values returned in interface_name, filespec and options
805 * are pointers to the 'sub-strings' within optionstr.
808 parse_file_options(char *optionstr,
809 const char **interface_name,
814 char *opt_cursor = optionstr;
815 char *tok1 = NULL, *tok2 = NULL, *tok3 = NULL, *tokptrsave = NULL;
818 * Handle the fact that strtok doesn't handle empty fields e.g. a::b
819 * and will return tok1-> a tok2-> b
823 if (*opt_cursor != ':') {
824 tok1 = strtok_r(opt_cursor, ":", &tokptrsave);
825 opt_cursor = strtok_r(NULL, "", &tokptrsave);
832 if (opt_cursor != NULL) {
833 if (*opt_cursor != ':') {
834 tok2 = strtok_r(opt_cursor, ":", &tokptrsave);
835 opt_cursor = strtok_r(NULL, "", &tokptrsave);
842 /* 3rd field is just the remainder if any */
845 if (tok1 == NULL || strlen(tok1) == 0) {
846 fprintf(stderr, "Missing -auditlog parameter\n");
851 /* If only one token, then it's the filespec */
852 if (tok2 == NULL && tok3 == NULL) {
855 *interface_name = tok1;
865 * Parse the options looking for comma-seperated values.
868 parse_option_string(const struct osi_audit_ops *ops, void *rock, char *options)
871 char *tok1, *tokptrsave = NULL;
873 tok1 = strtok_r(options, ",", &tokptrsave);
875 /* Handle opt=val or just opt */
879 opt = strtok_r(tok1, "=", &optvalsave);
880 val = strtok_r(NULL, "", &optvalsave);
882 code = ops->set_option(rock, opt, val);
888 tok1 = strtok_r(NULL, ",", &tokptrsave);
897 * [interface]:filespec[:options]
898 * interface - interface name (optional - defaults to default_interface)
899 * filespec - depends on the interface (required)
900 * options - optional string passed to interface
901 * Returns 0 - success
902 * EINVAL - option error
903 * ENOMEM - error allocating memory
907 osi_audit_file(const char *fileplusoptions)
913 char *optionstr = NULL;
915 const char *interface_name = NULL;
916 char *filespec = NULL;
917 char *options = NULL;
919 const struct osi_audit_ops *ops = NULL;
920 struct audit_log *new_alog = NULL;
922 /* Use the default unless specified */
923 interface_name = audit_interfaces[default_interface].name;
925 /* dup of the input string so the parsing can safely modify it */
926 optionstr = strdup(fileplusoptions);
932 code = parse_file_options(optionstr, &interface_name, &filespec, &options);
936 if (interface_name && strlen(interface_name) != 0) {
937 for (idx = 0; idx < N_INTERFACES; idx++) {
938 if (strcmp(interface_name, audit_interfaces[idx].name) == 0) {
939 ops = audit_interfaces[idx].ops;
944 /* Couldn't find the interface name */
945 fprintf(stderr, "Could not find the specified audit interface %s\n", interface_name);
950 fprintf(stderr, "Missing interface name\n");
955 if (filespec == NULL || strlen(filespec) == 0) {
956 fprintf(stderr, "Missing auditlog path for %s interface\n", interface_name);
961 opr_Assert(ops->create_interface != NULL);
962 opr_Assert(ops->close_interface != NULL);
963 opr_Assert(ops->open_file != NULL);
964 opr_Assert(ops->send_msg != NULL);
965 opr_Assert(ops->print_interface_stats != NULL);
966 /* open_interface, set_option and close_interface are optional */
968 new_alog = calloc(1, sizeof(*new_alog));
974 new_alog->audit_ops = ops;
975 new_alog->auditout_open = 0;
977 new_alog->context = ops->create_interface();
978 if (new_alog->context == NULL) {
983 if (options != NULL && ops->set_option != NULL) {
984 /* Split the option string at commas */
985 code = parse_option_string(ops, new_alog->context, options);
990 code = ops->open_file(new_alog->context, filespec);
992 /* Error opening file */
996 new_alog->auditout_open = 1;
999 /* Add to chain of active interfaces */
1000 opr_queue_Append(&audit_logs, &new_alog->link);
1007 /* Error condition present.. */
1009 ops->close_interface(&new_alog->context);
1020 * Set the default interface
1021 * return 0 for success
1022 * EINVAL missing or invalid interface name
1025 osi_audit_interface(const char *interface)
1029 if (interface == NULL || strlen(interface) == 0)
1032 for (idx = 0; idx < N_INTERFACES; idx++) {
1033 if (strcmp(interface, audit_interfaces[idx].name) == 0) {
1034 default_interface = idx;
1042 * Let the interfaces finish initialization
1045 osi_audit_open(void)
1047 struct opr_queue *cursor;
1049 for (opr_queue_Scan(&audit_logs, cursor)) {
1050 struct audit_log *alog;
1051 alog = opr_queue_Entry(cursor, struct audit_log, link);
1052 if (alog->auditout_open && alog->audit_ops->open_interface != NULL)
1053 alog->audit_ops->open_interface(alog->context);
1058 * Shutdown the interfaces
1061 osi_audit_close(void)
1063 struct opr_queue *cursor, *cursorsave;
1065 for (opr_queue_ScanSafe(&audit_logs, cursor, cursorsave)) {
1066 struct audit_log *alog;
1067 alog = opr_queue_Entry(cursor, struct audit_log, link);
1068 alog->audit_ops->close_interface(&alog->context);
1069 opr_queue_Remove(&alog->link);
1075 osi_audit_set_user_check(void *rock,
1076 int (*islocal) (void *rock, char *name, char *inst,
1079 audit_user_check.rock = rock;
1080 audit_user_check.islocal = islocal;
1084 audit_PrintStats(FILE *out)
1086 struct opr_queue *cursor;
1088 for (opr_queue_Scan(&audit_logs, cursor)) {
1089 struct audit_log *alog;
1090 alog = opr_queue_Entry(cursor, struct audit_log, link);
1091 if (alog->auditout_open)
1092 alog->audit_ops->print_interface_stats(alog->context, out);