auditlogs-for-everyone-20050702
[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     char *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             vaStr = (char *)va_arg(vaList, int);
67             if (vaStr) {
68                 strcpy(bufferPtr, vaStr);
69                 bufferPtr += strlen(vaStr) + 1;
70             } else {
71                 strcpy(bufferPtr, "");
72                 bufferPtr++;
73             }
74             break;
75         case AUD_INT:           /* Integer */
76             vaInt = va_arg(vaList, int);
77             *(int *)bufferPtr = vaInt;
78             bufferPtr += sizeof(vaInt);
79             break;
80         case AUD_DATE:          /* Date    */
81         case AUD_HOST:          /* Host ID */
82         case AUD_LONG:          /* long    */
83             vaLong = va_arg(vaList, afs_int32);
84             *(afs_int32 *) bufferPtr = vaLong;
85             bufferPtr += sizeof(vaLong);
86             break;
87         case AUD_LST:           /* Ptr to another list */
88             vaLst = (char *)va_arg(vaList, int);
89             audmakebuf(audEvent, vaLst);
90             break;
91         case AUD_FID:           /* AFSFid - contains 3 entries */
92             vaFid = (struct AFSFid *)va_arg(vaList, int);
93             if (vaFid) {
94                 memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
95             } else {
96                 memset(bufferPtr, 0, sizeof(struct AFSFid));
97             }
98             bufferPtr += sizeof(struct AFSFid);
99             break;
100
101             /* Whole array of fids-- don't know how to handle variable length audit
102              * data with AIX audit package, so for now we just store the first fid.
103              * Better one than none. */
104         case AUD_FIDS:
105             {
106                 struct AFSCBFids *Fids;
107
108                 Fids = (struct AFSCBFids *)va_arg(vaList, int);
109                 if (Fids && Fids->AFSCBFids_len) {
110                     *((u_int *) bufferPtr) = Fids->AFSCBFids_len;
111                     bufferPtr += sizeof(u_int);
112                     memcpy(bufferPtr, Fids->AFSCBFids_val,
113                            sizeof(struct AFSFid));
114                 } else {
115                     *((u_int *) bufferPtr) = 0;
116                     bufferPtr += sizeof(u_int);
117                     memset(bufferPtr, 0, sizeof(struct AFSFid));
118                 }
119                 bufferPtr += sizeof(struct AFSFid);
120                 break;
121             }
122         default:
123 #ifdef AFS_AIX32_ENV
124             code =
125                 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
126                          (strlen(audEvent) + 1));
127 #endif
128             return;
129             break;
130         }                       /* end switch */
131
132         vaEntry = va_arg(vaList, int);
133     }                           /* end while */
134 }
135
136 static void
137 printbuf(FILE *out, int rec, char *audEvent, afs_int32 errCode, va_list vaList)
138 {
139     int vaEntry;
140     int vaInt;
141     afs_int32 vaLong;
142     char *vaStr;
143     char *vaLst;
144     struct AFSFid *vaFid;
145     struct AFSCBFids *vaFids;
146     int num = LogThreadNum();
147
148     /* Don't print the thread id if we recursed */
149     if ((num > -1) && (rec == 0))
150         fprintf(out, "[%d]:", num);
151     
152     if (strcmp(audEvent, "VALST") != 0)
153         fprintf(out,  "%s %d ", audEvent, errCode);
154
155     vaEntry = va_arg(vaList, int);
156     while (vaEntry != AUD_END) {
157         switch (vaEntry) {
158         case AUD_STR:           /* String */
159             vaStr = (char *)va_arg(vaList, int);
160             if (vaStr)
161                 fprintf(out,  "%s ", vaStr);
162             else
163                 fprintf(out,  "<null>");
164             break;
165         case AUD_INT:           /* Integer */
166             vaInt = va_arg(vaList, int);
167             fprintf(out,  "%d ", vaInt);
168             break;
169         case AUD_DATE:          /* Date    */
170         case AUD_HOST:          /* Host ID */
171             vaLong = va_arg(vaList, afs_int32);
172             fprintf(out, "%u ", vaLong);
173             break;
174         case AUD_LONG:          /* afs_int32    */
175             vaLong = va_arg(vaList, afs_int32);
176             fprintf(out, "%d ", vaLong);
177             break;
178         case AUD_LST:           /* Ptr to another list */
179             vaLst = (char *)va_arg(vaList, int);
180             printbuf(out, 1, "VALST", 0, vaLst);
181             break;
182         case AUD_FID:           /* AFSFid - contains 3 entries */
183             vaFid = (struct AFSFid *)va_arg(vaList, int);
184             if (vaFid)
185                 fprintf(out, "%u:%u:%u ", vaFid->Volume, vaFid->Vnode,
186                        vaFid->Unique);
187             else
188                 fprintf(out, "%u:%u:%u ", 0, 0, 0);
189             break;
190         case AUD_FIDS:          /* array of Fids */
191             vaFids = (struct AFSCBFids *)va_arg(vaList, int);
192             vaFid = NULL;
193
194             if (vaFids)
195                 vaFid = vaFids->AFSCBFids_val;
196             if (vaFid)
197                 fprintf(out, "%u %u:%u:%u ", vaFids->AFSCBFids_len, vaFid->Volume,
198                        vaFid->Vnode, vaFid->Unique);
199             else
200                 fprintf(out, "0 0:0:0 ");
201             break;
202         default:
203             fprintf(out, "--badval-- ");
204             break;
205         }                       /* end switch */
206         vaEntry = va_arg(vaList, int);
207     }                           /* end while */
208
209     if (strcmp(audEvent, "VALST") != 0)
210         fprintf(out, "\n");
211 }
212
213 /* ************************************************************************** */
214 /* The routine that acually does the audit call.
215  * ************************************************************************** */
216 int
217 osi_audit(char *audEvent,       /* Event name (15 chars or less) */
218           afs_int32 errCode,    /* The error code */
219           ...)
220 {
221 #ifdef AFS_AIX32_ENV
222     afs_int32 code;
223     afs_int32 err;
224 #endif
225     int result;
226
227     va_list vaList;
228 #ifdef AFS_AIX32_ENV
229     static struct Lock audbuflock = { 0, 0, 0, 0,
230 #ifdef AFS_PTHREAD_ENV
231         PTHREAD_MUTEX_INITIALIZER,
232         PTHREAD_COND_INITIALIZER,
233         PTHREAD_COND_INITIALIZER
234 #endif /* AFS_PTHREAD_ENV */
235     };
236     static char BUFFER[32768];
237 #endif
238
239     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
240         osi_audit_check();
241     if (!osi_audit_all && !auditout)
242         return 0;
243
244     switch (errCode) {
245     case 0:
246         result = AUDIT_OK;
247         break;
248     case KANOAUTH:              /* kautils.h   */
249     case RXKADNOAUTH:           /* rxkad.h     */
250         result = AUDIT_FAIL_AUTH;
251         break;
252     case EPERM:         /* errno.h     */
253     case EACCES:                /* errno.h     */
254     case PRPERM:                /* pterror.h   */
255         result = AUDIT_FAIL_ACCESS;
256         break;
257     case VL_PERM:               /* vlserver.h  */
258     case BUDB_NOTPERMITTED:     /* budb_errs.h */
259     case BZACCESS:              /* bnode.h     */
260     case VOLSERBAD_ACCESS:      /* volser.h    */
261         result = AUDIT_FAIL_PRIV;
262         break;
263     default:
264         result = AUDIT_FAIL;
265         break;
266     }
267
268 #ifdef AFS_AIX32_ENV
269     ObtainWriteLock(&audbuflock);
270     bufferPtr = BUFFER;
271
272     /* Put the error code into the buffer list */
273     *(int *)bufferPtr = errCode;
274     bufferPtr += sizeof(errCode);
275
276     va_start(vaList, errCode);
277     audmakebuf(audEvent, vaList);
278 #endif
279
280     if (osi_echo_trail) {
281         va_start(vaList, errCode);
282         printbuf(stdout, 0, audEvent, errCode, vaList);
283     }
284
285 #ifdef AFS_AIX32_ENV
286     bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
287     code = auditlog(audEvent, result, BUFFER, bufferLen);
288 #ifdef notdef
289     if (code) {
290         err = errno;
291         code = auditlog("AFS_Aud_Fail", result, &err, sizeof(err));
292         if (code)
293             printf("Error while writing audit entry: %d.\n", errno);
294     }
295 #endif /* notdef */
296     ReleaseWriteLock(&audbuflock);
297 #else
298     if (auditout) {
299         va_start(vaList, errCode);
300         printbuf(auditout, 0, audEvent, errCode, vaList);
301         fflush(auditout);
302     }
303 #endif
304
305     return 0;
306 }
307
308 /* ************************************************************************** */
309 /* Given a RPC call structure, this routine extracts the name and host id from the 
310  * call and includes it within the audit information.
311  * ************************************************************************** */
312 int
313 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
314 {
315     struct rx_connection *conn;
316     struct rx_peer *peer;
317     afs_int32 secClass;
318     afs_int32 code;
319     char afsName[MAXKTCNAMELEN];
320     afs_int32 hostId;
321     va_list vaList;
322
323     if (osi_audit_all < 0)
324         osi_audit_check();
325     if (!osi_audit_all && !auditout)
326         return 0;
327
328     strcpy(afsName, "--Unknown--");
329     hostId = 0;
330
331     if (call) {
332         conn = rx_ConnectionOf(call);   /* call -> conn) */
333         if (conn) {
334             secClass = rx_SecurityClassOf(conn);        /* conn -> securityIndex */
335             if (secClass == 0) {        /* unauthenticated */
336                 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
337                 strcpy(afsName, "--UnAuth--");
338             } else if (secClass == 2) { /* authenticated */
339                 char tcell[MAXKTCREALMLEN];
340                 char name[MAXKTCNAMELEN];
341                 char inst[MAXKTCNAMELEN];
342                 char vname[256];
343                 int  ilen, clen;
344
345                 code =
346                     rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
347                                         NULL);
348                 if (code) {
349                     osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent,
350                               AUD_END);
351                     strcpy(afsName, "--NoName--");
352                 } else {
353                     strncpy(vname, name, sizeof(vname));
354                     if ((ilen = strlen(inst))) {
355                         if (strlen(vname) + 1 + ilen >= sizeof(vname))
356                             goto done;
357                         strcat(vname, ".");
358                         strcat(vname, inst);
359                     }
360                     if ((clen = strlen(tcell))) {
361 #if     defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
362                         static char local_realm[AFS_REALM_SZ] = "";
363                         if (!local_realm[0]) {
364                             if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
365                                 strncpy(local_realm, "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
366                         }
367                         if (strcasecmp(local_realm, tcell)) {
368                             if (strlen(vname) + 1 + clen >= sizeof(vname))
369                                 goto done;
370                             strcat(vname, "@");
371                             strcat(vname, tcell);
372                         }
373 #endif
374                         strcpy(afsName, vname);
375                     }
376                 }
377             } else {            /* Unauthenticated & unknown */
378
379                 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent,
380                           AUD_END);
381             }
382         done:
383             peer = rx_PeerOf(conn);     /* conn -> peer */
384             if (peer)
385                 hostId = rx_HostOf(peer);       /* peer -> host */
386             else
387                 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
388         } else {                /* null conn */
389
390             osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
391         }
392     } else {                    /* null call */
393
394         osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
395     }
396
397     va_start(vaList, errCode);
398     osi_audit(audEvent, errCode, AUD_STR, afsName, AUD_HOST, hostId, AUD_LST,
399               vaList, AUD_END);
400
401     return 0;
402 }
403
404 /* ************************************************************************** */
405 /* Determines whether auditing is on or off by looking at the Audit file.
406  * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be 
407  * enabled.
408  * ************************************************************************** */
409
410 int
411 osi_audit_check()
412 {
413     FILE *fds;
414     int onoff;
415     char event[257];
416
417     osi_audit_all = 1;          /* say we made check (>= 0) */
418     /* and assume audit all events (for now) */
419     onoff = 0;                  /* assume we will turn auditing off */
420     osi_echo_trail = 0;         /* assume no echoing   */
421
422     fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
423     if (fds) {
424         while (fscanf(fds, "%256s", event) > 0) {
425             if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
426                 onoff = 1;
427
428             if (strcmp(event, "Echo_Trail") == 0)
429                 osi_echo_trail = 1;
430         }
431         fclose(fds);
432     }
433
434     /* Audit this event all of the time */
435     if (onoff)
436         osi_audit("AFS_Aud_On", 0, AUD_END);
437     else
438         osi_audit("AFS_Aud_Off", 0, AUD_END);
439
440     /* Now set whether we audit all events from here on out */
441     osi_audit_all = onoff;
442
443     return 0;
444 }
445
446 int
447 osi_audit_file(FILE *out)
448 {
449     auditout = out;
450     return 0;
451 }