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