aeea18567ffefa5e6d211aabc3c6ffb35ec1a6a7
[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 static struct Lock audlock;
261 static afs_int32   lock_init = 0;
262 void
263 osi_audit_init(void)
264 {
265 #ifdef AFS_PTHREAD_ENV
266     if ( !lock_init ) {
267         Lock_Init(&audlock);
268         lock_init = 1;
269     }
270 #endif /* AFS_PTHREAD_ENV */
271 }
272
273 /* ************************************************************************** */
274 /* The routine that acually does the audit call.
275  * ************************************************************************** */
276 int
277 osi_audit(char *audEvent,       /* Event name (15 chars or less) */
278           afs_int32 errCode,    /* The error code */
279           ...)
280 {
281 #ifdef AFS_AIX32_ENV
282     afs_int32 code;
283     afs_int32 err;
284     static char BUFFER[32768];
285 #endif
286     int result;
287     va_list vaList;
288
289 #ifdef AFS_PTHREAD_ENV
290     /* This is not thread safe.   Lock initialization should 
291      * be done in a server initialization phase
292      */
293     if ( !lock_init )
294         osi_audit_init();
295 #endif /* AFS_PTHREAD_ENV */
296
297     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
298         osi_audit_check();
299     if (!osi_audit_all && !auditout)
300         return 0;
301
302     switch (errCode) {
303     case 0:
304         result = AUDIT_OK;
305         break;
306     case KANOAUTH:              /* kautils.h   */
307     case RXKADNOAUTH:           /* rxkad.h     */
308         result = AUDIT_FAIL_AUTH;
309         break;
310     case EPERM:         /* errno.h     */
311     case EACCES:                /* errno.h     */
312     case PRPERM:                /* pterror.h   */
313         result = AUDIT_FAIL_ACCESS;
314         break;
315     case VL_PERM:               /* vlserver.h  */
316     case BUDB_NOTPERMITTED:     /* budb_errs.h */
317     case BZACCESS:              /* bnode.h     */
318     case VOLSERBAD_ACCESS:      /* volser.h    */
319         result = AUDIT_FAIL_PRIV;
320         break;
321     default:
322         result = AUDIT_FAIL;
323         break;
324     }
325
326 #ifdef AFS_PTHREAD_ENV
327     ObtainWriteLock(&audlock);
328 #endif
329 #ifdef AFS_AIX32_ENV
330     bufferPtr = BUFFER;
331
332     /* Put the error code into the buffer list */
333     *(int *)bufferPtr = errCode;
334     bufferPtr += sizeof(errCode);
335
336     va_start(vaList, errCode);
337     audmakebuf(audEvent, vaList);
338 #endif
339
340     if (osi_echo_trail) {
341         va_start(vaList, errCode);
342         printbuf(stdout, 0, audEvent, errCode, vaList);
343     }
344
345 #ifdef AFS_AIX32_ENV
346     bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
347     code = auditlog(audEvent, result, BUFFER, bufferLen);
348 #ifdef notdef
349     if (code) {
350         err = errno;
351         code = auditlog("AFS_Aud_Fail", result, &err, sizeof(err));
352         if (code)
353             printf("Error while writing audit entry: %d.\n", errno);
354     }
355 #endif /* notdef */
356 #else
357     if (auditout) {
358         va_start(vaList, errCode);
359         printbuf(auditout, 0, audEvent, errCode, vaList);
360         fflush(auditout);
361     }
362 #endif
363 #ifdef AFS_PTHREAD_ENV
364     ReleaseWriteLock(&audlock);
365 #endif
366
367     return 0;
368 }
369
370 /* ************************************************************************** */
371 /* Given a RPC call structure, this routine extracts the name and host id from the 
372  * call and includes it within the audit information.
373  * ************************************************************************** */
374 int
375 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
376 {
377     struct rx_connection *conn;
378     struct rx_peer *peer;
379     afs_int32 secClass;
380     afs_int32 code;
381     char afsName[MAXKTCNAMELEN];
382     afs_int32 hostId;
383     va_list vaList;
384
385     if (osi_audit_all < 0)
386         osi_audit_check();
387     if (!osi_audit_all && !auditout)
388         return 0;
389
390     strcpy(afsName, "--Unknown--");
391     hostId = 0;
392
393     if (call) {
394         conn = rx_ConnectionOf(call);   /* call -> conn) */
395         if (conn) {
396             secClass = rx_SecurityClassOf(conn);        /* conn -> securityIndex */
397             if (secClass == 0) {        /* unauthenticated */
398                 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
399                 strcpy(afsName, "--UnAuth--");
400             } else if (secClass == 2) { /* authenticated */
401                 char tcell[MAXKTCREALMLEN];
402                 char name[MAXKTCNAMELEN];
403                 char inst[MAXKTCNAMELEN];
404                 char vname[256];
405                 int  ilen, clen;
406
407                 code =
408                     rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
409                                         NULL);
410                 if (code) {
411                     osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
412                     strcpy(afsName, "--NoName--");
413                 } else {
414                     strncpy(vname, name, sizeof(vname));
415                     if ((ilen = strlen(inst))) {
416                         if (strlen(vname) + 1 + ilen >= sizeof(vname))
417                             goto done;
418                         strcat(vname, ".");
419                         strcat(vname, inst);
420                     }
421                     if ((clen = strlen(tcell))) {
422 #if defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
423                         static char local_realm[AFS_REALM_SZ] = "";
424                         if (!local_realm[0]) {
425                             if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
426                                 strncpy(local_realm, "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
427                         }
428                         if (strcasecmp(local_realm, tcell)) {
429                             if (strlen(vname) + 1 + clen >= sizeof(vname))
430                                 goto done;
431                             strcat(vname, "@");
432                             strcat(vname, tcell);
433                         }
434 #endif
435                     }
436                     strcpy(afsName, vname);
437                 }
438             } else {            /* Unauthenticated & unknown */
439                 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
440                 strcpy(afsName, "--Unknown--");
441             }
442         done:
443             peer = rx_PeerOf(conn);     /* conn -> peer */
444             if (peer)
445                 hostId = rx_HostOf(peer);       /* peer -> host */
446             else
447                 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
448         } else {                /* null conn */
449             osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
450         }
451     } else {                    /* null call */
452         osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
453     }
454     va_start(vaList, errCode);
455     osi_audit(audEvent, errCode, AUD_NAME, afsName, AUD_HOST, hostId, 
456               AUD_LST, vaList, AUD_END);
457
458     return 0;
459 }
460
461 /* ************************************************************************** */
462 /* Determines whether auditing is on or off by looking at the Audit file.
463  * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be 
464  * enabled.
465  * ************************************************************************** */
466
467 int
468 osi_audit_check()
469 {
470     FILE *fds;
471     int onoff;
472     char event[257];
473
474     osi_audit_all = 1;          /* say we made check (>= 0) */
475     /* and assume audit all events (for now) */
476     onoff = 0;                  /* assume we will turn auditing off */
477     osi_echo_trail = 0;         /* assume no echoing   */
478
479     fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
480     if (fds) {
481         while (fscanf(fds, "%256s", event) > 0) {
482             if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
483                 onoff = 1;
484
485             if (strcmp(event, "Echo_Trail") == 0)
486                 osi_echo_trail = 1;
487         }
488         fclose(fds);
489     }
490
491     /* Audit this event all of the time */
492     if (onoff)
493         osi_audit("AFS_Aud_On", 0, AUD_END);
494     else
495         osi_audit("AFS_Aud_Off", 0, AUD_END);
496
497     /* Now set whether we audit all events from here on out */
498     osi_audit_all = onoff;
499
500     return 0;
501 }
502
503 int
504 osi_audit_file(FILE *out)
505 {
506     auditout = out;
507     return 0;
508 }