viced: incorrect FID audit of BulkStatus and InlineBulkStatus
[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 <rx/rx.h>
28 #include <rx/rxkad.h>
29 #include "audit.h"
30 #include "audit-api.h"
31 #include "lock.h"
32
33 #include <afs/afsutil.h>
34
35 extern struct osi_audit_ops audit_file_ops;
36 #ifdef HAVE_SYS_IPC_H
37 extern struct osi_audit_ops audit_sysvmq_ops;
38 #endif
39
40 static struct {
41     void *rock;
42     int (*islocal)(void *rock, char *name, char *inst, char *cell);
43 } audit_user_check = { NULL, NULL };
44
45 static struct {
46     const char *name;
47     const struct osi_audit_ops *ops;
48 } audit_interfaces[] = {
49
50     { "file", &audit_file_ops },
51 #ifdef HAVE_SYS_IPC_H
52     { "sysvmq", &audit_sysvmq_ops },
53 #endif
54 };
55
56 #define N_INTERFACES (sizeof(audit_interfaces) / sizeof(audit_interfaces[0]))
57
58 /* default to `file' audit interface */
59 static const struct osi_audit_ops *audit_ops = &audit_file_ops;
60
61 static int osi_audit_all = (-1);        /* Not determined yet */
62 static int osi_echo_trail = (-1);
63
64 static int auditout_open = 0;
65
66 static int osi_audit_check(void);
67
68 #ifdef AFS_AIX32_ENV
69 static char *bufferPtr;
70 static int bufferLen;
71
72 static void
73 audmakebuf(char *audEvent, va_list vaList)
74 {
75     int code;
76     int vaEntry;
77     int vaInt;
78     afs_int32 vaLong;
79     char *vaStr;
80     struct AFSFid *vaFid;
81
82     vaEntry = va_arg(vaList, int);
83     while (vaEntry != AUD_END) {
84         switch (vaEntry) {
85         case AUD_STR:           /* String */
86         case AUD_NAME:          /* Name */
87         case AUD_ACL:           /* ACL */
88             vaStr = (char *)va_arg(vaList, char *);
89             if (vaStr) {
90                 strcpy(bufferPtr, vaStr);
91                 bufferPtr += strlen(vaStr) + 1;
92             } else {
93                 strcpy(bufferPtr, "");
94                 bufferPtr++;
95             }
96             break;
97         case AUD_INT:           /* Integer */
98         case AUD_ID:            /* ViceId */
99             vaInt = va_arg(vaList, int);
100             *(int *)bufferPtr = vaInt;
101             bufferPtr += sizeof(vaInt);
102             break;
103         case AUD_DATE:          /* Date    */
104         case AUD_HOST:          /* Host ID */
105         case AUD_LONG:          /* long    */
106             vaLong = va_arg(vaList, afs_int32);
107             *(afs_int32 *) bufferPtr = vaLong;
108             bufferPtr += sizeof(vaLong);
109             break;
110         case AUD_FID:           /* AFSFid - contains 3 entries */
111             vaFid = (struct AFSFid *)va_arg(vaList, struct AFSFid *);
112             if (vaFid) {
113                 memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
114             } else {
115                 memset(bufferPtr, 0, sizeof(struct AFSFid));
116             }
117             bufferPtr += sizeof(struct AFSFid);
118             break;
119
120             /* Whole array of fids-- don't know how to handle variable length audit
121              * data with AIX audit package, so for now we just store the first fid.
122              * Better one than none. */
123         case AUD_FIDS:
124             {
125                 struct AFSCBFids *Fids;
126
127                 Fids = (struct AFSCBFids *)va_arg(vaList, struct AFSCBFids *);
128                 if (Fids && Fids->AFSCBFids_len) {
129                     *((u_int *) bufferPtr) = Fids->AFSCBFids_len;
130                     bufferPtr += sizeof(u_int);
131                     memcpy(bufferPtr, Fids->AFSCBFids_val,
132                            sizeof(struct AFSFid));
133                 } else {
134                     *((u_int *) bufferPtr) = 0;
135                     bufferPtr += sizeof(u_int);
136                     memset(bufferPtr, 0, sizeof(struct AFSFid));
137                 }
138                 bufferPtr += sizeof(struct AFSFid);
139                 break;
140             }
141         default:
142 #ifdef AFS_AIX32_ENV
143             code =
144                 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
145                          (strlen(audEvent) + 1));
146 #endif
147             return;
148             break;
149         }                       /* end switch */
150
151         vaEntry = va_arg(vaList, int);
152     }                           /* end while */
153 }
154 #endif
155
156 static void
157 printbuf(int rec, char *audEvent, char *afsName, afs_int32 hostId,
158          afs_int32 errCode, va_list vaList)
159 {
160     int vaEntry;
161     int vaInt;
162     afs_int32 vaLong;
163     char *vaStr;
164     struct AFSFid *vaFid;
165     struct AFSCBFids *vaFids;
166     int num = LogThreadNum();
167     struct in_addr hostAddr;
168     time_t currenttime;
169     char tbuffer[26];
170     struct tm tm;
171
172     /* Don't print the timestamp or thread id if we recursed */
173     if (rec == 0) {
174         currenttime = time(0);
175         if (strftime(tbuffer, sizeof(tbuffer), "%a %b %d %H:%M:%S %Y ",
176                      localtime_r(&currenttime, &tm)) !=0)
177             audit_ops->append_msg(tbuffer);
178
179         if (num > -1)
180             audit_ops->append_msg("[%d] ", num);
181     }
182
183     audit_ops->append_msg("EVENT %s CODE %d ", audEvent, errCode);
184
185     if (afsName) {
186         hostAddr.s_addr = hostId;
187         audit_ops->append_msg("NAME %s HOST %s ", afsName, inet_ntoa(hostAddr));
188     }
189
190     vaEntry = va_arg(vaList, int);
191     while (vaEntry != AUD_END) {
192         switch (vaEntry) {
193         case AUD_STR:           /* String */
194             vaStr = (char *)va_arg(vaList, char *);
195             if (vaStr)
196                 audit_ops->append_msg("STR %s ", vaStr);
197             else
198                 audit_ops->append_msg("STR <null>");
199             break;
200         case AUD_NAME:          /* Name */
201             vaStr = (char *)va_arg(vaList, char *);
202             if (vaStr)
203                 audit_ops->append_msg("NAME %s ", vaStr);
204             else
205                 audit_ops->append_msg("NAME <null>");
206             break;
207         case AUD_ACL:           /* ACL */
208             vaStr = (char *)va_arg(vaList, char *);
209             if (vaStr)
210                 audit_ops->append_msg("ACL %s ", vaStr);
211             else
212                 audit_ops->append_msg("ACL <null>");
213             break;
214         case AUD_INT:           /* Integer */
215             vaInt = va_arg(vaList, int);
216             audit_ops->append_msg("INT %d ", vaInt);
217             break;
218         case AUD_ID:            /* ViceId */
219             vaInt = va_arg(vaList, int);
220             audit_ops->append_msg("ID %d ", vaInt);
221             break;
222         case AUD_DATE:          /* Date    */
223             vaLong = va_arg(vaList, afs_int32);
224             audit_ops->append_msg("DATE %u ", vaLong);
225             break;
226         case AUD_HOST:          /* Host ID */
227             vaLong = va_arg(vaList, afs_int32);
228             hostAddr.s_addr = vaLong;
229             audit_ops->append_msg("HOST %s ", inet_ntoa(hostAddr));
230             break;
231         case AUD_LONG:          /* afs_int32    */
232             vaLong = va_arg(vaList, afs_int32);
233             audit_ops->append_msg("LONG %d ", vaLong);
234             break;
235         case AUD_FID:           /* AFSFid - contains 3 entries */
236             vaFid = va_arg(vaList, struct AFSFid *);
237             if (vaFid)
238                 audit_ops->append_msg("FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
239                        vaFid->Unique);
240             else
241                 audit_ops->append_msg("FID %u:%u:%u ", 0, 0, 0);
242             break;
243         case AUD_FIDS:          /* array of Fids */
244             vaFids = va_arg(vaList, struct AFSCBFids *);
245
246             if (vaFids) {
247                 unsigned int i;
248
249                 vaFid = vaFids->AFSCBFids_val;
250
251                 if (vaFid) {
252                     audit_ops->append_msg("FIDS %u ", vaFids->AFSCBFids_len);
253                     for ( i = 1; i <= vaFids->AFSCBFids_len; i++, vaFid++ )
254                         audit_ops->append_msg("FID %u:%u:%u ", vaFid->Volume,
255                                 vaFid->Vnode, vaFid->Unique);
256                 } else
257                     audit_ops->append_msg("FIDS 0 FID 0:0:0 ");
258
259             }
260             break;
261         default:
262             audit_ops->append_msg("--badval-- ");
263             break;
264         }                       /* end switch */
265         vaEntry = va_arg(vaList, int);
266     }                           /* end while */
267
268     audit_ops->send_msg();
269 }
270
271 #ifdef AFS_PTHREAD_ENV
272 static pthread_mutex_t audit_lock;
273 static volatile afs_int32   audit_lock_initialized = 0;
274 static pthread_once_t audit_lock_once = PTHREAD_ONCE_INIT;
275
276 static void
277 osi_audit_init_lock(void)
278 {
279     MUTEX_INIT(&audit_lock, "audit", MUTEX_DEFAULT, 0);
280     audit_lock_initialized = 1;
281 }
282 #endif
283
284 void
285 osi_audit_init(void)
286 {
287 #ifdef AFS_PTHREAD_ENV
288     if (!audit_lock_initialized) {
289         pthread_once(&audit_lock_once, osi_audit_init_lock);
290     }
291 #endif /* AFS_PTHREAD_ENV */
292 }
293
294 /* ************************************************************************** */
295 /* The routine that acually does the audit call.
296  * ************************************************************************** */
297 static int
298 osi_audit_internal(char *audEvent,      /* Event name (15 chars or less) */
299                    afs_int32 errCode,   /* The error code */
300                    char *afsName,
301                    afs_int32 hostId,
302                    va_list vaList)
303 {
304 #ifdef AFS_AIX32_ENV
305     afs_int32 code;
306     afs_int32 err;
307     static char BUFFER[32768];
308     int result;
309 #endif
310
311 #ifdef AFS_PTHREAD_ENV
312     /* i'm pretty sure all the server apps now call osi_audit_init(),
313      * but to be extra careful we'll leave this assert in here for a
314      * while to make sure */
315     opr_Assert(audit_lock_initialized);
316 #endif /* AFS_PTHREAD_ENV */
317
318     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
319         osi_audit_check();
320     if (!osi_audit_all && !auditout_open)
321         return 0;
322
323 #ifdef AFS_AIX32_ENV
324     switch (errCode) {
325     case 0:
326         result = AUDIT_OK;
327         break;
328     case KANOAUTH:              /* kautils.h   */
329     case RXKADNOAUTH:           /* rxkad.h     */
330         result = AUDIT_FAIL_AUTH;
331         break;
332     case EPERM:         /* errno.h     */
333     case EACCES:                /* errno.h     */
334     case PRPERM:                /* pterror.h   */
335         result = AUDIT_FAIL_ACCESS;
336         break;
337     case VL_PERM:               /* vlserver.h  */
338     case BUDB_NOTPERMITTED:     /* budb_errs.h */
339     case BZACCESS:              /* bnode.h     */
340     case VOLSERBAD_ACCESS:      /* volser.h    */
341         result = AUDIT_FAIL_PRIV;
342         break;
343     default:
344         result = AUDIT_FAIL;
345         break;
346     }
347 #endif
348
349     MUTEX_ENTER(&audit_lock);
350 #ifdef AFS_AIX32_ENV
351     bufferPtr = BUFFER;
352
353     /* Put the error code into the buffer list */
354     *(int *)bufferPtr = errCode;
355     bufferPtr += sizeof(errCode);
356
357     audmakebuf(audEvent, vaList);
358 #endif
359
360 #ifdef AFS_AIX32_ENV
361     bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
362     code = auditlog(audEvent, result, BUFFER, bufferLen);
363 #else
364     if (auditout_open) {
365         printbuf(0, audEvent, afsName, hostId, errCode, vaList);
366     }
367 #endif
368     MUTEX_EXIT(&audit_lock);
369
370     return 0;
371 }
372 int
373 osi_audit(char *audEvent,       /* Event name (15 chars or less) */
374           afs_int32 errCode,    /* The error code */
375           ...)
376 {
377     va_list vaList;
378
379     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
380         osi_audit_check();
381     if (!osi_audit_all && !auditout_open)
382         return 0;
383
384     va_start(vaList, errCode);
385     osi_audit_internal(audEvent, errCode, NULL, 0, vaList);
386     va_end(vaList);
387
388     return 0;
389 }
390
391 /* ************************************************************************** */
392 /* Given a RPC call structure, this routine extracts the name and host id from the
393  * call and includes it within the audit information.
394  * ************************************************************************** */
395 int
396 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
397 {
398     struct rx_connection *conn;
399     struct rx_peer *peer;
400     afs_int32 secClass;
401     afs_int32 code;
402     char afsName[MAXKTCNAMELEN + MAXKTCNAMELEN + MAXKTCREALMLEN + 3];
403     afs_int32 hostId;
404     va_list vaList;
405
406     if (osi_audit_all < 0)
407         osi_audit_check();
408     if (!osi_audit_all && !auditout_open)
409         return 0;
410
411     strcpy(afsName, "--Unknown--");
412     hostId = 0;
413
414     if (call) {
415         conn = rx_ConnectionOf(call);   /* call -> conn) */
416         if (conn) {
417             secClass = rx_SecurityClassOf(conn);        /* conn -> securityIndex */
418             if (secClass == RX_SECIDX_NULL) {   /* unauthenticated */
419                 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
420                 strcpy(afsName, "--UnAuth--");
421             } else if (secClass == RX_SECIDX_KAD || secClass == RX_SECIDX_KAE) {
422                 /* authenticated with rxkad */
423                 char tcell[MAXKTCREALMLEN];
424                 char name[MAXKTCNAMELEN];
425                 char inst[MAXKTCNAMELEN];
426
427                 code =
428                     rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
429                                         NULL);
430                 if (code) {
431                     osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
432                     strcpy(afsName, "--NoName--");
433                 } else {
434                     afs_int32 islocal = 0;
435                     if (audit_user_check.islocal) {
436                         islocal =
437                             audit_user_check.islocal(audit_user_check.rock,
438                                                      name, inst, tcell);
439                     }
440                     strlcpy(afsName, name, sizeof(afsName));
441                     if (inst[0]) {
442                         strlcat(afsName, ".", sizeof(afsName));
443                         strlcat(afsName, inst, sizeof(afsName));
444                     }
445                     if (tcell[0] && !islocal) {
446                         strlcat(afsName, "@", sizeof(afsName));
447                         strlcat(afsName, tcell, sizeof(afsName));
448                     }
449                 }
450             } else {            /* Unauthenticated and/or unknown */
451                 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
452                 strcpy(afsName, "--Unknown--");
453             }
454             peer = rx_PeerOf(conn);     /* conn -> peer */
455             if (peer)
456                 hostId = rx_HostOf(peer);       /* peer -> host */
457             else
458                 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
459         } else {                /* null conn */
460             osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
461         }
462     } else {                    /* null call */
463         osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
464     }
465     va_start(vaList, errCode);
466     osi_audit_internal(audEvent, errCode, afsName, hostId, vaList);
467     va_end(vaList);
468     return 0;
469 }
470
471 /* ************************************************************************** */
472 /* Determines whether auditing is on or off by looking at the Audit file.
473  * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
474  * enabled.
475  * ************************************************************************** */
476
477 int
478 osi_audit_check(void)
479 {
480     FILE *fds;
481     int onoff;
482     char event[257];
483
484     osi_audit_all = 1;          /* say we made check (>= 0) */
485     /* and assume audit all events (for now) */
486     onoff = 0;                  /* assume we will turn auditing off */
487     osi_echo_trail = 0;         /* assume no echoing   */
488
489     fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
490     if (fds) {
491         while (fscanf(fds, "%256s", event) > 0) {
492             if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
493                 onoff = 1;
494
495             if (strcmp(event, "Echo_Trail") == 0)
496                 osi_echo_trail = 1;
497         }
498         fclose(fds);
499     }
500
501     /* Audit this event all of the time */
502     if (onoff)
503         osi_audit("AFS_Aud_On", 0, AUD_END);
504     else
505         osi_audit("AFS_Aud_Off", 0, AUD_END);
506
507     /* Now set whether we audit all events from here on out */
508     osi_audit_all = onoff;
509
510     return 0;
511 }
512
513 int
514 osi_audit_file(const char *fileName)
515 {
516     if(!audit_ops->open_file(fileName)) {
517         auditout_open = 1;
518         return 0;
519     }
520     return 1;
521 }
522
523 int
524 osi_audit_interface(const char *interface)
525 {
526     int i;
527     for (i = 0; i < N_INTERFACES; ++i) {
528         if (strcmp(interface, audit_interfaces[i].name) == 0) {
529             audit_ops = audit_interfaces[i].ops;
530             return 0;
531         }
532     }
533
534     return 1;
535 }
536
537 void
538 osi_audit_set_user_check(void *rock,
539                          int (*islocal) (void *rock, char *name, char *inst,
540                                          char *cell))
541 {
542     audit_user_check.rock = rock;
543     audit_user_check.islocal = islocal;
544 }
545
546 void
547 audit_PrintStats(FILE *out)
548 {
549     audit_ops->print_interface_stats(out);
550 }