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