2 * Copyright 2000, International Business Machines Corporation and others.
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
10 #include <afsconfig.h>
11 #include <afs/param.h>
20 #include <sys/audit.h>
24 #define AUDIT_FAIL_AUTH 2
25 #define AUDIT_FAIL_ACCESS 3
26 #define AUDIT_FAIL_PRIV 4
27 #endif /* AFS_AIX32_ENV */
30 #include "afs/afsint.h"
36 #include <sys/audit.h>
38 #include <afs/afsutil.h>
40 /* C99 requires va_copy. Older versions of GCC provide __va_copy. Per t
41 Autoconf manual, memcpy is a generally portable fallback. */
44 # define va_copy(d, s) __va_copy((d), (s))
46 # define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list))
52 int osi_audit_all = (-1); /* Not determined yet */
53 int osi_echo_trail = (-1);
55 FILE *auditout = NULL;
57 int osi_audit_check();
60 audmakebuf(char *audEvent, va_list vaList)
72 vaEntry = va_arg(vaList, int);
73 while (vaEntry != AUD_END) {
75 case AUD_STR: /* String */
76 case AUD_NAME: /* Name */
77 case AUD_ACL: /* ACL */
78 vaStr = (char *)va_arg(vaList, char *);
80 strcpy(bufferPtr, vaStr);
81 bufferPtr += strlen(vaStr) + 1;
83 strcpy(bufferPtr, "");
87 case AUD_INT: /* Integer */
88 case AUD_ID: /* ViceId */
89 vaInt = va_arg(vaList, int);
90 *(int *)bufferPtr = vaInt;
91 bufferPtr += sizeof(vaInt);
93 case AUD_DATE: /* Date */
94 case AUD_HOST: /* Host ID */
95 case AUD_LONG: /* long */
96 vaLong = va_arg(vaList, afs_int32);
97 *(afs_int32 *) bufferPtr = vaLong;
98 bufferPtr += sizeof(vaLong);
100 case AUD_LST: /* Ptr to another list */
101 va_copy(vaLst, va_arg(vaList, va_list));
102 audmakebuf(audEvent, vaLst);
105 case AUD_FID: /* AFSFid - contains 3 entries */
106 vaFid = (struct AFSFid *)va_arg(vaList, struct AFSFid *);
108 memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
110 memset(bufferPtr, 0, sizeof(struct AFSFid));
112 bufferPtr += sizeof(struct AFSFid);
115 /* Whole array of fids-- don't know how to handle variable length audit
116 * data with AIX audit package, so for now we just store the first fid.
117 * Better one than none. */
120 struct AFSCBFids *Fids;
122 Fids = (struct AFSCBFids *)va_arg(vaList, struct AFSCBFids *);
123 if (Fids && Fids->AFSCBFids_len) {
124 *((u_int *) bufferPtr) = Fids->AFSCBFids_len;
125 bufferPtr += sizeof(u_int);
126 memcpy(bufferPtr, Fids->AFSCBFids_val,
127 sizeof(struct AFSFid));
129 *((u_int *) bufferPtr) = 0;
130 bufferPtr += sizeof(u_int);
131 memset(bufferPtr, 0, sizeof(struct AFSFid));
133 bufferPtr += sizeof(struct AFSFid);
139 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
140 (strlen(audEvent) + 1));
146 vaEntry = va_arg(vaList, int);
151 printbuf(FILE *out, int rec, char *audEvent, afs_int32 errCode, va_list vaList)
158 struct AFSFid *vaFid;
159 struct AFSCBFids *vaFids;
160 int num = LogThreadNum();
161 struct in_addr hostAddr;
166 /* Don't print the timestamp or thread id if we recursed */
168 currenttime = time(0);
169 timeStamp = afs_ctime(¤ttime, tbuffer,
171 timeStamp[24] = ' '; /* ts[24] is the newline, 25 is the null */
172 fprintf(out, timeStamp);
175 fprintf(out, "[%d] ", num);
178 if (strcmp(audEvent, "VALST") != 0)
179 fprintf(out, "EVENT %s CODE %d ", audEvent, errCode);
181 vaEntry = va_arg(vaList, int);
182 while (vaEntry != AUD_END) {
184 case AUD_STR: /* String */
185 vaStr = (char *)va_arg(vaList, char *);
187 fprintf(out, "STR %s ", vaStr);
189 fprintf(out, "STR <null>");
191 case AUD_NAME: /* Name */
192 vaStr = (char *)va_arg(vaList, char *);
194 fprintf(out, "NAME %s ", vaStr);
196 fprintf(out, "NAME <null>");
198 case AUD_ACL: /* ACL */
199 vaStr = (char *)va_arg(vaList, char *);
201 fprintf(out, "ACL %s ", vaStr);
203 fprintf(out, "ACL <null>");
205 case AUD_INT: /* Integer */
206 vaInt = va_arg(vaList, int);
207 fprintf(out, "INT %d ", vaInt);
209 case AUD_ID: /* ViceId */
210 vaInt = va_arg(vaList, int);
211 fprintf(out, "ID %d ", vaInt);
213 case AUD_DATE: /* Date */
214 vaLong = va_arg(vaList, afs_int32);
215 fprintf(out, "DATE %u ", vaLong);
217 case AUD_HOST: /* Host ID */
218 vaLong = va_arg(vaList, afs_int32);
219 hostAddr.s_addr = vaLong;
220 fprintf(out, "HOST %s ", inet_ntoa(hostAddr));
222 case AUD_LONG: /* afs_int32 */
223 vaLong = va_arg(vaList, afs_int32);
224 fprintf(out, "LONG %d ", vaLong);
226 case AUD_LST: /* Ptr to another list */
227 va_copy(vaLst, va_arg(vaList, va_list));
228 printbuf(out, 1, "VALST", 0, vaLst);
231 case AUD_FID: /* AFSFid - contains 3 entries */
232 vaFid = va_arg(vaList, struct AFSFid *);
234 fprintf(out, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
237 fprintf(out, "FID %u:%u:%u ", 0, 0, 0);
239 case AUD_FIDS: /* array of Fids */
240 vaFids = va_arg(vaList, struct AFSCBFids *);
246 fprintf(out, "FIDS %u FID %u:%u:%u ", vaFids->AFSCBFids_len, vaFid->Volume,
247 vaFid->Vnode, vaFid->Unique);
249 fprintf(out, "FIDS 0 FID 0:0:0 ");
251 for ( i = 1; i < vaFids->AFSCBFids_len; i++ ) {
252 vaFid = vaFids->AFSCBFids_val;
254 fprintf(out, "FID %u:%u:%u ", vaFid->Volume,
255 vaFid->Vnode, vaFid->Unique);
257 fprintf(out, "FID 0:0:0 ");
262 fprintf(out, "--badval-- ");
265 vaEntry = va_arg(vaList, int);
268 if (strcmp(audEvent, "VALST") != 0)
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;
278 osi_audit_init_lock(void)
280 pthread_mutex_init(&audit_lock, NULL);
281 audit_lock_initialized = 1;
288 #ifdef AFS_PTHREAD_ENV
289 if (!audit_lock_initialized) {
290 pthread_once(&audit_lock_once, osi_audit_init_lock);
292 #endif /* AFS_PTHREAD_ENV */
295 /* ************************************************************************** */
296 /* The routine that acually does the audit call.
297 * ************************************************************************** */
299 osi_audit(char *audEvent, /* Event name (15 chars or less) */
300 afs_int32 errCode, /* The error code */
306 static char BUFFER[32768];
311 #ifdef AFS_PTHREAD_ENV
312 /* i'm pretty sure all the server apps now call osi_audit_init(),
313 * but to be extra careful we'll leave this assert in here for a
314 * while to make sure */
315 assert(audit_lock_initialized);
316 #endif /* AFS_PTHREAD_ENV */
318 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
320 if (!osi_audit_all && !auditout)
327 case KANOAUTH: /* kautils.h */
328 case RXKADNOAUTH: /* rxkad.h */
329 result = AUDIT_FAIL_AUTH;
331 case EPERM: /* errno.h */
332 case EACCES: /* errno.h */
333 case PRPERM: /* pterror.h */
334 result = AUDIT_FAIL_ACCESS;
336 case VL_PERM: /* vlserver.h */
337 case BUDB_NOTPERMITTED: /* budb_errs.h */
338 case BZACCESS: /* bnode.h */
339 case VOLSERBAD_ACCESS: /* volser.h */
340 result = AUDIT_FAIL_PRIV;
347 #ifdef AFS_PTHREAD_ENV
348 pthread_mutex_lock(&audit_lock);
353 /* Put the error code into the buffer list */
354 *(int *)bufferPtr = errCode;
355 bufferPtr += sizeof(errCode);
357 va_start(vaList, errCode);
358 audmakebuf(audEvent, vaList);
361 if (osi_echo_trail) {
362 va_start(vaList, errCode);
363 printbuf(stdout, 0, audEvent, errCode, vaList);
367 bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
368 code = auditlog(audEvent, result, BUFFER, bufferLen);
372 code = auditlog("AFS_Aud_Fail", result, &err, sizeof(err));
374 printf("Error while writing audit entry: %d.\n", errno);
379 va_start(vaList, errCode);
380 printbuf(auditout, 0, audEvent, errCode, vaList);
384 #ifdef AFS_PTHREAD_ENV
385 pthread_mutex_unlock(&audit_lock);
391 /* ************************************************************************** */
392 /* Given a RPC call structure, this routine extracts the name and host id from the
393 * call and includes it within the audit information.
394 * ************************************************************************** */
396 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
398 struct rx_connection *conn;
399 struct rx_peer *peer;
402 char afsName[MAXKTCNAMELEN];
406 if (osi_audit_all < 0)
408 if (!osi_audit_all && !auditout)
411 strcpy(afsName, "--Unknown--");
415 conn = rx_ConnectionOf(call); /* call -> conn) */
417 secClass = rx_SecurityClassOf(conn); /* conn -> securityIndex */
418 if (secClass == 0) { /* unauthenticated */
419 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
420 strcpy(afsName, "--UnAuth--");
421 } else if (secClass == 2) { /* authenticated */
422 char tcell[MAXKTCREALMLEN];
423 char name[MAXKTCNAMELEN];
424 char inst[MAXKTCNAMELEN];
429 rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
432 osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
433 strcpy(afsName, "--NoName--");
435 strncpy(vname, name, sizeof(vname));
436 if ((ilen = strlen(inst))) {
437 if (strlen(vname) + 1 + ilen >= sizeof(vname))
442 if ((clen = strlen(tcell))) {
443 #if defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
444 static char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
445 static int num_lrealms = -1;
448 if (num_lrealms == -1) {
449 for (i=0; i<AFS_NUM_LREALMS; i++) {
450 if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
455 strncpy(local_realms[0], "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
459 /* Check to see if the ticket cell matches one of the local realms */
461 for ( i=0;i<num_lrealms;i++ ) {
462 if (!strcasecmp(local_realms[i], tcell)) {
467 /* If yes, then make sure that the name is not present in
468 * an exclusion list */
472 snprintf(uname,sizeof(uname),"%s.%s@%s",name,inst,tcell);
474 snprintf(uname,sizeof(uname),"%s@%s",name,tcell);
476 if (afs_krb_exclusion(uname))
481 if (strlen(vname) + 1 + clen >= sizeof(vname))
484 strcat(vname, tcell);
488 strcpy(afsName, vname);
490 } else { /* Unauthenticated & unknown */
491 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
492 strcpy(afsName, "--Unknown--");
495 peer = rx_PeerOf(conn); /* conn -> peer */
497 hostId = rx_HostOf(peer); /* peer -> host */
499 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
500 } else { /* null conn */
501 osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
503 } else { /* null call */
504 osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
506 va_start(vaList, errCode);
507 osi_audit(audEvent, errCode, AUD_NAME, afsName, AUD_HOST, hostId,
508 AUD_LST, vaList, AUD_END);
513 /* ************************************************************************** */
514 /* Determines whether auditing is on or off by looking at the Audit file.
515 * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
517 * ************************************************************************** */
526 osi_audit_all = 1; /* say we made check (>= 0) */
527 /* and assume audit all events (for now) */
528 onoff = 0; /* assume we will turn auditing off */
529 osi_echo_trail = 0; /* assume no echoing */
531 fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
533 while (fscanf(fds, "%256s", event) > 0) {
534 if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
537 if (strcmp(event, "Echo_Trail") == 0)
543 /* Audit this event all of the time */
545 osi_audit("AFS_Aud_On", 0, AUD_END);
547 osi_audit("AFS_Aud_Off", 0, AUD_END);
549 /* Now set whether we audit all events from here on out */
550 osi_audit_all = onoff;
556 osi_audit_file(FILE *out)