audit-add-and-fix-messages-20050708
[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         case AUD_NAME:          /* Name */
67         case AUD_ACL:           /* ACL */
68             vaStr = (char *)va_arg(vaList, int);
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 = (char *)va_arg(vaList, int);
92             audmakebuf(audEvent, vaLst);
93             break;
94         case AUD_FID:           /* AFSFid - contains 3 entries */
95             vaFid = (struct AFSFid *)va_arg(vaList, int);
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, int);
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     char *vaLst;
147     struct AFSFid *vaFid;
148     struct AFSCBFids *vaFids;
149     int num = LogThreadNum();
150     struct in_addr hostAddr;
151
152     /* Don't print the thread id if we recursed */
153     if ((num > -1) && (rec == 0))
154         fprintf(out, "[%d]:", num);
155     
156     if (strcmp(audEvent, "VALST") != 0)
157         fprintf(out,  "EVENT %s CODE %d ", audEvent, errCode);
158
159     vaEntry = va_arg(vaList, int);
160     while (vaEntry != AUD_END) {
161         switch (vaEntry) {
162         case AUD_STR:           /* String */
163             vaStr = (char *)va_arg(vaList, int);
164             if (vaStr)
165                 fprintf(out,  "STR %s ", vaStr);
166             else
167                 fprintf(out,  "STR <null>");
168             break;
169         case AUD_NAME:          /* Name */
170             vaStr = (char *)va_arg(vaList, int);
171             if (vaStr)
172                 fprintf(out,  "NAME %s ", vaStr);
173             else
174                 fprintf(out,  "NAME <null>");
175             break;
176         case AUD_ACL:           /* ACL */
177             vaStr = (char *)va_arg(vaList, int);
178             if (vaStr)
179                 fprintf(out,  "ACL %s ", vaStr);
180             else
181                 fprintf(out,  "ACL <null>");
182             break;
183         case AUD_INT:           /* Integer */
184             vaInt = va_arg(vaList, int);
185             fprintf(out,  "INT %d ", vaInt);
186             break;
187         case AUD_ID:            /* ViceId */
188             vaInt = va_arg(vaList, int);
189             fprintf(out,  "ID %d ", vaInt);
190             break;
191         case AUD_DATE:          /* Date    */
192             vaLong = va_arg(vaList, afs_int32);
193             fprintf(out, "DATE %u ", vaLong);
194             break;
195         case AUD_HOST:          /* Host ID */
196             vaLong = va_arg(vaList, afs_int32);
197             hostAddr.s_addr = vaLong;
198             fprintf(out, "HOST %s ", inet_ntoa(hostAddr));
199             break;
200         case AUD_LONG:          /* afs_int32    */
201             vaLong = va_arg(vaList, afs_int32);
202             fprintf(out, "LONG %d ", vaLong);
203             break;
204         case AUD_LST:           /* Ptr to another list */
205             vaLst = (char *)va_arg(vaList, int);
206             printbuf(out, 1, "VALST", 0, vaLst);
207             break;
208         case AUD_FID:           /* AFSFid - contains 3 entries */
209             vaFid = (struct AFSFid *)va_arg(vaList, int);
210             if (vaFid)
211                 fprintf(out, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
212                        vaFid->Unique);
213             else
214                 fprintf(out, "FID %u:%u:%u ", 0, 0, 0);
215             break;
216         case AUD_FIDS:          /* array of Fids */
217             vaFids = (struct AFSCBFids *)va_arg(vaList, int);
218             vaFid = NULL;
219
220             if (vaFids) {
221                 int i;
222                 if (vaFid)
223                     fprintf(out, "FIDS %u FID %u:%u:%u ", vaFids->AFSCBFids_len, vaFid->Volume,
224                              vaFid->Vnode, vaFid->Unique);
225                 else
226                     fprintf(out, "FIDS 0 FID 0:0:0 ");
227
228                 for ( i = 1; i < vaFids->AFSCBFids_len; i++ ) {
229                     vaFid = vaFids->AFSCBFids_val;
230                     if (vaFid)
231                         fprintf(out, "FID %u:%u:%u ", vaFid->Volume,
232                                  vaFid->Vnode, vaFid->Unique);
233                     else
234                         fprintf(out, "FID 0:0:0 ");
235                 }
236             }
237             break;
238         default:
239             fprintf(out, "--badval-- ");
240             break;
241         }                       /* end switch */
242         vaEntry = va_arg(vaList, int);
243     }                           /* end while */
244
245     if (strcmp(audEvent, "VALST") != 0)
246         fprintf(out, "\n");
247 }
248
249 /* ************************************************************************** */
250 /* The routine that acually does the audit call.
251  * ************************************************************************** */
252 int
253 osi_audit(char *audEvent,       /* Event name (15 chars or less) */
254           afs_int32 errCode,    /* The error code */
255           ...)
256 {
257 #ifdef AFS_AIX32_ENV
258     afs_int32 code;
259     afs_int32 err;
260 #endif
261     int result;
262
263     va_list vaList;
264 #ifdef AFS_AIX32_ENV
265     static struct Lock audbuflock = { 0, 0, 0, 0,
266 #ifdef AFS_PTHREAD_ENV
267         PTHREAD_MUTEX_INITIALIZER,
268         PTHREAD_COND_INITIALIZER,
269         PTHREAD_COND_INITIALIZER
270 #endif /* AFS_PTHREAD_ENV */
271     };
272     static char BUFFER[32768];
273 #endif
274
275     if ((osi_audit_all < 0) || (osi_echo_trail < 0))
276         osi_audit_check();
277     if (!osi_audit_all && !auditout)
278         return 0;
279
280     switch (errCode) {
281     case 0:
282         result = AUDIT_OK;
283         break;
284     case KANOAUTH:              /* kautils.h   */
285     case RXKADNOAUTH:           /* rxkad.h     */
286         result = AUDIT_FAIL_AUTH;
287         break;
288     case EPERM:         /* errno.h     */
289     case EACCES:                /* errno.h     */
290     case PRPERM:                /* pterror.h   */
291         result = AUDIT_FAIL_ACCESS;
292         break;
293     case VL_PERM:               /* vlserver.h  */
294     case BUDB_NOTPERMITTED:     /* budb_errs.h */
295     case BZACCESS:              /* bnode.h     */
296     case VOLSERBAD_ACCESS:      /* volser.h    */
297         result = AUDIT_FAIL_PRIV;
298         break;
299     default:
300         result = AUDIT_FAIL;
301         break;
302     }
303
304 #ifdef AFS_AIX32_ENV
305     ObtainWriteLock(&audbuflock);
306     bufferPtr = BUFFER;
307
308     /* Put the error code into the buffer list */
309     *(int *)bufferPtr = errCode;
310     bufferPtr += sizeof(errCode);
311
312     va_start(vaList, errCode);
313     audmakebuf(audEvent, vaList);
314 #endif
315
316     if (osi_echo_trail) {
317         va_start(vaList, errCode);
318         printbuf(stdout, 0, audEvent, errCode, vaList);
319     }
320
321 #ifdef AFS_AIX32_ENV
322     bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
323     code = auditlog(audEvent, result, BUFFER, bufferLen);
324 #ifdef notdef
325     if (code) {
326         err = errno;
327         code = auditlog("AFS_Aud_Fail", result, &err, sizeof(err));
328         if (code)
329             printf("Error while writing audit entry: %d.\n", errno);
330     }
331 #endif /* notdef */
332     ReleaseWriteLock(&audbuflock);
333 #else
334     if (auditout) {
335         va_start(vaList, errCode);
336         printbuf(auditout, 0, audEvent, errCode, vaList);
337         fflush(auditout);
338     }
339 #endif
340
341     return 0;
342 }
343
344 /* ************************************************************************** */
345 /* Given a RPC call structure, this routine extracts the name and host id from the 
346  * call and includes it within the audit information.
347  * ************************************************************************** */
348 int
349 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
350 {
351     struct rx_connection *conn;
352     struct rx_peer *peer;
353     afs_int32 secClass;
354     afs_int32 code;
355     char afsName[MAXKTCNAMELEN];
356     afs_int32 hostId;
357     va_list vaList;
358
359     if (osi_audit_all < 0)
360         osi_audit_check();
361     if (!osi_audit_all && !auditout)
362         return 0;
363
364     strcpy(afsName, "--Unknown--");
365     hostId = 0;
366
367     if (call) {
368         conn = rx_ConnectionOf(call);   /* call -> conn) */
369         if (conn) {
370             secClass = rx_SecurityClassOf(conn);        /* conn -> securityIndex */
371             if (secClass == 0) {        /* unauthenticated */
372                 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
373                 strcpy(afsName, "--UnAuth--");
374             } else if (secClass == 2) { /* authenticated */
375                 char tcell[MAXKTCREALMLEN];
376                 char name[MAXKTCNAMELEN];
377                 char inst[MAXKTCNAMELEN];
378                 char vname[256];
379                 int  ilen, clen;
380
381                 code =
382                     rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
383                                         NULL);
384                 if (code) {
385                     osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
386                     strcpy(afsName, "--NoName--");
387                 } else {
388                     strncpy(vname, name, sizeof(vname));
389                     if ((ilen = strlen(inst))) {
390                         if (strlen(vname) + 1 + ilen >= sizeof(vname))
391                             goto done;
392                         strcat(vname, ".");
393                         strcat(vname, inst);
394                     }
395                     if ((clen = strlen(tcell))) {
396 #if defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
397                         static char local_realm[AFS_REALM_SZ] = "";
398                         if (!local_realm[0]) {
399                             if (afs_krb_get_lrealm(local_realm, 0) != 0 /*KSUCCESS*/)
400                                 strncpy(local_realm, "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
401                         }
402                         if (strcasecmp(local_realm, tcell)) {
403                             if (strlen(vname) + 1 + clen >= sizeof(vname))
404                                 goto done;
405                             strcat(vname, "@");
406                             strcat(vname, tcell);
407                         }
408 #endif
409                     }
410                     strcpy(afsName, vname);
411                 }
412             } else {            /* Unauthenticated & unknown */
413                 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
414                 strcpy(afsName, "--Unknown--");
415             }
416         done:
417             peer = rx_PeerOf(conn);     /* conn -> peer */
418             if (peer)
419                 hostId = rx_HostOf(peer);       /* peer -> host */
420             else
421                 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
422         } else {                /* null conn */
423             osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
424         }
425     } else {                    /* null call */
426         osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
427     }
428     va_start(vaList, errCode);
429     osi_audit(audEvent, errCode, AUD_NAME, afsName, AUD_HOST, hostId, 
430               AUD_LST, vaList, AUD_END);
431
432     return 0;
433 }
434
435 /* ************************************************************************** */
436 /* Determines whether auditing is on or off by looking at the Audit file.
437  * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be 
438  * enabled.
439  * ************************************************************************** */
440
441 int
442 osi_audit_check()
443 {
444     FILE *fds;
445     int onoff;
446     char event[257];
447
448     osi_audit_all = 1;          /* say we made check (>= 0) */
449     /* and assume audit all events (for now) */
450     onoff = 0;                  /* assume we will turn auditing off */
451     osi_echo_trail = 0;         /* assume no echoing   */
452
453     fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
454     if (fds) {
455         while (fscanf(fds, "%256s", event) > 0) {
456             if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
457                 onoff = 1;
458
459             if (strcmp(event, "Echo_Trail") == 0)
460                 osi_echo_trail = 1;
461         }
462         fclose(fds);
463     }
464
465     /* Audit this event all of the time */
466     if (onoff)
467         osi_audit("AFS_Aud_On", 0, AUD_END);
468     else
469         osi_audit("AFS_Aud_Off", 0, AUD_END);
470
471     /* Now set whether we audit all events from here on out */
472     osi_audit_all = onoff;
473
474     return 0;
475 }
476
477 int
478 osi_audit_file(FILE *out)
479 {
480     auditout = out;
481     return 0;
482 }