diff --git a/contrib/openbsm/CREDITS b/contrib/openbsm/CREDITS index 18b3ad7dc03f..2721de1e487d 100644 --- a/contrib/openbsm/CREDITS +++ b/contrib/openbsm/CREDITS @@ -1,42 +1,45 @@ OpenBSM Credits The following organizations and individuals have contributed substantially to the development of OpenBSM: Apple Inc. McAfee Research, McAfee, Inc. SPARTA, Inc. Robert Watson Wayne Salamon Suresh Krishnaswamy Kevin Van Vechten Tom Rhodes Wojciech Koszek Chunyang Yuan Poul-Henning Kamp Christian Brueffer Olivier Houchard Christian Peron Martin Fong Pawel Worach Martin Englund Ruslan Ermilov Martin Voros Diego Giagio Alex Samorukov Eric Hall Xin LI Stacey Son Todd Heberlein Gary Hoo Dave Bertouille Jonathan Anderson Pawel Jakub Dawidek Joel Dahl Ryan Steinmetz The FreeBSD Foundation Brooks Davis + Mateusz Piotrowski + Alan Somers + Aniket Pandey In addition, Coverity, Inc.'s Prevent(tm) static analysis tool and Gimpel Software's FlexeLint tool were used to identify a number of bugs in the OpenBSM implementation. diff --git a/contrib/openbsm/bin/auditd/auditd.c b/contrib/openbsm/bin/auditd/auditd.c index a165cf314e08..bd00a6b16191 100644 --- a/contrib/openbsm/bin/auditd/auditd.c +++ b/contrib/openbsm/bin/auditd/auditd.c @@ -1,869 +1,869 @@ /*- * Copyright (c) 2004-2009 Apple Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #ifdef HAVE_FULL_QUEUE_H #include #else /* !HAVE_FULL_QUEUE_H */ #include #endif /* !HAVE_FULL_QUEUE_H */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "auditd.h" #ifndef HAVE_STRLCPY #include #endif /* * XXX The following are temporary until these can be added to the kernel * audit.h header. */ #ifndef AUDIT_TRIGGER_INITIALIZE #define AUDIT_TRIGGER_INITIALIZE 7 #endif #ifndef AUDIT_TRIGGER_EXPIRE_TRAILS #define AUDIT_TRIGGER_EXPIRE_TRAILS 8 #endif /* * LaunchD flag (Mac OS X and, maybe, FreeBSD only.) See launchd(8) and * http://wiki.freebsd.org/launchd for more information. * * In order for auditd to work "on demand" with launchd(8) it can't: * call daemon(3) * call fork and having the parent process exit * change uids or gids. * set up the current working directory or chroot. * set the session id * change stdio to /dev/null. * call setrusage(2) * call setpriority(2) * Ignore SIGTERM. * auditd (in 'launchd mode') is launched on demand so it must catch * SIGTERM to exit cleanly. */ static int launchd_flag = 0; /* * The GID of the audit review group (if used). The audit trail files and * system logs (Mac OS X only) can only be reviewed by members of this group * or the audit administrator (aka. "root"). */ static gid_t audit_review_gid = -1; /* * The path and file name of the last audit trail file. */ static char *lastfile = NULL; /* * Error starting auditd. Run warn script and exit. */ static void fail_exit(void) { audit_warn_nostart(); exit(1); } /* * Follow the 'current' symlink to get the active trail file name. */ static char * get_curfile(void) { char *cf; int len; cf = malloc(MAXPATHLEN); if (cf == NULL) { auditd_log_err("malloc failed: %m"); return (NULL); } len = readlink(AUDIT_CURRENT_LINK, cf, MAXPATHLEN - 1); if (len < 0) { free(cf); return (NULL); } /* readlink() doesn't terminate string. */ cf[len] = '\0'; return (cf); } /* * Close the previous audit trail file. */ static int close_lastfile(char *TS) { char *ptr; char *oldname; /* If lastfile is NULL try to get it from the 'current' link. */ if (lastfile == NULL) lastfile = get_curfile(); if (lastfile != NULL) { oldname = strdup(lastfile); if (oldname == NULL) return (-1); /* Rename the last file -- append timestamp. */ if ((ptr = strstr(lastfile, NOT_TERMINATED)) != NULL) { memcpy(ptr, TS, POSTFIX_LEN); if (auditd_rename(oldname, lastfile) != 0) auditd_log_err( "Could not rename %s to %s: %m", oldname, lastfile); else { /* * Remove the 'current' symlink since the link * is now invalid. */ (void) unlink(AUDIT_CURRENT_LINK); auditd_log_notice("renamed %s to %s", oldname, lastfile); audit_warn_closefile(lastfile); } } else auditd_log_err("Could not rename %s to %s", oldname, lastfile); free(lastfile); free(oldname); lastfile = NULL; } return (0); } /* * Create the new file name, swap with existing audit file. */ static int swap_audit_file(void) { int err; char *newfile, *name; char TS[TIMESTAMP_LEN + 1]; time_t tt; if (getTSstr(tt, TS, sizeof(TS)) != 0) return (-1); /* * If prefix and suffix are the same, it means that records are * being produced too fast. We don't want to rename now, because * next trail file can get the same name and once that one is * terminated also within one second it will overwrite the current * one. Just keep writing to the same trail and wait for the next * trigger from the kernel. * FREEBSD KERNEL WAS UPDATED TO KEEP SENDING TRIGGERS, WHICH MIGHT * NOT BE THE CASE FOR OTHER OSES. * If the kernel will not keep sending triggers, trail file will not * be terminated. */ if (lastfile == NULL) { name = NULL; } else { name = strrchr(lastfile, '/'); if (name != NULL) name++; } if (name != NULL && strncmp(name, TS, TIMESTAMP_LEN) == 0) { auditd_log_debug("Not ready to terminate trail file yet."); return (0); } err = auditd_swap_trail(TS, &newfile, audit_review_gid, audit_warn_getacdir); if (err != ADE_NOERR) { auditd_log_err("%s: %m", auditd_strerror(err)); if (err != ADE_ACTL) return (-1); } /* * Only close the last file if were in an auditing state before * calling swap_audit_file(). We may need to recover from a crash. */ if (auditd_get_state() == AUD_STATE_ENABLED) close_lastfile(TS); /* * auditd_swap_trail() potentially enables auditing (if not already * enabled) so updated the cached state as well. */ auditd_set_state(AUD_STATE_ENABLED); /* * Create 'current' symlink. Recover from crash, if needed. */ if (auditd_new_curlink(newfile) != 0) auditd_log_err("auditd_new_curlink(\"%s\") failed: %s: %m", newfile, auditd_strerror(err)); lastfile = newfile; auditd_log_notice("New audit file is %s", newfile); return (0); } /* * Create a new audit log trail file and swap with the current one, if any. */ static int do_trail_file(void) { int err; /* * First, refresh the list of audit log directories. */ err = auditd_read_dirs(audit_warn_soft, audit_warn_hard); if (err) { auditd_log_err("auditd_read_dirs(): %s", auditd_strerror(err)); if (err == ADE_HARDLIM) audit_warn_allhard(); if (err != ADE_SOFTLIM) return (-1); else audit_warn_allsoft(); /* continue on with soft limit error */ } /* * Create a new file and swap with the one being used in kernel. */ if (swap_audit_file() == -1) { /* * XXX Faulty directory listing? - user should be given * XXX an opportunity to change the audit_control file * XXX switch to a reduced mode of auditing? */ return (-1); } /* * Finally, see if there are any trail files to expire. */ err = auditd_expire_trails(audit_warn_expired); if (err) auditd_log_err("auditd_expire_trails(): %s", auditd_strerror(err)); return (0); } /* * Start up auditing. */ static void audit_setup(void) { int err; /* Configure trail files distribution. */ err = auditd_set_dist(); if (err) { auditd_log_err("auditd_set_dist() %s: %m", auditd_strerror(err)); } else auditd_log_debug("Configured trail files distribution."); if (do_trail_file() == -1) { auditd_log_err("Error creating audit trail file"); fail_exit(); } /* Generate an audit record. */ err = auditd_gen_record(AUE_audit_startup, NULL); if (err) auditd_log_err("auditd_gen_record(AUE_audit_startup) %s: %m", auditd_strerror(err)); if (auditd_config_controls() == 0) auditd_log_info("Audit controls init successful"); else auditd_log_err("Audit controls init failed"); } /* * Close auditd pid file and trigger mechanism. */ static int close_misc(void) { auditd_close_dirs(); if (unlink(AUDITD_PIDFILE) == -1 && errno != ENOENT) { auditd_log_err("Couldn't remove %s: %m", AUDITD_PIDFILE); return (1); } endac(); if (auditd_close_trigger() != 0) { auditd_log_err("Error closing trigger messaging mechanism"); return (1); } return (0); } /* * Close all log files, control files, and tell the audit system. */ static int close_all(void) { int err_ret = 0; char TS[TIMESTAMP_LEN + 1]; int err; int cond; time_t tt; err = auditd_gen_record(AUE_audit_shutdown, NULL); if (err) auditd_log_err("auditd_gen_record(AUE_audit_shutdown) %s: %m", auditd_strerror(err)); /* Flush contents. */ cond = AUC_DISABLED; err_ret = audit_set_cond(&cond); if (err_ret != 0) { auditd_log_err("Disabling audit failed! : %s", strerror(errno)); err_ret = 1; } /* * Updated the cached state that auditing has been disabled. */ auditd_set_state(AUD_STATE_DISABLED); if (getTSstr(tt, TS, sizeof(TS)) == 0) close_lastfile(TS); if (lastfile != NULL) free(lastfile); err_ret += close_misc(); if (err_ret) { auditd_log_err("Could not unregister"); audit_warn_postsigterm(); } auditd_log_info("Finished"); return (err_ret); } /* * Register the daemon with the signal handler and the auditd pid file. */ static int register_daemon(void) { struct sigaction action; FILE * pidfile; int fd; pid_t pid; /* Set up the signal hander. */ action.sa_handler = auditd_relay_signal; /* * sa_flags must not include SA_RESTART, so that read(2) will be * interruptible in auditd_wait_for_events */ action.sa_flags = 0; sigemptyset(&action.sa_mask); if (sigaction(SIGTERM, &action, NULL) != 0) { auditd_log_err( "Could not set signal handler for SIGTERM"); fail_exit(); } if (sigaction(SIGCHLD, &action, NULL) != 0) { auditd_log_err( "Could not set signal handler for SIGCHLD"); fail_exit(); } if (sigaction(SIGHUP, &action, NULL) != 0) { auditd_log_err( "Could not set signal handler for SIGHUP"); fail_exit(); } if (sigaction(SIGALRM, &action, NULL) != 0) { auditd_log_err( "Could not set signal handler for SIGALRM"); fail_exit(); } if ((pidfile = fopen(AUDITD_PIDFILE, "a")) == NULL) { auditd_log_err("Could not open PID file"); audit_warn_tmpfile(); return (-1); } /* Attempt to lock the pid file; if a lock is present, exit. */ fd = fileno(pidfile); if (flock(fd, LOCK_EX | LOCK_NB) < 0) { auditd_log_err( "PID file is locked (is another auditd running?)."); audit_warn_ebusy(); return (-1); } pid = getpid(); ftruncate(fd, 0); if (fprintf(pidfile, "%u\n", pid) < 0) { /* Should not start the daemon. */ fail_exit(); } fflush(pidfile); return (0); } /* * Handle the audit trigger event. * * We suppress (ignore) duplicated triggers in close succession in order to * try to avoid thrashing-like behavior. However, not all triggers can be * ignored, as triggers generally represent edge triggers, not level * triggers, and won't be retransmitted if the condition persists. Of * specific concern is the rotate trigger -- if one is dropped, then it will * not be retransmitted, and the log file will grow in an unbounded fashion. */ #define DUPLICATE_INTERVAL 30 void auditd_handle_trigger(int trigger) { static int last_trigger, last_warning; static time_t last_time; struct timeval ts; struct timezone tzp; time_t tt; int au_state; int err = 0; /* * Suppress duplicate messages from the kernel within the specified * interval. */ if (gettimeofday(&ts, &tzp) == 0) { tt = (time_t)ts.tv_sec; switch (trigger) { case AUDIT_TRIGGER_LOW_SPACE: case AUDIT_TRIGGER_NO_SPACE: /* * Triggers we can suppress. Of course, we also need * to rate limit the warnings, so apply the same * interval limit on syslog messages. */ if ((trigger == last_trigger) && (tt < (last_time + DUPLICATE_INTERVAL))) { if (tt >= (last_warning + DUPLICATE_INTERVAL)) auditd_log_info( "Suppressing duplicate trigger %d", trigger); return; } last_warning = tt; break; case AUDIT_TRIGGER_ROTATE_KERNEL: case AUDIT_TRIGGER_ROTATE_USER: case AUDIT_TRIGGER_READ_FILE: case AUDIT_TRIGGER_CLOSE_AND_DIE: case AUDIT_TRIGGER_INITIALIZE: /* * Triggers that we cannot suppress. */ break; } /* * Only update last_trigger after aborting due to a duplicate * trigger, not before, or we will never allow that trigger * again. */ last_trigger = trigger; last_time = tt; } au_state = auditd_get_state(); /* * Message processing is done here. */ switch(trigger) { case AUDIT_TRIGGER_LOW_SPACE: auditd_log_notice("Got low space trigger"); if (do_trail_file() == -1) auditd_log_err("Error swapping audit file"); break; case AUDIT_TRIGGER_NO_SPACE: auditd_log_notice("Got no space trigger"); if (do_trail_file() == -1) auditd_log_err("Error swapping audit file"); break; case AUDIT_TRIGGER_ROTATE_KERNEL: case AUDIT_TRIGGER_ROTATE_USER: auditd_log_info("Got open new trigger from %s", trigger == AUDIT_TRIGGER_ROTATE_KERNEL ? "kernel" : "user"); if (au_state == AUD_STATE_ENABLED && do_trail_file() == -1) auditd_log_err("Error swapping audit file"); break; case AUDIT_TRIGGER_READ_FILE: auditd_log_info("Got read file trigger"); if (au_state == AUD_STATE_ENABLED) { if (auditd_config_controls() == -1) auditd_log_err("Error setting audit controls"); else if (do_trail_file() == -1) auditd_log_err("Error swapping audit file"); } break; case AUDIT_TRIGGER_CLOSE_AND_DIE: auditd_log_info("Got close and die trigger"); if (au_state == AUD_STATE_ENABLED) err = close_all(); /* * Running under launchd don't exit. Wait for launchd to * send SIGTERM. */ if (!launchd_flag) { auditd_log_info("auditd exiting."); exit (err); } break; case AUDIT_TRIGGER_INITIALIZE: auditd_log_info("Got audit initialize trigger"); if (au_state == AUD_STATE_DISABLED) audit_setup(); break; case AUDIT_TRIGGER_EXPIRE_TRAILS: auditd_log_info("Got audit expire trails trigger"); err = auditd_expire_trails(audit_warn_expired); if (err) auditd_log_err("auditd_expire_trails(): %s", auditd_strerror(err)); break; default: auditd_log_err("Got unknown trigger %d", trigger); break; } } /* * Reap our children. */ void auditd_reap_children(void) { pid_t child; int wstatus; while ((child = waitpid(-1, &wstatus, WNOHANG)) > 0) { if (!wstatus) continue; auditd_log_info("warn process [pid=%d] %s %d.", child, ((WIFEXITED(wstatus)) ? "exited with non-zero status" : "exited as a result of signal"), ((WIFEXITED(wstatus)) ? WEXITSTATUS(wstatus) : WTERMSIG(wstatus))); } } /* * Reap any children and terminate. If under launchd don't shutdown auditing * but just the other stuff. */ void auditd_terminate(void) { int ret; auditd_reap_children(); if (launchd_flag) ret = close_misc(); else ret = close_all(); exit(ret); } /* * Configure the audit controls in the kernel: the event to class mapping, * kernel preselection mask, etc. */ int auditd_config_controls(void) { int cnt, err; int ret = 0; /* * Configure event to class mappings in kernel. */ cnt = auditd_set_evcmap(); if (cnt < 0) { auditd_log_err("auditd_set_evcmap() failed: %m"); ret = -1; } else if (cnt == 0) { auditd_log_err("No events to class mappings registered."); ret = -1; } else auditd_log_debug("Registered %d event to class mappings.", cnt); /* * Configure non-attributable event mask in kernel. */ err = auditd_set_namask(); if (err) { auditd_log_err("auditd_set_namask() %s: %m", auditd_strerror(err)); ret = -1; } else auditd_log_debug("Registered non-attributable event mask."); /* * Configure audit policy in kernel. */ err = auditd_set_policy(); if (err) { auditd_log_err("auditd_set_policy() %s: %m", auditd_strerror(err)); ret = -1; } else auditd_log_debug("Set audit policy in kernel."); /* * Configure audit trail log size in kernel. */ err = auditd_set_fsize(); if (err) { auditd_log_err("audit_set_fsize() %s: %m", auditd_strerror(err)); ret = -1; } else auditd_log_debug("Set audit trail size in kernel."); /* * Configure audit trail queue size in kernel. */ err = auditd_set_qsize(); if (err) { - auditd_log_err("audit_set_qsize() %s: %m", + auditd_log_err("auditd_set_qsize() %s: %m", auditd_strerror(err)); ret = -1; } else auditd_log_debug("Set audit trail queue in kernel."); /* * Configure audit trail volume minimum free percentage of blocks in * kernel. */ err = auditd_set_minfree(); if (err) { auditd_log_err("auditd_set_minfree() %s: %m", auditd_strerror(err)); ret = -1; } else auditd_log_debug( "Set audit trail min free percent in kernel."); /* * Configure host address in the audit kernel information. */ err = auditd_set_host(); if (err) { if (err == ADE_PARSE) { auditd_log_notice( "audit_control(5) may be missing 'host:' field"); } else { auditd_log_err("auditd_set_host() %s: %m", auditd_strerror(err)); ret = -1; } } else auditd_log_debug( "Set audit host address information in kernel."); return (ret); } /* * Setup and initialize auditd. */ static void setup(void) { int err; if (auditd_open_trigger(launchd_flag) < 0) { auditd_log_err("Error opening trigger messaging mechanism"); fail_exit(); } /* * To prevent event feedback cycles and avoid auditd becoming * stalled if auditing is suspended, auditd and its children run * without their events being audited. We allow the uid, tid, and * mask fields to be implicitly set to zero, but do set the pid. We * run this after opening the trigger device to avoid configuring * audit state without audit present in the system. */ err = auditd_prevent_audit(); if (err) { auditd_log_err("auditd_prevent_audit() %s: %m", auditd_strerror(err)); fail_exit(); } /* * Make sure auditd auditing state is correct. */ auditd_set_state(AUD_STATE_INIT); /* * If under launchd, don't start auditing. Wait for a trigger to * do so. */ if (!launchd_flag) audit_setup(); } int main(int argc, char **argv) { int ch; int debug = 0; #ifdef AUDIT_REVIEW_GROUP struct group *grp; #endif while ((ch = getopt(argc, argv, "dl")) != -1) { switch(ch) { case 'd': /* Debug option. */ debug = 1; break; case 'l': /* Be launchd friendly. */ launchd_flag = 1; break; case '?': default: (void)fprintf(stderr, "usage: auditd [-d] [-l]\n"); exit(1); } } audit_review_gid = getgid(); #ifdef AUDIT_REVIEW_GROUP /* * XXXRW: Currently, this code falls back to the daemon gid, which is * likely the wheel group. Is there a better way to deal with this? */ grp = getgrnam(AUDIT_REVIEW_GROUP); if (grp != NULL) audit_review_gid = grp->gr_gid; #endif auditd_openlog(debug, audit_review_gid); if (launchd_flag) auditd_log_info("started by launchd..."); else auditd_log_info("starting..."); #ifdef AUDIT_REVIEW_GROUP if (grp == NULL) auditd_log_info( "Audit review group '%s' not available, using daemon gid (%d)", AUDIT_REVIEW_GROUP, audit_review_gid); #endif if (debug == 0 && launchd_flag == 0 && daemon(0, 0) == -1) { auditd_log_err("Failed to daemonize"); exit(1); } if (register_daemon() == -1) { auditd_log_err("Could not register as daemon"); exit(1); } setup(); /* * auditd_wait_for_events() shouldn't return unless something is wrong. */ auditd_wait_for_events(); auditd_log_err("abnormal exit."); close_all(); exit(-1); } diff --git a/contrib/openbsm/bin/auditdistd/auditdistd.c b/contrib/openbsm/bin/auditdistd/auditdistd.c index 696f0488b27a..8468353f4cbc 100644 --- a/contrib/openbsm/bin/auditdistd/auditdistd.c +++ b/contrib/openbsm/bin/auditdistd/auditdistd.c @@ -1,798 +1,798 @@ /*- * Copyright (c) 2012 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #if defined(HAVE_SYS_ENDIAN_H) && defined(HAVE_BSWAP) #include #else /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ #ifdef HAVE_MACHINE_ENDIAN_H #include #else /* !HAVE_MACHINE_ENDIAN_H */ #ifdef HAVE_ENDIAN_H #include #else /* !HAVE_ENDIAN_H */ #error "No supported endian.h" #endif /* !HAVE_ENDIAN_H */ #endif /* !HAVE_MACHINE_ENDIAN_H */ #include #endif /* !HAVE_SYS_ENDIAN_H || !HAVE_BSWAP */ #include #include #include #include #include #include #ifdef HAVE_LIBUTIL_H #include #endif #include #include #include #include #include #include #include #ifndef HAVE_PIDFILE_OPEN #include #endif #ifndef HAVE_STRLCPY #include #endif #ifndef HAVE_SIGTIMEDWAIT #include "sigtimedwait.h" #endif #include "auditdistd.h" #include "pjdlog.h" #include "proto.h" #include "subr.h" #include "synch.h" /* Path to configuration file. */ const char *cfgpath = ADIST_CONFIG; /* Auditdistd configuration. */ static struct adist_config *adcfg; /* Was SIGINT or SIGTERM signal received? */ bool sigexit_received = false; /* PID file handle. */ struct pidfh *pfh; /* How often check for hooks running for too long. */ #define SIGNALS_CHECK_INTERVAL 5 static void usage(void) { errx(EX_USAGE, "[-dFhl] [-c config] [-P pidfile]"); } void descriptors_cleanup(struct adist_host *adhost) { struct adist_host *adh; struct adist_listen *lst; TAILQ_FOREACH(adh, &adcfg->adc_hosts, adh_next) { if (adh == adhost) continue; if (adh->adh_remote != NULL) { proto_close(adh->adh_remote); adh->adh_remote = NULL; } } TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { if (lst->adl_conn != NULL) proto_close(lst->adl_conn); } (void)pidfile_close(pfh); pjdlog_fini(); } static void child_cleanup(struct adist_host *adhost) { if (adhost->adh_conn != NULL) { PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER); proto_close(adhost->adh_conn); adhost->adh_conn = NULL; } adhost->adh_worker_pid = 0; } static void child_exit_log(const char *type, unsigned int pid, int status) { if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { pjdlog_debug(1, "%s process exited gracefully (pid=%u).", type, pid); } else if (WIFSIGNALED(status)) { pjdlog_error("%s process killed (pid=%u, signal=%d).", type, pid, WTERMSIG(status)); } else { pjdlog_error("%s process exited ungracefully (pid=%u, exitcode=%d).", type, pid, WIFEXITED(status) ? WEXITSTATUS(status) : -1); } } static void child_exit(void) { struct adist_host *adhost; bool restart; int status; pid_t pid; restart = false; while ((pid = wait3(&status, WNOHANG, NULL)) > 0) { /* Find host related to the process that just exited. */ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (pid == adhost->adh_worker_pid) break; } if (adhost == NULL) { child_exit_log("Sandbox", pid, status); } else { if (adhost->adh_role == ADIST_ROLE_SENDER) restart = true; pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, role2str(adhost->adh_role)); child_exit_log("Worker", pid, status); child_cleanup(adhost); pjdlog_prefix_set("%s", ""); } } if (!restart) return; /* We have some sender processes to restart. */ sleep(1); TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role != ADIST_ROLE_SENDER) continue; if (adhost->adh_worker_pid != 0) continue; pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, role2str(adhost->adh_role)); pjdlog_info("Restarting sender process."); adist_sender(adcfg, adhost); pjdlog_prefix_set("%s", ""); } } /* TODO */ static void adist_reload(void) { pjdlog_info("Reloading configuration is not yet implemented."); } static void terminate_workers(void) { struct adist_host *adhost; pjdlog_info("Termination signal received, exiting."); TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_worker_pid == 0) continue; pjdlog_info("Terminating worker process (adhost=%s, role=%s, pid=%u).", adhost->adh_name, role2str(adhost->adh_role), adhost->adh_worker_pid); if (kill(adhost->adh_worker_pid, SIGTERM) == 0) continue; pjdlog_errno(LOG_WARNING, "Unable to send signal to worker process (adhost=%s, role=%s, pid=%u).", adhost->adh_name, role2str(adhost->adh_role), adhost->adh_worker_pid); } } static void listen_accept(struct adist_listen *lst) { unsigned char rnd[32], hash[32], resp[32]; struct adist_host *adhost; struct proto_conn *conn; char adname[ADIST_HOSTSIZE]; char laddr[256], raddr[256]; char welcome[8]; int status, version; pid_t pid; proto_local_address(lst->adl_conn, laddr, sizeof(laddr)); pjdlog_debug(1, "Accepting connection to %s.", laddr); if (proto_accept(lst->adl_conn, &conn) == -1) { pjdlog_errno(LOG_ERR, "Unable to accept connection to %s", laddr); return; } proto_local_address(conn, laddr, sizeof(laddr)); proto_remote_address(conn, raddr, sizeof(raddr)); pjdlog_info("Connection from %s to %s.", raddr, laddr); /* Error in setting timeout is not critical, but why should it fail? */ if (proto_timeout(conn, ADIST_TIMEOUT) < 0) pjdlog_errno(LOG_WARNING, "Unable to set connection timeout"); /* * Before receiving any data see if remote host is known. */ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role != ADIST_ROLE_RECEIVER) continue; if (!proto_address_match(conn, adhost->adh_remoteaddr)) continue; break; } if (adhost == NULL) { pjdlog_error("Client %s is not known.", raddr); goto close; } /* Ok, remote host is known. */ /* Exchange welcome message, which include version number. */ bzero(welcome, sizeof(welcome)); if (proto_recv(conn, welcome, sizeof(welcome)) == -1) { pjdlog_errno(LOG_WARNING, "Unable to receive welcome message from %s", adhost->adh_remoteaddr); goto close; } if (strncmp(welcome, "ADIST", 5) != 0 || !isdigit(welcome[5]) || !isdigit(welcome[6]) || welcome[7] != '\0') { pjdlog_warning("Invalid welcome message from %s.", adhost->adh_remoteaddr); goto close; } version = MIN(ADIST_VERSION, atoi(welcome + 5)); (void)snprintf(welcome, sizeof(welcome), "ADIST%02d", version); if (proto_send(conn, welcome, sizeof(welcome)) == -1) { pjdlog_errno(LOG_WARNING, "Unable to send welcome message to %s", adhost->adh_remoteaddr); goto close; } if (proto_recv(conn, adname, sizeof(adhost->adh_name)) < 0) { pjdlog_errno(LOG_ERR, "Unable to receive hostname from %s", raddr); goto close; } /* Find host now that we have hostname. */ TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role != ADIST_ROLE_RECEIVER) continue; if (!proto_address_match(conn, adhost->adh_remoteaddr)) continue; if (strcmp(adhost->adh_name, adname) != 0) continue; break; } if (adhost == NULL) { pjdlog_error("No configuration for host %s from address %s.", adname, raddr); goto close; } adhost->adh_version = version; pjdlog_debug(1, "Version %d negotiated with %s.", adhost->adh_version, adhost->adh_remoteaddr); /* Now that we know host name setup log prefix. */ pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, role2str(adhost->adh_role)); if (adist_random(rnd, sizeof(rnd)) == -1) { pjdlog_error("Unable to generate challenge."); goto close; } pjdlog_debug(1, "Challenge generated."); if (proto_send(conn, rnd, sizeof(rnd)) == -1) { pjdlog_errno(LOG_ERR, "Unable to send challenge to %s", adhost->adh_remoteaddr); goto close; } pjdlog_debug(1, "Challenge sent."); if (proto_recv(conn, resp, sizeof(resp)) == -1) { pjdlog_errno(LOG_ERR, "Unable to receive response from %s", adhost->adh_remoteaddr); goto close; } pjdlog_debug(1, "Response received."); if (HMAC(EVP_sha256(), adhost->adh_password, (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash, NULL) == NULL) { pjdlog_error("Unable to generate hash."); goto close; } pjdlog_debug(1, "Hash generated."); if (memcmp(resp, hash, sizeof(hash)) != 0) { pjdlog_error("Invalid response from %s (wrong password?).", adhost->adh_remoteaddr); goto close; } pjdlog_info("Sender authenticated."); if (proto_recv(conn, rnd, sizeof(rnd)) == -1) { pjdlog_errno(LOG_ERR, "Unable to receive challenge from %s", adhost->adh_remoteaddr); goto close; } pjdlog_debug(1, "Challenge received."); if (HMAC(EVP_sha256(), adhost->adh_password, (int)strlen(adhost->adh_password), rnd, (int)sizeof(rnd), hash, NULL) == NULL) { pjdlog_error("Unable to generate response."); goto close; } pjdlog_debug(1, "Response generated."); if (proto_send(conn, hash, sizeof(hash)) == -1) { pjdlog_errno(LOG_ERR, "Unable to send response to %s", adhost->adh_remoteaddr); goto close; } pjdlog_debug(1, "Response sent."); if (adhost->adh_worker_pid != 0) { pjdlog_debug(1, "Receiver process exists (pid=%u), stopping it.", (unsigned int)adhost->adh_worker_pid); /* Stop child process. */ if (kill(adhost->adh_worker_pid, SIGINT) == -1) { pjdlog_errno(LOG_ERR, "Unable to stop worker process (pid=%u)", (unsigned int)adhost->adh_worker_pid); /* * Other than logging the problem we * ignore it - nothing smart to do. */ } /* Wait for it to exit. */ else if ((pid = waitpid(adhost->adh_worker_pid, &status, 0)) != adhost->adh_worker_pid) { /* We can only log the problem. */ pjdlog_errno(LOG_ERR, "Waiting for worker process (pid=%u) failed", (unsigned int)adhost->adh_worker_pid); } else { child_exit_log("Worker", adhost->adh_worker_pid, status); } child_cleanup(adhost); } adhost->adh_remote = conn; adist_receiver(adcfg, adhost); pjdlog_prefix_set("%s", ""); return; close: proto_close(conn); pjdlog_prefix_set("%s", ""); } static void connection_migrate(struct adist_host *adhost) { struct proto_conn *conn; int16_t val = 0; pjdlog_prefix_set("[%s] (%s) ", adhost->adh_name, role2str(adhost->adh_role)); PJDLOG_ASSERT(adhost->adh_role == ADIST_ROLE_SENDER); if (proto_recv(adhost->adh_conn, &val, sizeof(val)) < 0) { pjdlog_errno(LOG_WARNING, "Unable to receive connection command"); return; } if (proto_set("tls:fingerprint", adhost->adh_fingerprint) == -1) { val = errno; pjdlog_errno(LOG_WARNING, "Unable to set fingerprint"); goto out; } if (proto_connect(adhost->adh_localaddr[0] != '\0' ? adhost->adh_localaddr : NULL, adhost->adh_remoteaddr, -1, &conn) < 0) { val = errno; pjdlog_errno(LOG_WARNING, "Unable to connect to %s", adhost->adh_remoteaddr); goto out; } val = 0; out: if (proto_send(adhost->adh_conn, &val, sizeof(val)) < 0) { pjdlog_errno(LOG_WARNING, "Unable to send reply to connection request"); } if (val == 0 && proto_connection_send(adhost->adh_conn, conn) < 0) pjdlog_errno(LOG_WARNING, "Unable to send connection"); pjdlog_prefix_set("%s", ""); } static void check_signals(void) { struct timespec sigtimeout; sigset_t mask; int signo; sigtimeout.tv_sec = 0; sigtimeout.tv_nsec = 0; PJDLOG_VERIFY(sigemptyset(&mask) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0); while ((signo = sigtimedwait(&mask, NULL, &sigtimeout)) != -1) { switch (signo) { case SIGINT: case SIGTERM: sigexit_received = true; terminate_workers(); exit(EX_OK); break; case SIGCHLD: child_exit(); break; case SIGHUP: adist_reload(); break; default: PJDLOG_ABORT("Unexpected signal (%d).", signo); } } } static void main_loop(void) { struct adist_host *adhost; struct adist_listen *lst; struct timeval seltimeout; int fd, maxfd, ret; fd_set rfds; seltimeout.tv_sec = SIGNALS_CHECK_INTERVAL; seltimeout.tv_usec = 0; pjdlog_info("Started successfully."); for (;;) { check_signals(); /* Setup descriptors for select(2). */ FD_ZERO(&rfds); maxfd = -1; TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { if (lst->adl_conn == NULL) continue; fd = proto_descriptor(lst->adl_conn); PJDLOG_ASSERT(fd >= 0); FD_SET(fd, &rfds); maxfd = fd > maxfd ? fd : maxfd; } TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role == ADIST_ROLE_SENDER) { - /* Only sender workers asks for connections. */ + /* Only sender workers ask for connections. */ PJDLOG_ASSERT(adhost->adh_conn != NULL); fd = proto_descriptor(adhost->adh_conn); PJDLOG_ASSERT(fd >= 0); FD_SET(fd, &rfds); maxfd = fd > maxfd ? fd : maxfd; } else { PJDLOG_ASSERT(adhost->adh_conn == NULL); } } PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE); ret = select(maxfd + 1, &rfds, NULL, NULL, &seltimeout); if (ret == 0) { /* * select(2) timed out, so there should be no * descriptors to check. */ continue; } else if (ret == -1) { if (errno == EINTR) continue; KEEP_ERRNO((void)pidfile_remove(pfh)); pjdlog_exit(EX_OSERR, "select() failed"); } PJDLOG_ASSERT(ret > 0); /* * Check for signals before we do anything to update our * info about terminated workers in the meantime. */ check_signals(); TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { if (lst->adl_conn == NULL) continue; if (FD_ISSET(proto_descriptor(lst->adl_conn), &rfds)) listen_accept(lst); } TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role == ADIST_ROLE_SENDER) { PJDLOG_ASSERT(adhost->adh_conn != NULL); if (FD_ISSET(proto_descriptor(adhost->adh_conn), &rfds)) { connection_migrate(adhost); } } else { PJDLOG_ASSERT(adhost->adh_conn == NULL); } } } } static void adist_config_dump(struct adist_config *cfg) { struct adist_host *adhost; struct adist_listen *lst; pjdlog_debug(2, "Configuration:"); pjdlog_debug(2, " Global:"); pjdlog_debug(2, " pidfile: %s", cfg->adc_pidfile); pjdlog_debug(2, " timeout: %d", cfg->adc_timeout); if (TAILQ_EMPTY(&cfg->adc_listen)) { pjdlog_debug(2, " Sender only, not listening."); } else { pjdlog_debug(2, " Listening on:"); TAILQ_FOREACH(lst, &cfg->adc_listen, adl_next) { pjdlog_debug(2, " listen: %s", lst->adl_addr); pjdlog_debug(2, " conn: %p", lst->adl_conn); } } pjdlog_debug(2, " Hosts:"); TAILQ_FOREACH(adhost, &cfg->adc_hosts, adh_next) { pjdlog_debug(2, " name: %s", adhost->adh_name); pjdlog_debug(2, " role: %s", role2str(adhost->adh_role)); pjdlog_debug(2, " version: %d", adhost->adh_version); pjdlog_debug(2, " localaddr: %s", adhost->adh_localaddr); pjdlog_debug(2, " remoteaddr: %s", adhost->adh_remoteaddr); pjdlog_debug(2, " remote: %p", adhost->adh_remote); pjdlog_debug(2, " directory: %s", adhost->adh_directory); pjdlog_debug(2, " compression: %d", adhost->adh_compression); pjdlog_debug(2, " checksum: %d", adhost->adh_checksum); pjdlog_debug(2, " pid: %ld", (long)adhost->adh_worker_pid); pjdlog_debug(2, " conn: %p", adhost->adh_conn); } } static void dummy_sighandler(int sig __unused) { /* Nothing to do. */ } int main(int argc, char *argv[]) { struct adist_host *adhost; struct adist_listen *lst; const char *execpath, *pidfile; bool foreground, launchd; pid_t otherpid; int debuglevel; sigset_t mask; execpath = argv[0]; if (execpath[0] != '/') { errx(EX_USAGE, "auditdistd requires execution with an absolute path."); } /* * We are executed from proto to create sandbox. */ if (argc > 1 && strcmp(argv[1], "proto") == 0) { argc -= 2; argv += 2; if (proto_exec(argc, argv) == -1) err(EX_USAGE, "Unable to execute proto"); } foreground = false; debuglevel = 0; launchd = false; pidfile = NULL; for (;;) { int ch; ch = getopt(argc, argv, "c:dFhlP:"); if (ch == -1) break; switch (ch) { case 'c': cfgpath = optarg; break; case 'd': debuglevel++; break; case 'F': foreground = true; break; case 'l': launchd = true; break; case 'P': pidfile = optarg; break; case 'h': default: usage(); } } argc -= optind; argv += optind; pjdlog_init(PJDLOG_MODE_STD); pjdlog_debug_set(debuglevel); if (proto_set("execpath", execpath) == -1) pjdlog_exit(EX_TEMPFAIL, "Unable to set executable name"); if (proto_set("user", ADIST_USER) == -1) pjdlog_exit(EX_TEMPFAIL, "Unable to set proto user"); if (proto_set("tcp:port", ADIST_TCP_PORT) == -1) pjdlog_exit(EX_TEMPFAIL, "Unable to set default TCP port"); /* * When path to the configuration file is relative, obtain full path, * so we can always find the file, even after daemonizing and changing * working directory to /. */ if (cfgpath[0] != '/') { const char *newcfgpath; newcfgpath = realpath(cfgpath, NULL); if (newcfgpath == NULL) { pjdlog_exit(EX_CONFIG, "Unable to obtain full path of %s", cfgpath); } cfgpath = newcfgpath; } adcfg = yy_config_parse(cfgpath, true); PJDLOG_ASSERT(adcfg != NULL); adist_config_dump(adcfg); if (proto_set("tls:certfile", adcfg->adc_certfile) == -1) pjdlog_exit(EX_TEMPFAIL, "Unable to set certfile path"); if (proto_set("tls:keyfile", adcfg->adc_keyfile) == -1) pjdlog_exit(EX_TEMPFAIL, "Unable to set keyfile path"); if (pidfile != NULL) { if (strlcpy(adcfg->adc_pidfile, pidfile, sizeof(adcfg->adc_pidfile)) >= sizeof(adcfg->adc_pidfile)) { pjdlog_exitx(EX_CONFIG, "Pidfile path is too long."); } } if (foreground && pidfile == NULL) { pfh = NULL; } else { pfh = pidfile_open(adcfg->adc_pidfile, 0600, &otherpid); if (pfh == NULL) { if (errno == EEXIST) { pjdlog_exitx(EX_TEMPFAIL, "Another auditdistd is already running, pid: %jd.", (intmax_t)otherpid); } /* * If we cannot create pidfile from other reasons, * only warn. */ pjdlog_errno(LOG_WARNING, "Unable to open or create pidfile %s", adcfg->adc_pidfile); } } /* * Restore default actions for interesting signals in case parent * process (like init(8)) decided to ignore some of them (like SIGHUP). */ PJDLOG_VERIFY(signal(SIGHUP, SIG_DFL) != SIG_ERR); PJDLOG_VERIFY(signal(SIGINT, SIG_DFL) != SIG_ERR); PJDLOG_VERIFY(signal(SIGTERM, SIG_DFL) != SIG_ERR); /* * Because SIGCHLD is ignored by default, setup dummy handler for it, * so we can mask it. */ PJDLOG_VERIFY(signal(SIGCHLD, dummy_sighandler) != SIG_ERR); PJDLOG_VERIFY(sigemptyset(&mask) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGHUP) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGINT) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGTERM) == 0); PJDLOG_VERIFY(sigaddset(&mask, SIGCHLD) == 0); PJDLOG_VERIFY(sigprocmask(SIG_SETMASK, &mask, NULL) == 0); /* Listen for remote connections. */ TAILQ_FOREACH(lst, &adcfg->adc_listen, adl_next) { if (proto_server(lst->adl_addr, &lst->adl_conn) == -1) { KEEP_ERRNO((void)pidfile_remove(pfh)); pjdlog_exit(EX_OSERR, "Unable to listen on address %s", lst->adl_addr); } } if (!foreground) { if (!launchd && daemon(0, 0) == -1) { KEEP_ERRNO((void)pidfile_remove(pfh)); pjdlog_exit(EX_OSERR, "Unable to daemonize"); } /* Start logging to syslog. */ pjdlog_mode_set(PJDLOG_MODE_SYSLOG); } if (pfh != NULL) { /* Write PID to a file. */ if (pidfile_write(pfh) < 0) { pjdlog_errno(LOG_WARNING, "Unable to write PID to a file"); } } TAILQ_FOREACH(adhost, &adcfg->adc_hosts, adh_next) { if (adhost->adh_role == ADIST_ROLE_SENDER) adist_sender(adcfg, adhost); } main_loop(); exit(0); } diff --git a/contrib/openbsm/bin/auditdistd/proto_tls.c b/contrib/openbsm/bin/auditdistd/proto_tls.c index ff251c5b0c81..31673084d5b5 100644 --- a/contrib/openbsm/bin/auditdistd/proto_tls.c +++ b/contrib/openbsm/bin/auditdistd/proto_tls.c @@ -1,1074 +1,1074 @@ /*- * Copyright (c) 2011 The FreeBSD Foundation * All rights reserved. * * This software was developed by Pawel Jakub Dawidek under sponsorship from * the FreeBSD Foundation. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include /* MAXHOSTNAMELEN */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_CLOSEFROM #include #endif #ifndef HAVE_STRLCPY #include #endif #include "pjdlog.h" #include "proto_impl.h" #include "sandbox.h" #include "subr.h" #define TLS_CTX_MAGIC 0x715c7 struct tls_ctx { int tls_magic; struct proto_conn *tls_sock; struct proto_conn *tls_tcp; char tls_laddr[256]; char tls_raddr[256]; int tls_side; #define TLS_SIDE_CLIENT 0 #define TLS_SIDE_SERVER_LISTEN 1 #define TLS_SIDE_SERVER_WORK 2 bool tls_wait_called; }; #define TLS_DEFAULT_TIMEOUT 30 static int tls_connect_wait(void *ctx, int timeout); static void tls_close(void *ctx); static void block(int fd) { int flags; flags = fcntl(fd, F_GETFL); if (flags == -1) pjdlog_exit(EX_TEMPFAIL, "fcntl(F_GETFL) failed"); flags &= ~O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) pjdlog_exit(EX_TEMPFAIL, "fcntl(F_SETFL) failed"); } static void nonblock(int fd) { int flags; flags = fcntl(fd, F_GETFL); if (flags == -1) pjdlog_exit(EX_TEMPFAIL, "fcntl(F_GETFL) failed"); flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) == -1) pjdlog_exit(EX_TEMPFAIL, "fcntl(F_SETFL) failed"); } static int wait_for_fd(int fd, int timeout) { struct timeval tv; fd_set fdset; int error, ret; error = 0; for (;;) { FD_ZERO(&fdset); FD_SET(fd, &fdset); tv.tv_sec = timeout; tv.tv_usec = 0; ret = select(fd + 1, NULL, &fdset, NULL, timeout == -1 ? NULL : &tv); if (ret == 0) { error = ETIMEDOUT; break; } else if (ret == -1) { if (errno == EINTR) continue; error = errno; break; } PJDLOG_ASSERT(ret > 0); PJDLOG_ASSERT(FD_ISSET(fd, &fdset)); break; } return (error); } static void ssl_log_errors(void) { unsigned long error; while ((error = ERR_get_error()) != 0) pjdlog_error("SSL error: %s", ERR_error_string(error, NULL)); } static int ssl_check_error(SSL *ssl, int ret) { int error; error = SSL_get_error(ssl, ret); switch (error) { case SSL_ERROR_NONE: return (0); case SSL_ERROR_WANT_READ: pjdlog_debug(2, "SSL_ERROR_WANT_READ"); return (-1); case SSL_ERROR_WANT_WRITE: pjdlog_debug(2, "SSL_ERROR_WANT_WRITE"); return (-1); case SSL_ERROR_ZERO_RETURN: pjdlog_exitx(EX_OK, "Connection closed."); case SSL_ERROR_SYSCALL: ssl_log_errors(); pjdlog_exitx(EX_TEMPFAIL, "SSL I/O error."); case SSL_ERROR_SSL: ssl_log_errors(); pjdlog_exitx(EX_TEMPFAIL, "SSL protocol error."); default: ssl_log_errors(); pjdlog_exitx(EX_TEMPFAIL, "Unknown SSL error (%d).", error); } } static void tcp_recv_ssl_send(int recvfd, SSL *sendssl) { static unsigned char buf[65536]; ssize_t tcpdone; int sendfd, ssldone; sendfd = SSL_get_fd(sendssl); PJDLOG_ASSERT(sendfd >= 0); pjdlog_debug(2, "%s: start %d -> %d", __func__, recvfd, sendfd); for (;;) { tcpdone = recv(recvfd, buf, sizeof(buf), 0); pjdlog_debug(2, "%s: recv() returned %zd", __func__, tcpdone); if (tcpdone == 0) { pjdlog_debug(1, "Connection terminated."); exit(0); } else if (tcpdone == -1) { if (errno == EINTR) continue; else if (errno == EAGAIN) break; pjdlog_exit(EX_TEMPFAIL, "recv() failed"); } for (;;) { ssldone = SSL_write(sendssl, buf, (int)tcpdone); pjdlog_debug(2, "%s: send() returned %d", __func__, ssldone); if (ssl_check_error(sendssl, ssldone) == -1) { (void)wait_for_fd(sendfd, -1); continue; } PJDLOG_ASSERT(ssldone == tcpdone); break; } } pjdlog_debug(2, "%s: done %d -> %d", __func__, recvfd, sendfd); } static void ssl_recv_tcp_send(SSL *recvssl, int sendfd) { static unsigned char buf[65536]; unsigned char *ptr; ssize_t tcpdone; size_t todo; int recvfd, ssldone; recvfd = SSL_get_fd(recvssl); PJDLOG_ASSERT(recvfd >= 0); pjdlog_debug(2, "%s: start %d -> %d", __func__, recvfd, sendfd); for (;;) { ssldone = SSL_read(recvssl, buf, sizeof(buf)); pjdlog_debug(2, "%s: SSL_read() returned %d", __func__, ssldone); if (ssl_check_error(recvssl, ssldone) == -1) break; todo = (size_t)ssldone; ptr = buf; do { tcpdone = send(sendfd, ptr, todo, MSG_NOSIGNAL); pjdlog_debug(2, "%s: send() returned %zd", __func__, tcpdone); if (tcpdone == 0) { pjdlog_debug(1, "Connection terminated."); exit(0); } else if (tcpdone == -1) { if (errno == EINTR || errno == ENOBUFS) continue; if (errno == EAGAIN) { (void)wait_for_fd(sendfd, -1); continue; } pjdlog_exit(EX_TEMPFAIL, "send() failed"); } todo -= tcpdone; ptr += tcpdone; } while (todo > 0); } pjdlog_debug(2, "%s: done %d -> %d", __func__, recvfd, sendfd); } static void tls_loop(int sockfd, SSL *tcpssl) { fd_set fds; int maxfd, tcpfd; tcpfd = SSL_get_fd(tcpssl); PJDLOG_ASSERT(tcpfd >= 0); for (;;) { FD_ZERO(&fds); FD_SET(sockfd, &fds); FD_SET(tcpfd, &fds); maxfd = MAX(sockfd, tcpfd); PJDLOG_ASSERT(maxfd + 1 <= (int)FD_SETSIZE); if (select(maxfd + 1, &fds, NULL, NULL, NULL) == -1) { if (errno == EINTR) continue; pjdlog_exit(EX_TEMPFAIL, "select() failed"); } if (FD_ISSET(sockfd, &fds)) tcp_recv_ssl_send(sockfd, tcpssl); if (FD_ISSET(tcpfd, &fds)) ssl_recv_tcp_send(tcpssl, sockfd); } } static void tls_certificate_verify(SSL *ssl, const char *fingerprint) { unsigned char md[EVP_MAX_MD_SIZE]; char mdstr[sizeof("SHA256=") - 1 + EVP_MAX_MD_SIZE * 3]; char *mdstrp; unsigned int i, mdsize; X509 *cert; if (fingerprint[0] == '\0') { pjdlog_debug(1, "No fingerprint verification requested."); return; } cert = SSL_get_peer_certificate(ssl); if (cert == NULL) pjdlog_exitx(EX_TEMPFAIL, "No peer certificate received."); if (X509_digest(cert, EVP_sha256(), md, &mdsize) != 1) pjdlog_exitx(EX_TEMPFAIL, "X509_digest() failed."); PJDLOG_ASSERT(mdsize <= EVP_MAX_MD_SIZE); X509_free(cert); (void)strlcpy(mdstr, "SHA256=", sizeof(mdstr)); mdstrp = mdstr + strlen(mdstr); for (i = 0; i < mdsize; i++) { PJDLOG_VERIFY(mdstrp + 3 <= mdstr + sizeof(mdstr)); (void)sprintf(mdstrp, "%02hhX:", md[i]); mdstrp += 3; } /* Clear last colon. */ mdstrp[-1] = '\0'; if (strcasecmp(mdstr, fingerprint) != 0) { pjdlog_exitx(EX_NOPERM, "Finger print doesn't match. Received \"%s\", expected \"%s\"", mdstr, fingerprint); } } static void tls_exec_client(const char *user, int startfd, const char *srcaddr, const char *dstaddr, const char *fingerprint, const char *defport, int timeout, int debuglevel) { struct proto_conn *tcp; char *saddr, *daddr; SSL_CTX *sslctx; SSL *ssl; long ret; int sockfd, tcpfd; uint8_t connected; pjdlog_debug_set(debuglevel); pjdlog_prefix_set("[TLS sandbox] (client) "); #ifdef HAVE_SETPROCTITLE setproctitle("[TLS sandbox] (client) "); #endif proto_set("tcp:port", defport); sockfd = startfd; /* Change tls:// to tcp://. */ if (srcaddr == NULL) { saddr = NULL; } else { saddr = strdup(srcaddr); if (saddr == NULL) pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory."); bcopy("tcp://", saddr, 6); } daddr = strdup(dstaddr); if (daddr == NULL) pjdlog_exitx(EX_TEMPFAIL, "Unable to allocate memory."); bcopy("tcp://", daddr, 6); /* Establish TCP connection. */ if (proto_connect(saddr, daddr, timeout, &tcp) == -1) exit(EX_TEMPFAIL); SSL_load_error_strings(); SSL_library_init(); /* * TODO: On FreeBSD we could move this below sandbox() once libc and * libcrypto use sysctl kern.arandom to obtain random data * instead of /dev/urandom and friends. */ sslctx = SSL_CTX_new(TLS_client_method()); if (sslctx == NULL) pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed."); if (sandbox(user, true, "proto_tls client: %s", dstaddr) != 0) pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS client."); pjdlog_debug(1, "Privileges successfully dropped."); SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); /* Load CA certs. */ /* TODO */ //SSL_CTX_load_verify_locations(sslctx, cacerts_file, NULL); ssl = SSL_new(sslctx); if (ssl == NULL) pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed."); tcpfd = proto_descriptor(tcp); block(tcpfd); if (SSL_set_fd(ssl, tcpfd) != 1) pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed."); ret = SSL_connect(ssl); ssl_check_error(ssl, (int)ret); nonblock(sockfd); nonblock(tcpfd); tls_certificate_verify(ssl, fingerprint); /* - * The following byte is send to make proto_connect_wait() to work. + * The following byte is sent to make proto_connect_wait() work. */ connected = 1; for (;;) { switch (send(sockfd, &connected, sizeof(connected), 0)) { case -1: if (errno == EINTR || errno == ENOBUFS) continue; if (errno == EAGAIN) { (void)wait_for_fd(sockfd, -1); continue; } pjdlog_exit(EX_TEMPFAIL, "send() failed"); case 0: pjdlog_debug(1, "Connection terminated."); exit(0); case 1: break; } break; } tls_loop(sockfd, ssl); } static void tls_call_exec_client(struct proto_conn *sock, const char *srcaddr, const char *dstaddr, int timeout) { char *timeoutstr, *startfdstr, *debugstr; int startfd; /* Declare that we are receiver. */ proto_recv(sock, NULL, 0); if (pjdlog_mode_get() == PJDLOG_MODE_STD) startfd = 3; else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */ startfd = 0; if (proto_descriptor(sock) != startfd) { /* Move socketpair descriptor to descriptor number startfd. */ if (dup2(proto_descriptor(sock), startfd) == -1) pjdlog_exit(EX_OSERR, "dup2() failed"); proto_close(sock); } else { /* - * The FD_CLOEXEC is cleared by dup2(2), so when we not + * The FD_CLOEXEC is cleared by dup2(2), so when we do not * call it, we have to clear it by hand in case it is set. */ if (fcntl(startfd, F_SETFD, 0) == -1) pjdlog_exit(EX_OSERR, "fcntl() failed"); } closefrom(startfd + 1); if (asprintf(&startfdstr, "%d", startfd) == -1) pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); if (timeout == -1) timeout = TLS_DEFAULT_TIMEOUT; if (asprintf(&timeoutstr, "%d", timeout) == -1) pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1) pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls", proto_get("user"), "client", startfdstr, srcaddr == NULL ? "" : srcaddr, dstaddr, proto_get("tls:fingerprint"), proto_get("tcp:port"), timeoutstr, debugstr, NULL); pjdlog_exit(EX_SOFTWARE, "execl() failed"); } static int tls_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) { struct tls_ctx *tlsctx; struct proto_conn *sock; pid_t pid; int error; PJDLOG_ASSERT(srcaddr == NULL || srcaddr[0] != '\0'); PJDLOG_ASSERT(dstaddr != NULL); PJDLOG_ASSERT(timeout >= -1); PJDLOG_ASSERT(ctxp != NULL); if (strncmp(dstaddr, "tls://", 6) != 0) return (-1); if (srcaddr != NULL && strncmp(srcaddr, "tls://", 6) != 0) return (-1); if (proto_connect(NULL, "socketpair://", -1, &sock) == -1) return (errno); #if 0 /* * We use rfork() with the following flags to disable SIGCHLD * delivery upon the sandbox process exit. */ pid = rfork(RFFDG | RFPROC | RFTSIGZMB | RFTSIGFLAGS(0)); #else /* * We don't use rfork() to be able to log information about sandbox * process exiting. */ pid = fork(); #endif switch (pid) { case -1: /* Failure. */ error = errno; proto_close(sock); return (error); case 0: /* Child. */ pjdlog_prefix_set("[TLS sandbox] (client) "); #ifdef HAVE_SETPROCTITLE setproctitle("[TLS sandbox] (client) "); #endif tls_call_exec_client(sock, srcaddr, dstaddr, timeout); /* NOTREACHED */ default: /* Parent. */ tlsctx = calloc(1, sizeof(*tlsctx)); if (tlsctx == NULL) { error = errno; proto_close(sock); (void)kill(pid, SIGKILL); return (error); } proto_send(sock, NULL, 0); tlsctx->tls_sock = sock; tlsctx->tls_tcp = NULL; tlsctx->tls_side = TLS_SIDE_CLIENT; tlsctx->tls_wait_called = false; tlsctx->tls_magic = TLS_CTX_MAGIC; if (timeout >= 0) { error = tls_connect_wait(tlsctx, timeout); if (error != 0) { (void)kill(pid, SIGKILL); tls_close(tlsctx); return (error); } } *ctxp = tlsctx; return (0); } } static int tls_connect_wait(void *ctx, int timeout) { struct tls_ctx *tlsctx = ctx; int error, sockfd; uint8_t connected; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT); PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_ASSERT(!tlsctx->tls_wait_called); PJDLOG_ASSERT(timeout >= 0); sockfd = proto_descriptor(tlsctx->tls_sock); error = wait_for_fd(sockfd, timeout); if (error != 0) return (error); for (;;) { switch (recv(sockfd, &connected, sizeof(connected), MSG_WAITALL)) { case -1: if (errno == EINTR || errno == ENOBUFS) continue; error = errno; break; case 0: pjdlog_debug(1, "Connection terminated."); error = ENOTCONN; break; case 1: tlsctx->tls_wait_called = true; break; } break; } return (error); } static int tls_server(const char *lstaddr, void **ctxp) { struct proto_conn *tcp; struct tls_ctx *tlsctx; char *laddr; int error; if (strncmp(lstaddr, "tls://", 6) != 0) return (-1); tlsctx = malloc(sizeof(*tlsctx)); if (tlsctx == NULL) { pjdlog_warning("Unable to allocate memory."); return (ENOMEM); } laddr = strdup(lstaddr); if (laddr == NULL) { free(tlsctx); pjdlog_warning("Unable to allocate memory."); return (ENOMEM); } bcopy("tcp://", laddr, 6); if (proto_server(laddr, &tcp) == -1) { error = errno; free(tlsctx); free(laddr); return (error); } free(laddr); tlsctx->tls_sock = NULL; tlsctx->tls_tcp = tcp; tlsctx->tls_side = TLS_SIDE_SERVER_LISTEN; tlsctx->tls_wait_called = true; tlsctx->tls_magic = TLS_CTX_MAGIC; *ctxp = tlsctx; return (0); } static void tls_exec_server(const char *user, int startfd, const char *privkey, const char *cert, int debuglevel) { SSL_CTX *sslctx; SSL *ssl; int sockfd, tcpfd, ret; pjdlog_debug_set(debuglevel); pjdlog_prefix_set("[TLS sandbox] (server) "); #ifdef HAVE_SETPROCTITLE setproctitle("[TLS sandbox] (server) "); #endif sockfd = startfd; tcpfd = startfd + 1; SSL_load_error_strings(); SSL_library_init(); sslctx = SSL_CTX_new(TLS_server_method()); if (sslctx == NULL) pjdlog_exitx(EX_TEMPFAIL, "SSL_CTX_new() failed."); SSL_CTX_set_options(sslctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3); ssl = SSL_new(sslctx); if (ssl == NULL) pjdlog_exitx(EX_TEMPFAIL, "SSL_new() failed."); if (SSL_use_RSAPrivateKey_file(ssl, privkey, SSL_FILETYPE_PEM) != 1) { ssl_log_errors(); pjdlog_exitx(EX_CONFIG, "SSL_use_RSAPrivateKey_file(%s) failed.", privkey); } if (SSL_use_certificate_file(ssl, cert, SSL_FILETYPE_PEM) != 1) { ssl_log_errors(); pjdlog_exitx(EX_CONFIG, "SSL_use_certificate_file(%s) failed.", cert); } if (sandbox(user, true, "proto_tls server") != 0) pjdlog_exitx(EX_CONFIG, "Unable to sandbox TLS server."); pjdlog_debug(1, "Privileges successfully dropped."); nonblock(sockfd); nonblock(tcpfd); if (SSL_set_fd(ssl, tcpfd) != 1) pjdlog_exitx(EX_TEMPFAIL, "SSL_set_fd() failed."); ret = SSL_accept(ssl); ssl_check_error(ssl, ret); tls_loop(sockfd, ssl); } static void tls_call_exec_server(struct proto_conn *sock, struct proto_conn *tcp) { int startfd, sockfd, tcpfd, safefd; char *startfdstr, *debugstr; if (pjdlog_mode_get() == PJDLOG_MODE_STD) startfd = 3; else /* if (pjdlog_mode_get() == PJDLOG_MODE_SYSLOG) */ startfd = 0; /* Declare that we are receiver. */ proto_send(sock, NULL, 0); sockfd = proto_descriptor(sock); tcpfd = proto_descriptor(tcp); safefd = MAX(sockfd, tcpfd); safefd = MAX(safefd, startfd); safefd++; /* Move sockfd and tcpfd to safe numbers first. */ if (dup2(sockfd, safefd) == -1) pjdlog_exit(EX_OSERR, "dup2() failed"); proto_close(sock); sockfd = safefd; if (dup2(tcpfd, safefd + 1) == -1) pjdlog_exit(EX_OSERR, "dup2() failed"); proto_close(tcp); tcpfd = safefd + 1; /* Move socketpair descriptor to descriptor number startfd. */ if (dup2(sockfd, startfd) == -1) pjdlog_exit(EX_OSERR, "dup2() failed"); (void)close(sockfd); /* Move tcp descriptor to descriptor number startfd + 1. */ if (dup2(tcpfd, startfd + 1) == -1) pjdlog_exit(EX_OSERR, "dup2() failed"); (void)close(tcpfd); closefrom(startfd + 2); /* * Even if FD_CLOEXEC was set on descriptors before dup2(), it should * have been cleared on dup2(), but better be safe than sorry. */ if (fcntl(startfd, F_SETFD, 0) == -1) pjdlog_exit(EX_OSERR, "fcntl() failed"); if (fcntl(startfd + 1, F_SETFD, 0) == -1) pjdlog_exit(EX_OSERR, "fcntl() failed"); if (asprintf(&startfdstr, "%d", startfd) == -1) pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); if (asprintf(&debugstr, "%d", pjdlog_debug_get()) == -1) pjdlog_exit(EX_TEMPFAIL, "asprintf() failed"); execl(proto_get("execpath"), proto_get("execpath"), "proto", "tls", proto_get("user"), "server", startfdstr, proto_get("tls:keyfile"), proto_get("tls:certfile"), debugstr, NULL); pjdlog_exit(EX_SOFTWARE, "execl() failed"); } static int tls_accept(void *ctx, void **newctxp) { struct tls_ctx *tlsctx = ctx; struct tls_ctx *newtlsctx; struct proto_conn *sock, *tcp; pid_t pid; int error; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_SERVER_LISTEN); if (proto_connect(NULL, "socketpair://", -1, &sock) == -1) return (errno); /* Accept TCP connection. */ if (proto_accept(tlsctx->tls_tcp, &tcp) == -1) { error = errno; proto_close(sock); return (error); } pid = fork(); switch (pid) { case -1: /* Failure. */ error = errno; proto_close(sock); return (error); case 0: /* Child. */ pjdlog_prefix_set("[TLS sandbox] (server) "); #ifdef HAVE_SETPROCTITLE setproctitle("[TLS sandbox] (server) "); #endif /* Close listen socket. */ proto_close(tlsctx->tls_tcp); tls_call_exec_server(sock, tcp); /* NOTREACHED */ PJDLOG_ABORT("Unreachable."); default: /* Parent. */ newtlsctx = calloc(1, sizeof(*tlsctx)); if (newtlsctx == NULL) { error = errno; proto_close(sock); proto_close(tcp); (void)kill(pid, SIGKILL); return (error); } proto_local_address(tcp, newtlsctx->tls_laddr, sizeof(newtlsctx->tls_laddr)); PJDLOG_ASSERT(strncmp(newtlsctx->tls_laddr, "tcp://", 6) == 0); bcopy("tls://", newtlsctx->tls_laddr, 6); *strrchr(newtlsctx->tls_laddr, ':') = '\0'; proto_remote_address(tcp, newtlsctx->tls_raddr, sizeof(newtlsctx->tls_raddr)); PJDLOG_ASSERT(strncmp(newtlsctx->tls_raddr, "tcp://", 6) == 0); bcopy("tls://", newtlsctx->tls_raddr, 6); *strrchr(newtlsctx->tls_raddr, ':') = '\0'; proto_close(tcp); proto_recv(sock, NULL, 0); newtlsctx->tls_sock = sock; newtlsctx->tls_tcp = NULL; newtlsctx->tls_wait_called = true; newtlsctx->tls_side = TLS_SIDE_SERVER_WORK; newtlsctx->tls_magic = TLS_CTX_MAGIC; *newctxp = newtlsctx; return (0); } } static int tls_wrap(int fd, bool client, void **ctxp) { struct tls_ctx *tlsctx; struct proto_conn *sock; int error; tlsctx = calloc(1, sizeof(*tlsctx)); if (tlsctx == NULL) return (errno); if (proto_wrap("socketpair", client, fd, &sock) == -1) { error = errno; free(tlsctx); return (error); } tlsctx->tls_sock = sock; tlsctx->tls_tcp = NULL; tlsctx->tls_wait_called = (client ? false : true); tlsctx->tls_side = (client ? TLS_SIDE_CLIENT : TLS_SIDE_SERVER_WORK); tlsctx->tls_magic = TLS_CTX_MAGIC; *ctxp = tlsctx; return (0); } static int tls_send(void *ctx, const unsigned char *data, size_t size, int fd) { struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT || tlsctx->tls_side == TLS_SIDE_SERVER_WORK); PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_ASSERT(tlsctx->tls_wait_called); PJDLOG_ASSERT(fd == -1); if (proto_send(tlsctx->tls_sock, data, size) == -1) return (errno); return (0); } static int tls_recv(void *ctx, unsigned char *data, size_t size, int *fdp) { struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); PJDLOG_ASSERT(tlsctx->tls_side == TLS_SIDE_CLIENT || tlsctx->tls_side == TLS_SIDE_SERVER_WORK); PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_ASSERT(tlsctx->tls_wait_called); PJDLOG_ASSERT(fdp == NULL); if (proto_recv(tlsctx->tls_sock, data, size) == -1) return (errno); return (0); } static int tls_descriptor(const void *ctx) { const struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); switch (tlsctx->tls_side) { case TLS_SIDE_CLIENT: case TLS_SIDE_SERVER_WORK: PJDLOG_ASSERT(tlsctx->tls_sock != NULL); return (proto_descriptor(tlsctx->tls_sock)); case TLS_SIDE_SERVER_LISTEN: PJDLOG_ASSERT(tlsctx->tls_tcp != NULL); return (proto_descriptor(tlsctx->tls_tcp)); default: PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side); } } static bool tcp_address_match(const void *ctx, const char *addr) { const struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); return (strcmp(tlsctx->tls_raddr, addr) == 0); } static void tls_local_address(const void *ctx, char *addr, size_t size) { const struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); PJDLOG_ASSERT(tlsctx->tls_wait_called); switch (tlsctx->tls_side) { case TLS_SIDE_CLIENT: PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_VERIFY(strlcpy(addr, "tls://N/A", size) < size); break; case TLS_SIDE_SERVER_WORK: PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_VERIFY(strlcpy(addr, tlsctx->tls_laddr, size) < size); break; case TLS_SIDE_SERVER_LISTEN: PJDLOG_ASSERT(tlsctx->tls_tcp != NULL); proto_local_address(tlsctx->tls_tcp, addr, size); PJDLOG_ASSERT(strncmp(addr, "tcp://", 6) == 0); /* Replace tcp:// prefix with tls:// */ bcopy("tls://", addr, 6); break; default: PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side); } } static void tls_remote_address(const void *ctx, char *addr, size_t size) { const struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); PJDLOG_ASSERT(tlsctx->tls_wait_called); switch (tlsctx->tls_side) { case TLS_SIDE_CLIENT: PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_VERIFY(strlcpy(addr, "tls://N/A", size) < size); break; case TLS_SIDE_SERVER_WORK: PJDLOG_ASSERT(tlsctx->tls_sock != NULL); PJDLOG_VERIFY(strlcpy(addr, tlsctx->tls_raddr, size) < size); break; case TLS_SIDE_SERVER_LISTEN: PJDLOG_ASSERT(tlsctx->tls_tcp != NULL); proto_remote_address(tlsctx->tls_tcp, addr, size); PJDLOG_ASSERT(strncmp(addr, "tcp://", 6) == 0); /* Replace tcp:// prefix with tls:// */ bcopy("tls://", addr, 6); break; default: PJDLOG_ABORT("Invalid side (%d).", tlsctx->tls_side); } } static void tls_close(void *ctx) { struct tls_ctx *tlsctx = ctx; PJDLOG_ASSERT(tlsctx != NULL); PJDLOG_ASSERT(tlsctx->tls_magic == TLS_CTX_MAGIC); if (tlsctx->tls_sock != NULL) { proto_close(tlsctx->tls_sock); tlsctx->tls_sock = NULL; } if (tlsctx->tls_tcp != NULL) { proto_close(tlsctx->tls_tcp); tlsctx->tls_tcp = NULL; } tlsctx->tls_side = 0; tlsctx->tls_magic = 0; free(tlsctx); } static int tls_exec(int argc, char *argv[]) { PJDLOG_ASSERT(argc > 3); PJDLOG_ASSERT(strcmp(argv[0], "tls") == 0); pjdlog_init(atoi(argv[3]) == 0 ? PJDLOG_MODE_SYSLOG : PJDLOG_MODE_STD); if (strcmp(argv[2], "client") == 0) { if (argc != 10) return (EINVAL); tls_exec_client(argv[1], atoi(argv[3]), argv[4][0] == '\0' ? NULL : argv[4], argv[5], argv[6], argv[7], atoi(argv[8]), atoi(argv[9])); } else if (strcmp(argv[2], "server") == 0) { if (argc != 7) return (EINVAL); tls_exec_server(argv[1], atoi(argv[3]), argv[4], argv[5], atoi(argv[6])); } return (EINVAL); } static struct proto tls_proto = { .prt_name = "tls", .prt_connect = tls_connect, .prt_connect_wait = tls_connect_wait, .prt_server = tls_server, .prt_accept = tls_accept, .prt_wrap = tls_wrap, .prt_send = tls_send, .prt_recv = tls_recv, .prt_descriptor = tls_descriptor, .prt_address_match = tcp_address_match, .prt_local_address = tls_local_address, .prt_remote_address = tls_remote_address, .prt_close = tls_close, .prt_exec = tls_exec }; static __constructor void tls_ctor(void) { proto_register(&tls_proto, false); } diff --git a/contrib/openbsm/libauditd/auditd_lib.c b/contrib/openbsm/libauditd/auditd_lib.c index 1e21adb39bb7..e6c1312bf49f 100644 --- a/contrib/openbsm/libauditd/auditd_lib.c +++ b/contrib/openbsm/libauditd/auditd_lib.c @@ -1,1294 +1,1294 @@ /*- * Copyright (c) 2008-2009 Apple Inc. * Copyright (c) 2016 Robert N. M. Watson * All rights reserved. * * Portions of this software were developed by BAE Systems, the University of * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent * Computing (TC) research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include #include #include #ifdef HAVE_FULL_QUEUE_H #include #else /* !HAVE_FULL_QUEUE_H */ #include #endif /* !HAVE_FULL_QUEUE_H */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __APPLE__ #include #ifndef __BSM_INTERNAL_NOTIFY_KEY #define __BSM_INTERNAL_NOTIFY_KEY "com.apple.audit.change" #endif /* __BSM_INTERNAL_NOTIFY_KEY */ #endif /* __APPLE__ */ /* * XXX This is temporary until this is moved to and shared with * the kernel. */ #ifndef AUDIT_HARD_LIMIT_FREE_BLOCKS #define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 #endif /* * Number of seconds to January 1, 2000 */ #define JAN_01_2000 946598400 struct dir_ent { char *dirname; uint8_t softlim; uint8_t hardlim; TAILQ_ENTRY(dir_ent) dirs; }; static TAILQ_HEAD(, dir_ent) dir_q; struct audit_trail { time_t at_time; char *at_path; off_t at_size; TAILQ_ENTRY(audit_trail) at_trls; }; static int auditd_minval = -1; static int auditd_dist = 0; static char auditd_host[MAXHOSTNAMELEN]; static int auditd_hostlen = -1; static char *auditd_errmsg[] = { "no error", /* ADE_NOERR ( 0) */ "could not parse audit_control(5) file", /* ADE_PARSE ( 1) */ "auditon(2) failed", /* ADE_AUDITON ( 2) */ "malloc(3) failed", /* ADE_NOMEM ( 3) */ "all audit log directories over soft limit", /* ADE_SOFTLIM ( 4) */ "all audit log directories over hard limit", /* ADE_HARDLIM ( 5) */ "could not create file name string", /* ADE_STRERR ( 6) */ "could not open audit record", /* ADE_AU_OPEN ( 7) */ "could not close audit record", /* ADE_AU_CLOSE ( 8) */ "could not set active audit session state", /* ADE_SETAUDIT ( 9) */ "auditctl(2) failed (trail still swapped)", /* ADE_ACTL (10) */ "auditctl(2) failed (trail not swapped)", /* ADE_ACTLERR (11) */ "could not swap audit trail file", /* ADE_SWAPERR (12) */ "could not rename crash recovery file", /* ADE_RENAME (13) */ "could not read 'current' link file", /* ADE_READLINK (14) */ "could not create 'current' link file", /* ADE_SYMLINK (15) */ "invalid argument", /* ADE_INVAL (16) */ "could not resolve hostname to address", /* ADE_GETADDR (17) */ "address family not supported", /* ADE_ADDRFAM (18) */ "error expiring audit trail files", /* ADE_EXPIRE (19) */ }; #define MAXERRCODE (sizeof(auditd_errmsg) / sizeof(auditd_errmsg[0])) #define NA_EVENT_STR_SIZE 128 #define POL_STR_SIZE 128 /* * Look up and return the error string for the given audit error code. */ const char * auditd_strerror(int errcode) { int idx = -errcode; if (idx < 0 || idx > (int)MAXERRCODE) return ("Invalid auditd error code"); return (auditd_errmsg[idx]); } /* * Free our local list of directory names and init list. */ static void free_dir_q(void) { struct dir_ent *d1, *d2; d1 = TAILQ_FIRST(&dir_q); while (d1 != NULL) { d2 = TAILQ_NEXT(d1, dirs); free(d1->dirname); free(d1); d1 = d2; } TAILQ_INIT(&dir_q); } /* * Concat the directory name to the given file name. * XXX We should affix the hostname also */ static char * affixdir(char *name, struct dir_ent *dirent) { char *fn = NULL; /* * Sanity check on file name. */ if (strlen(name) != FILENAME_LEN) { errno = EINVAL; return (NULL); } /* * If the host is set then also add the hostname to the filename. */ if (auditd_hostlen > 0) asprintf(&fn, "%s/%s.%s", dirent->dirname, name, auditd_host); else asprintf(&fn, "%s/%s", dirent->dirname, name); return (fn); } /* * Insert the directory entry in the list by the way they are ordered in * audit_control(5). Move the entries that are over the soft and hard limits * toward the tail. */ static void insert_orderly(struct dir_ent *denew) { struct dir_ent *dep; TAILQ_FOREACH(dep, &dir_q, dirs) { if (dep->softlim == 1 && denew->softlim == 0) { TAILQ_INSERT_BEFORE(dep, denew, dirs); return; } if (dep->hardlim == 1 && denew->hardlim == 0) { TAILQ_INSERT_BEFORE(dep, denew, dirs); return; } } TAILQ_INSERT_TAIL(&dir_q, denew, dirs); } /* * Get the min percentage of free blocks from audit_control(5) and that * value in the kernel. Return: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), */ int auditd_set_dist(void) { int ret; ret = getacdist(); if (ret < 0) return (ADE_PARSE); auditd_dist = ret; return (ADE_NOERR); } /* * Get the host from audit_control(5) and set it in the audit kernel * information. Return: * ADE_NOERR on success. * ADE_PARSE error parsing audit_control(5). * ADE_AUDITON error getting/setting auditon(2) value. * ADE_GETADDR error getting address info for host. * ADE_ADDRFAM un-supported address family. */ int auditd_set_host(void) { struct sockaddr_in6 *sin6; struct sockaddr_in *sin; struct addrinfo *res; struct auditinfo_addr aia; int error, ret = ADE_NOERR; if ((getachost(auditd_host, sizeof(auditd_host)) != 0) || ((auditd_hostlen = strlen(auditd_host)) == 0)) { ret = ADE_PARSE; /* * To maintain reverse compatability with older audit_control * files, simply drop a warning if the host parameter has not * been set. However, we will explicitly disable the * generation of extended audit header by passing in a zeroed * termid structure. */ bzero(&aia, sizeof(aia)); aia.ai_termid.at_type = AU_IPv4; error = audit_set_kaudit(&aia, sizeof(aia)); if (error < 0 && errno != ENOSYS) ret = ADE_AUDITON; return (ret); } error = getaddrinfo(auditd_host, NULL, NULL, &res); if (error) return (ADE_GETADDR); switch (res->ai_family) { case PF_INET6: sin6 = (struct sockaddr_in6 *) res->ai_addr; bcopy(&sin6->sin6_addr.s6_addr, &aia.ai_termid.at_addr[0], sizeof(struct in6_addr)); aia.ai_termid.at_type = AU_IPv6; break; case PF_INET: sin = (struct sockaddr_in *) res->ai_addr; bcopy(&sin->sin_addr.s_addr, &aia.ai_termid.at_addr[0], sizeof(struct in_addr)); aia.ai_termid.at_type = AU_IPv4; break; default: /* Un-supported address family in host parameter. */ errno = EAFNOSUPPORT; return (ADE_ADDRFAM); } if (audit_set_kaudit(&aia, sizeof(aia)) < 0) ret = ADE_AUDITON; return (ret); } /* * Get the min percentage of free blocks from audit_control(5) and that * value in the kernel. Return: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), * ADE_AUDITON error getting/setting auditon(2) value. */ int auditd_set_minfree(void) { au_qctrl_t qctrl; if (getacmin(&auditd_minval) != 0) return (ADE_PARSE); if (audit_get_qctrl(&qctrl, sizeof(qctrl)) != 0) return (ADE_AUDITON); if (qctrl.aq_minfree != auditd_minval) { qctrl.aq_minfree = auditd_minval; if (audit_set_qctrl(&qctrl, sizeof(qctrl)) != 0) return (ADE_AUDITON); } return (0); } /* * Convert a trailname into a timestamp (seconds). Return 0 if the conversion * was successful. */ static int trailname_to_tstamp(char *fn, time_t *tstamp) { struct tm tm; char ts[TIMESTAMP_LEN + 1]; char *p; *tstamp = 0; /* * Get the ending time stamp. */ if ((p = strchr(fn, '.')) == NULL) return (1); strlcpy(ts, ++p, sizeof(ts)); if (strlen(ts) != POSTFIX_LEN) return (1); bzero(&tm, sizeof(tm)); /* seconds (0-60) */ p = ts + POSTFIX_LEN - 2; tm.tm_sec = atol(p); if (tm.tm_sec < 0 || tm.tm_sec > 60) return (1); /* minutes (0-59) */ *p = '\0'; p -= 2; tm.tm_min = atol(p); if (tm.tm_min < 0 || tm.tm_min > 59) return (1); /* hours (0 - 23) */ *p = '\0'; p -= 2; tm.tm_hour = atol(p); if (tm.tm_hour < 0 || tm.tm_hour > 23) return (1); /* day of month (1-31) */ *p = '\0'; p -= 2; tm.tm_mday = atol(p); if (tm.tm_mday < 1 || tm.tm_mday > 31) return (1); /* month (0 - 11) */ *p = '\0'; p -= 2; tm.tm_mon = atol(p) - 1; if (tm.tm_mon < 0 || tm.tm_mon > 11) return (1); /* year (year - 1900) */ *p = '\0'; p -= 4; tm.tm_year = atol(p) - 1900; if (tm.tm_year < 0) return (1); *tstamp = timegm(&tm); return (0); } /* * Remove audit trails files according to the expiration conditions. Returns: * ADE_NOERR on success or there is nothing to do. * ADE_PARSE if error parsing audit_control(5). * ADE_NOMEM if could not allocate memory. * ADE_READLINK if could not read link file. * ADE_EXPIRE if there was an unexpected error. */ int auditd_expire_trails(int (*warn_expired)(char *)) { int andflg, len, ret = ADE_NOERR; size_t expire_size, total_size = 0L; time_t expire_age, oldest_time, current_time = time(NULL); struct dir_ent *traildir; struct audit_trail *at; char *afnp, *pn; TAILQ_HEAD(au_trls_head, audit_trail) head = TAILQ_HEAD_INITIALIZER(head); struct stat stbuf; char activefn[MAXPATHLEN]; /* * Read the expiration conditions. If no conditions then return no * error. */ if (getacexpire(&andflg, &expire_age, &expire_size) < 0) return (ADE_PARSE); if (!expire_age && !expire_size) return (ADE_NOERR); /* * Read the 'current' trail file name. Trim off directory path. */ activefn[0] = '\0'; len = readlink(AUDIT_CURRENT_LINK, activefn, MAXPATHLEN - 1); if (len < 0) return (ADE_READLINK); if ((afnp = strrchr(activefn, '/')) != NULL) afnp++; /* * Build tail queue of the trail files. */ TAILQ_FOREACH(traildir, &dir_q, dirs) { DIR *dirp; struct dirent *dp; dirp = opendir(traildir->dirname); while ((dp = readdir(dirp)) != NULL) { time_t tstamp = 0; struct audit_trail *new; /* * Quickly filter non-trail files. */ if (dp->d_namlen < FILENAME_LEN || dp->d_name[POSTFIX_LEN] != '.') continue; if (asprintf(&pn, "%s/%s", traildir->dirname, dp->d_name) < 0) { ret = ADE_NOMEM; break; } if (stat(pn, &stbuf) < 0 || !S_ISREG(stbuf.st_mode)) { free(pn); continue; } total_size += stbuf.st_size; /* * If this is the 'current' audit trail then * don't add it to the tail queue. */ if (NULL != afnp && strcmp(dp->d_name, afnp) == 0) { free(pn); continue; } /* * Get the ending time stamp encoded in the trail * name. If we can't read it or if it is older * than Jan 1, 2000 then use the mtime. */ if (trailname_to_tstamp(dp->d_name, &tstamp) != 0 || tstamp < JAN_01_2000) tstamp = stbuf.st_mtime; /* * If the time stamp is older than Jan 1, 2000 then * update the mtime of the trail file to the current * time. This is so we don't prematurely remove a trail * file that was created while the system clock reset - * to the * "beginning of time" but later the system + * to the "beginning of time" but later the system * clock is set to the correct current time. */ if (current_time >= JAN_01_2000 && tstamp < JAN_01_2000) { struct timeval tv[2]; tstamp = stbuf.st_mtime = current_time; TIMESPEC_TO_TIMEVAL(&tv[0], &stbuf.st_atimespec); TIMESPEC_TO_TIMEVAL(&tv[1], &stbuf.st_mtimespec); utimes(pn, tv); } /* * Allocate and populate the new entry. */ new = malloc(sizeof(*new)); if (NULL == new) { free(pn); ret = ADE_NOMEM; break; } new->at_time = tstamp; new->at_size = stbuf.st_size; new->at_path = pn; /* * Check to see if we have a new head. Otherwise, * walk the tailq from the tail first and do a simple * insertion sort. */ if (TAILQ_EMPTY(&head) || new->at_time <= TAILQ_FIRST(&head)->at_time) { TAILQ_INSERT_HEAD(&head, new, at_trls); continue; } TAILQ_FOREACH_REVERSE(at, &head, au_trls_head, at_trls) if (new->at_time >= at->at_time) { TAILQ_INSERT_AFTER(&head, at, new, at_trls); break; } } closedir(dirp); } oldest_time = current_time - expire_age; /* * Expire trail files, oldest (mtime) first, if the given * conditions are met. */ at = TAILQ_FIRST(&head); while (NULL != at) { struct audit_trail *at_next = TAILQ_NEXT(at, at_trls); if (andflg) { if ((expire_size && total_size > expire_size) && (expire_age && at->at_time < oldest_time)) { if (warn_expired) (*warn_expired)(at->at_path); if (unlink(at->at_path) < 0) ret = ADE_EXPIRE; total_size -= at->at_size; } } else { if ((expire_size && total_size > expire_size) || (expire_age && at->at_time < oldest_time)) { if (warn_expired) (*warn_expired)(at->at_path); if (unlink(at->at_path) < 0) ret = ADE_EXPIRE; total_size -= at->at_size; } } free(at->at_path); free(at); at = at_next; } return (ret); } /* * Parses the "dir" entry in audit_control(5) into an ordered list. Also, will * set the minfree and host values if not already set. Arguments include * function pointers to audit_warn functions for soft and hard limits. Returns: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), * ADE_AUDITON error getting/setting auditon(2) value, * ADE_NOMEM error allocating memory, * ADE_SOFTLIM if all the directories are over the soft limit, * ADE_HARDLIM if all the directories are over the hard limit, */ int auditd_read_dirs(int (*warn_soft)(char *), int (*warn_hard)(char *)) { char cur_dir[MAXNAMLEN]; struct dir_ent *dirent; struct statfs sfs; int err; char soft, hard; int tcnt = 0; int scnt = 0; int hcnt = 0; if (auditd_minval == -1 && (err = auditd_set_minfree()) != 0) return (err); if (auditd_hostlen == -1) auditd_set_host(); /* * Init directory q. Force a re-read of the file the next time. */ free_dir_q(); endac(); /* * Read the list of directories into an ordered linked list * admin's preference, then those over soft limit and, finally, * those over the hard limit. * * XXX We should use the reentrant interfaces once they are * available. */ while (getacdir(cur_dir, MAXNAMLEN) >= 0) { if (statfs(cur_dir, &sfs) < 0) continue; /* XXX should warn */ soft = (sfs.f_bfree < (sfs.f_blocks * auditd_minval / 100 )) ? 1 : 0; hard = (sfs.f_bfree < AUDIT_HARD_LIMIT_FREE_BLOCKS) ? 1 : 0; if (soft) { if (warn_soft) (*warn_soft)(cur_dir); scnt++; } if (hard) { if (warn_hard) (*warn_hard)(cur_dir); hcnt++; } dirent = (struct dir_ent *) malloc(sizeof(struct dir_ent)); if (dirent == NULL) return (ADE_NOMEM); dirent->softlim = soft; dirent->hardlim = hard; dirent->dirname = (char *) malloc(MAXNAMLEN); if (dirent->dirname == NULL) { free(dirent); return (ADE_NOMEM); } strlcpy(dirent->dirname, cur_dir, MAXNAMLEN); insert_orderly(dirent); tcnt++; } if (hcnt == tcnt) return (ADE_HARDLIM); if (scnt == tcnt) return (ADE_SOFTLIM); return (0); } void auditd_close_dirs(void) { free_dir_q(); auditd_minval = -1; auditd_hostlen = -1; } /* * Process the audit event file, obtaining a class mapping for each event, and * set that mapping into the kernel. Return: * n number of event mappings that were successfully processed, * ADE_NOMEM if there was an error allocating memory. * * Historically, this code only set up the in-kernel class mapping. On * systems with an in-kernel event-to-name mapping, it also now installs that, * as it is iterating over the event list anyway. Failures there will be * ignored as not all kernels support the feature. */ int auditd_set_evcmap(void) { au_event_ent_t ev, *evp; au_evclass_map_t evc_map; au_evname_map_t evn_map; int ctr = 0; /* * XXX There's a risk here that the BSM library will return NULL * for an event when it can't properly map it to a class. In that * case, we will not process any events beyond the one that failed, * but should. We need a way to get a count of the events. */ ev.ae_name = (char *)malloc(AU_EVENT_NAME_MAX); ev.ae_desc = (char *)malloc(AU_EVENT_DESC_MAX); if (ev.ae_name == NULL || ev.ae_desc == NULL) { if (ev.ae_name != NULL) free(ev.ae_name); return (ADE_NOMEM); } /* * XXXRW: Currently we have no way to remove mappings from the kernel * when they are removed from the file-based mappings. */ evp = &ev; setauevent(); while ((evp = getauevent_r(evp)) != NULL) { /* * Set the event-to-name mapping entry. If there's not room * in the in-kernel string, then we skip the entry. Possibly * better than truncating...? */ if (strlcpy(evn_map.en_name, evp->ae_name, sizeof(evn_map.en_name)) < sizeof(evn_map.en_name)) { evn_map.en_number = evp->ae_number; (void)audit_set_event(&evn_map, sizeof(evn_map)); } /* * Set the event-to-class mapping entry. */ evc_map.ec_number = evp->ae_number; evc_map.ec_class = evp->ae_class; if (audit_set_class(&evc_map, sizeof(evc_map)) == 0) ctr++; } endauevent(); free(ev.ae_name); free(ev.ae_desc); return (ctr); } /* * Get the non-attributable event string and set the kernel mask. Return: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), * ADE_AUDITON error setting the mask using auditon(2). */ int auditd_set_namask(void) { au_mask_t aumask; char naeventstr[NA_EVENT_STR_SIZE]; if (getacna(naeventstr, NA_EVENT_STR_SIZE) != 0 || getauditflagsbin(naeventstr, &aumask) != 0) return (ADE_PARSE); if (audit_set_kmask(&aumask, sizeof(aumask)) != 0) return (ADE_AUDITON); return (ADE_NOERR); } /* * Set the audit control policy if a policy is configured in audit_control(5), * implement the policy. However, if one isn't defined or if there is an error * parsing the control file, set AUDIT_CNT to avoid leaving the system in a * fragile state. Return: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), * ADE_AUDITON error setting policy using auditon(2). */ int auditd_set_policy(void) { int policy; char polstr[POL_STR_SIZE]; if (getacpol(polstr, POL_STR_SIZE) != 0 || au_strtopol(polstr, &policy) != 0) { policy = AUDIT_CNT; if (audit_set_policy(&policy) != 0) return (ADE_AUDITON); return (ADE_PARSE); } if (audit_set_policy(&policy) != 0) return (ADE_AUDITON); return (ADE_NOERR); } /* * Set trail rotation size. Return: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), * ADE_AUDITON error setting file size using auditon(2). */ int auditd_set_fsize(void) { size_t filesz; au_fstat_t au_fstat; /* * Set trail rotation size. */ if (getacfilesz(&filesz) != 0) return (ADE_PARSE); bzero(&au_fstat, sizeof(au_fstat)); au_fstat.af_filesz = filesz; if (audit_set_fsize(&au_fstat, sizeof(au_fstat)) != 0) return (ADE_AUDITON); return (ADE_NOERR); } /* * Set trail rotation size. Return: * ADE_NOERR on success, * ADE_PARSE error parsing audit_control(5), * ADE_AUDITON error setting queue size using auditon(2). */ int auditd_set_qsize(void) { int qsz; au_qctrl_t au_qctrl; /* * Set trail rotation size. */ if (getacqsize(&qsz) != 0) return (ADE_PARSE); if (audit_get_qctrl(&au_qctrl, sizeof(au_qctrl)) != 0) return (ADE_AUDITON); if (qsz != USE_DEFAULT_QSZ) au_qctrl.aq_hiwater = qsz; if (audit_set_qctrl(&au_qctrl, sizeof(au_qctrl)) != 0) return (ADE_AUDITON); return (ADE_NOERR); } static void inject_dist(const char *fromname, char *toname, size_t tonamesize) { char *ptr; ptr = strrchr(fromname, '/'); assert(ptr != NULL); assert(ptr - fromname < (ssize_t)tonamesize); strlcpy(toname, fromname, ptr - fromname + 1); strlcat(toname, "/dist/", tonamesize); strlcat(toname, ptr + 1, tonamesize); } static int auditdist_link(const char *filename) { char fname[MAXPATHLEN]; if (auditd_dist) { inject_dist(filename, fname, sizeof(fname)); /* Ignore errors. */ (void) link(filename, fname); } return (0); } int auditd_rename(const char *fromname, const char *toname) { char fname[MAXPATHLEN], tname[MAXPATHLEN]; if (auditd_dist) { inject_dist(fromname, fname, sizeof(fname)); inject_dist(toname, tname, sizeof(tname)); /* Ignore errors. */ (void) rename(fname, tname); } return (rename(fromname, toname)); } /* * Create the new audit file with appropriate permissions and ownership. * Call auditctl(2) for this file. * Try to clean up if something goes wrong. * *errorp is modified only on auditctl(2) failure. */ static int open_trail(char *fname, gid_t gid, int *errorp) { int fd; /* XXXPJD: What should we do if the file already exists? */ fd = open(fname, O_RDONLY | O_CREAT, S_IRUSR); if (fd < 0) return (-1); if (fchown(fd, -1, gid) < 0 || fchmod(fd, S_IRUSR | S_IRGRP) < 0) { (void) close(fd); (void) unlink(fname); return (-1); } (void) close(fd); if (auditctl(fname) < 0) { *errorp = errno; (void) unlink(fname); return (-1); } (void) auditdist_link(fname); return (0); } /* * Create the new audit trail file, swap with existing audit file. Arguments * include timestamp for the filename, a pointer to a string for returning the * new file name, GID for trail file, and audit_warn function pointer for * 'getacdir()' errors. Returns: * ADE_NOERR on success, * ADE_STRERR if the file name string could not be created, * ADE_SWAPERR if the audit trail file could not be swapped, * ADE_ACTL if the auditctl(2) call failed but file swap still * successful. * ADE_ACTLERR if the auditctl(2) call failed and file swap failed. * ADE_SYMLINK if symlink(2) failed updating the current link. */ int auditd_swap_trail(char *TS, char **newfile, gid_t gid, int (*warn_getacdir)(char *)) { char timestr[FILENAME_LEN + 1]; char *fn; struct dir_ent *dirent; int saverrno = 0; if (strlen(TS) != TIMESTAMP_LEN || snprintf(timestr, sizeof(timestr), "%s.%s", TS, NOT_TERMINATED) < 0) { errno = EINVAL; return (ADE_STRERR); } /* Try until we succeed. */ TAILQ_FOREACH(dirent, &dir_q, dirs) { if (dirent->hardlim) continue; if ((fn = affixdir(timestr, dirent)) == NULL) return (ADE_STRERR); /* * Create the file and pass to the kernel if all went well. */ if (open_trail(fn, gid, &saverrno) == 0) { /* Success. */ *newfile = fn; if (saverrno) { /* * auditctl() failed but still * successful. Return errno and "soft" * error. */ errno = saverrno; return (ADE_ACTL); } return (ADE_NOERR); } /* * auditctl failed setting log file. Try again. */ /* * Tell the administrator about lack of permissions for dir. */ if (warn_getacdir != NULL) (*warn_getacdir)(dirent->dirname); } if (saverrno) { errno = saverrno; return (ADE_ACTLERR); } else return (ADE_SWAPERR); } /* * Mask calling process from being audited. Returns: * ADE_NOERR on success, * ADE_SETAUDIT if setaudit(2) fails. */ #ifdef __APPLE__ int auditd_prevent_audit(void) { auditinfo_addr_t aia; /* * To prevent event feedback cycles and avoid audit becoming stalled if * auditing is suspended we mask this processes events from being * audited. We allow the uid, tid, and mask fields to be implicitly * set to zero, but do set the audit session ID to the PID. * * XXXRW: Is there more to it than this? */ bzero(&aia, sizeof(aia)); aia.ai_asid = AU_ASSIGN_ASID; aia.ai_termid.at_type = AU_IPv4; if (setaudit_addr(&aia, sizeof(aia)) != 0) return (ADE_SETAUDIT); return (ADE_NOERR); } #else int auditd_prevent_audit(void) { auditinfo_t ai; /* * To prevent event feedback cycles and avoid audit becoming stalled if * auditing is suspended we mask this processes events from being * audited. We allow the uid, tid, and mask fields to be implicitly * set to zero, but do set the audit session ID to the PID. * * XXXRW: Is there more to it than this? */ bzero(&ai, sizeof(ai)); ai.ai_asid = getpid(); if (setaudit(&ai) != 0) return (ADE_SETAUDIT); return (ADE_NOERR); } #endif /* !__APPLE__ */ /* * Generate and submit audit record for audit startup or shutdown. The event * argument can be AUE_audit_recovery, AUE_audit_startup or * AUE_audit_shutdown. The path argument will add a path token, if not NULL. * Returns: * AUE_NOERR on success, * ADE_NOMEM if memory allocation fails, * ADE_AU_OPEN if au_open(3) fails, * ADE_AU_CLOSE if au_close(3) fails. */ int auditd_gen_record(int event, char *path) { int aufd; uid_t uid; pid_t pid; char *autext = NULL; token_t *tok; struct auditinfo_addr aia; if (event == AUE_audit_startup) asprintf(&autext, "%s::Audit startup", getprogname()); else if (event == AUE_audit_shutdown) asprintf(&autext, "%s::Audit shutdown", getprogname()); else if (event == AUE_audit_recovery) asprintf(&autext, "%s::Audit recovery", getprogname()); else return (ADE_INVAL); if (autext == NULL) return (ADE_NOMEM); if ((aufd = au_open()) == -1) { free(autext); return (ADE_AU_OPEN); } bzero(&aia, sizeof(aia)); uid = getuid(); pid = getpid(); if ((tok = au_to_subject32_ex(uid, geteuid(), getegid(), uid, getgid(), pid, pid, &aia.ai_termid)) != NULL) au_write(aufd, tok); if ((tok = au_to_text(autext)) != NULL) au_write(aufd, tok); free(autext); if (path != NULL && (tok = au_to_path(path)) != NULL) au_write(aufd, tok); if ((tok = au_to_return32(0, 0)) != NULL) au_write(aufd, tok); if (au_close(aufd, 1, event) == -1) return (ADE_AU_CLOSE); return (ADE_NOERR); } /* * Check for a 'current' symlink and do crash recovery, if needed. Create a new * 'current' symlink. The argument 'curfile' is the file the 'current' symlink * should point to. Returns: * ADE_NOERR on success, * ADE_AU_OPEN if au_open(3) fails, * ADE_AU_CLOSE if au_close(3) fails. * ADE_RENAME if error renaming audit trail file, * ADE_READLINK if error reading the 'current' link, * ADE_SYMLINK if error creating 'current' link. */ int auditd_new_curlink(char *curfile) { int len, err; char *ptr; char *path = NULL; struct stat sb; char recoveredname[MAXPATHLEN]; char newname[MAXPATHLEN]; /* * Check to see if audit was shutdown properly. If not, clean up, * recover previous audit trail file, and generate audit record. */ len = readlink(AUDIT_CURRENT_LINK, recoveredname, sizeof(recoveredname) - 1); if (len > 0) { /* 'current' exist but is it pointing at a valid file? */ recoveredname[len++] = '\0'; if (stat(recoveredname, &sb) == 0) { /* Yes, rename it to a crash recovery file. */ strlcpy(newname, recoveredname, sizeof(newname)); if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { memcpy(ptr, CRASH_RECOVERY, POSTFIX_LEN); if (auditd_rename(recoveredname, newname) != 0) return (ADE_RENAME); } else return (ADE_STRERR); path = newname; } /* 'current' symlink is (now) invalid so remove it. */ (void) unlink(AUDIT_CURRENT_LINK); /* Note the crash recovery in current audit trail */ err = auditd_gen_record(AUE_audit_recovery, path); if (err) return (err); } if (len < 0 && errno != ENOENT) return (ADE_READLINK); if (symlink(curfile, AUDIT_CURRENT_LINK) != 0) return (ADE_SYMLINK); return (0); } /* * Do just what we need to quickly start auditing. Assume no system logging or * notify. Return: * 0 on success, * -1 on failure. */ int audit_quick_start(void) { int err; char *newfile = NULL; time_t tt; char TS[TIMESTAMP_LEN + 1]; int ret = 0; /* * Mask auditing of this process. */ if (auditd_prevent_audit() != 0) return (-1); /* * Read audit_control and get log directories. */ err = auditd_read_dirs(NULL, NULL); if (err != ADE_NOERR && err != ADE_SOFTLIM) return (-1); /* * Setup trail file distribution. */ (void) auditd_set_dist(); /* * Create a new audit trail log. */ if (getTSstr(tt, TS, sizeof(TS)) != 0) return (-1); err = auditd_swap_trail(TS, &newfile, getgid(), NULL); if (err != ADE_NOERR && err != ADE_ACTL) { ret = -1; goto out; } /* * Add the current symlink and recover from crash, if needed. */ if (auditd_new_curlink(newfile) != 0) { ret = -1; goto out; } /* * At this point auditing has started so generate audit start-up record. */ if (auditd_gen_record(AUE_audit_startup, NULL) != 0) { ret = -1; goto out; } /* * Configure the audit controls. */ (void) auditd_set_evcmap(); (void) auditd_set_namask(); (void) auditd_set_policy(); (void) auditd_set_fsize(); (void) auditd_set_minfree(); (void) auditd_set_host(); out: if (newfile != NULL) free(newfile); return (ret); } /* * Shut down auditing quickly. Assumes that is only called on system shutdown. * Returns: * 0 on success, * -1 on failure. */ int audit_quick_stop(void) { int len; int cond; char *ptr; time_t tt; char oldname[MAXPATHLEN]; char newname[MAXPATHLEN]; char TS[TIMESTAMP_LEN + 1]; /* * Auditing already disabled? */ if (audit_get_cond(&cond) != 0) return (-1); if (cond == AUC_NOAUDIT) return (0); /* * Generate audit shutdown record. */ (void) auditd_gen_record(AUE_audit_shutdown, NULL); /* * Shutdown auditing in the kernel. */ cond = AUC_DISABLED; if (audit_set_cond(&cond) != 0) return (-1); #ifdef __BSM_INTERNAL_NOTIFY_KEY notify_post(__BSM_INTERNAL_NOTIFY_KEY); #endif /* * Rename last audit trail and remove 'current' link. */ len = readlink(AUDIT_CURRENT_LINK, oldname, sizeof(oldname) - 1); if (len < 0) return (-1); oldname[len++] = '\0'; if (getTSstr(tt, TS, sizeof(TS)) != 0) return (-1); strlcpy(newname, oldname, sizeof(newname)); if ((ptr = strstr(newname, NOT_TERMINATED)) != NULL) { memcpy(ptr, TS, POSTFIX_LEN); if (auditd_rename(oldname, newname) != 0) return (-1); } else return (-1); (void) unlink(AUDIT_CURRENT_LINK); return (0); } diff --git a/contrib/openbsm/libbsm/au_control.3 b/contrib/openbsm/libbsm/au_control.3 index fbf37b50b21c..c5a28f557222 100644 --- a/contrib/openbsm/libbsm/au_control.3 +++ b/contrib/openbsm/libbsm/au_control.3 @@ -1,272 +1,272 @@ .\"- .\" Copyright (c) 2005-2006 Robert N. M. Watson .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd December 2, 2016 .Dt AU_CONTROL 3 .Os .Sh NAME .Nm setac , .Nm endac , .Nm getacdir , .Nm getacdist , .Nm getacexpire , .Nm getacfilesz , .Nm getacflg , .Nm getachost , .Nm getacmin , .Nm getacna , .Nm getacpol , .Nm au_poltostr , .Nm au_strtopol .Nd "look up information from the audit_control database" .Sh LIBRARY .Lb libbsm .Sh SYNOPSIS .In bsm/libbsm.h .Ft void .Fn setac void .Ft void .Fn endac void .Ft int .Fn getacdir "char *name" "int len" .Ft int .Fn getacdist "void" .Ft int .Fn getacexpire "int *andflg" "time_t *age" "size_t *size" .Ft int .Fn getacfilesz "size_t *size_val" .Ft int .Fn getacflg "char *auditstr" "int len" .Ft int .Fn getachost "char *auditstr" "int len" .Ft int .Fn getacmin "int *min_val" .Ft int .Fn getacna "char *auditstr" "int len" .Ft int .Fn getacpol "char *auditstr" "size_t len" .Ft int .Fn getacqsize "int *size_val" .Ft ssize_t .Fn au_poltostr "int policy" "size_t maxsize" "char *buf" .Ft int .Fn au_strtopol "const char *polstr" "int *policy" .Sh DESCRIPTION These interfaces may be used to look up information from the .Xr audit_control 5 database, which contains various audit-related administrative parameters. .Pp The .Fn setac function resets the database iterator to the beginning of the database; see the .Sx BUGS section for more information. .Pp The .Fn endac function closes the .Xr audit_control 5 database. .Pp The .Fn getacdir function returns the name of the directory where log data is stored via the passed character buffer .Fa name of length .Fa len . .Pp The .Fn getacdist function returns a value that allows to decide if trail files distribution is turned on or off. .Pp The .Fn getacexpire function returns the audit trail file expiration parameters in the passed .Vt int buffer .Fa andflg , .Vt time_t buffer .Fa age and .Vt size_t buffer .Fa size . If the parameter is not specified in the .Xr audit_control 5 file it is set to zero. .Pp The .Fn getacfilesz function returns the audit trail rotation size in the passed .Vt size_t buffer .Fa size_val . .Pp The .Fn getacflg function returns the audit system flags via the the passed character buffer .Fa auditstr of length .Fa len . .Pp The .Fn getachost function returns the local systems's audit host information via the the passed character buffer .Fa auditstr of length .Fa len . .Pp The .Fn getacmin function returns the minimum free disk space for the audit log target file system via the passed .Fa min_val variable. .Pp The .Fn getacna function returns the non-attributable flags via the passed character buffer .Fa auditstr of length .Fa len . .Pp The .Fn getacpol function returns the audit policy flags via the passed character buffer .Fa auditstr of length .Fa len . .Pp The .Fn getacqsize function returns the size of the audit post-commit queue in the passed .Fa size_val buffer. If the parameter is not specified in the .Xr audit_control 5 file it is set to .Dv -1 , indicating that the kernel's default queue size is being used. .Pp The .Fn au_poltostr function converts a numeric audit policy mask, .Fa policy , to a string in the passed character buffer .Fa buf of lenth .Fa maxsize . .Pp The .Fn au_strtopol function converts an audit policy flags string, .Fa polstr , to a numeric audit policy mask returned via .Fa policy . -.Sh RETURN VALULES +.Sh RETURN VALUES The .Fn getacfilesz , .Fn getacdir , .Fn getacexpire , .Fn getacflg , .Fn getachost , .Fn getacmin , .Fn getacna , .Fn getacpol , .Fn getacqsize , and .Fn au_strtopol functions return 0 on success, or a negative value on failure, along with error information in .Va errno . .Pp The .Fn au_poltostr function returns a string length of 0 or more on success, or a negative value on if there is a failure. .Pp The .Fn getacdist function returns 1 if trail files distribution is turned on, 0 if it is turned off or negative value on failure. .Pp Functions that return a string value will return a failure if there is insufficient room in the passed character buffer for the full string. .Sh SEE ALSO .Xr libbsm 3 , .Xr audit_control 5 .Sh HISTORY The OpenBSM implementation was created by McAfee Research, the security division of McAfee Inc., under contract to Apple Computer, Inc., in 2004. It was subsequently adopted by the TrustedBSD Project as the foundation for the OpenBSM distribution. .Sh AUTHORS .An -nosplit This software was created by .An Robert Watson , .An Wayne Salamon , and .An Suresh Krishnaswamy for McAfee Research, the security research division of McAfee, Inc., under contract to Apple Computer, Inc. .Pp The Basic Security Module (BSM) interface to audit records and audit event stream format were defined by Sun Microsystems. .Sh BUGS These routines cannot currently distinguish between an entry not being found and an error accessing the database. The implementation should be changed to return an error via .Va errno when .Dv NULL is returned. .Pp There is no reason for the .Fn setac interface to be exposed as part of the public API, as it is called implicitly by other access functions and iteration is not supported. .Pp These interfaces inconsistently return various negative values depending on the failure mode, and do not always set .Va errno on failure. diff --git a/contrib/openbsm/libbsm/au_domain.3 b/contrib/openbsm/libbsm/au_domain.3 index 2f16b3848151..9d3415fb3c30 100644 --- a/contrib/openbsm/libbsm/au_domain.3 +++ b/contrib/openbsm/libbsm/au_domain.3 @@ -1,86 +1,86 @@ .\"- .\" Copyright (c) 2008 Apple Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of Apple Inc. ("Apple") nor the names of .\" its contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR .\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 28, 2008 .Dt AU_BSM_TO_DOMAIN 3 .Os .Sh NAME .Nm au_bsm_to_domain , .Nm au_domain_to_bsm .Nd "convert between BSM and local protocol domains" .Sh LIBRARY .Lb libbsm .Sh SYNOPSIS .In bsm/libbsm.h .Ft int .Fn au_bsm_to_domain "u_short bsm_domain" "int *local_domainp" .Ft u_short .Fn au_domain_to_bsm "int local_domain" .Sh DESCRIPTION These interfaces may be used to convert between the local and BSM protocol domains. The .Fn au_bsm_to_domain function accepts a BSM domain, .Fa bsm_domain , and converts it to a local domain, such as those passed to .Xr socket 2 , that will be stored in the integer pointed to by .Fa local_domainp if successful. This call will fail if the BSM domain cannot be mapped into a local domain, which may occur if the socket token was generated on another operating system. .Pp The .Fn au_domain_to_bsm function accepts a local domain, and returns the BSM domain for it. This call cannot fail, and instead returns a BSM domain indicating to a later decoder that the domain could not be encoded. -.Sh RETURN VALULES +.Sh RETURN VALUES On success, .Fn au_bsm_to_domain returns 0 and a converted domain; on failure, it returns -1 but does not set .Xr errno 2 . .Sh SEE ALSO .Xr au_bsm_to_socket_type 3 , .Xr au_socket_type_to_bsm 3 , .Xr au_to_socket_ex 3 , .Xr libbsm 3 .Sh HISTORY .Fn au_bsm_to_domain and .Fn au_domain_to_bsm were introduced in OpenBSM 1.1. .Sh AUTHORS These functions were implemented by .An Robert Watson under contract to Apple Inc. .Pp The Basic Security Module (BSM) interface to audit records and audit event stream format were defined by Sun Microsystems. diff --git a/contrib/openbsm/libbsm/au_errno.3 b/contrib/openbsm/libbsm/au_errno.3 index 93873cec7323..9a3d51db0123 100644 --- a/contrib/openbsm/libbsm/au_errno.3 +++ b/contrib/openbsm/libbsm/au_errno.3 @@ -1,110 +1,110 @@ .\"- .\" Copyright (c) 2008 Apple Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of Apple Inc. ("Apple") nor the names of .\" its contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR .\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 8, 2008 .Dt AU_BSM_TO_ERRNO 3 .Os .Sh NAME .Nm au_bsm_to_errno , .Nm au_errno_to_bsm , .Nm au_strerror .Nd "convert between BSM and local error numbers" .Sh LIBRARY .Lb libbsm .Sh SYNOPSIS .In bsm/libbsm.h .Ft int .Fn au_bsm_to_errno "u_char bsm_error" "int *errorp" .Ft u_char .Fn au_errno_to_bsm "int error" .Ft const char * .Fn au_strerror "int bsm_error" .Sh DESCRIPTION These interfaces may be used to convert between the local ( .Xr errno 2 ) and BSM error number spaces found in BSM return tokens. .Pp The .Fn au_bsm_to_errno function accepts a BSM error value, .Fa bsm_error , and converts it to an .Xr errno 2 that will be stored in the integer pointed to by .Fa errorp if successful. This call will fail if the BSM error cannot be mapped into a local error number, which may occur if the return token was generated on another operating system. .Pp The .Fn au_errno_to_bsm function accepts a local .Xr errno 2 value, and returns the BSM error number for it. This call cannot fail, and instead returns a BSM error number indicating to a later decoder that the error could not be encoded. .Pp The .Fn au_strerror function converts a BSM error value to a string, generally by converting first to a local error number and using the local .Xr strerror 3 function, but will also work for errors that are not locally defined. -.Sh RETURN VALULES +.Sh RETURN VALUES On success, .Fn au_bsm_to_errno returns 0 and a converted error value; on failure, it returns -1 but does not set .Xr errno 2 . .Pp On success, .Fn au_strerror returns a pointer to an error string; on failure it will return .Dv NULL . .Sh SEE ALSO .Xr au_to_return 3 , .Xr au_to_return32 3 , .Xr au_to_return64 3 , .Xr libbsm 3 .Sh HISTORY .Fn au_bsm_to_errno and .Fn au_errno_to_bsm were introduced in OpenBSM 1.1. .Sh AUTHORS These functions were implemented by .An Robert Watson under contract to Apple Inc. .Pp The Basic Security Module (BSM) interface to audit records and audit event stream format were defined by Sun Microsystems. .Sh BUGS .Nm au_strerror is unable to provide localized strings for errors not available in the local operating system. diff --git a/contrib/openbsm/libbsm/au_socket_type.3 b/contrib/openbsm/libbsm/au_socket_type.3 index 5668569f7b4d..54534b3fe80f 100644 --- a/contrib/openbsm/libbsm/au_socket_type.3 +++ b/contrib/openbsm/libbsm/au_socket_type.3 @@ -1,91 +1,91 @@ .\"- .\" Copyright (c) 2008 Apple Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" 3. Neither the name of Apple Inc. ("Apple") nor the names of .\" its contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR .\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, .\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING .\" IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" .Dd December 28, 2008 .Dt AU_BSM_TO_SOCKET_TYPE 3 .Os .Sh NAME .Nm au_bsm_to_socket_type , .Nm au_socket_type_to_bsm .Nd "convert between BSM and local socket types" .Sh LIBRARY .Lb libbsm .Sh SYNOPSIS .In bsm/libbsm.h .Ft int .Fn au_bsm_to_socket_type "u_short bsm_socket_type" "int *local_socket_typep" .Ft u_short .Fn au_socket_type_to_bsm "int local_socket_type" .Sh DESCRIPTION These interfaces may be used to convert between the local and BSM socket types. The .Fn au_bsm_to_socket_type function accepts a BSM socket type, .Fa bsm_socket_type , and converts it to a local socket type, such as those passed to .Xr socket 2 , that will be stored in the integer pointed to by .Fa local_socket_typep if successful. This call will fail if the BSM socket type cannot be mapped into a local socket type, which may occur if the socket token was generated on another operating system. .Pp .Fn au_socket_type_to_bsm function accepts a local socket type, and returns the BSM socket type for it. This call cannot fail, and instead returns a BSM socket type indicating to a later decoder that the socket type could not be encoded. -.Sh RETURN VALULES +.Sh RETURN VALUES On success, .Fn au_bsm_to_socket_type returns 0 and a converted socket type; on failure, it returns -1 but does not set .Xr errno 2 . .Pp On success, .Fn au_strerror returns a pointer to an error string; on failure it will return .Dv NULL . .Sh SEE ALSO .Xr au_bsm_to_domain 3 , .Xr au_domain_to_bsm 3 , .Xr au_to_socket_ex 3 , .Xr libbsm 3 .Sh HISTORY .Fn au_bsm_to_socket_type and .Fn au_socket_type_to_bsm were introduced in OpenBSM 1.1. .Sh AUTHORS These functions were implemented by .An Robert Watson under contract to Apple Inc. .Pp The Basic Security Module (BSM) interface to audit records and audit event stream format were defined by Sun Microsystems. diff --git a/contrib/openbsm/man/audit.log.5 b/contrib/openbsm/man/audit.log.5 index d85fdccb2bf0..a1db9981acd6 100644 --- a/contrib/openbsm/man/audit.log.5 +++ b/contrib/openbsm/man/audit.log.5 @@ -1,670 +1,670 @@ .\"- .\" Copyright (c) 2005-2006 Robert N. M. Watson .\" Copyright (c) 2008 Apple Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .Dd November 5, 2006 .Dt AUDIT.LOG 5 .Os .Sh NAME .Nm audit .Nd "Basic Security Module (BSM) file format" .Sh DESCRIPTION The .Nm file format is based on Sun's Basic Security Module (BSM) file format, a token-based record stream to represent system audit data. This file format is both flexible and extensible, able to describe a broad range of data types, and easily extended to describe new data types in a moderately backward and forward compatible way. .Pp BSM token streams typically begin and end with a .Dq file token, which provides time stamp and file name information for the stream; when processing a BSM token stream from a stream as opposed to a single file source, file tokens may be seen at any point between ordinary records identifying when particular parts of the stream begin and end. All other tokens will appear in the context of a complete BSM audit record, which begins with a .Dq header token, and ends with a .Dq trailer token, which describe the audit record. Between these two tokens will appear a variety of data tokens, such as process information, file path names, IPC object information, MAC labels, socket information, and so on. .Pp The BSM file format defines specific token orders for each record event type; however, some variation may occur depending on the operating system in use, what system options, such as mandatory access control, are present. .Pp This manual page documents the common token types and their binary format, and is intended for reference purposes only. It is recommended that application programmers use the .Xr libbsm 3 interface to read and write tokens, rather than parsing or constructing records by hand. .Ss File Token The .Dq file token is used at the beginning and end of an audit log file to indicate when the audit log begins and ends. It includes a pathname so that, if concatenated together, original file boundaries are still observable, and gaps in the audit log can be identified. A .Dq file token can be created using .Xr au_to_file 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Seconds 4 bytes File time stamp" .It "Microseconds 4 bytes File time stamp" .It "File name length 2 bytes File name of audit trail" .It "File pathname N bytes + 1 NUL File name of audit trail" .El .Ss Header Token The .Dq header token is used to mark the beginning of a complete audit record, and includes the length of the total record in bytes, a version number for the record layout, the event type and subtype, and the time at which the event occurred. A 32-bit .Dq header token can be created using .Xr au_to_header32 3 ; a 64-bit .Dq header token can be created using .Xr au_to_header64 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Record Byte Count 4 bytes Number of bytes in record" -.It "Version Number 2 bytes Record version number" +.It "Version Number 1 byte Record version number" .It "Event Type 2 bytes Event type" .It "Event Modifier 2 bytes Event sub-type" .It "Seconds 4/8 bytes Record time stamp (32/64-bits)" .It "Nanoseconds 4/8 bytes Record time stamp (32/64-bits)" .El .Ss Expanded Header Token The .Dq expanded header token is an expanded version of the .Dq header token, with the addition of a machine IPv4 or IPv6 address. A 32-bit extended .Dq header token can be created using .Xr au_to_header32_ex 3 ; a 64-bit extended .Dq header token can be created using .Xr au_to_header64_ex 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Record Byte Count 4 bytes Number of bytes in record" -.It "Version Number 2 bytes Record version number" +.It "Version Number 1 byte Record version number" .It "Event Type 2 bytes Event type" .It "Event Modifier 2 bytes Event sub-type" .It "Address Type/Length 1 byte Host address type and length" .It "Machine Address 4/16 bytes IPv4 or IPv6 address" .It "Seconds 4/8 bytes Record time stamp (32/64-bits)" .It "Nanoseconds 4/8 bytes Record time stamp (32/64-bits)" .El .Ss Trailer Token The .Dq trailer terminates a BSM audit record, and contains a magic number, .Dv AUT_TRAILER_MAGIC and length that can be used to validate that the record was read properly. A .Dq trailer token can be created using .Xr au_to_trailer 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Trailer Magic 2 bytes Trailer magic number" .It "Record Byte Count 4 bytes Number of bytes in record" .El .Ss Arbitrary Data Token The .Dq arbitrary data token contains a byte stream of opaque (untyped) data. The size of the data is calculated as the size of each unit of data multiplied by the number of units of data. A .Dq How to print field is present to specify how to print the data, but interpretation of that field is not currently defined. An .Dq arbitrary data token can be created using .Xr au_to_data 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "How to Print 1 byte User-defined printing information" .It "Basic Unit 1 byte Size of a unit in bytes" .It "Unit Count 1 byte Number of units of data present" .It "Data Items Variable User data" .El .Ss in_addr Token The .Dq in_addr token holds a network byte order IPv4 address. An .Dq in_addr token can be created using .Xr au_to_in_addr 3 for an IPv4 address. .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "IP Address 4 bytes IPv4 address" .El .Ss Expanded in_addr Token The .Dq in_addr_ex token holds a network byte order IPv4 or IPv6 address. An .Dq in_addr_ex token can be created using .Xr au_to_in_addr_ex 3 for an IPv6 address. .Pp See the .Sx BUGS section for information on the storage of this token. .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "IP Address Type 1 byte Type of address" .It "IP Address 4/16 bytes IPv4 or IPv6 address" .El .Ss ip Token The .Dq ip token contains an IP packet header in network byte order. An .Dq ip token can be created using .Xr au_to_ip 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Version and IHL 1 byte Version and IP header length" .It "Type of Service 1 byte IP TOS field" .It "Length 2 bytes IP packet length in network byte order" .It "ID 2 bytes IP header ID for reassembly" .It "Offset 2 bytes IP fragment offset and flags, network byte order" .It "TTL 1 byte IP Time-to-Live" .It "Protocol 1 byte IP protocol number" .It "Checksum 2 bytes IP header checksum, network byte order" .It "Source Address 4 bytes IPv4 source address" .It "Destination Address 4 bytes IPv4 destination address" .El .Ss iport Token The .Dq iport token stores an IP port number in network byte order. An .Dq iport token can be created using .Xr au_to_iport 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Port Number 2 bytes Port number in network byte order" .El .Ss Path Token The .Dq path token contains a pathname. A .Dq path token can be created using .Xr au_to_path 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Path Length 2 bytes Length of path in bytes" .It "Path N bytes + 1 NUL Path name" .El .Ss path_attr Token The .Dq path_attr token contains a set of NUL-terminated path names. The .Xr libbsm 3 API cannot currently create a .Dq path_attr token. .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Count 2 bytes Number of NUL-terminated string(s) in token" .It "Path Variable count NUL-terminated string(s)" .El .Ss Process Token The .Dq process token contains a description of the security properties of a process involved as the target of an auditable event, such as the destination for signal delivery. It should not be confused with the .Dq subject token, which describes the subject performing an auditable event. This includes both the traditional .Ux security properties, such as user IDs and group IDs, but also audit information such as the audit user ID and session. A .Dq process token can be created using .Xr au_to_process32 3 or .Xr au_to_process64 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Audit ID 4 bytes Audit user ID" .It "Effective User ID 4 bytes Effective user ID" .It "Effective Group ID 4 bytes Effective group ID" .It "Real User ID 4 bytes Real user ID" .It "Real Group ID 4 bytes Real group ID" .It "Process ID 4 bytes Process ID" .It "Session ID 4 bytes Audit session ID" .It "Terminal Port ID 4/8 bytes Terminal port ID (32/64-bits)" .It "Terminal Machine Address 4 bytes IP address of machine" .El .Ss Expanded Process Token The .Dq expanded process token contains the contents of the .Dq process token, with the addition of a machine address type and variable length address storage capable of containing IPv6 addresses. An .Dq expanded process token can be created using .Xr au_to_process32_ex 3 or .Xr au_to_process64_ex 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Audit ID 4 bytes Audit user ID" .It "Effective User ID 4 bytes Effective user ID" .It "Effective Group ID 4 bytes Effective group ID" .It "Real User ID 4 bytes Real user ID" .It "Real Group ID 4 bytes Real group ID" .It "Process ID 4 bytes Process ID" .It "Session ID 4 bytes Audit session ID" .It "Terminal Port ID 4/8 bytes Terminal port ID (32/64-bits)" -.It "Terminal Address Type/Length 1 byte Length of machine address" +.It "Terminal Address Type/Length 4 bytes Length of machine address" .It "Terminal Machine Address 4 bytes IPv4 or IPv6 address of machine" .El .Ss Return Token The .Dq return token contains a system call or library function return condition, including return value and error number associated with the global variable .Er errno . A .Dq return token can be created using .Xr au_to_return32 3 or .Xr au_to_return64 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Error Number 1 byte Errno value, or 0 if undefined" .It "Return Value 4/8 bytes Return value (32/64-bits)" .El .Ss Subject Token The .Dq subject token contains information on the subject performing the operation described by an audit record, and includes similar information to that found in the .Dq process and .Dq expanded process tokens. However, those tokens are used where the process being described is the target of the operation, not the authorizing party. A .Dq subject token can be created using .Xr au_to_subject32 3 and .Xr au_to_subject64 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Audit ID 4 bytes Audit user ID" .It "Effective User ID 4 bytes Effective user ID" .It "Effective Group ID 4 bytes Effective group ID" .It "Real User ID 4 bytes Real user ID" .It "Real Group ID 4 bytes Real group ID" .It "Process ID 4 bytes Process ID" .It "Session ID 4 bytes Audit session ID" .It "Terminal Port ID 4/8 bytes Terminal port ID (32/64-bits)" .It "Terminal Machine Address 4 bytes IP address of machine" .El .Ss Expanded Subject Token The .Dq expanded subject token consists of the same elements as the .Dq subject token, with the addition of type/length and variable size machine address information in the terminal ID. An .Dq expanded subject token can be created using .Xr au_to_subject32_ex 3 or .Xr au_to_subject64_ex 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Audit ID 4 bytes Audit user ID" .It "Effective User ID 4 bytes Effective user ID" .It "Effective Group ID 4 bytes Effective group ID" .It "Real User ID 4 bytes Real user ID" .It "Real Group ID 4 bytes Real group ID" .It "Process ID 4 bytes Process ID" .It "Session ID 4 bytes Audit session ID" .It "Terminal Port ID 4/8 bytes Terminal port ID (32/64-bits)" .It "Terminal Address Type/Length 1 byte Length of machine address" .It "Terminal Machine Address 4 bytes IPv4 or IPv6 address of machine" .El .Ss System V IPC Token The .Dq System V IPC token contains the System V IPC message handle, semaphore handle or shared memory handle. A System V IPC token may be created using +.Xr au_to_ipc 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Object ID type 1 byte Object ID" .It "Object ID 4 bytes Object ID" .El .Ss Text Token The .Dq text token contains a single NUL-terminated text string. A .Dq text token may be created using .Xr au_to_text 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Text Length 2 bytes Length of text string including NUL" .It "Text N bytes + 1 NUL Text string including NUL" .El .Ss Attribute Token The .Dq attribute token describes the attributes of a file associated with the audit event. As files may be identified by 0, 1, or many path names, a path name is not included with the attribute block for a file; optional .Dq path tokens may also be present in an audit record indicating which path, if any, was used to reach the object. An .Dq attribute token can be created using .Xr au_to_attr32 3 or .Xr au_to_attr64 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "File Access Mode 1 byte mode_t associated with file" .It "Owner User ID 4 bytes uid_t associated with file" .It "Owner Group ID 4 bytes gid_t associated with file" .It "File System ID 4 bytes fsid_t associated with file" .It "File System Node ID 8 bytes ino_t associated with file" .It "Device 4/8 bytes Device major/minor number (32/64-bit)" .El .Ss Groups Token The .Dq groups token contains a list of group IDs associated with the audit event. A .Dq groups token can be created using .Xr au_to_groups 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Number of Groups 2 bytes Number of groups in token" .It "Group List N * 4 bytes List of N group IDs" .El .Ss System V IPC Permission Token The .Dq System V IPC permission token contains a System V IPC access permissions. A System V IPC permission token may be created using .Xr au_to_ipc_perm 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It Li "Owner user ID" Ta "4 bytes" Ta "User ID of IPC owner" .It Li "Owner group ID" Ta "4 bytes" Ta "Group ID of IPC owner" .It Li "Creator user ID" Ta "4 bytes" Ta "User ID of IPC creator" .It Li "Creator group ID" Ta "4 bytes" Ta "Group ID of IPC creator" .It Li "Access mode" Ta "4 bytes" Ta "Access mode" .It Li "Sequence number" Ta "4 bytes" Ta "Sequence number" .It Li "Key" Ta "4 bytes" Ta "IPC key" .El .Ss Arg Token The .Dq arg token contains information about arguments of the system call. Depending on the size of the desired argument value, an Arg token may be created using .Xr au_to_arg32 3 or .Xr au_to_arg64 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It Li "Argument ID" Ta "1 byte" Ta "Argument ID" .It Li "Argument value" Ta "4/8 bytes" Ta "Argument value" .It Li "Length" Ta "2 bytes" Ta "Length of the text" .It Li "Text" Ta "N bytes + 1 nul" Ta "The string including nul" .El .Ss exec_args Token The .Dq exec_args token contains information about arguments of the exec() system call. An exec_args token may be created using .Xr au_to_exec_args 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It Li "Count" Ta "4 bytes" Ta "Number of arguments" .It Li "Text" Ta "* bytes" Ta "Count nul-terminated strings" .El .Ss exec_env Token The .Dq exec_env token contains current environment variables to an exec() system call. An exec_args token may be created using .Xr au_to_exec_env 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It Li "Count ID" Ta "4 bytes" Ta "Number of variables" .It Li "Text" Ta "* bytes" Ta "Count nul-terminated strings" .El .Ss Exit Token The .Dq exit token contains process exit/return code information. An .Dq exit token can be created using .Xr au_to_exit 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Status 4 bytes Process status on exit" .It "Return Value 4 bytes Process return value on exit" .El .Ss Socket Token The .Dq socket token contains information about UNIX domain and Internet sockets. Each token has four or eight fields. Depending on the type of socket, a socket token may be created using .Xr au_to_sock_unix 3 , .Xr au_to_sock_inet32 3 or .Xr au_to_sock_inet128 3 . .Bl -column -offset 3n ".Sy Field Name Width XX" ".Sy XX Bytes XXXX" ".Sy Description" .It Sy "Field" Ta Sy Bytes Ta Sy Description .It Li "Token ID" Ta "1 byte" Ta "Token ID" .It Li "Socket family" Ta "2 bytes" Ta "Socket family" .It Li "Local port" Ta "2 bytes" Ta "Local port" .It Li "Socket address" Ta "4 bytes" Ta "Socket address" .El .Ss Expanded Socket Token The .Dq expanded socket token contains information about IPv4 and IPv6 sockets. A .Dq expanded socket token can be created using .Xr au_to_socket_ex 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It Li "Token ID" Ta "1 byte" Ta "Token ID" .It Li "Socket domain" Ta "2 bytes" Ta "Socket domain" .It Li "Socket type" Ta "2 bytes" Ta "Socket type" .It Li "Address type" Ta "2 byte" Ta "Address type (IPv4/IPv6)" .It Li "Local port" Ta "2 bytes" Ta "Local port" .It Li "Local IP address" Ta "4/16 bytes" Ta "Local IP address" .It Li "Remote port" Ta "2 bytes" Ta "Remote port" .It Li "Remote IP address" Ta "4/16 bytes" Ta "Remote IP address" .El .Ss Seq Token The .Dq seq token contains a unique and monotonically increasing audit event sequence ID. Due to the limited range of 32 bits, serial number arithmetic and caution should be used when comparing sequence numbers. .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Sequence Number 4 bytes Audit event sequence number" .El .Ss privilege Token The .Dq privilege token ... .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .El .Ss Use-of-auth Token The .Dq use-of-auth token ... .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .El .Ss Command Token The .Dq command token ... .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .El .Ss ACL Token The .Dq ACL token ... .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .El .Ss Zonename Token The .Dq zonename token holds a NUL-terminated string with the name of the zone or jail from which the record originated. A .Dq zonename token can be created using .Xr au_to_zonename 3 . .Bl -column -offset 3n ".No Terminal Address Type/Length" ".No N bytes + 1 NUL" .It Sy "Field Bytes Description" .It "Token ID 1 byte Token ID" .It "Zonename length 2 bytes Length of zonename string including NUL" .It "Zonename N bytes + 1 NUL Zonename string including NUL" .El .Sh SEE ALSO .Xr auditreduce 1 , .Xr praudit 1 , .Xr libbsm 3 , .Xr audit 4 , .Xr auditpipe 4 , .Xr audit 8 .Sh HISTORY The OpenBSM implementation was created by McAfee Research, the security division of McAfee Inc., under contract to Apple Computer Inc.\& in 2004. It was subsequently adopted by the TrustedBSD Project as the foundation for the OpenBSM distribution. .Sh AUTHORS The Basic Security Module (BSM) interface to audit records and audit event stream format were defined by Sun Microsystems. .Pp This manual page was written by .An Robert Watson Aq rwatson@FreeBSD.org . .Sh BUGS The .Dq How to print field in the .Dq arbitrary data token has undefined values. .Pp The .Dq in_addr and .Dq in_addr_ex token layout documented here appears to be in conflict with the .Xr libbsm 3 implementation of .Xr au_to_in_addr_ex 3 . diff --git a/contrib/openbsm/man/getaudit.2 b/contrib/openbsm/man/getaudit.2 index ae5843d45a25..8165c8819007 100644 --- a/contrib/openbsm/man/getaudit.2 +++ b/contrib/openbsm/man/getaudit.2 @@ -1,186 +1,187 @@ .\"- .\" Copyright (c) 2005 Robert N. M. Watson .\" Copyright (c) 2008 Apple Inc. .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" 1. Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. .\" .\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd October 19, 2008 +.Dd March 14, 2018 .Dt GETAUDIT 2 .Os .Sh NAME .Nm getaudit , .Nm getaudit_addr .Nd "retrieve audit session state" .Sh SYNOPSIS .In bsm/audit.h .Ft int .Fn getaudit "auditinfo_t *auditinfo" .Ft int .Fn getaudit_addr "auditinfo_addr_t *auditinfo_addr" "u_int length" .Sh DESCRIPTION The .Fn getaudit system call retrieves the active audit session state for the current process via the .Vt auditinfo_t pointed to by .Fa auditinfo . The .Fn getaudit_addr system call retrieves extended state via .Fa auditinfo_addr and .Fa length . .Pp The .Fa auditinfo_t data structure is defined as follows: .Bd -literal -offset indent struct auditinfo { au_id_t ai_auid; /* Audit user ID */ au_mask_t ai_mask; /* Audit masks */ au_tid_t ai_termid; /* Terminal ID */ au_asid_t ai_asid; /* Audit session ID */ + au_asflgs_t ai_flags; /* Audit session flags. */ }; typedef struct auditinfo auditinfo_t; .Ed .Pp The .Fa ai_auid variable contains the audit identifier which is recorded in the audit log for each event the process caused. .Pp The .Fa au_mask_t data structure defines the bit mask for auditing successful and failed events out of the predefined list of event classes. It is defined as follows: .Bd -literal -offset indent struct au_mask { unsigned int am_success; /* success bits */ unsigned int am_failure; /* failure bits */ }; typedef struct au_mask au_mask_t; .Ed .Pp The .Fa au_termid_t data structure defines the Terminal ID recorded with every event caused by the process. It is defined as follows: .Bd -literal -offset indent struct au_tid { dev_t port; u_int32_t machine; }; typedef struct au_tid au_tid_t; .Ed .Pp The .Fa ai_asid variable contains the audit session ID which is recorded with every event caused by the process. .Pp The .Fn getaudit_addr system call uses the expanded .Fa auditinfo_addr_t data structure and supports Terminal IDs with larger addresses such as those used in IP version 6. It is defined as follows: .Bd -literal -offset indent struct auditinfo_addr { au_id_t ai_auid; /* Audit user ID. */ au_mask_t ai_mask; /* Audit masks. */ au_tid_addr_t ai_termid; /* Terminal ID. */ au_asid_t ai_asid; /* Audit session ID. */ }; typedef struct auditinfo_addr auditinfo_addr_t; .Ed .Pp The .Fa au_tid_addr_t data structure which includes a larger address storage field and an additional field with the type of address stored: .Bd -literal -offset indent struct au_tid_addr { dev_t at_port; u_int32_t at_type; u_int32_t at_addr[4]; }; typedef struct au_tid_addr au_tid_addr_t; .Ed .Pp These system calls require an appropriate privilege to complete. .Sh RETURN VALUES .Rv -std getaudit getaudit_addr .Sh ERRORS The .Fn getaudit function will fail if: .Bl -tag -width Er .It Bq Er EFAULT A failure occurred while data transferred to or from the kernel failed. .It Bq Er EINVAL Illegal argument was passed by a system call. .It Bq Er EPERM The process does not have sufficient permission to complete the operation. .It Bq Er EOVERFLOW The .Fa length argument indicates an overflow condition will occur. .It Bq Er E2BIG The address is too big and, therefore, .Fn getaudit_addr should be used instead. .El .Sh SEE ALSO .Xr audit 2 , .Xr auditon 2 , .Xr getauid 2 , .Xr setaudit 2 , .Xr setauid 2 , .Xr libbsm 3 .Sh HISTORY The OpenBSM implementation was created by McAfee Research, the security division of McAfee Inc., under contract to Apple Computer Inc.\& in 2004. It was subsequently adopted by the TrustedBSD Project as the foundation for the OpenBSM distribution. .Sh AUTHORS .An -nosplit This software was created by McAfee Research, the security research division of McAfee, Inc., under contract to Apple Computer Inc. Additional authors include .An Wayne Salamon , .An Robert Watson , and SPARTA Inc. .Pp The Basic Security Module (BSM) interface to audit records and audit event stream format were defined by Sun Microsystems. .Pp This manual page was written by .An Robert Watson Aq rwatson@FreeBSD.org . diff --git a/contrib/openbsm/sys/bsm/audit.h b/contrib/openbsm/sys/bsm/audit.h index 73077b33bd53..26ac4cbf7584 100644 --- a/contrib/openbsm/sys/bsm/audit.h +++ b/contrib/openbsm/sys/bsm/audit.h @@ -1,343 +1,343 @@ /*- * Copyright (c) 2005-2009 Apple Inc. * Copyright (c) 2016 Robert N. M. Watson * All rights reserved. * * Portions of this software were developed by BAE Systems, the University of * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent * Computing (TC) research program. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _BSM_AUDIT_H #define _BSM_AUDIT_H #include #include #define AUDIT_RECORD_MAGIC 0x828a0f1b #define MAX_AUDIT_RECORDS 20 #define MAXAUDITDATA (0x8000 - 1) #define MAX_AUDIT_RECORD_SIZE MAXAUDITDATA #define MIN_AUDIT_FILE_SIZE (512 * 1024) /* - * Minimum noumber of free blocks on the filesystem containing the audit + * Minimum number of free blocks on the filesystem containing the audit * log necessary to avoid a hard log rotation. DO NOT SET THIS VALUE TO 0 * as the kernel does an unsigned compare, plus we want to leave a few blocks * free so userspace can terminate the log, etc. */ #define AUDIT_HARD_LIMIT_FREE_BLOCKS 4 /* * Triggers for the audit daemon. */ #define AUDIT_TRIGGER_MIN 1 #define AUDIT_TRIGGER_LOW_SPACE 1 /* Below low watermark. */ #define AUDIT_TRIGGER_ROTATE_KERNEL 2 /* Kernel requests rotate. */ #define AUDIT_TRIGGER_READ_FILE 3 /* Re-read config file. */ #define AUDIT_TRIGGER_CLOSE_AND_DIE 4 /* Terminate audit. */ #define AUDIT_TRIGGER_NO_SPACE 5 /* Below min free space. */ #define AUDIT_TRIGGER_ROTATE_USER 6 /* User requests rotate. */ #define AUDIT_TRIGGER_INITIALIZE 7 /* User initialize of auditd. */ #define AUDIT_TRIGGER_EXPIRE_TRAILS 8 /* User expiration of trails. */ #define AUDIT_TRIGGER_MAX 8 /* * The special device filename (FreeBSD). */ #define AUDITDEV_FILENAME "audit" #define AUDIT_TRIGGER_FILE ("/dev/" AUDITDEV_FILENAME) /* * Pre-defined audit IDs */ #define AU_DEFAUDITID (uid_t)(-1) #define AU_DEFAUDITSID 0 #define AU_ASSIGN_ASID -1 /* * IPC types. */ #define AT_IPC_MSG ((u_char)1) /* Message IPC id. */ #define AT_IPC_SEM ((u_char)2) /* Semaphore IPC id. */ #define AT_IPC_SHM ((u_char)3) /* Shared mem IPC id. */ /* * Audit conditions. */ #define AUC_UNSET 0 #define AUC_AUDITING 1 #define AUC_NOAUDIT 2 #define AUC_DISABLED -1 /* * auditon(2) commands. */ #define A_OLDGETPOLICY 2 #define A_OLDSETPOLICY 3 #define A_GETKMASK 4 #define A_SETKMASK 5 #define A_OLDGETQCTRL 6 #define A_OLDSETQCTRL 7 #define A_GETCWD 8 #define A_GETCAR 9 #define A_GETSTAT 12 #define A_SETSTAT 13 #define A_SETUMASK 14 #define A_SETSMASK 15 #define A_OLDGETCOND 20 #define A_OLDSETCOND 21 #define A_GETCLASS 22 #define A_SETCLASS 23 #define A_GETPINFO 24 #define A_SETPMASK 25 #define A_SETFSIZE 26 #define A_GETFSIZE 27 #define A_GETPINFO_ADDR 28 #define A_GETKAUDIT 29 #define A_SETKAUDIT 30 #define A_SENDTRIGGER 31 #define A_GETSINFO_ADDR 32 #define A_GETPOLICY 33 #define A_SETPOLICY 34 #define A_GETQCTRL 35 #define A_SETQCTRL 36 #define A_GETCOND 37 #define A_SETCOND 38 #define A_GETEVENT 39 /* Get audit event-to-name mapping. */ #define A_SETEVENT 40 /* Set audit event-to-name mapping. */ /* * Audit policy controls. */ #define AUDIT_CNT 0x0001 #define AUDIT_AHLT 0x0002 #define AUDIT_ARGV 0x0004 #define AUDIT_ARGE 0x0008 #define AUDIT_SEQ 0x0010 #define AUDIT_WINDATA 0x0020 #define AUDIT_USER 0x0040 #define AUDIT_GROUP 0x0080 #define AUDIT_TRAIL 0x0100 #define AUDIT_PATH 0x0200 #define AUDIT_SCNT 0x0400 #define AUDIT_PUBLIC 0x0800 #define AUDIT_ZONENAME 0x1000 #define AUDIT_PERZONE 0x2000 /* * Default audit queue control parameters. */ #define AQ_HIWATER 100 #define AQ_MAXHIGH 10000 #define AQ_LOWATER 10 #define AQ_BUFSZ MAXAUDITDATA #define AQ_MAXBUFSZ 1048576 /* * Default minimum percentage free space on file system. */ #define AU_FS_MINFREE 20 /* * Type definitions used indicating the length of variable length addresses * in tokens containing addresses, such as header fields. */ #define AU_IPv4 4 #define AU_IPv6 16 __BEGIN_DECLS typedef uid_t au_id_t; typedef pid_t au_asid_t; typedef u_int16_t au_event_t; typedef u_int16_t au_emod_t; typedef u_int32_t au_class_t; typedef u_int64_t au_asflgs_t __attribute__ ((aligned (8))); struct au_tid { dev_t port; u_int32_t machine; }; typedef struct au_tid au_tid_t; struct au_tid_addr { dev_t at_port; u_int32_t at_type; u_int32_t at_addr[4]; }; typedef struct au_tid_addr au_tid_addr_t; struct au_mask { unsigned int am_success; /* Success bits. */ unsigned int am_failure; /* Failure bits. */ }; typedef struct au_mask au_mask_t; struct auditinfo { au_id_t ai_auid; /* Audit user ID. */ au_mask_t ai_mask; /* Audit masks. */ au_tid_t ai_termid; /* Terminal ID. */ au_asid_t ai_asid; /* Audit session ID. */ }; typedef struct auditinfo auditinfo_t; struct auditinfo_addr { au_id_t ai_auid; /* Audit user ID. */ au_mask_t ai_mask; /* Audit masks. */ au_tid_addr_t ai_termid; /* Terminal ID. */ au_asid_t ai_asid; /* Audit session ID. */ au_asflgs_t ai_flags; /* Audit session flags. */ }; typedef struct auditinfo_addr auditinfo_addr_t; struct auditpinfo { pid_t ap_pid; /* ID of target process. */ au_id_t ap_auid; /* Audit user ID. */ au_mask_t ap_mask; /* Audit masks. */ au_tid_t ap_termid; /* Terminal ID. */ au_asid_t ap_asid; /* Audit session ID. */ }; typedef struct auditpinfo auditpinfo_t; struct auditpinfo_addr { pid_t ap_pid; /* ID of target process. */ au_id_t ap_auid; /* Audit user ID. */ au_mask_t ap_mask; /* Audit masks. */ au_tid_addr_t ap_termid; /* Terminal ID. */ au_asid_t ap_asid; /* Audit session ID. */ au_asflgs_t ap_flags; /* Audit session flags. */ }; typedef struct auditpinfo_addr auditpinfo_addr_t; struct au_session { auditinfo_addr_t *as_aia_p; /* Ptr to full audit info. */ au_mask_t as_mask; /* Process Audit Masks. */ }; typedef struct au_session au_session_t; /* * Contents of token_t are opaque outside of libbsm. */ typedef struct au_token token_t; /* * Kernel audit queue control parameters: * Default: Maximum: - * aq_hiwater: AQ_HIWATER (100) AQ_MAXHIGH (10000) + * aq_hiwater: AQ_HIWATER (100) AQ_MAXHIGH (10000) * aq_lowater: AQ_LOWATER (10) mach_port_name_t audit_session_self(void); au_asid_t audit_session_join(mach_port_name_t port); #endif /* __APPLE_API_PRIVATE */ #endif /* defined(_KERNEL) || defined(KERNEL) */ __END_DECLS #endif /* !_BSM_AUDIT_H */