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