AIX: Fix undefined symbols
[openafs.git] / src / audit / audit.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
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
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13 #include <roken.h>
14
15 #ifdef AFS_AIX32_ENV
16 #include <sys/audit.h>
17 #else
18 #define AUDIT_OK 0
19 #define AUDIT_FAIL 1
20 #define AUDIT_FAIL_AUTH 2
21 #define AUDIT_FAIL_ACCESS 3
22 #define AUDIT_FAIL_PRIV 4
23 #endif /* AFS_AIX32_ENV */
24
25 #include <afs/opr.h>
26 #include "afs/afsint.h"
27 #include "afs/butc.h"
28 #include <rx/rx.h>
29 #include <rx/rxkad.h>
30 #include "audit.h"
31 #include "audit-api.h"
32 #include "lock.h"
33
34 #include <afs/afsutil.h>
35
36 extern struct osi_audit_ops audit_file_ops;
37 #ifdef HAVE_SYS_IPC_H
38 extern struct osi_audit_ops audit_sysvmq_ops;
39 #endif
40
41 static struct {
42     void *rock;
43     int (*islocal)(void *rock, char *name, char *inst, char *cell);
44 } audit_user_check = { NULL, NULL };
45
46 static struct {
47     const char *name;
48     const struct osi_audit_ops *ops;
49 } audit_interfaces[] = {
50
51     { "file", &audit_file_ops },
52 #ifdef HAVE_SYS_IPC_H
53     { "sysvmq", &audit_sysvmq_ops },
54 #endif
55 };
56 /* default_interface indexes into the audit_interfaces list. */
57 static int default_interface = 0; /* Set default to the file interface */
58
59 #define N_INTERFACES (sizeof(audit_interfaces) / sizeof(audit_interfaces[0]))
60
61 /*
62  * Audit interface calling sequence:
63  * osi_audit_interface - sets the default audit interface
64  * osi_audit_file
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
71  * osi_audit
72  *    send_msg - Called during audit events
73  */
74 struct audit_log {
75     struct opr_queue link;
76     const struct osi_audit_ops *audit_ops;
77     int auditout_open;
78     void *context;
79 };
80
81 struct audit_msg {
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? */
85 };
86
87 #ifdef AFS_PTHREAD_ENV
88 static pthread_mutex_t audit_lock;
89 static pthread_once_t audit_lock_once = PTHREAD_ONCE_INIT;
90 #endif
91
92 /* Chain of active interfaces */
93 static struct opr_queue audit_logs = {&audit_logs, &audit_logs};
94
95 static int osi_audit_all = (-1);        /* Not determined yet */
96 static int osi_echo_trail = (-1);
97
98 static int auditout_open = 0;           /* True if any interface is open */
99
100 static int osi_audit_check(void);
101
102 /*
103  * Send the message to all the interfaces
104  * @pre audit_lock held
105  */
106 static void
107 multi_send_msg(struct audit_msg *msg)
108 {
109     struct opr_queue *cursor;
110
111     if (msg->len < 1) /* Don't send empty strings */
112         return;
113
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,
119                                       msg->truncated);
120         }
121     }
122 }
123 static void
124 append_msg(struct audit_msg *msg, const char *format, ...)
125 {
126     va_list ap;
127     int remaining, printed;
128
129     if (msg->truncated) {
130         return;
131     }
132
133     if (msg->len >= OSI_AUDIT_MAXMSG - 1) {
134         /* Make sure we have at least some space left */
135         msg->truncated = 1;
136         return;
137     }
138
139     remaining = OSI_AUDIT_MAXMSG - msg->len;
140
141     va_start(ap, format);
142
143     printed = vsnprintf(&msg->buf[msg->len], remaining, format, ap);
144
145     if (printed < 0) {
146         /* Error during formatting. */
147         msg->truncated = 1;
148         printed = 0;
149
150     } else if (printed >= remaining) {
151         /* We tried to write more characters than we had space for. */
152         msg->truncated = 1;
153         printed = remaining - 1;
154
155         /* Make sure we're still terminated. */
156         msg->buf[OSI_AUDIT_MAXMSG - 1] = '\0';
157     }
158
159     msg->len += printed;
160     opr_Assert(msg->len < OSI_AUDIT_MAXMSG);
161
162     va_end(ap);
163 }
164 #ifdef AFS_AIX32_ENV
165 static char *bufferPtr;
166 static int bufferLen;
167
168 static void
169 audmakebuf(char *audEvent, va_list vaList)
170 {
171     int code;
172     int vaEntry;
173     int vaInt;
174     afs_int32 vaLong;
175     char *vaStr;
176     struct AFSFid *vaFid;
177
178     vaEntry = va_arg(vaList, int);
179     while (vaEntry != AUD_END) {
180         switch (vaEntry) {
181         case AUD_STR:           /* String */
182         case AUD_NAME:          /* Name */
183         case AUD_ACL:           /* ACL */
184             vaStr = (char *)va_arg(vaList, char *);
185             if (vaStr) {
186                 strcpy(bufferPtr, vaStr);
187                 bufferPtr += strlen(vaStr) + 1;
188             } else {
189                 strcpy(bufferPtr, "");
190                 bufferPtr++;
191             }
192             break;
193         case AUD_INT:           /* Integer */
194         case AUD_ID:            /* ViceId */
195             vaInt = va_arg(vaList, int);
196             *(int *)bufferPtr = vaInt;
197             bufferPtr += sizeof(vaInt);
198             break;
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);
205             break;
206         case AUD_FID:           /* AFSFid - contains 3 entries */
207             vaFid = (struct AFSFid *)va_arg(vaList, struct AFSFid *);
208             if (vaFid) {
209                 memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
210             } else {
211                 memset(bufferPtr, 0, sizeof(struct AFSFid));
212             }
213             bufferPtr += sizeof(struct AFSFid);
214             break;
215
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. */
219         case AUD_FIDS:
220             {
221                 struct AFSCBFids *Fids;
222
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));
229                 } else {
230                     *((u_int *) bufferPtr) = 0;
231                     bufferPtr += sizeof(u_int);
232                     memset(bufferPtr, 0, sizeof(struct AFSFid));
233                 }
234                 bufferPtr += sizeof(struct AFSFid);
235                 break;
236             }
237         /* butc tape label */
238         case AUD_TLBL:
239             {
240                 struct tc_tapeLabel *label;
241
242                 label = (struct tc_tapeLabel *)va_arg(vaList,
243                                                       struct tc_tapeLabel *);
244                 if (label)
245                     memcpy(bufferPtr, label, sizeof(*label));
246                 else
247                     memset(bufferPtr, 0, sizeof(*label));
248                 bufferPtr += sizeof(label);
249                 break;
250             }
251         /* butc dump interface */
252         case AUD_TDI:
253             {
254                 struct tc_dumpInterface *di;
255
256                 di = (struct tc_dumpInterface *)
257                         va_arg(vaList, struct tc_dumpInterface *);
258                 if (di)
259                     memcpy(bufferPtr, di, sizeof(*di));
260                 else
261                     memset(bufferPtr, 0, sizeof(*di));
262                 bufferPtr += sizeof(*di);
263                 break;
264             }
265         /*
266          * butc dump array
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.
269          */
270         case AUD_TDA:
271             {
272                 struct tc_dumpArray *da;
273
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]));
281                 } else {
282                     memset(bufferPtr, 0, sizeof(u_int));
283                     bufferPtr += sizeof(u_int);
284                     memset(bufferPtr, 0, sizeof(da->tc_dumpArray_val[0]));
285                 }
286                 bufferPtr += sizeof(da->tc_dumpArray_val[0]);
287                 break;
288             }
289         /*
290          * butc restore array
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.
293          */
294         case AUD_TRA:
295             {
296                 struct tc_restoreArray *ra;
297
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]));
305                 } else {
306                     memset(bufferPtr, 0, sizeof(u_int));
307                     bufferPtr += sizeof(u_int);
308                     memset(bufferPtr, 0, sizeof(ra->tc_restoreArray_val[0]));
309                 }
310                 bufferPtr += sizeof(ra->tc_restoreArray_val[0]);
311                 break;
312             }
313         /* butc tape controller status */
314         case AUD_TSTT:
315             {
316                 struct tciStatusS *status;
317
318                 status = (struct tciStatusS *)va_arg(vaList,
319                                                      struct tciStatusS *);
320                 if (status)
321                     memcpy(bufferPtr, status, sizeof(*status));
322                 else
323                     memset(bufferPtr, 0, sizeof(*status));
324                 bufferPtr += sizeof(*status);
325                 break;
326             }
327         default:
328 #ifdef AFS_AIX32_ENV
329             code =
330                 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
331                          (strlen(audEvent) + 1));
332 #endif
333             return;
334             break;
335         }                       /* end switch */
336
337         vaEntry = va_arg(vaList, int);
338     }                           /* end while */
339 }
340 #endif
341
342 static void
343 printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
344          afs_int32 errCode, va_list vaList)
345 {
346     int vaEntry;
347     int vaInt;
348     afs_int32 vaLong;
349     char *vaStr;
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;
359     time_t currenttime;
360     char tbuffer[26];
361     struct tm tm;
362     struct audit_msg *msg = calloc(1, sizeof(*msg));
363
364     if (!msg) {
365         return;
366     }
367
368     /* Don't print the timestamp or thread id if we recursed */
369     if (rec == 0) {
370         currenttime = time(0);
371         if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y ",
372                      localtime_r(&currenttime, &tm)) !=0)
373             append_msg(msg, tbuffer);
374
375         if (num > -1)
376             append_msg(msg, "[%d] ", num);
377     }
378
379     append_msg(msg, "EVENT %s CODE %d ", audEvent, errCode);
380
381     if (afsName) {
382         hostAddr.s_addr = hostId;
383         append_msg(msg, "NAME %s HOST %s ", afsName, inet_ntoa(hostAddr));
384     }
385
386     vaEntry = va_arg(vaList, int);
387     while (vaEntry != AUD_END) {
388         switch (vaEntry) {
389         case AUD_STR:           /* String */
390             vaStr = (char *)va_arg(vaList, char *);
391             if (vaStr)
392                 append_msg(msg, "STR %s ", vaStr);
393             else
394                 append_msg(msg, "STR <null>");
395             break;
396         case AUD_NAME:          /* Name */
397             vaStr = (char *)va_arg(vaList, char *);
398             if (vaStr)
399                 append_msg(msg, "NAME %s ", vaStr);
400             else
401                 append_msg(msg, "NAME <null>");
402             break;
403         case AUD_ACL:           /* ACL */
404             vaStr = (char *)va_arg(vaList, char *);
405             if (vaStr)
406                 append_msg(msg, "ACL %s ", vaStr);
407             else
408                 append_msg(msg, "ACL <null>");
409             break;
410         case AUD_INT:           /* Integer */
411             vaInt = va_arg(vaList, int);
412             append_msg(msg, "INT %d ", vaInt);
413             break;
414         case AUD_ID:            /* ViceId */
415             vaInt = va_arg(vaList, int);
416             append_msg(msg, "ID %d ", vaInt);
417             break;
418         case AUD_DATE:          /* Date    */
419             vaLong = va_arg(vaList, afs_int32);
420             append_msg(msg, "DATE %u ", vaLong);
421             break;
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));
426             break;
427         case AUD_LONG:          /* afs_int32    */
428             vaLong = va_arg(vaList, afs_int32);
429             append_msg(msg, "LONG %d ", vaLong);
430             break;
431         case AUD_FID:           /* AFSFid - contains 3 entries */
432             vaFid = va_arg(vaList, struct AFSFid *);
433             if (vaFid)
434                 append_msg(msg, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
435                            vaFid->Unique);
436             else
437                 append_msg(msg, "FID %u:%u:%u ", 0, 0, 0);
438             break;
439         case AUD_FIDS:          /* array of Fids */
440             vaFids = va_arg(vaList, struct AFSCBFids *);
441
442             if (vaFids) {
443                 unsigned int i;
444
445                 vaFid = vaFids->AFSCBFids_val;
446
447                 if (vaFid) {
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);
452                 } else
453                     append_msg(msg, "FIDS 0 FID 0:0:0 ");
454
455             }
456             break;
457         case AUD_TLBL:          /* butc tape label */
458             vaLabel = va_arg(vaList, struct tc_tapeLabel *);
459
460             if (vaLabel) {
461                 append_msg(msg, "TAPELABEL %d:%.*s:%.*s:%u ",
462                            vaLabel->size,
463                            TC_MAXTAPELEN, vaLabel->afsname,
464                            TC_MAXTAPELEN, vaLabel->pname,
465                            vaLabel->tapeId);
466             } else {
467                 append_msg(msg, "TAPELABEL <null>");
468             }
469             break;
470         case AUD_TDI:
471             vaDI = va_arg(vaList, struct tc_dumpInterface *);
472
473             if (vaDI) {
474                 append_msg(msg,
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,
478     vaDI->doAppend,
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);
483             } else {
484                 append_msg(msg, "TCDUMPINTERFACE <null>");
485             }
486             break;
487         case AUD_TDA:
488             vaDA = va_arg(vaList, struct tc_dumpArray *);
489
490             if (vaDA) {
491                 u_int i;
492                 struct tc_dumpDesc *desc;
493                 struct in_addr hostAddr;
494
495                 desc = vaDA->tc_dumpArray_val;
496                 if (desc) {
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));
504                     }
505                 } else {
506                     append_msg(msg, "DUMPS 0 DUMP 0:0::0:0:0:0.0.0.0");
507                 }
508             }
509             break;
510         case AUD_TRA:
511             vaRA = va_arg(vaList, struct tc_restoreArray *);
512
513             if (vaRA) {
514                 u_int i;
515                 struct tc_restoreDesc *desc;
516                 struct in_addr hostAddr;
517
518                 desc = vaRA->tc_restoreArray_val;
519                 if (desc) {
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;
524                         append_msg(msg,
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);
532                     }
533                 } else {
534                     append_msg(msg,
535                         "RESTORES 0 RESTORE 0::0:0:0:0:0:0:0:0.0.0.0::: ");
536                 }
537             }
538             break;
539         case AUD_TSTT:
540             vaTCstatus = va_arg(vaList, struct tciStatusS *);
541
542             if (vaTCstatus)
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);
550             else
551                 append_msg(msg, "TCSTATUS <null>");
552             break;
553         default:
554             append_msg(msg, "--badval-- ");
555             break;
556         }                       /* end switch */
557         vaEntry = va_arg(vaList, int);
558     }                           /* end while */
559
560     MUTEX_ENTER(&audit_lock);
561     multi_send_msg(msg);
562     MUTEX_EXIT(&audit_lock);
563
564     free(msg);
565 }
566
567 #ifdef AFS_PTHREAD_ENV
568 static void
569 osi_audit_init_lock(void)
570 {
571     MUTEX_INIT(&audit_lock, "audit", MUTEX_DEFAULT, 0);
572 }
573 #endif
574
575 void
576 osi_audit_init(void)
577 {
578 #ifdef AFS_PTHREAD_ENV
579     pthread_once(&audit_lock_once, osi_audit_init_lock);
580 #endif /* AFS_PTHREAD_ENV */
581 }
582
583 /* ************************************************************************** */
584 /* The routine that acually does the audit call.
585  * ************************************************************************** */
586 static int
587 osi_audit_internal(char *audEvent,      /* Event name (15 chars or less) */
588                    afs_int32 errCode,   /* The error code */
589                    char *afsName,
590                    afs_int32 hostId,
591                    va_list vaList)
592 {
593 #ifdef AFS_AIX32_ENV
594     afs_int32 code;
595     afs_int32 err;
596     static char BUFFER[32768];
597     int result;
598 #endif
599
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 */
606
607     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
608         osi_audit_check();
609     if (!osi_audit_all && !auditout_open)
610         return 0;
611
612 #ifdef AFS_AIX32_ENV
613     switch (errCode) {
614     case 0:
615         result = AUDIT_OK;
616         break;
617     case KANOAUTH:              /* kautils.h   */
618     case RXKADNOAUTH:           /* rxkad.h     */
619         result = AUDIT_FAIL_AUTH;
620         break;
621     case EPERM:         /* errno.h     */
622     case EACCES:                /* errno.h     */
623     case PRPERM:                /* pterror.h   */
624         result = AUDIT_FAIL_ACCESS;
625         break;
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;
631         break;
632     default:
633         result = AUDIT_FAIL;
634         break;
635     }
636 #endif
637
638 #ifdef AFS_AIX32_ENV
639     MUTEX_ENTER(&audit_lock);
640     bufferPtr = BUFFER;
641
642     /* Put the error code into the buffer list */
643     *(int *)bufferPtr = errCode;
644     bufferPtr += sizeof(errCode);
645
646     audmakebuf(audEvent, vaList);
647
648     bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
649     code = auditlog(audEvent, result, BUFFER, bufferLen);
650     MUTEX_EXIT(&audit_lock);
651 #else
652     if (auditout_open) {
653         printbuf(0, audEvent, afsName, hostId, errCode, vaList);
654     }
655 #endif
656
657     return 0;
658 }
659 int
660 osi_audit(char *audEvent,       /* Event name (15 chars or less) */
661           afs_int32 errCode,    /* The error code */
662           ...)
663 {
664     va_list vaList;
665
666     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
667         osi_audit_check();
668     if (!osi_audit_all && !auditout_open)
669         return 0;
670
671     va_start(vaList, errCode);
672     osi_audit_internal(audEvent, errCode, NULL, 0, vaList);
673     va_end(vaList);
674
675     return 0;
676 }
677
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  * ************************************************************************** */
682 int
683 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
684 {
685     struct rx_connection *conn;
686     struct rx_peer *peer;
687     afs_int32 secClass;
688     afs_int32 code;
689     char afsName[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
690     afs_int32 hostId;
691     va_list vaList;
692
693     if (osi_audit_all < 0)
694         osi_audit_check();
695     if (!osi_audit_all && !auditout_open)
696         return 0;
697
698     strcpy(afsName, "--Unknown--");
699     hostId = 0;
700
701     if (call) {
702         conn = rx_ConnectionOf(call);   /* call -> conn) */
703         if (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];
713
714                 code =
715                     rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
716                                         NULL);
717                 if (code) {
718                     osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
719                     strcpy(afsName, "--NoName--");
720                 } else {
721                     afs_int32 islocal = 0;
722                     if (audit_user_check.islocal) {
723                         islocal =
724                             audit_user_check.islocal(audit_user_check.rock,
725                                                      name, inst, tcell);
726                     }
727                     strlcpy(afsName, name, sizeof(afsName));
728                     if (inst[0]) {
729                         strlcat(afsName, ".", sizeof(afsName));
730                         strlcat(afsName, inst, sizeof(afsName));
731                     }
732                     if (tcell[0] && !islocal) {
733                         strlcat(afsName, "@", sizeof(afsName));
734                         strlcat(afsName, tcell, sizeof(afsName));
735                     }
736                 }
737             } else {            /* Unauthenticated and/or unknown */
738                 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
739                 strcpy(afsName, "--Unknown--");
740             }
741             peer = rx_PeerOf(conn);     /* conn -> peer */
742             if (peer)
743                 hostId = rx_HostOf(peer);       /* peer -> host */
744             else
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);
748         }
749     } else {                    /* null call */
750         osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
751     }
752     va_start(vaList, errCode);
753     osi_audit_internal(audEvent, errCode, afsName, hostId, vaList);
754     va_end(vaList);
755     return 0;
756 }
757
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
761  * enabled.
762  * ************************************************************************** */
763
764 int
765 osi_audit_check(void)
766 {
767     FILE *fds;
768     int onoff;
769     char event[257];
770
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   */
775
776     fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
777     if (fds) {
778         while (fscanf(fds, "%256s", event) > 0) {
779             if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
780                 onoff = 1;
781
782             if (strcmp(event, "Echo_Trail") == 0)
783                 osi_echo_trail = 1;
784         }
785         fclose(fds);
786     }
787
788     /* Audit this event all of the time */
789     if (onoff)
790         osi_audit("AFS_Aud_On", 0, AUD_END);
791     else
792         osi_audit("AFS_Aud_Off", 0, AUD_END);
793
794     /* Now set whether we audit all events from here on out */
795     osi_audit_all = onoff;
796
797     return 0;
798 }
799
800 /*!
801  * Helper for processing cmd line options
802  *
803  * Process the parameters for the -audit-interface and -auditlog command line
804  * options
805  *
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
810  *
811  * @return status
812  * @retval      0       - success
813  * @retval      -1      - Error (message printed to stderr)
814  */
815
816 int
817 osi_audit_cmd_Options(char *default_iface, struct cmd_item *audit_loglist)
818 {
819
820     if (default_iface) {
821         if (osi_audit_interface(default_iface)) {
822             fprintf(stderr, "Invalid auditinterface '%s'\n", default_iface);
823             return -1;
824         }
825     }
826
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);
831             return -1;
832         }
833         audit_loglist = audit_loglist->next;
834     }
835     return 0;
836 }
837
838  /*
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.
845  */
846 static int
847 parse_file_options(char *optionstr,
848                    const char **interface_name,
849                    char **filespec,
850                    char **options)
851 {
852     int code = 0;
853     char *opt_cursor = optionstr;
854     char *tok1 = NULL, *tok2 = NULL, *tok3 = NULL, *tokptrsave = NULL;
855
856     /*
857      * Handle the fact that strtok doesn't handle empty fields e.g. a::b
858      * and will return tok1-> a tok2-> b
859      */
860
861     /* 1st field */
862     if (*opt_cursor != ':') {
863         tok1 = strtok_r(opt_cursor, ":", &tokptrsave);
864         opt_cursor = strtok_r(NULL, "", &tokptrsave);
865     } else  {
866         /* Skip the ':' */
867         opt_cursor++;
868     }
869
870     /* 2nd field */
871     if (opt_cursor != NULL) {
872         if (*opt_cursor != ':') {
873             tok2 = strtok_r(opt_cursor, ":", &tokptrsave);
874             opt_cursor = strtok_r(NULL, "", &tokptrsave);
875         } else {
876             /* Skip the ':' */
877             opt_cursor++;
878         }
879     }
880
881     /* 3rd field is just the remainder if any */
882     tok3 = opt_cursor;
883
884     if (tok1 == NULL || strlen(tok1) == 0) {
885         fprintf(stderr, "Missing -auditlog parameter\n");
886         code = EINVAL;
887         goto done;
888     }
889
890     /* If only one token, then it's the filespec */
891     if (tok2 == NULL && tok3 == NULL) {
892         *filespec = tok1;
893     } else {
894         *interface_name = tok1;
895         *filespec = tok2;
896         *options = tok3;
897     }
898
899  done:
900     return code;
901 }
902
903 /*
904  * Parse the options looking for comma-seperated values.
905  */
906 static int
907 parse_option_string(const struct osi_audit_ops *ops, void *rock, char *options)
908 {
909     int code = 0;
910     char *tok1, *tokptrsave = NULL;
911
912     tok1 = strtok_r(options, ",", &tokptrsave);
913     while (tok1) {
914         /* Handle opt=val or just opt */
915         char *opt, *val;
916         char *optvalsave;
917
918         opt = strtok_r(tok1, "=", &optvalsave);
919         val = strtok_r(NULL, "", &optvalsave);
920
921         code = ops->set_option(rock, opt, val);
922
923         if (code) {
924             /* Bad option */
925             goto done;
926         }
927         tok1 = strtok_r(NULL, ",", &tokptrsave);
928     }
929
930  done:
931     return code;
932 }
933
934 /*
935  * Process -auditlog
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
943  */
944
945 int
946 osi_audit_file(const char *fileplusoptions)
947 {
948
949     int idx;
950     int code;
951
952     char *optionstr = NULL;
953
954     const char *interface_name = NULL;
955     char *filespec = NULL;
956     char *options = NULL;
957
958     const struct osi_audit_ops *ops = NULL;
959     struct audit_log *new_alog = NULL;
960
961     /* Use the default unless specified */
962     interface_name = audit_interfaces[default_interface].name;
963
964     /* dup of the input string so the parsing can safely modify it */
965     optionstr = strdup(fileplusoptions);
966     if (!optionstr) {
967         code = ENOMEM;
968         goto done;
969     }
970
971     code = parse_file_options(optionstr, &interface_name, &filespec, &options);
972     if (code)
973         goto done;
974
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;
979                 break;
980             }
981         }
982         if (ops == NULL) {
983             /* Couldn't find the interface name */
984             fprintf(stderr, "Could not find the specified audit interface %s\n", interface_name);
985             code = EINVAL;
986             goto done;
987         }
988     } else {
989         fprintf(stderr, "Missing interface name\n");
990         code = EINVAL;
991         goto done;
992     }
993
994     if (filespec == NULL || strlen(filespec) == 0) {
995         fprintf(stderr, "Missing auditlog path for %s interface\n", interface_name);
996         code = EINVAL;
997         goto done;
998     }
999
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 */
1006
1007     new_alog = calloc(1, sizeof(*new_alog));
1008     if (!new_alog) {
1009         code = ENOMEM;
1010         goto done;
1011     }
1012
1013     new_alog->audit_ops = ops;
1014     new_alog->auditout_open = 0;
1015
1016     new_alog->context = ops->create_interface();
1017     if (new_alog->context == NULL) {
1018             code = ENOMEM;
1019             goto done;
1020     }
1021
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);
1025         if (code)
1026             goto done;
1027     }
1028
1029     code = ops->open_file(new_alog->context, filespec);
1030     if (code) {
1031         /* Error opening file */
1032         goto done;
1033     }
1034
1035     new_alog->auditout_open = 1;
1036     auditout_open = 1;
1037
1038     /* Add to chain of active interfaces */
1039     opr_queue_Append(&audit_logs, &new_alog->link);
1040     new_alog = NULL;
1041
1042     code = 0;
1043
1044  done:
1045      if (code) {
1046          /* Error condition present.. */
1047          if (new_alog) {
1048              ops->close_interface(&new_alog->context);
1049              free(new_alog);
1050          }
1051      }
1052
1053     if (optionstr)
1054         free(optionstr);
1055     return code;
1056 }
1057
1058 /*
1059  * Set the default interface
1060  * return 0 for success
1061  *        EINVAL missing or invalid interface name
1062  */
1063 int
1064 osi_audit_interface(const char *interface)
1065 {
1066     int idx;
1067
1068     if (interface == NULL || strlen(interface) == 0)
1069         return EINVAL;
1070
1071     for (idx = 0; idx < N_INTERFACES; idx++) {
1072         if (strcmp(interface, audit_interfaces[idx].name) == 0) {
1073             default_interface = idx;
1074             return 0;
1075         }
1076     }
1077     return EINVAL;
1078 }
1079
1080 /*
1081  * Let the interfaces finish initialization
1082  */
1083 void
1084 osi_audit_open(void)
1085 {
1086     struct opr_queue *cursor;
1087
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);
1093     }
1094 }
1095
1096 /*
1097  * Shutdown the interfaces
1098  */
1099 void
1100 osi_audit_close(void)
1101 {
1102     struct opr_queue *cursor, *cursorsave;
1103
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);
1109         free(alog);
1110     }
1111 }
1112
1113 void
1114 osi_audit_set_user_check(void *rock,
1115                          int (*islocal) (void *rock, char *name, char *inst,
1116                                          char *cell))
1117 {
1118     audit_user_check.rock = rock;
1119     audit_user_check.islocal = islocal;
1120 }
1121
1122 void
1123 audit_PrintStats(FILE *out)
1124 {
1125     struct opr_queue *cursor;
1126
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);
1132     }
1133 }