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 */
316 struct tciStatusS *status;
318 status = (struct tciStatusS *)va_arg(vaList,
319 struct tciStatusS *);
321 memcpy(bufferPtr, status, sizeof(*status));
323 memset(bufferPtr, 0, sizeof(*status));
324 bufferPtr += sizeof(*status);
330 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
331 (strlen(audEvent) + 1));
337 vaEntry = va_arg(vaList, int);
343 printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
344 afs_int32 errCode, va_list vaList)
350 struct AFSFid *vaFid;
351 struct AFSCBFids *vaFids;
352 struct tc_tapeLabel *vaLabel;
353 struct tc_dumpInterface *vaDI;
354 struct tc_dumpArray *vaDA;
355 struct tc_restoreArray *vaRA;
356 struct tciStatusS *vaTCstatus;
357 int num = LogThreadNum();
358 struct in_addr hostAddr;
362 struct audit_msg *msg = calloc(1, sizeof(*msg));
368 /* Don't print the timestamp or thread id if we recursed */
370 currenttime = time(0);
371 if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y ",
372 localtime_r(¤ttime, &tm)) !=0)
373 append_msg(msg, tbuffer);
376 append_msg(msg, "[%d] ", num);
379 append_msg(msg, "EVENT %s CODE %d ", audEvent, errCode);
382 hostAddr.s_addr = hostId;
383 append_msg(msg, "NAME %s HOST %s ", afsName, inet_ntoa(hostAddr));
386 vaEntry = va_arg(vaList, int);
387 while (vaEntry != AUD_END) {
389 case AUD_STR: /* String */
390 vaStr = (char *)va_arg(vaList, char *);
392 append_msg(msg, "STR %s ", vaStr);
394 append_msg(msg, "STR <null>");
396 case AUD_NAME: /* Name */
397 vaStr = (char *)va_arg(vaList, char *);
399 append_msg(msg, "NAME %s ", vaStr);
401 append_msg(msg, "NAME <null>");
403 case AUD_ACL: /* ACL */
404 vaStr = (char *)va_arg(vaList, char *);
406 append_msg(msg, "ACL %s ", vaStr);
408 append_msg(msg, "ACL <null>");
410 case AUD_INT: /* Integer */
411 vaInt = va_arg(vaList, int);
412 append_msg(msg, "INT %d ", vaInt);
414 case AUD_ID: /* ViceId */
415 vaInt = va_arg(vaList, int);
416 append_msg(msg, "ID %d ", vaInt);
418 case AUD_DATE: /* Date */
419 vaLong = va_arg(vaList, afs_int32);
420 append_msg(msg, "DATE %u ", vaLong);
422 case AUD_HOST: /* Host ID */
423 vaLong = va_arg(vaList, afs_int32);
424 hostAddr.s_addr = vaLong;
425 append_msg(msg, "HOST %s ", inet_ntoa(hostAddr));
427 case AUD_LONG: /* afs_int32 */
428 vaLong = va_arg(vaList, afs_int32);
429 append_msg(msg, "LONG %d ", vaLong);
431 case AUD_FID: /* AFSFid - contains 3 entries */
432 vaFid = va_arg(vaList, struct AFSFid *);
434 append_msg(msg, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
437 append_msg(msg, "FID %u:%u:%u ", 0, 0, 0);
439 case AUD_FIDS: /* array of Fids */
440 vaFids = va_arg(vaList, struct AFSCBFids *);
445 vaFid = vaFids->AFSCBFids_val;
448 append_msg(msg, "FIDS %u ", vaFids->AFSCBFids_len);
449 for ( i = 1; i <= vaFids->AFSCBFids_len; i++, vaFid++ )
450 append_msg(msg, "FID %u:%u:%u ", vaFid->Volume,
451 vaFid->Vnode, vaFid->Unique);
453 append_msg(msg, "FIDS 0 FID 0:0:0 ");
457 case AUD_TLBL: /* butc tape label */
458 vaLabel = va_arg(vaList, struct tc_tapeLabel *);
461 append_msg(msg, "TAPELABEL %d:%.*s:%.*s:%u ",
463 TC_MAXTAPELEN, vaLabel->afsname,
464 TC_MAXTAPELEN, vaLabel->pname,
467 append_msg(msg, "TAPELABEL <null>");
471 vaDI = va_arg(vaList, struct tc_dumpInterface *);
475 "TCDUMPINTERFACE %.*s:%.*s:%.*s:%d:%d:%d:%d:%.*s:%.*s:%d:%d:%d:%d:%d ",
476 TC_MAXDUMPPATH, vaDI->dumpPath, TC_MAXNAMELEN, vaDI->volumeSetName,
477 TC_MAXNAMELEN, vaDI->dumpName, vaDI->parentDumpId, vaDI->dumpLevel,
479 vaDI->tapeSet.id, TC_MAXHOSTLEN, vaDI->tapeSet.tapeServer,
480 TC_MAXFORMATLEN, vaDI->tapeSet.format, vaDI->tapeSet.maxTapes,
481 vaDI->tapeSet.a, vaDI->tapeSet.b, vaDI->tapeSet.expDate,
482 vaDI->tapeSet.expType);
484 append_msg(msg, "TCDUMPINTERFACE <null>");
488 vaDA = va_arg(vaList, struct tc_dumpArray *);
492 struct tc_dumpDesc *desc;
493 struct in_addr hostAddr;
495 desc = vaDA->tc_dumpArray_val;
497 append_msg(msg, "DUMPS %d ", vaDA->tc_dumpArray_len);
498 for (i = 0; i < vaDA->tc_dumpArray_len; i++, desc++) {
499 hostAddr.s_addr = desc->hostAddr;
500 append_msg(msg, "DUMP %d:%d:%.*s:%d:%d:%d:%s ",
501 desc->vid, desc->vtype, TC_MAXNAMELEN, desc->name,
502 desc->partition, desc->date, desc->cloneDate,
503 inet_ntoa(hostAddr));
506 append_msg(msg, "DUMPS 0 DUMP 0:0::0:0:0:0.0.0.0");
511 vaRA = va_arg(vaList, struct tc_restoreArray *);
515 struct tc_restoreDesc *desc;
516 struct in_addr hostAddr;
518 desc = vaRA->tc_restoreArray_val;
520 append_msg(msg, "RESTORES %d ",
521 vaRA->tc_restoreArray_len);
522 for(i = 0; i < vaRA->tc_restoreArray_len; i++, desc++) {
523 hostAddr.s_addr = desc->hostAddr;
525 "RESTORE %d:%.*s:%d:%d:%d:%d:%d:%d:%d:%s:%.*s:%.*s ",
526 desc->flags, TC_MAXTAPELEN, desc->tapeName,
527 desc->dbDumpId, desc->initialDumpId,
528 desc->position, desc->origVid, desc->vid,
529 desc->partition, desc->dumpLevel,
530 inet_ntoa(hostAddr), TC_MAXNAMELEN,
531 desc->oldName, TC_MAXNAMELEN, desc->newName);
535 "RESTORES 0 RESTORE 0::0:0:0:0:0:0:0:0.0.0.0::: ");
540 vaTCstatus = va_arg(vaList, struct tciStatusS *);
543 append_msg(msg, "TCSTATUS %.*s:%d:%d:%d:%d:%.*s:%d:%d ",
544 TC_MAXNAMELEN, vaTCstatus->taskName,
545 vaTCstatus->taskId, vaTCstatus->flags,
546 vaTCstatus->dbDumpId, vaTCstatus->nKBytes,
547 TC_MAXNAMELEN, vaTCstatus->volumeName,
548 vaTCstatus->volsFailed,
549 vaTCstatus->lastPolled);
551 append_msg(msg, "TCSTATUS <null>");
554 append_msg(msg, "--badval-- ");
557 vaEntry = va_arg(vaList, int);
560 MUTEX_ENTER(&audit_lock);
562 MUTEX_EXIT(&audit_lock);
567 #ifdef AFS_PTHREAD_ENV
569 osi_audit_init_lock(void)
571 MUTEX_INIT(&audit_lock, "audit", MUTEX_DEFAULT, 0);
578 #ifdef AFS_PTHREAD_ENV
579 pthread_once(&audit_lock_once, osi_audit_init_lock);
580 #endif /* AFS_PTHREAD_ENV */
583 /* ************************************************************************** */
584 /* The routine that acually does the audit call.
585 * ************************************************************************** */
587 osi_audit_internal(char *audEvent, /* Event name (15 chars or less) */
588 afs_int32 errCode, /* The error code */
596 static char BUFFER[32768];
600 #ifdef AFS_PTHREAD_ENV
601 /* i'm pretty sure all the server apps now call osi_audit_init(),
602 * but to be extra careful we'll leave this in here for a
603 * while to make sure */
604 pthread_once(&audit_lock_once, osi_audit_init_lock);
605 #endif /* AFS_PTHREAD_ENV */
607 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
609 if (!osi_audit_all && !auditout_open)
617 case KANOAUTH: /* kautils.h */
618 case RXKADNOAUTH: /* rxkad.h */
619 result = AUDIT_FAIL_AUTH;
621 case EPERM: /* errno.h */
622 case EACCES: /* errno.h */
623 case PRPERM: /* pterror.h */
624 result = AUDIT_FAIL_ACCESS;
626 case VL_PERM: /* vlserver.h */
627 case BUDB_NOTPERMITTED: /* budb_errs.h */
628 case BZACCESS: /* bnode.h */
629 case VOLSERBAD_ACCESS: /* volser.h */
630 result = AUDIT_FAIL_PRIV;
639 MUTEX_ENTER(&audit_lock);
642 /* Put the error code into the buffer list */
643 *(int *)bufferPtr = errCode;
644 bufferPtr += sizeof(errCode);
646 audmakebuf(audEvent, vaList);
648 bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
649 code = auditlog(audEvent, result, BUFFER, bufferLen);
650 MUTEX_EXIT(&audit_lock);
653 printbuf(0, audEvent, afsName, hostId, errCode, vaList);
660 osi_audit(char *audEvent, /* Event name (15 chars or less) */
661 afs_int32 errCode, /* The error code */
666 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
668 if (!osi_audit_all && !auditout_open)
671 va_start(vaList, errCode);
672 osi_audit_internal(audEvent, errCode, NULL, 0, vaList);
678 /* ************************************************************************** */
679 /* Given a RPC call structure, this routine extracts the name and host id from the
680 * call and includes it within the audit information.
681 * ************************************************************************** */
683 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
685 struct rx_connection *conn;
686 struct rx_peer *peer;
689 char afsName[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
693 if (osi_audit_all < 0)
695 if (!osi_audit_all && !auditout_open)
698 strcpy(afsName, "--Unknown--");
702 conn = rx_ConnectionOf(call); /* call -> conn) */
704 secClass = rx_SecurityClassOf(conn); /* conn -> securityIndex */
705 if (secClass == RX_SECIDX_NULL) { /* unauthenticated */
706 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
707 strcpy(afsName, "--UnAuth--");
708 } else if (secClass == RX_SECIDX_KAD || secClass == RX_SECIDX_KAE) {
709 /* authenticated with rxkad */
710 char tcell[MAXKTCREALMLEN];
711 char name[MAXKTCNAMELEN];
712 char inst[MAXKTCNAMELEN];
715 rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
718 osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
719 strcpy(afsName, "--NoName--");
721 afs_int32 islocal = 0;
722 if (audit_user_check.islocal) {
724 audit_user_check.islocal(audit_user_check.rock,
727 strlcpy(afsName, name, sizeof(afsName));
729 strlcat(afsName, ".", sizeof(afsName));
730 strlcat(afsName, inst, sizeof(afsName));
732 if (tcell[0] && !islocal) {
733 strlcat(afsName, "@", sizeof(afsName));
734 strlcat(afsName, tcell, sizeof(afsName));
737 } else { /* Unauthenticated and/or unknown */
738 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
739 strcpy(afsName, "--Unknown--");
741 peer = rx_PeerOf(conn); /* conn -> peer */
743 hostId = rx_HostOf(peer); /* peer -> host */
745 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
746 } else { /* null conn */
747 osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
749 } else { /* null call */
750 osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
752 va_start(vaList, errCode);
753 osi_audit_internal(audEvent, errCode, afsName, hostId, vaList);
758 /* ************************************************************************** */
759 /* Determines whether auditing is on or off by looking at the Audit file.
760 * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
762 * ************************************************************************** */
765 osi_audit_check(void)
771 osi_audit_all = 1; /* say we made check (>= 0) */
772 /* and assume audit all events (for now) */
773 onoff = 0; /* assume we will turn auditing off */
774 osi_echo_trail = 0; /* assume no echoing */
776 fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
778 while (fscanf(fds, "%256s", event) > 0) {
779 if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
782 if (strcmp(event, "Echo_Trail") == 0)
788 /* Audit this event all of the time */
790 osi_audit("AFS_Aud_On", 0, AUD_END);
792 osi_audit("AFS_Aud_Off", 0, AUD_END);
794 /* Now set whether we audit all events from here on out */
795 osi_audit_all = onoff;
801 * Helper for processing cmd line options
803 * Process the parameters for the -audit-interface and -auditlog command line
806 * @param[in] default_iface
807 * String for the default audit interface or NULL
808 * @param[in] audit_loglist
809 * Pointer to a cmd_item list of audit logs or NULL
812 * @retval 0 - success
813 * @retval -1 - Error (message printed to stderr)
817 osi_audit_cmd_Options(char *default_iface, struct cmd_item *audit_loglist)
821 if (osi_audit_interface(default_iface)) {
822 fprintf(stderr, "Invalid auditinterface '%s'\n", default_iface);
827 while (audit_loglist != NULL) {
828 if (osi_audit_file(audit_loglist->data)) {
829 fprintf(stderr, "Error processing auditlog options '%s'\n",
830 audit_loglist->data);
833 audit_loglist = audit_loglist->next;
839 * Handle parsing a string: [interface_name:]filespec[:options]
840 * The string a:b will parse 'a' as the interface name and 'b' as the filespec.
841 * Note that the string pointed by optionstr will be modified
842 * by strtok_r by inserting '\0' between the tokens.
843 * The values returned in interface_name, filespec and options
844 * are pointers to the 'sub-strings' within optionstr.
847 parse_file_options(char *optionstr,
848 const char **interface_name,
853 char *opt_cursor = optionstr;
854 char *tok1 = NULL, *tok2 = NULL, *tok3 = NULL, *tokptrsave = NULL;
857 * Handle the fact that strtok doesn't handle empty fields e.g. a::b
858 * and will return tok1-> a tok2-> b
862 if (*opt_cursor != ':') {
863 tok1 = strtok_r(opt_cursor, ":", &tokptrsave);
864 opt_cursor = strtok_r(NULL, "", &tokptrsave);
871 if (opt_cursor != NULL) {
872 if (*opt_cursor != ':') {
873 tok2 = strtok_r(opt_cursor, ":", &tokptrsave);
874 opt_cursor = strtok_r(NULL, "", &tokptrsave);
881 /* 3rd field is just the remainder if any */
884 if (tok1 == NULL || strlen(tok1) == 0) {
885 fprintf(stderr, "Missing -auditlog parameter\n");
890 /* If only one token, then it's the filespec */
891 if (tok2 == NULL && tok3 == NULL) {
894 *interface_name = tok1;
904 * Parse the options looking for comma-seperated values.
907 parse_option_string(const struct osi_audit_ops *ops, void *rock, char *options)
910 char *tok1, *tokptrsave = NULL;
912 tok1 = strtok_r(options, ",", &tokptrsave);
914 /* Handle opt=val or just opt */
918 opt = strtok_r(tok1, "=", &optvalsave);
919 val = strtok_r(NULL, "", &optvalsave);
921 code = ops->set_option(rock, opt, val);
927 tok1 = strtok_r(NULL, ",", &tokptrsave);
936 * [interface]:filespec[:options]
937 * interface - interface name (optional - defaults to default_interface)
938 * filespec - depends on the interface (required)
939 * options - optional string passed to interface
940 * Returns 0 - success
941 * EINVAL - option error
942 * ENOMEM - error allocating memory
946 osi_audit_file(const char *fileplusoptions)
952 char *optionstr = NULL;
954 const char *interface_name = NULL;
955 char *filespec = NULL;
956 char *options = NULL;
958 const struct osi_audit_ops *ops = NULL;
959 struct audit_log *new_alog = NULL;
961 /* Use the default unless specified */
962 interface_name = audit_interfaces[default_interface].name;
964 /* dup of the input string so the parsing can safely modify it */
965 optionstr = strdup(fileplusoptions);
971 code = parse_file_options(optionstr, &interface_name, &filespec, &options);
975 if (interface_name && strlen(interface_name) != 0) {
976 for (idx = 0; idx < N_INTERFACES; idx++) {
977 if (strcmp(interface_name, audit_interfaces[idx].name) == 0) {
978 ops = audit_interfaces[idx].ops;
983 /* Couldn't find the interface name */
984 fprintf(stderr, "Could not find the specified audit interface %s\n", interface_name);
989 fprintf(stderr, "Missing interface name\n");
994 if (filespec == NULL || strlen(filespec) == 0) {
995 fprintf(stderr, "Missing auditlog path for %s interface\n", interface_name);
1000 opr_Assert(ops->create_interface != NULL);
1001 opr_Assert(ops->close_interface != NULL);
1002 opr_Assert(ops->open_file != NULL);
1003 opr_Assert(ops->send_msg != NULL);
1004 opr_Assert(ops->print_interface_stats != NULL);
1005 /* open_interface, set_option and close_interface are optional */
1007 new_alog = calloc(1, sizeof(*new_alog));
1013 new_alog->audit_ops = ops;
1014 new_alog->auditout_open = 0;
1016 new_alog->context = ops->create_interface();
1017 if (new_alog->context == NULL) {
1022 if (options != NULL && ops->set_option != NULL) {
1023 /* Split the option string at commas */
1024 code = parse_option_string(ops, new_alog->context, options);
1029 code = ops->open_file(new_alog->context, filespec);
1031 /* Error opening file */
1035 new_alog->auditout_open = 1;
1038 /* Add to chain of active interfaces */
1039 opr_queue_Append(&audit_logs, &new_alog->link);
1046 /* Error condition present.. */
1048 ops->close_interface(&new_alog->context);
1059 * Set the default interface
1060 * return 0 for success
1061 * EINVAL missing or invalid interface name
1064 osi_audit_interface(const char *interface)
1068 if (interface == NULL || strlen(interface) == 0)
1071 for (idx = 0; idx < N_INTERFACES; idx++) {
1072 if (strcmp(interface, audit_interfaces[idx].name) == 0) {
1073 default_interface = idx;
1081 * Let the interfaces finish initialization
1084 osi_audit_open(void)
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 && alog->audit_ops->open_interface != NULL)
1092 alog->audit_ops->open_interface(alog->context);
1097 * Shutdown the interfaces
1100 osi_audit_close(void)
1102 struct opr_queue *cursor, *cursorsave;
1104 for (opr_queue_ScanSafe(&audit_logs, cursor, cursorsave)) {
1105 struct audit_log *alog;
1106 alog = opr_queue_Entry(cursor, struct audit_log, link);
1107 alog->audit_ops->close_interface(&alog->context);
1108 opr_queue_Remove(&alog->link);
1114 osi_audit_set_user_check(void *rock,
1115 int (*islocal) (void *rock, char *name, char *inst,
1118 audit_user_check.rock = rock;
1119 audit_user_check.islocal = islocal;
1123 audit_PrintStats(FILE *out)
1125 struct opr_queue *cursor;
1127 for (opr_queue_Scan(&audit_logs, cursor)) {
1128 struct audit_log *alog;
1129 alog = opr_queue_Entry(cursor, struct audit_log, link);
1130 if (alog->auditout_open)
1131 alog->audit_ops->print_interface_stats(alog->context, out);