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