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