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>
19 #include <sys/types.h>
23 #include <sys/audit.h>
27 #define AUDIT_FAIL_AUTH 2
28 #define AUDIT_FAIL_ACCESS 3
29 #define AUDIT_FAIL_PRIV 4
30 #endif /* AFS_AIX32_ENV */
33 #include "afs/afsint.h"
39 #include <sys/audit.h>
41 #include <afs/afsutil.h>
43 /* C99 requires va_copy. Older versions of GCC provide __va_copy. Per t
44 Autoconf manual, memcpy is a generally portable fallback. */
47 # define va_copy(d, s) __va_copy((d), (s))
49 # define va_copy(d, s) memcpy(&(d), &(s), sizeof(va_list))
55 int osi_audit_all = (-1); /* Not determined yet */
56 int osi_echo_trail = (-1);
58 FILE *auditout = NULL;
60 int osi_audit_check();
63 audmakebuf(char *audEvent, va_list vaList)
75 vaEntry = va_arg(vaList, int);
76 while (vaEntry != AUD_END) {
78 case AUD_STR: /* String */
79 case AUD_NAME: /* Name */
80 case AUD_ACL: /* ACL */
81 vaStr = (char *)va_arg(vaList, char *);
83 strcpy(bufferPtr, vaStr);
84 bufferPtr += strlen(vaStr) + 1;
86 strcpy(bufferPtr, "");
90 case AUD_INT: /* Integer */
91 case AUD_ID: /* ViceId */
92 vaInt = va_arg(vaList, int);
93 *(int *)bufferPtr = vaInt;
94 bufferPtr += sizeof(vaInt);
96 case AUD_DATE: /* Date */
97 case AUD_HOST: /* Host ID */
98 case AUD_LONG: /* long */
99 vaLong = va_arg(vaList, afs_int32);
100 *(afs_int32 *) bufferPtr = vaLong;
101 bufferPtr += sizeof(vaLong);
103 case AUD_FID: /* AFSFid - contains 3 entries */
104 vaFid = (struct AFSFid *)va_arg(vaList, struct AFSFid *);
106 memcpy(bufferPtr, vaFid, sizeof(struct AFSFid));
108 memset(bufferPtr, 0, sizeof(struct AFSFid));
110 bufferPtr += sizeof(struct AFSFid);
113 /* Whole array of fids-- don't know how to handle variable length audit
114 * data with AIX audit package, so for now we just store the first fid.
115 * Better one than none. */
118 struct AFSCBFids *Fids;
120 Fids = (struct AFSCBFids *)va_arg(vaList, struct AFSCBFids *);
121 if (Fids && Fids->AFSCBFids_len) {
122 *((u_int *) bufferPtr) = Fids->AFSCBFids_len;
123 bufferPtr += sizeof(u_int);
124 memcpy(bufferPtr, Fids->AFSCBFids_val,
125 sizeof(struct AFSFid));
127 *((u_int *) bufferPtr) = 0;
128 bufferPtr += sizeof(u_int);
129 memset(bufferPtr, 0, sizeof(struct AFSFid));
131 bufferPtr += sizeof(struct AFSFid);
137 auditlog("AFS_Aud_EINVAL", (-1), audEvent,
138 (strlen(audEvent) + 1));
144 vaEntry = va_arg(vaList, int);
149 printbuf(FILE *out, int rec, char *audEvent, char *afsName, afs_int32 hostId,
150 afs_int32 errCode, va_list vaList)
157 struct AFSFid *vaFid;
158 struct AFSCBFids *vaFids;
159 int num = LogThreadNum();
160 struct in_addr hostAddr;
165 /* Don't print the timestamp or thread id if we recursed */
167 currenttime = time(0);
168 timeStamp = afs_ctime(¤ttime, tbuffer,
170 timeStamp[24] = ' '; /* ts[24] is the newline, 25 is the null */
171 fprintf(out, timeStamp);
174 fprintf(out, "[%d] ", num);
177 fprintf(out, "EVENT %s CODE %d ", audEvent, errCode);
180 hostAddr.s_addr = hostId;
181 fprintf(out, "NAME %s HOST %s ", afsName, inet_ntoa(hostAddr));
184 vaEntry = va_arg(vaList, int);
185 while (vaEntry != AUD_END) {
187 case AUD_STR: /* String */
188 vaStr = (char *)va_arg(vaList, char *);
190 fprintf(out, "STR %s ", vaStr);
192 fprintf(out, "STR <null>");
194 case AUD_NAME: /* Name */
195 vaStr = (char *)va_arg(vaList, char *);
197 fprintf(out, "NAME %s ", vaStr);
199 fprintf(out, "NAME <null>");
201 case AUD_ACL: /* ACL */
202 vaStr = (char *)va_arg(vaList, char *);
204 fprintf(out, "ACL %s ", vaStr);
206 fprintf(out, "ACL <null>");
208 case AUD_INT: /* Integer */
209 vaInt = va_arg(vaList, int);
210 fprintf(out, "INT %d ", vaInt);
212 case AUD_ID: /* ViceId */
213 vaInt = va_arg(vaList, int);
214 fprintf(out, "ID %d ", vaInt);
216 case AUD_DATE: /* Date */
217 vaLong = va_arg(vaList, afs_int32);
218 fprintf(out, "DATE %u ", vaLong);
220 case AUD_HOST: /* Host ID */
221 vaLong = va_arg(vaList, afs_int32);
222 hostAddr.s_addr = vaLong;
223 fprintf(out, "HOST %s ", inet_ntoa(hostAddr));
225 case AUD_LONG: /* afs_int32 */
226 vaLong = va_arg(vaList, afs_int32);
227 fprintf(out, "LONG %d ", vaLong);
229 case AUD_FID: /* AFSFid - contains 3 entries */
230 vaFid = va_arg(vaList, struct AFSFid *);
232 fprintf(out, "FID %u:%u:%u ", vaFid->Volume, vaFid->Vnode,
235 fprintf(out, "FID %u:%u:%u ", 0, 0, 0);
237 case AUD_FIDS: /* array of Fids */
238 vaFids = va_arg(vaList, struct AFSCBFids *);
243 vaFid = vaFids->AFSCBFids_val;
246 fprintf(out, "FIDS %u FID %u:%u:%u ", vaFids->AFSCBFids_len, vaFid->Volume,
247 vaFid->Vnode, vaFid->Unique);
248 for ( i = 1; i < vaFids->AFSCBFids_len; i++, vaFid++ )
249 fprintf(out, "FID %u:%u:%u ", vaFid->Volume,
250 vaFid->Vnode, vaFid->Unique);
252 fprintf(out, "FIDS 0 FID 0:0:0 ");
257 fprintf(out, "--badval-- ");
260 vaEntry = va_arg(vaList, int);
266 #ifdef AFS_PTHREAD_ENV
267 static pthread_mutex_t audit_lock;
268 static volatile afs_int32 audit_lock_initialized = 0;
269 static pthread_once_t audit_lock_once = PTHREAD_ONCE_INIT;
272 osi_audit_init_lock(void)
274 pthread_mutex_init(&audit_lock, NULL);
275 audit_lock_initialized = 1;
282 #ifdef AFS_PTHREAD_ENV
283 if (!audit_lock_initialized) {
284 pthread_once(&audit_lock_once, osi_audit_init_lock);
286 #endif /* AFS_PTHREAD_ENV */
289 /* ************************************************************************** */
290 /* The routine that acually does the audit call.
291 * ************************************************************************** */
293 osi_audit_internal(char *audEvent, /* Event name (15 chars or less) */
294 afs_int32 errCode, /* The error code */
302 static char BUFFER[32768];
307 #ifdef AFS_PTHREAD_ENV
308 /* i'm pretty sure all the server apps now call osi_audit_init(),
309 * but to be extra careful we'll leave this assert in here for a
310 * while to make sure */
311 assert(audit_lock_initialized);
312 #endif /* AFS_PTHREAD_ENV */
314 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
316 if (!osi_audit_all && !auditout)
319 va_copy(vaCopy, vaList);
325 case KANOAUTH: /* kautils.h */
326 case RXKADNOAUTH: /* rxkad.h */
327 result = AUDIT_FAIL_AUTH;
329 case EPERM: /* errno.h */
330 case EACCES: /* errno.h */
331 case PRPERM: /* pterror.h */
332 result = AUDIT_FAIL_ACCESS;
334 case VL_PERM: /* vlserver.h */
335 case BUDB_NOTPERMITTED: /* budb_errs.h */
336 case BZACCESS: /* bnode.h */
337 case VOLSERBAD_ACCESS: /* volser.h */
338 result = AUDIT_FAIL_PRIV;
345 #ifdef AFS_PTHREAD_ENV
346 pthread_mutex_lock(&audit_lock);
351 /* Put the error code into the buffer list */
352 *(int *)bufferPtr = errCode;
353 bufferPtr += sizeof(errCode);
355 audmakebuf(audEvent, vaList);
358 if (osi_echo_trail) {
359 printbuf(stdout, 0, audEvent, afsName, hostId, errCode, vaList);
364 bufferLen = (int)((afs_int32) bufferPtr - (afs_int32) & BUFFER[0]);
365 code = auditlog(audEvent, result, BUFFER, bufferLen);
368 printbuf(auditout, 0, audEvent, afsName, hostId, errCode, vaList);
372 #ifdef AFS_PTHREAD_ENV
373 pthread_mutex_unlock(&audit_lock);
379 osi_audit(char *audEvent, /* Event name (15 chars or less) */
380 afs_int32 errCode, /* The error code */
385 if ((osi_audit_all < 0) || (osi_echo_trail < 0))
387 if (!osi_audit_all && !auditout)
390 va_start(vaList, errCode);
391 osi_audit_internal(audEvent, errCode, NULL, 0, vaList);
397 /* ************************************************************************** */
398 /* Given a RPC call structure, this routine extracts the name and host id from the
399 * call and includes it within the audit information.
400 * ************************************************************************** */
402 osi_auditU(struct rx_call *call, char *audEvent, int errCode, ...)
404 struct rx_connection *conn;
405 struct rx_peer *peer;
408 char afsName[MAXKTCNAMELEN];
412 if (osi_audit_all < 0)
414 if (!osi_audit_all && !auditout)
417 strcpy(afsName, "--Unknown--");
421 conn = rx_ConnectionOf(call); /* call -> conn) */
423 secClass = rx_SecurityClassOf(conn); /* conn -> securityIndex */
424 if (secClass == 0) { /* unauthenticated */
425 osi_audit("AFS_Aud_Unauth", (-1), AUD_STR, audEvent, AUD_END);
426 strcpy(afsName, "--UnAuth--");
427 } else if (secClass == 2) { /* authenticated */
428 char tcell[MAXKTCREALMLEN];
429 char name[MAXKTCNAMELEN];
430 char inst[MAXKTCNAMELEN];
435 rxkad_GetServerInfo(conn, NULL, NULL, name, inst, tcell,
438 osi_audit("AFS_Aud_NoAFSId", (-1), AUD_STR, audEvent, AUD_END);
439 strcpy(afsName, "--NoName--");
441 strncpy(vname, name, sizeof(vname));
442 if ((ilen = strlen(inst))) {
443 if (strlen(vname) + 1 + ilen >= sizeof(vname))
448 if ((clen = strlen(tcell))) {
449 #if defined(AFS_ATHENA_STDENV) || defined(AFS_KERBREALM_ENV)
450 static char local_realms[AFS_NUM_LREALMS][AFS_REALM_SZ];
451 static int num_lrealms = -1;
454 if (num_lrealms == -1) {
455 for (i=0; i<AFS_NUM_LREALMS; i++) {
456 if (afs_krb_get_lrealm(local_realms[i], i) != 0 /*KSUCCESS*/)
461 strncpy(local_realms[0], "UNKNOWN.LOCAL.REALM", AFS_REALM_SZ);
465 /* Check to see if the ticket cell matches one of the local realms */
467 for ( i=0;i<num_lrealms;i++ ) {
468 if (!strcasecmp(local_realms[i], tcell)) {
473 /* If yes, then make sure that the name is not present in
474 * an exclusion list */
478 snprintf(uname,sizeof(uname),"%s.%s@%s",name,inst,tcell);
480 snprintf(uname,sizeof(uname),"%s@%s",name,tcell);
482 if (afs_krb_exclusion(uname))
487 if (strlen(vname) + 1 + clen >= sizeof(vname))
490 strcat(vname, tcell);
494 strcpy(afsName, vname);
496 } else { /* Unauthenticated & unknown */
497 osi_audit("AFS_Aud_UnknSec", (-1), AUD_STR, audEvent, AUD_END);
498 strcpy(afsName, "--Unknown--");
501 peer = rx_PeerOf(conn); /* conn -> peer */
503 hostId = rx_HostOf(peer); /* peer -> host */
505 osi_audit("AFS_Aud_NoHost", (-1), AUD_STR, audEvent, AUD_END);
506 } else { /* null conn */
507 osi_audit("AFS_Aud_NoConn", (-1), AUD_STR, audEvent, AUD_END);
509 } else { /* null call */
510 osi_audit("AFS_Aud_NoCall", (-1), AUD_STR, audEvent, AUD_END);
512 va_start(vaList, errCode);
513 osi_audit_internal(audEvent, errCode, afsName, hostId, vaList);
518 /* ************************************************************************** */
519 /* Determines whether auditing is on or off by looking at the Audit file.
520 * If the string AFS_AUDIT_AllEvents is defined in the file, then auditing will be
522 * ************************************************************************** */
531 osi_audit_all = 1; /* say we made check (>= 0) */
532 /* and assume audit all events (for now) */
533 onoff = 0; /* assume we will turn auditing off */
534 osi_echo_trail = 0; /* assume no echoing */
536 fds = fopen(AFSDIR_SERVER_AUDIT_FILEPATH, "r");
538 while (fscanf(fds, "%256s", event) > 0) {
539 if (strcmp(event, "AFS_AUDIT_AllEvents") == 0)
542 if (strcmp(event, "Echo_Trail") == 0)
548 /* Audit this event all of the time */
550 osi_audit("AFS_Aud_On", 0, AUD_END);
552 osi_audit("AFS_Aud_Off", 0, AUD_END);
554 /* Now set whether we audit all events from here on out */
555 osi_audit_all = onoff;
561 osi_audit_file(char *fileName)
564 char oldName[MAXPATHLEN];
569 if ((lstat(fileName, &statbuf) == 0)
570 && (S_ISFIFO(statbuf.st_mode))) {
571 flags = O_WRONLY | O_NONBLOCK;
575 strcpy(oldName, fileName);
576 strcat(oldName, ".old");
577 renamefile(fileName, oldName);
578 flags = O_WRONLY | O_TRUNC | O_CREAT;
580 tempfd = open(fileName, flags, 0666);
582 auditout = fdopen(tempfd, "a");
584 printf("Warning: auditlog %s not writable, ignored.\n", fileName);
588 printf("Warning: auditlog %s not writable, ignored.\n", fileName);