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