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