/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 2019, Joyent, Inc. */ /* * auditconfig - set and display audit parameters */ #include <locale.h> #include <sys/types.h> #include <ctype.h> #include <stdlib.h> #include <stdarg.h> #include <unistd.h> #include <errno.h> #include <sys/param.h> #include <stdio.h> #include <string.h> #include <strings.h> #include <nlist.h> #include <fcntl.h> #include <sys/socket.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/mkdev.h> #include <sys/param.h> #include <pwd.h> #include <libintl.h> #include <zone.h> #include <libscf_priv.h> #include <tsol/label.h> #include <bsm/libbsm.h> #include <audit_policy.h> #include <audit_scf.h> enum commands { AC_ARG_ACONF, AC_ARG_AUDIT, AC_ARG_CHKACONF, AC_ARG_CHKCONF, AC_ARG_CONF, AC_ARG_GETASID, AC_ARG_GETAUDIT, AC_ARG_GETAUID, AC_ARG_GETCAR, AC_ARG_GETCLASS, AC_ARG_GETCOND, AC_ARG_GETCWD, AC_ARG_GETESTATE, AC_ARG_GETFLAGS, AC_ARG_GETKAUDIT, AC_ARG_GETKMASK, AC_ARG_GETNAFLAGS, AC_ARG_GETPINFO, AC_ARG_GETPLUGIN, AC_ARG_GETPOLICY, AC_ARG_GETQBUFSZ, AC_ARG_GETQCTRL, AC_ARG_GETQDELAY, AC_ARG_GETQHIWATER, AC_ARG_GETQLOWATER, AC_ARG_GETSTAT, AC_ARG_GETTERMID, AC_ARG_LSEVENT, AC_ARG_LSPOLICY, AC_ARG_SETASID, AC_ARG_SETAUDIT, AC_ARG_SETAUID, AC_ARG_SETCLASS, AC_ARG_SETFLAGS, AC_ARG_SETKAUDIT, AC_ARG_SETKMASK, AC_ARG_SETNAFLAGS, AC_ARG_SETPLUGIN, AC_ARG_SETPMASK, AC_ARG_SETPOLICY, AC_ARG_SETQBUFSZ, AC_ARG_SETQCTRL, AC_ARG_SETQDELAY, AC_ARG_SETQHIWATER, AC_ARG_SETQLOWATER, AC_ARG_SETSMASK, AC_ARG_SETSTAT, AC_ARG_SETUMASK, AC_ARG_SET_TEMPORARY }; #define AC_KERN_EVENT 0 #define AC_USER_EVENT 1 #define NONE(s) (!strlen(s) ? gettext("none") : s) #define ONEK 1024 /* * remove this after the audit.h is fixed */ struct arg_entry { char *arg_str; char *arg_opts; enum commands auditconfig_cmd; boolean_t temporary_allowed; /* -t allowed for the option */ }; typedef struct arg_entry arg_entry_t; /* arg_table - command option and usage message table */ static arg_entry_t arg_table[] = { { "-aconf", "", AC_ARG_ACONF, B_FALSE}, { "-audit", " event sorf retval string", AC_ARG_AUDIT, B_FALSE}, { "-chkaconf", "", AC_ARG_CHKACONF, B_FALSE}, { "-chkconf", "", AC_ARG_CHKCONF, B_FALSE}, { "-conf", "", AC_ARG_CONF, B_FALSE}, { "-getasid", "", AC_ARG_GETASID, B_FALSE}, { "-getaudit", "", AC_ARG_GETAUDIT, B_FALSE}, { "-getauid", "", AC_ARG_GETAUID, B_FALSE}, { "-getcar", "", AC_ARG_GETCAR, B_FALSE}, { "-getclass", " event", AC_ARG_GETCLASS, B_FALSE}, { "-getcond", "", AC_ARG_GETCOND, B_FALSE}, { "-getcwd", "", AC_ARG_GETCWD, B_FALSE}, { "-getestate", " event", AC_ARG_GETESTATE, B_FALSE}, { "-getflags", "", AC_ARG_GETFLAGS, B_FALSE}, { "-getkaudit", "", AC_ARG_GETKAUDIT, B_FALSE}, { "-getkmask", "", AC_ARG_GETKMASK, B_FALSE}, { "-getnaflags", "", AC_ARG_GETNAFLAGS, B_FALSE}, { "-getpinfo", " pid", AC_ARG_GETPINFO, B_FALSE}, { "-getplugin", " [plugin]", AC_ARG_GETPLUGIN, B_FALSE}, { "-getpolicy", "", AC_ARG_GETPOLICY, B_TRUE}, { "-getqbufsz", "", AC_ARG_GETQBUFSZ, B_TRUE}, { "-getqctrl", "", AC_ARG_GETQCTRL, B_TRUE}, { "-getqdelay", "", AC_ARG_GETQDELAY, B_TRUE}, { "-getqhiwater", "", AC_ARG_GETQHIWATER, B_TRUE}, { "-getqlowater", "", AC_ARG_GETQLOWATER, B_TRUE}, { "-getstat", "", AC_ARG_GETSTAT, B_FALSE}, { "-gettid", "", AC_ARG_GETTERMID, B_FALSE}, { "-lsevent", "", AC_ARG_LSEVENT, B_FALSE}, { "-lspolicy", "", AC_ARG_LSPOLICY, B_FALSE}, { "-setasid", " asid [cmd]", AC_ARG_SETASID, B_FALSE}, { "-setaudit", " auid audit_flags termid asid [cmd]", AC_ARG_SETAUDIT, B_FALSE}, { "-setauid", " auid [cmd]", AC_ARG_SETAUID, B_FALSE}, { "-setclass", " event audit_flags", AC_ARG_SETCLASS, B_FALSE}, { "-setflags", " audit_flags", AC_ARG_SETFLAGS, B_FALSE}, { "-setkaudit", " type IP_address", AC_ARG_SETKAUDIT, B_FALSE}, { "-setkmask", " audit_flags", AC_ARG_SETKMASK, B_FALSE}, { "-setnaflags", " audit_naflags", AC_ARG_SETNAFLAGS, B_FALSE}, { "-setplugin", " name active|inactive [attributes [qsize]]", AC_ARG_SETPLUGIN, B_FALSE}, { "-setpmask", " pid audit_flags", AC_ARG_SETPMASK, B_FALSE}, { "-setpolicy", " [+|-]policy_flags", AC_ARG_SETPOLICY, B_TRUE}, { "-setqbufsz", " bufsz", AC_ARG_SETQBUFSZ, B_TRUE}, { "-setqctrl", " hiwater lowater bufsz delay", AC_ARG_SETQCTRL, B_TRUE}, { "-setqdelay", " delay", AC_ARG_SETQDELAY, B_TRUE}, { "-setqhiwater", " hiwater", AC_ARG_SETQHIWATER, B_TRUE}, { "-setqlowater", " lowater", AC_ARG_SETQLOWATER, B_TRUE}, { "-setsmask", " asid audit_flags", AC_ARG_SETSMASK, B_FALSE}, { "-setstat", "", AC_ARG_SETSTAT, B_FALSE}, { "-setumask", " user audit_flags", AC_ARG_SETUMASK, B_FALSE}, { "-t", "", AC_ARG_SET_TEMPORARY, B_FALSE}, }; #define ARG_TBL_SZ (sizeof (arg_table) / sizeof (arg_entry_t)) char *progname = "auditconfig"; /* * temporary_set true to get/set only kernel settings, * false to get/set kernel settings and service properties */ static boolean_t temporary_set = B_FALSE; static au_event_ent_t *egetauevnam(char *event_name); static au_event_ent_t *egetauevnum(au_event_t event_number); static int arg_ent_compare(const void *aep1, const void *aep2); static char *cond2str(void); static int policy2str(uint32_t policy, char *policy_str, size_t len); static int str2type(char *s, uint_t *type); static int str2policy(char *policy_str, uint32_t *policy_mask); static int str2ipaddr(char *s, uint32_t *addr, uint32_t type); static int strisipaddr(char *s); static int strisnum(char *s); static arg_entry_t *get_arg_ent(char *arg_str); static uid_t get_user_id(char *user); static void chk_arg_len(char *argv, uint_t len); static void chk_event_num(int etype, au_event_t event); static void chk_event_str(int etype, char *event_str); static void chk_known_plugin(char *plugin_str); static void chk_retval(char *retval_str); static void chk_sorf(char *sorf_str); static void do_aconf(void); static void do_args(char **argv, au_mask_t *mask); static void do_audit(char *, char, int, char *); static void do_chkaconf(void); static void do_chkconf(void); static void do_conf(void); static void do_getasid(void); static void do_getaudit(void); static void do_getkaudit(void); static void do_setkaudit(char *t, char *s); static void do_getauid(void); static void do_getcar(void); static void do_getclass(char *event_str); static void do_getcond(void); static void do_getcwd(void); static void do_getflags(void); static void do_getkmask(void); static void do_getnaflags(void); static void do_getpinfo(char *pid_str); static void do_getplugin(char *plugin_str); static void do_getpolicy(void); static void do_getqbufsz(void); static void do_getqctrl(void); static void do_getqdelay(void); static void do_getqhiwater(void); static void do_getqlowater(void); static void do_getstat(void); static void do_gettermid(void); static void do_lsevent(void); static void do_lspolicy(void); static void do_setasid(char *sid_str, char **argv); static void do_setaudit(char *user_str, char *mask_str, char *tid_str, char *sid_str, char **argv); static void do_setauid(char *user, char **argv); static void do_setclass(char *event_str, au_mask_t *mask); static void do_setflags(char *audit_flags, au_mask_t *amask); static void do_setkmask(au_mask_t *pmask); static void do_setnaflags(char *audit_naflags, au_mask_t *namask); static void do_setpmask(char *pid_str, au_mask_t *mask); static void do_setsmask(char *asid_str, au_mask_t *mask); static void do_setumask(char *auid_str, au_mask_t *mask); static void do_setplugin(char *plugin_str, boolean_t plugin_state, char *plugin_attr, int plugin_qsize); static void do_setpolicy(char *policy_str); static void do_setqbufsz(char *bufsz); static void do_setqctrl(char *hiwater, char *lowater, char *bufsz, char *delay); static void do_setqdelay(char *delay); static void do_setqhiwater(char *hiwater); static void do_setqlowater(char *lowater); static void do_setstat(void); static void str2tid(char *tid_str, au_tid_addr_t *tp); static void eauditon(int cmd, caddr_t data, int length); static void echkflags(char *auditflags, au_mask_t *mask); static void egetaudit(auditinfo_addr_t *ai, int size); static void egetauditflagsbin(char *auditflags, au_mask_t *pmask); static void egetauid(au_id_t *auid); static void egetkaudit(auditinfo_addr_t *ai, int size); static void esetaudit(auditinfo_addr_t *ai, int size); static void esetauid(au_id_t *auid); static void esetkaudit(auditinfo_addr_t *ai, int size); static void execit(char **argv); static void exit_error(char *fmt, ...); static void exit_usage(int status); static void parse_args(int argc, char **argv, au_mask_t *mask); static void print_asid(au_asid_t asid); static void print_auid(au_id_t auid); static void print_mask(char *desc, au_mask_t *pmp); static void print_plugin(char *plugin_name, kva_t *plugin_kva); static void print_tid_ex(au_tid_addr_t *tidp); #if !defined(TEXT_DOMAIN) #define TEXT_DOMAIN "SUNW_OST_OSCMD" #endif int main(int argc, char **argv) { au_mask_t mask; /* for options manipulating flags */ (void) setlocale(LC_ALL, ""); (void) textdomain(TEXT_DOMAIN); if (argc == 1) { exit_usage(0); } if (argc == 2 && (argv[1][0] == '?' || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "-?") == 0)) { exit_usage(0); } parse_args(argc, argv, &mask); do_args(argv, &mask); return (0); } /* * parse_args() * Desc: Checks command line argument syntax. * Inputs: Command line argv; * Returns: If a syntax error is detected, a usage message is printed * and exit() is called. If a syntax error is not detected, * parse_args() returns without a value. */ static void parse_args(int argc, char **argv, au_mask_t *mask) { arg_entry_t *ae; uint_t type; uint_t addr[4]; for (++argv; *argv; argv++) { if ((ae = get_arg_ent(*argv)) == NULL) { exit_usage(1); } switch (ae->auditconfig_cmd) { case AC_ARG_AUDIT: ++argv; if (!*argv) exit_usage(1); if (strisnum(*argv)) { chk_event_num(AC_USER_EVENT, (au_event_t)atol(*argv)); } else { chk_event_str(AC_USER_EVENT, *argv); } ++argv; if (!*argv) exit_usage(1); chk_sorf(*argv); ++argv; if (!*argv) exit_usage(1); chk_retval(*argv); ++argv; if (!*argv) exit_usage(1); break; case AC_ARG_CHKCONF: case AC_ARG_CONF: case AC_ARG_ACONF: case AC_ARG_CHKACONF: case AC_ARG_GETASID: case AC_ARG_GETAUID: case AC_ARG_GETAUDIT: case AC_ARG_GETKAUDIT: break; case AC_ARG_GETCLASS: case AC_ARG_GETESTATE: ++argv; if (!*argv) exit_usage(1); if (strisnum(*argv)) { chk_event_num(AC_KERN_EVENT, (au_event_t)atol(*argv)); } else { chk_event_str(AC_KERN_EVENT, *argv); } break; case AC_ARG_GETCAR: case AC_ARG_GETCOND: case AC_ARG_GETCWD: case AC_ARG_GETFLAGS: case AC_ARG_GETKMASK: case AC_ARG_GETNAFLAGS: break; case AC_ARG_GETPLUGIN: if (*++argv == NULL) { --argv; break; } if (get_arg_ent(*argv) != NULL) { --argv; } else { chk_arg_len(*argv, PLUGIN_MAXBUF); chk_known_plugin(*argv); } break; case AC_ARG_GETPOLICY: case AC_ARG_GETQBUFSZ: case AC_ARG_GETQCTRL: case AC_ARG_GETQDELAY: case AC_ARG_GETQHIWATER: case AC_ARG_GETQLOWATER: case AC_ARG_GETSTAT: case AC_ARG_GETTERMID: case AC_ARG_LSEVENT: case AC_ARG_LSPOLICY: break; case AC_ARG_SETASID: case AC_ARG_SETAUID: case AC_ARG_SETAUDIT: ++argv; if (!*argv) exit_usage(1); while (*argv) ++argv; --argv; break; case AC_ARG_SETKAUDIT: ++argv; if (!*argv) exit_usage(1); if (str2type (*argv, &type)) exit_error(gettext( "Invalid IP address type specified.")); ++argv; if (!*argv) exit_usage(1); if (str2ipaddr(*argv, addr, type)) exit_error( gettext("Invalid IP address specified.")); break; case AC_ARG_SETCLASS: ++argv; if (!*argv) exit_usage(1); if (strisnum(*argv)) chk_event_num(AC_KERN_EVENT, (au_event_t)atol(*argv)); else chk_event_str(AC_KERN_EVENT, *argv); ++argv; if (!*argv) exit_usage(1); echkflags(*argv, mask); break; case AC_ARG_SETFLAGS: ++argv; if (!*argv) exit_usage(1); chk_arg_len(*argv, PRESELECTION_MAXBUF); echkflags(*argv, mask); break; case AC_ARG_SETKMASK: ++argv; if (!*argv) exit_usage(1); echkflags(*argv, mask); break; case AC_ARG_SETNAFLAGS: ++argv; if (!*argv) exit_usage(1); chk_arg_len(*argv, PRESELECTION_MAXBUF); echkflags(*argv, mask); break; case AC_ARG_SETPLUGIN: if (*++argv == NULL || get_arg_ent(*argv) != NULL) { exit_usage(1); } chk_known_plugin(*argv); chk_arg_len(*argv, PLUGIN_MAXBUF); if (*++argv == NULL || strcmp(*argv, "active") != 0 && strcmp(*argv, "inactive") != 0) { exit_usage(1); } if (*++argv == NULL || get_arg_ent(*argv) != NULL) { --argv; break; } chk_arg_len(*argv, PLUGIN_MAXATT); if (*++argv == NULL || get_arg_ent(*argv) != NULL) { --argv; break; } if (atoi(*argv) < 0) { exit_error(gettext("Incorrect qsize specified " "(%s)."), *argv); } break; case AC_ARG_SETPOLICY: ++argv; if (!*argv) exit_usage(1); break; case AC_ARG_SETSTAT: break; case AC_ARG_GETPINFO: ++argv; if (!*argv) exit_usage(1); break; case AC_ARG_SETPMASK: ++argv; if (!*argv) exit_usage(1); ++argv; if (!*argv) exit_usage(1); echkflags(*argv, mask); break; case AC_ARG_SETQBUFSZ: ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) exit_error(gettext("Invalid bufsz specified.")); break; case AC_ARG_SETQCTRL: ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) exit_error( gettext("Invalid hiwater specified.")); ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) exit_error( gettext("Invalid lowater specified.")); ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) exit_error(gettext("Invalid bufsz specified.")); ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) exit_error(gettext("Invalid delay specified.")); break; case AC_ARG_SETQDELAY: ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) exit_error(gettext("Invalid delay specified.")); break; case AC_ARG_SETQHIWATER: ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) { exit_error( gettext("Invalid hiwater specified.")); } break; case AC_ARG_SETQLOWATER: ++argv; if (!*argv) exit_usage(1); if (!strisnum(*argv)) { exit_error( gettext("Invalid lowater specified.")); } break; case AC_ARG_SETSMASK: case AC_ARG_SETUMASK: ++argv; if (!*argv) exit_usage(1); ++argv; if (!*argv) exit_usage(1); echkflags(*argv, mask); break; case AC_ARG_SET_TEMPORARY: /* Do not accept single -t option. */ if (argc == 2) { exit_error( gettext("Only the -t option specified " "(it is not a standalone option).")); } temporary_set = B_TRUE; break; default: exit_error(gettext("Internal error #1.")); break; } } } /* * do_args() - do command line arguments in the order in which they appear. * Function return values returned by the underlying functions; the semantics * they should follow is to return B_TRUE on successful execution, B_FALSE * otherwise. */ static void do_args(char **argv, au_mask_t *mask) { arg_entry_t *ae; for (++argv; *argv; argv++) { ae = get_arg_ent(*argv); switch (ae->auditconfig_cmd) { case AC_ARG_AUDIT: { char sorf; int retval; char *event_name; char *audit_str; ++argv; event_name = *argv; ++argv; sorf = (char)atoi(*argv); ++argv; retval = atoi(*argv); ++argv; audit_str = *argv; do_audit(event_name, sorf, retval, audit_str); } break; case AC_ARG_CHKCONF: do_chkconf(); break; case AC_ARG_CONF: do_conf(); break; case AC_ARG_CHKACONF: do_chkaconf(); break; case AC_ARG_ACONF: do_aconf(); break; case AC_ARG_GETASID: do_getasid(); break; case AC_ARG_GETAUID: do_getauid(); break; case AC_ARG_GETAUDIT: do_getaudit(); break; case AC_ARG_GETKAUDIT: do_getkaudit(); break; case AC_ARG_GETCLASS: case AC_ARG_GETESTATE: ++argv; do_getclass(*argv); break; case AC_ARG_GETCAR: do_getcar(); break; case AC_ARG_GETCOND: do_getcond(); break; case AC_ARG_GETCWD: do_getcwd(); break; case AC_ARG_GETFLAGS: do_getflags(); break; case AC_ARG_GETKMASK: do_getkmask(); break; case AC_ARG_GETNAFLAGS: do_getnaflags(); break; case AC_ARG_GETPLUGIN: { char *plugin_str = NULL; ++argv; if (*argv != NULL) { if (get_arg_ent(*argv) != NULL) { --argv; } else { plugin_str = *argv; } } else { --argv; } do_getplugin(plugin_str); } break; case AC_ARG_GETPOLICY: do_getpolicy(); break; case AC_ARG_GETQBUFSZ: do_getqbufsz(); break; case AC_ARG_GETQCTRL: do_getqctrl(); break; case AC_ARG_GETQDELAY: do_getqdelay(); break; case AC_ARG_GETQHIWATER: do_getqhiwater(); break; case AC_ARG_GETQLOWATER: do_getqlowater(); break; case AC_ARG_GETSTAT: do_getstat(); break; case AC_ARG_GETTERMID: do_gettermid(); break; case AC_ARG_LSEVENT: do_lsevent(); break; case AC_ARG_LSPOLICY: do_lspolicy(); break; case AC_ARG_SETASID: { char *sid_str; ++argv; sid_str = *argv; ++argv; do_setasid(sid_str, argv); } break; case AC_ARG_SETAUID: { char *user; ++argv; user = *argv; ++argv; do_setauid(user, argv); } break; case AC_ARG_SETAUDIT: { char *user_str; char *mask_str; char *tid_str; char *sid_str; ++argv; user_str = *argv; ++argv; mask_str = *argv; ++argv; tid_str = *argv; ++argv; sid_str = *argv; ++argv; do_setaudit(user_str, mask_str, tid_str, sid_str, argv); } break; case AC_ARG_SETKAUDIT: { char *address_type, *address; ++argv; address_type = *argv; ++argv; address = *argv; do_setkaudit(address_type, address); } break; case AC_ARG_SETCLASS: { char *event_str; ++argv; event_str = *argv; do_setclass(event_str, mask); ++argv; } break; case AC_ARG_SETFLAGS: ++argv; do_setflags(*argv, mask); break; case AC_ARG_SETKMASK: ++argv; do_setkmask(mask); break; case AC_ARG_SETNAFLAGS: ++argv; do_setnaflags(*argv, mask); break; case AC_ARG_SETPLUGIN: { char *plugin_str = NULL; boolean_t plugin_state = B_FALSE; char *plugin_att = NULL; int plugin_qsize = -1; plugin_str = *++argv; if (strcmp(*++argv, "active") == 0) { plugin_state = B_TRUE; } if (*++argv != NULL && get_arg_ent(*argv) == NULL) { plugin_att = *argv; if (*++argv != NULL && get_arg_ent(*argv) == NULL) { plugin_qsize = atoi(*argv); } else { --argv; } } else { --argv; } do_setplugin(plugin_str, plugin_state, plugin_att, plugin_qsize); } break; case AC_ARG_SETPOLICY: ++argv; do_setpolicy(*argv); break; case AC_ARG_GETPINFO: { char *pid_str; ++argv; pid_str = *argv; do_getpinfo(pid_str); } break; case AC_ARG_SETPMASK: { char *pid_str; ++argv; pid_str = *argv; do_setpmask(pid_str, mask); ++argv; } break; case AC_ARG_SETSTAT: do_setstat(); break; case AC_ARG_SETQBUFSZ: ++argv; do_setqbufsz(*argv); break; case AC_ARG_SETQCTRL: { char *hiwater, *lowater, *bufsz, *delay; ++argv; hiwater = *argv; ++argv; lowater = *argv; ++argv; bufsz = *argv; ++argv; delay = *argv; do_setqctrl(hiwater, lowater, bufsz, delay); } break; case AC_ARG_SETQDELAY: ++argv; do_setqdelay(*argv); break; case AC_ARG_SETQHIWATER: ++argv; do_setqhiwater(*argv); break; case AC_ARG_SETQLOWATER: ++argv; do_setqlowater(*argv); break; case AC_ARG_SETSMASK: { char *asid_str; ++argv; asid_str = *argv; do_setsmask(asid_str, mask); ++argv; } break; case AC_ARG_SETUMASK: { char *auid_str; ++argv; auid_str = *argv; do_setumask(auid_str, mask); ++argv; } break; case AC_ARG_SET_TEMPORARY: break; default: exit_error(gettext("Internal error #2.")); break; } } } /* * do_chkconf() - the returned value is for the global zone unless AUDIT_PERZONE * is set. */ static void do_chkconf(void) { register au_event_ent_t *evp; au_mask_t pmask; char conf_aflags[256]; char run_aflags[256]; au_stat_t as; int class; int len; struct au_evclass_map cmap; pmask.am_success = pmask.am_failure = 0; eauditon(A_GETSTAT, (caddr_t)&as, 0); setauevent(); if (getauevent() == NULL) { exit_error(gettext("NO AUDIT EVENTS: Could not read %s\n."), AUDITEVENTFILE); } setauevent(); while ((evp = getauevent()) != NULL) { cmap.ec_number = evp->ae_number; len = sizeof (struct au_evclass_map); if (evp->ae_number <= as.as_numevent) { if (auditon(A_GETCLASS, (caddr_t)&cmap, len) == -1) { (void) printf("%s(%hu):%s", evp->ae_name, evp->ae_number, gettext("UNKNOWN EVENT: Could not get " "class for event. Configuration may " "be bad.\n")); } else { class = cmap.ec_class; if (class != evp->ae_class) { conf_aflags[0] = run_aflags[0] = '\0'; pmask.am_success = class; pmask.am_failure = class; (void) getauditflagschar(run_aflags, &pmask, 0); pmask.am_success = evp->ae_class; pmask.am_failure = evp->ae_class; (void) getauditflagschar(conf_aflags, &pmask, 0); (void) printf(gettext( "%s(%hu): CLASS MISMATCH: " "runtime class (%s) != " "configured class (%s)\n"), evp->ae_name, evp->ae_number, NONE(run_aflags), NONE(conf_aflags)); } } } } endauevent(); } /* * do_conf() - configure the kernel events. The value returned to the user is * for the global zone unless AUDIT_PERZONE is set. */ static void do_conf(void) { register au_event_ent_t *evp; register int i; au_evclass_map_t ec; au_stat_t as; eauditon(A_GETSTAT, (caddr_t)&as, 0); i = 0; setauevent(); while ((evp = getauevent()) != NULL) { if (evp->ae_number <= as.as_numevent) { ++i; ec.ec_number = evp->ae_number; ec.ec_class = evp->ae_class; eauditon(A_SETCLASS, (caddr_t)&ec, sizeof (ec)); } } endauevent(); (void) printf(gettext("Configured %d kernel events.\n"), i); } /* * do_chkaconf() - report a mismatch if the runtime class mask of a kernel audit * event does not match the configured class mask. The value returned to the * user is for the global zone unless AUDIT_PERZONE is set. */ static void do_chkaconf(void) { char *namask_cfg; au_mask_t pmask, kmask; if (!do_getnaflags_scf(&namask_cfg) || namask_cfg == NULL) { exit_error(gettext("Could not get configured value.")); } egetauditflagsbin(namask_cfg, &pmask); eauditon(A_GETKMASK, (caddr_t)&kmask, sizeof (kmask)); if ((pmask.am_success != kmask.am_success) || (pmask.am_failure != kmask.am_failure)) { char kbuf[2048]; if (getauditflagschar(kbuf, &kmask, 0) < 0) { free(namask_cfg); (void) fprintf(stderr, gettext("bad kernel non-attributable mask\n")); exit(1); } (void) printf( gettext("non-attributable event flags mismatch:\n")); (void) printf(gettext("active non-attributable audit flags " "= %s\n"), kbuf); (void) printf(gettext("configured non-attributable audit flags " "= %s\n"), namask_cfg); } free(namask_cfg); } /* * do_aconf - configures the non-attributable events. The value returned to the * user is for the global zone unless AUDIT_PERZONE is set. */ static void do_aconf(void) { au_mask_t namask; char *namask_cfg; if (!do_getnaflags_scf(&namask_cfg) || namask_cfg == NULL) { exit_error(gettext("Could not get configured value.")); } egetauditflagsbin(namask_cfg, &namask); free(namask_cfg); eauditon(A_SETKMASK, (caddr_t)&namask, sizeof (namask)); (void) printf(gettext("Configured non-attributable event mask.\n")); } /* * do_audit() - construct an audit record for audit event event using the * process's audit characteristics containing a text token string audit_str. The * return token is constructed from the success/failure flag sort. Returned * value retval is an errno value. */ static void do_audit(char *event, char sorf, int retval, char *audit_str) { int rtn; int rd; au_event_t event_num; au_event_ent_t *evp; auditinfo_addr_t ai; token_t *tokp; egetaudit(&ai, sizeof (ai)); if (strisnum(event)) { event_num = (au_event_t)atoi(event); evp = egetauevnum(event_num); } else { evp = egetauevnam(event); } rtn = au_preselect(evp->ae_number, &ai.ai_mask, (int)sorf, AU_PRS_USECACHE); if (rtn == -1) { exit_error("%s\n%s %hu\n", gettext("Check audit event configuration."), gettext("Could not get audit class for event number"), evp->ae_number); } /* record is preselected */ if (rtn == 1) { if ((rd = au_open()) == -1) { exit_error(gettext( "Could not get and audit record descriptor\n")); } if ((tokp = au_to_me()) == NULL) { exit_error( gettext("Could not allocate subject token\n")); } if (au_write(rd, tokp) == -1) { exit_error(gettext("Could not construct subject token " "of audit record\n")); } if (is_system_labeled()) { if ((tokp = au_to_mylabel()) == NULL) { exit_error(gettext( "Could not allocate label token\n")); } if (au_write(rd, tokp) == -1) { exit_error(gettext("Could not " "construct label token of audit record\n")); } } if ((tokp = au_to_text(audit_str)) == NULL) exit_error(gettext("Could not allocate text token\n")); if (au_write(rd, tokp) == -1) exit_error(gettext("Could not construct text token of " "audit record\n")); #ifdef _LP64 if ((tokp = au_to_return64(sorf, retval)) == NULL) #else if ((tokp = au_to_return32(sorf, retval)) == NULL) #endif exit_error( gettext("Could not allocate return token\n")); if (au_write(rd, tokp) == -1) { exit_error(gettext("Could not construct return token " "of audit record\n")); } if (au_close(rd, 1, evp->ae_number) == -1) { exit_error( gettext("Could not write audit record: %s\n"), strerror(errno)); } } } /* * do_getauid() - print the audit id of the current process. */ static void do_getauid(void) { au_id_t auid; egetauid(&auid); print_auid(auid); } /* * do_getaudit() - print the audit characteristics of the current process. */ static void do_getaudit(void) { auditinfo_addr_t ai; egetaudit(&ai, sizeof (ai)); print_auid(ai.ai_auid); print_mask(gettext("process preselection mask"), &ai.ai_mask); print_tid_ex(&ai.ai_termid); print_asid(ai.ai_asid); } /* * do_getkaudit() - print the audit characteristics of the current zone. */ static void do_getkaudit(void) { auditinfo_addr_t ai; egetkaudit(&ai, sizeof (ai)); print_auid(ai.ai_auid); print_mask(gettext("process preselection mask"), &ai.ai_mask); print_tid_ex(&ai.ai_termid); print_asid(ai.ai_asid); } /* * do_setkaudit() - set IP address_type/address of machine to specified values; * valid per zone if AUDIT_PERZONE is set, else only in global zone. */ static void do_setkaudit(char *t, char *s) { uint_t type; auditinfo_addr_t ai; egetkaudit(&ai, sizeof (ai)); (void) str2type(t, &type); (void) str2ipaddr(s, &ai.ai_termid.at_addr[0], type); ai.ai_termid.at_type = type; esetkaudit(&ai, sizeof (ai)); } /* * do_getcar() - print the zone-relative root */ static void do_getcar(void) { char path[MAXPATHLEN]; eauditon(A_GETCAR, (caddr_t)path, sizeof (path)); (void) printf(gettext("current active root = %s\n"), path); } /* * do_getclass() - print the preselection mask associated with the specified * kernel audit event. The displayed value is for the global zone unless * AUDIT_PERZONE is set. */ static void do_getclass(char *event_str) { au_evclass_map_t ec; au_event_ent_t *evp; au_event_t event_number; char *event_name; if (strisnum(event_str)) { event_number = atol(event_str); if ((evp = egetauevnum(event_number)) != NULL) { event_number = evp->ae_number; event_name = evp->ae_name; } else { event_name = gettext("unknown"); } } else { event_name = event_str; if ((evp = egetauevnam(event_str)) != NULL) { event_number = evp->ae_number; } } ec.ec_number = event_number; eauditon(A_GETCLASS, (caddr_t)&ec, 0); (void) printf(gettext("audit class mask for event %s(%hu) = 0x%x\n"), event_name, event_number, ec.ec_class); } /* * do_getcond() - the printed value is for the global zone unless * AUDIT_PERZONE is set. (AUC_DISABLED is always global, the other states are * per zone if AUDIT_PERZONE is set) */ static void do_getcond(void) { (void) printf(gettext("audit condition = %s\n"), cond2str()); } /* * do_getcwd() - the printed path is relative to the current zone root */ static void do_getcwd(void) { char path[MAXPATHLEN]; eauditon(A_GETCWD, (caddr_t)path, sizeof (path)); (void) printf(gettext("current working directory = %s\n"), path); } /* * do_getflags() - the printed value is for the global zone unless AUDIT_PERZONE * is set. */ static void do_getflags(void) { au_mask_t amask; char *amask_cfg; eauditon(A_GETAMASK, (caddr_t)&amask, sizeof (amask)); print_mask(gettext("active user default audit flags"), &amask); if (!do_getflags_scf(&amask_cfg) || amask_cfg == NULL) { exit_error(gettext("Could not get configured value.")); } egetauditflagsbin(amask_cfg, &amask); print_mask(gettext("configured user default audit flags"), &amask); free(amask_cfg); } /* * do_getkmask() - the printed value is for the global zone unless AUDIT_PERZONE * is set. */ static void do_getkmask(void) { au_mask_t pmask; eauditon(A_GETKMASK, (caddr_t)&pmask, sizeof (pmask)); print_mask(gettext("active non-attributable audit flags"), &pmask); } /* * do_getnaflags() - the printed value is for the global zone unless * AUDIT_PERZONE is set. */ static void do_getnaflags(void) { au_mask_t namask; char *namask_cfg; eauditon(A_GETKMASK, (caddr_t)&namask, sizeof (namask)); print_mask(gettext("active non-attributable audit flags"), &namask); if (!do_getnaflags_scf(&namask_cfg) || namask_cfg == NULL) { exit_error(gettext("Could not get configured value.")); } egetauditflagsbin(namask_cfg, &namask); print_mask(gettext("configured non-attributable audit flags"), &namask); free(namask_cfg); } /* * do_getpolicy() - print active and configured kernel audit policy relative to * the current zone. */ static void do_getpolicy(void) { char policy_str[1024]; uint32_t policy; if (!temporary_set) { if (!do_getpolicy_scf(&policy)) { exit_error(gettext("Could not get configured values.")); } (void) policy2str(policy, policy_str, sizeof (policy_str)); (void) printf(gettext("configured audit policies = %s\n"), policy_str); } eauditon(A_GETPOLICY, (caddr_t)&policy, 0); (void) policy2str(policy, policy_str, sizeof (policy_str)); (void) printf(gettext("active audit policies = %s\n"), policy_str); } /* * do_getpinfo() - print the audit ID, preselection mask, terminal ID, and * audit session ID for the specified process. */ static void do_getpinfo(char *pid_str) { struct auditpinfo_addr ap; if (strisnum(pid_str)) ap.ap_pid = (pid_t)atoi(pid_str); else exit_usage(1); eauditon(A_GETPINFO_ADDR, (caddr_t)&ap, sizeof (ap)); print_auid(ap.ap_auid); print_mask(gettext("process preselection mask"), &(ap.ap_mask)); print_tid_ex(&(ap.ap_termid)); print_asid(ap.ap_asid); } /* * do_getplugin() - print plugin configuration. */ static void do_getplugin(char *plugin_str) { scf_plugin_kva_node_t *plugin_kva_ll; scf_plugin_kva_node_t *plugin_kva_ll_head; if (!do_getpluginconfig_scf(plugin_str, &plugin_kva_ll)) { exit_error(gettext("Could not get plugin configuration.")); } plugin_kva_ll_head = plugin_kva_ll; while (plugin_kva_ll != NULL) { print_plugin(plugin_kva_ll->plugin_name, plugin_kva_ll->plugin_kva); plugin_kva_ll = plugin_kva_ll->next; if (plugin_kva_ll != NULL) { (void) printf("\n"); } } plugin_kva_ll_free(plugin_kva_ll_head); } /* * do_getqbufsz() - print the active and configured audit queue write buffer * size relative to the current zone. */ static void do_getqbufsz(void) { struct au_qctrl qctrl; if (!temporary_set) { if (!do_getqbufsz_scf(&qctrl.aq_bufsz)) { exit_error(gettext("Could not get configured value.")); } if (qctrl.aq_bufsz == 0) { (void) printf(gettext( "no configured audit queue buffer size\n")); } else { (void) printf(gettext("configured audit queue " "buffer size (bytes) = %d\n"), qctrl.aq_bufsz); } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); (void) printf(gettext("active audit queue buffer size (bytes) = %d\n"), qctrl.aq_bufsz); } /* * do_getqctrl() - print the configured and active audit queue write buffer * size, audit queue hiwater mark, audit queue lowater mark, audit queue prod * interval (ticks) relative to the current zone. */ static void do_getqctrl(void) { struct au_qctrl qctrl; if (!temporary_set) { if (!do_getqctrl_scf(&qctrl)) { exit_error(gettext("Could not get configured values.")); } if (qctrl.aq_hiwater == 0) { (void) printf(gettext( "no configured audit queue hiwater mark\n")); } else { (void) printf(gettext("configured audit queue " "hiwater mark (records) = %d\n"), qctrl.aq_hiwater); } if (qctrl.aq_lowater == 0) { (void) printf(gettext( "no configured audit queue lowater mark\n")); } else { (void) printf(gettext("configured audit queue " "lowater mark (records) = %d\n"), qctrl.aq_lowater); } if (qctrl.aq_bufsz == 0) { (void) printf(gettext( "no configured audit queue buffer size\n")); } else { (void) printf(gettext("configured audit queue " "buffer size (bytes) = %d\n"), qctrl.aq_bufsz); } if (qctrl.aq_delay == 0) { (void) printf(gettext( "no configured audit queue delay\n")); } else { (void) printf(gettext("configured audit queue " "delay (ticks) = %ld\n"), qctrl.aq_delay); } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); (void) printf(gettext("active audit queue hiwater mark " "(records) = %d\n"), qctrl.aq_hiwater); (void) printf(gettext("active audit queue lowater mark " "(records) = %d\n"), qctrl.aq_lowater); (void) printf(gettext("active audit queue buffer size (bytes) = %d\n"), qctrl.aq_bufsz); (void) printf(gettext("active audit queue delay (ticks) = %ld\n"), qctrl.aq_delay); } /* * do_getqdelay() - print, relative to the current zone, the configured and * active interval at which audit queue is prodded to start output. */ static void do_getqdelay(void) { struct au_qctrl qctrl; if (!temporary_set) { if (!do_getqdelay_scf(&qctrl.aq_delay)) { exit_error(gettext("Could not get configured value.")); } if (qctrl.aq_delay == 0) { (void) printf(gettext( "no configured audit queue delay\n")); } else { (void) printf(gettext("configured audit queue " "delay (ticks) = %ld\n"), qctrl.aq_delay); } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); (void) printf(gettext("active audit queue delay (ticks) = %ld\n"), qctrl.aq_delay); } /* * do_getqhiwater() - print, relative to the current zone, the high water * point in undelivered audit records when audit generation will block. */ static void do_getqhiwater(void) { struct au_qctrl qctrl; if (!temporary_set) { if (!do_getqhiwater_scf(&qctrl.aq_hiwater)) { exit_error(gettext("Could not get configured value.")); } if (qctrl.aq_hiwater == 0) { (void) printf(gettext( "no configured audit queue hiwater mark\n")); } else { (void) printf(gettext("configured audit queue " "hiwater mark (records) = %d\n"), qctrl.aq_hiwater); } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); (void) printf(gettext("active audit queue hiwater mark " "(records) = %d\n"), qctrl.aq_hiwater); } /* * do_getqlowater() - print, relative to the current zone, the low water point * in undelivered audit records where blocked processes will resume. */ static void do_getqlowater(void) { struct au_qctrl qctrl; if (!temporary_set) { if (!do_getqlowater_scf(&qctrl.aq_lowater)) { exit_error(gettext("Could not get configured value.")); } if (qctrl.aq_lowater == 0) { (void) printf(gettext( "no configured audit queue lowater mark\n")); } else { (void) printf(gettext("configured audit queue " "lowater mark (records) = %d\n"), qctrl.aq_lowater); } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); (void) printf(gettext("active audit queue lowater mark " "(records) = %d\n"), qctrl.aq_lowater); } /* * do_getasid() - print out the audit session-ID. */ static void do_getasid(void) { auditinfo_addr_t ai; if (getaudit_addr(&ai, sizeof (ai))) { exit_error(gettext("getaudit_addr(2) failed")); } print_asid(ai.ai_asid); } /* * do_getstat() - the printed statistics are for the entire system unless * AUDIT_PERZONE is set. */ static void do_getstat(void) { au_stat_t as; int offset[12]; /* used to line the header up correctly */ char buf[512]; eauditon(A_GETSTAT, (caddr_t)&as, 0); (void) sprintf(buf, "%4lu %n%4lu %n%4lu %n%4lu %n%4lu %n%4lu %n%4lu " "%n%4lu %n%4lu %n%4lu %n%4lu %n%4lu%n", (ulong_t)as.as_generated, &(offset[0]), (ulong_t)as.as_nonattrib, &(offset[1]), (ulong_t)as.as_kernel, &(offset[2]), (ulong_t)as.as_audit, &(offset[3]), (ulong_t)as.as_auditctl, &(offset[4]), (ulong_t)as.as_enqueue, &(offset[5]), (ulong_t)as.as_written, &(offset[6]), (ulong_t)as.as_wblocked, &(offset[7]), (ulong_t)as.as_rblocked, &(offset[8]), (ulong_t)as.as_dropped, &(offset[9]), (ulong_t)as.as_totalsize / ONEK, &(offset[10]), (ulong_t)as.as_memused / ONEK, &(offset[11])); /* * TRANSLATION_NOTE * Print a properly aligned header. */ (void) printf("%*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s\n", offset[0] - 1, gettext("gen"), offset[1] - offset[0] -1, gettext("nona"), offset[2] - offset[1] -1, gettext("kern"), offset[3] - offset[2] -1, gettext("aud"), offset[4] - offset[3] -1, gettext("ctl"), offset[5] - offset[4] -1, gettext("enq"), offset[6] - offset[5] -1, gettext("wrtn"), offset[7] - offset[6] -1, gettext("wblk"), offset[8] - offset[7] -1, gettext("rblk"), offset[9] - offset[8] -1, gettext("drop"), offset[10] - offset[9] -1, gettext("tot"), offset[11] - offset[10], gettext("mem")); (void) printf("%s\n", buf); } /* * do_gettermid() - print audit terminal ID for current process. */ static void do_gettermid(void) { auditinfo_addr_t ai; if (getaudit_addr(&ai, sizeof (ai))) { exit_error(gettext("getaudit_addr(2) failed")); } print_tid_ex(&ai.ai_termid); } /* * do_lsevent() - display the active kernel and user level audit event * information. The printed events are for the global zone unless AUDIT_PERZONE * is set. */ static void do_lsevent(void) { register au_event_ent_t *evp; au_mask_t pmask; char auflags[256]; setauevent(); if (getauevent() == NULL) { exit_error(gettext("NO AUDIT EVENTS: Could not read %s\n."), AUDITEVENTFILE); } setauevent(); while ((evp = getauevent()) != NULL) { pmask.am_success = pmask.am_failure = evp->ae_class; if (getauditflagschar(auflags, &pmask, 0) == -1) (void) strcpy(auflags, "unknown"); (void) printf("%-30s %5hu %s %s\n", evp->ae_name, evp->ae_number, auflags, evp->ae_desc); } endauevent(); } /* * do_lspolicy() - display the kernel audit policies with a description of each * policy. The printed value is for the global zone unless AUDIT_PERZONE is set. */ static void do_lspolicy(void) { int i; /* * TRANSLATION_NOTE * Print a properly aligned header. */ (void) printf(gettext("policy string description:\n")); for (i = 0; i < POLICY_TBL_SZ; i++) { (void) printf("%-17s%s\n", policy_table[i].policy_str, gettext(policy_table[i].policy_desc)); } } /* * do_setasid() - execute shell or cmd with specified session-ID. */ static void do_setasid(char *sid_str, char **argv) { struct auditinfo_addr ai; if (getaudit_addr(&ai, sizeof (ai))) { exit_error(gettext("getaudit_addr(2) failed")); } ai.ai_asid = (au_asid_t)atol(sid_str); if (setaudit_addr(&ai, sizeof (ai))) { exit_error(gettext("setaudit_addr(2) failed")); } execit(argv); } /* * do_setaudit() - execute shell or cmd with specified audit characteristics. */ static void do_setaudit(char *user_str, char *mask_str, char *tid_str, char *sid_str, char **argv) { auditinfo_addr_t ai; ai.ai_auid = (au_id_t)get_user_id(user_str); egetauditflagsbin(mask_str, &ai.ai_mask), str2tid(tid_str, &ai.ai_termid); ai.ai_asid = (au_asid_t)atol(sid_str); esetaudit(&ai, sizeof (ai)); execit(argv); } /* * do_setauid() - execute shell or cmd with specified audit-ID. */ static void do_setauid(char *user, char **argv) { au_id_t auid; auid = get_user_id(user); esetauid(&auid); execit(argv); } /* * do_setpmask() - set the preselection mask of the specified process; valid * per zone if AUDIT_PERZONE is set, else only in global zone. */ static void do_setpmask(char *pid_str, au_mask_t *mask) { struct auditpinfo ap; if (strisnum(pid_str)) { ap.ap_pid = (pid_t)atoi(pid_str); } else { exit_usage(1); } ap.ap_mask.am_success = mask->am_success; ap.ap_mask.am_failure = mask->am_failure; eauditon(A_SETPMASK, (caddr_t)&ap, sizeof (ap)); } /* * do_setsmask() - set the preselection mask of all processes with the specified * audit session-ID; valid per zone if AUDIT_PERZONE is set, else only in global * zone. */ static void do_setsmask(char *asid_str, au_mask_t *mask) { struct auditinfo ainfo; if (strisnum(asid_str)) { ainfo.ai_asid = (au_asid_t)atoi(asid_str); } else { exit_usage(1); } ainfo.ai_mask.am_success = mask->am_success; ainfo.ai_mask.am_failure = mask->am_failure; eauditon(A_SETSMASK, (caddr_t)&ainfo, sizeof (ainfo)); } /* * do_setumask() - set the preselection mask of all processes with the * specified audit-ID; valid per zone if AUDIT_PERZONE is set, else only in * global zone. */ static void do_setumask(char *auid_str, au_mask_t *mask) { struct auditinfo ainfo; if (strisnum(auid_str)) { ainfo.ai_auid = (au_id_t)atoi(auid_str); } else { exit_usage(1); } ainfo.ai_mask.am_success = mask->am_success; ainfo.ai_mask.am_failure = mask->am_failure; eauditon(A_SETUMASK, (caddr_t)&ainfo, sizeof (ainfo)); } /* * do_setstat() - reset audit statistics counters; local zone use is valid if * AUDIT_PERZONE is set, otherwise the syscall returns EPERM. */ static void do_setstat(void) { au_stat_t as; as.as_audit = (uint_t)-1; as.as_auditctl = (uint_t)-1; as.as_dropped = (uint_t)-1; as.as_enqueue = (uint_t)-1; as.as_generated = (uint_t)-1; as.as_kernel = (uint_t)-1; as.as_nonattrib = (uint_t)-1; as.as_rblocked = (uint_t)-1; as.as_totalsize = (uint_t)-1; as.as_wblocked = (uint_t)-1; as.as_written = (uint_t)-1; eauditon(A_SETSTAT, (caddr_t)&as, sizeof (as)); (void) printf("%s\n", gettext("audit stats reset")); } /* * do_setclass() - map the kernel event event_str to the classes specified by * audit flags (mask); valid per zone if AUDIT_PERZONE is set, else only in * global zone. */ static void do_setclass(char *event_str, au_mask_t *mask) { au_event_t event; au_evclass_map_t ec; au_event_ent_t *evp; if (strisnum(event_str)) { event = (uint_t)atol(event_str); } else { if ((evp = egetauevnam(event_str)) != NULL) { event = evp->ae_number; } } ec.ec_number = event; ec.ec_class = (mask->am_success | mask->am_failure); eauditon(A_SETCLASS, (caddr_t)&ec, sizeof (ec)); } /* * do_setflags() - set configured and active default user preselection masks; * valid per zone if AUDIT_PERZONE is set, else only in global zone. */ static void do_setflags(char *audit_flags, au_mask_t *amask) { eauditon(A_SETAMASK, (caddr_t)amask, sizeof (*amask)); if (!do_setflags_scf(audit_flags)) { print_mask(gettext("active user default audit flags"), amask); exit_error(gettext("Could not store configuration value.")); } print_mask(gettext("user default audit flags"), amask); } /* * do_setkmask() - set non-attributable audit flags of machine; valid per zone * if AUDIT_PERZONE is set, else only in global zone. */ static void do_setkmask(au_mask_t *pmask) { eauditon(A_SETKMASK, (caddr_t)pmask, sizeof (*pmask)); print_mask(gettext("active non-attributable audit flags"), pmask); } /* * do_setnaflags() - set configured and active non-attributable selection flags * of machine; valid per zone if AUDIT_PERZONE is set, else only in global zone. */ static void do_setnaflags(char *audit_naflags, au_mask_t *namask) { eauditon(A_SETKMASK, (caddr_t)namask, sizeof (*namask)); if (!do_setnaflags_scf(audit_naflags)) { print_mask( gettext("active non-attributable audit flags"), namask); exit_error(gettext("Could not store configuration value.")); } print_mask(gettext("non-attributable audit flags"), namask); } /* * do_setplugin() - set the given plugin plugin_str configuration values. */ static void do_setplugin(char *plugin_str, boolean_t plugin_state, char *plugin_attr, int plugin_qsize) { if (!do_setpluginconfig_scf(plugin_str, plugin_state, plugin_attr, plugin_qsize)) { exit_error(gettext("Could not set plugin configuration.")); } } /* * do_setpolicy() - set the active and configured kernel audit policy; active * values can be changed per zone if AUDIT_PERZONE is set, else only in global * zone. * * ahlt and perzone are global zone only. The kernel ensures that a local zone * can't change ahlt and perzone (EINVAL). */ static void do_setpolicy(char *policy_str) { uint32_t policy = 0; switch (str2policy(policy_str, &policy)) { case 0: if (!temporary_set) { if (!do_getpolicy_scf(&policy)) { exit_error(gettext("Unable to get current " "policy values from the SMF repository")); } (void) str2policy(policy_str, &policy); if (!do_setpolicy_scf(policy)) { exit_error(gettext("Could not store " "configuration values.")); } } eauditon(A_SETPOLICY, (caddr_t)&policy, 0); break; case 2: exit_error(gettext("policy (%s) invalid in a local zone."), policy_str); break; default: exit_error(gettext("Invalid policy (%s) specified."), policy_str); break; } } /* * do_setqbufsz() - set the active and configured audit queue write buffer size * (bytes); active values can be changed per zone if AUDIT_PERZONE is set, else * only in global zone. */ static void do_setqbufsz(char *bufsz) { struct au_qctrl qctrl; if (!temporary_set) { qctrl.aq_bufsz = (size_t)atol(bufsz); if (!do_setqbufsz_scf(&qctrl.aq_bufsz)) { exit_error(gettext( "Could not store configuration value.")); } if (qctrl.aq_bufsz == 0) { return; } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); qctrl.aq_bufsz = (size_t)atol(bufsz); eauditon(A_SETQCTRL, (caddr_t)&qctrl, 0); } /* * do_setqctrl() - set the active and configured audit queue write buffer size * (bytes), hiwater audit record count, lowater audit record count, and wakeup * interval (ticks); active values can be changed per zone if AUDIT_PERZONE is * set, else only in global zone. */ static void do_setqctrl(char *hiwater, char *lowater, char *bufsz, char *delay) { struct au_qctrl qctrl; qctrl.aq_hiwater = (size_t)atol(hiwater); qctrl.aq_lowater = (size_t)atol(lowater); qctrl.aq_bufsz = (size_t)atol(bufsz); qctrl.aq_delay = (clock_t)atol(delay); if (!temporary_set) { struct au_qctrl qctrl_act; if (!do_setqctrl_scf(&qctrl)) { exit_error(gettext( "Could not store configuration values.")); } eauditon(A_GETQCTRL, (caddr_t)&qctrl_act, 0); if (qctrl.aq_hiwater == 0) { qctrl.aq_hiwater = qctrl_act.aq_hiwater; } if (qctrl.aq_lowater == 0) { qctrl.aq_lowater = qctrl_act.aq_lowater; } if (qctrl.aq_bufsz == 0) { qctrl.aq_bufsz = qctrl_act.aq_bufsz; } if (qctrl.aq_delay == 0) { qctrl.aq_delay = qctrl_act.aq_delay; } } eauditon(A_SETQCTRL, (caddr_t)&qctrl, 0); } /* * do_setqdelay() - set the active and configured audit queue wakeup interval * (ticks); active values can be changed per zone if AUDIT_PERZONE is set, else * only in global zone. */ static void do_setqdelay(char *delay) { struct au_qctrl qctrl; if (!temporary_set) { qctrl.aq_delay = (clock_t)atol(delay); if (!do_setqdelay_scf(&qctrl.aq_delay)) { exit_error(gettext( "Could not store configuration value.")); } if (qctrl.aq_delay == 0) { return; } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); qctrl.aq_delay = (clock_t)atol(delay); eauditon(A_SETQCTRL, (caddr_t)&qctrl, 0); } /* * do_setqhiwater() - sets the active and configured number of undelivered audit * records in the audit queue at which audit record generation blocks; active * values can be changed per zone if AUDIT_PERZONE is set, else only in global * zone. */ static void do_setqhiwater(char *hiwater) { struct au_qctrl qctrl; if (!temporary_set) { qctrl.aq_hiwater = (size_t)atol(hiwater); if (!do_setqhiwater_scf(&qctrl.aq_hiwater)) { exit_error(gettext( "Could not store configuration value.")); } if (qctrl.aq_hiwater == 0) { return; } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); qctrl.aq_hiwater = (size_t)atol(hiwater); eauditon(A_SETQCTRL, (caddr_t)&qctrl, 0); } /* * do_setqlowater() - set the active and configured number of undelivered audit * records in the audit queue at which blocked auditing processes unblock; * active values can be changed per zone if AUDIT_PERZONE is set, else only in * global zone. */ static void do_setqlowater(char *lowater) { struct au_qctrl qctrl; if (!temporary_set) { qctrl.aq_lowater = (size_t)atol(lowater); if (!do_setqlowater_scf(&qctrl.aq_lowater)) { exit_error(gettext( "Could not store configuration value.")); } if (qctrl.aq_lowater == 0) { return; } } eauditon(A_GETQCTRL, (caddr_t)&qctrl, 0); qctrl.aq_lowater = (size_t)atol(lowater); eauditon(A_SETQCTRL, (caddr_t)&qctrl, 0); } static void eauditon(int cmd, caddr_t data, int length) { if (auditon(cmd, data, length) == -1) exit_error(gettext("auditon(2) failed.")); } static void egetauid(au_id_t *auid) { if (getauid(auid) == -1) exit_error(gettext("getauid(2) failed.")); } static void egetaudit(auditinfo_addr_t *ai, int size) { if (getaudit_addr(ai, size) == -1) exit_error(gettext("getaudit_addr(2) failed.")); } static void egetkaudit(auditinfo_addr_t *ai, int size) { if (auditon(A_GETKAUDIT, (char *)ai, size) < 0) exit_error(gettext("auditon: A_GETKAUDIT failed.")); } static void esetkaudit(auditinfo_addr_t *ai, int size) { if (auditon(A_SETKAUDIT, (char *)ai, size) < 0) exit_error(gettext("auditon: A_SETKAUDIT failed.")); } static void egetauditflagsbin(char *auditflags, au_mask_t *pmask) { if (strcmp(auditflags, "none") == 0) { pmask->am_success = pmask->am_failure = 0; return; } if (getauditflagsbin(auditflags, pmask) < 0) { exit_error(gettext("Could not get audit flags (%s)"), auditflags); } } static void echkflags(char *auditflags, au_mask_t *mask) { char *err = ""; char *err_ptr; if (!__chkflags(auditflags, mask, B_FALSE, &err)) { err_ptr = err; while (*err_ptr != ',' && *err_ptr != '\0') { err_ptr++; } *err_ptr = '\0'; exit_error(gettext("Unknown audit flags and/or prefixes " "encountered: %s"), err); } } static au_event_ent_t * egetauevnum(au_event_t event_number) { au_event_ent_t *evp; if ((evp = getauevnum(event_number)) == NULL) { exit_error(gettext("Could not get audit event %hu"), event_number); } return (evp); } static au_event_ent_t * egetauevnam(char *event_name) { register au_event_ent_t *evp; if ((evp = getauevnam(event_name)) == NULL) exit_error(gettext("Could not get audit event %s"), event_name); return (evp); } static void esetauid(au_id_t *auid) { if (setauid(auid) == -1) exit_error(gettext("setauid(2) failed.")); } static void esetaudit(auditinfo_addr_t *ai, int size) { if (setaudit_addr(ai, size) == -1) exit_error(gettext("setaudit_addr(2) failed.")); } static uid_t get_user_id(char *user) { struct passwd *pwd; uid_t uid; if (isdigit(*user)) { uid = atoi(user); if ((pwd = getpwuid(uid)) == NULL) { exit_error(gettext("Invalid user: %s"), user); } } else { if ((pwd = getpwnam(user)) == NULL) { exit_error(gettext("Invalid user: %s"), user); } } return (pwd->pw_uid); } /* * get_arg_ent() * Inputs: command line argument string * Returns ptr to struct arg_entry if found; null, if not found */ static arg_entry_t * get_arg_ent(char *arg_str) { arg_entry_t key; key.arg_str = arg_str; return ((arg_entry_t *)bsearch((char *)&key, (char *)arg_table, ARG_TBL_SZ, sizeof (arg_entry_t), arg_ent_compare)); } /* * arg_ent_compare() * Compares two command line arguments to determine which is * lexicographically greater. * Inputs: two argument map table entry pointers * Returns: > 1: aep1->arg_str > aep2->arg_str * < 1: aep1->arg_str < aep2->arg_str * 0: aep1->arg_str = aep->arg_str2 */ static int arg_ent_compare(const void *aep1, const void *aep2) { return (strcmp(((arg_entry_t *)aep1)->arg_str, ((arg_entry_t *)aep2)->arg_str)); } /* * tid_str is major,minor,host -- host is a name or an ip address */ static void str2tid(char *tid_str, au_tid_addr_t *tp) { char *major_str; char *minor_str; char *host_str = NULL; major_t major = 0; major_t minor = 0; dev_t dev = 0; struct hostent *phe; int err; uint32_t ibuf; uint32_t ibuf6[4]; tp->at_port = 0; tp->at_type = 0; bzero(tp->at_addr, 16); major_str = tid_str; if ((minor_str = strchr(tid_str, ',')) != NULL) { *minor_str = '\0'; minor_str++; } if (minor_str) { if ((host_str = strchr(minor_str, ',')) != NULL) { *host_str = '\0'; host_str++; } } if (major_str) major = (major_t)atoi(major_str); if (minor_str) minor = (minor_t)atoi(minor_str); if ((dev = makedev(major, minor)) != NODEV) tp->at_port = dev; if (host_str) { if (strisipaddr(host_str)) { if (inet_pton(AF_INET, host_str, &ibuf)) { tp->at_addr[0] = ibuf; tp->at_type = AU_IPv4; } else if (inet_pton(AF_INET6, host_str, ibuf6)) { tp->at_addr[0] = ibuf6[0]; tp->at_addr[1] = ibuf6[1]; tp->at_addr[2] = ibuf6[2]; tp->at_addr[3] = ibuf6[3]; tp->at_type = AU_IPv6; } } else { phe = getipnodebyname((const void *)host_str, AF_INET, 0, &err); if (phe == 0) { phe = getipnodebyname((const void *)host_str, AF_INET6, 0, &err); } if (phe != NULL) { if (phe->h_addrtype == AF_INET6) { /* address is IPv6 (128 bits) */ (void) memcpy(&tp->at_addr[0], phe->h_addr_list[0], 16); tp->at_type = AU_IPv6; } else { /* address is IPv4 (32 bits) */ (void) memcpy(&tp->at_addr[0], phe->h_addr_list[0], 4); tp->at_type = AU_IPv4; } freehostent(phe); } } } } static char * cond2str(void) { uint_t cond; eauditon(A_GETCOND, (caddr_t)&cond, sizeof (cond)); switch (cond) { case AUC_AUDITING: return ("auditing"); case AUC_NOAUDIT: case AUC_INIT_AUDIT: return ("noaudit"); case AUC_UNSET: return ("unset"); case AUC_NOSPACE: return ("nospace"); default: return (""); } } /* * exit = 0, success * 1, error * 2, bad zone */ static int str2policy(char *policy_str, uint32_t *policy_mask) { char *buf; char *tok; char pfix; boolean_t is_all = B_FALSE; uint32_t pm = 0; uint32_t curp; pfix = *policy_str; if (pfix == '-' || pfix == '+' || pfix == '=') ++policy_str; if ((buf = strdup(policy_str)) == NULL) return (1); for (tok = strtok(buf, ","); tok != NULL; tok = strtok(NULL, ",")) { uint32_t tok_pm; if (((tok_pm = get_policy(tok)) == 0) && ((strcasecmp(tok, "none") != 0))) { free(buf); return (1); } else { pm |= tok_pm; if (tok_pm == ALL_POLICIES) { is_all = B_TRUE; } } } free(buf); /* reuse policy mask if already set to some value */ if (*policy_mask != 0) { curp = *policy_mask; } else { (void) auditon(A_GETPOLICY, (caddr_t)&curp, 0); } if (pfix == '-') { if (!is_all && (getzoneid() != GLOBAL_ZONEID) && (pm & ~AUDIT_LOCAL)) { return (2); } if (getzoneid() != GLOBAL_ZONEID) curp &= AUDIT_LOCAL; *policy_mask = curp & ~pm; } else if (pfix == '+') { /* * In a local zone, accept specifying "all", but not * individually specifying global-zone only policies. * Limit to all locally allowed, so system call doesn't * fail. */ if (!is_all && (getzoneid() != GLOBAL_ZONEID) && (pm & ~AUDIT_LOCAL)) { return (2); } if (getzoneid() != GLOBAL_ZONEID) { curp &= AUDIT_LOCAL; if (is_all) { pm &= AUDIT_LOCAL; } } *policy_mask = curp | pm; } else { /* * In a local zone, accept specifying "all", but not * individually specifying global-zone only policies. * Limit to all locally allowed, so system call doesn't * fail. */ if (!is_all && (getzoneid() != GLOBAL_ZONEID) && (pm & ~AUDIT_LOCAL)) { return (2); } if (is_all && (getzoneid() != GLOBAL_ZONEID)) { pm &= AUDIT_LOCAL; } *policy_mask = pm; } return (0); } static int policy2str(uint32_t policy, char *policy_str, size_t len) { int i, j; if (policy == ALL_POLICIES) { (void) strcpy(policy_str, "all"); return (1); } if (policy == NO_POLICIES) { (void) strcpy(policy_str, "none"); return (1); } *policy_str = '\0'; for (i = 0, j = 0; i < POLICY_TBL_SZ; i++) { if (policy & policy_table[i].policy_mask && policy_table[i].policy_mask != ALL_POLICIES) { if (j++) { (void) strcat(policy_str, ","); } (void) strlcat(policy_str, policy_table[i].policy_str, len); } } if (*policy_str) return (0); return (1); } static int strisnum(char *s) { if (s == NULL || !*s) return (0); for (; *s == '-' || *s == '+'; s++) { if (!*s) return (0); } for (; *s; s++) { if (!isdigit(*s)) return (0); } return (1); } static int strisipaddr(char *s) { int dot = 0; int colon = 0; /* no string */ if ((s == NULL) || (!*s)) return (0); for (; *s; s++) { if (!(isxdigit(*s) || *s != '.' || *s != ':')) return (0); if (*s == '.') dot++; if (*s == ':') colon++; } if (dot && colon) return (0); if (!dot && !colon) return (0); return (1); } static void chk_arg_len(char *argv, uint_t len) { if ((strlen(argv) + 1) > len) { *(argv + len - 1) = '\0'; exit_error(gettext("Argument too long (%s..)."), argv); } } static void chk_event_num(int etype, au_event_t event) { au_stat_t as; eauditon(A_GETSTAT, (caddr_t)&as, 0); if (etype == AC_KERN_EVENT) { if (event > as.as_numevent) { exit_error(gettext( "Invalid kernel audit event number specified.\n" "\t%hu is outside allowable range 0-%d."), event, as.as_numevent); } } else { /* user event */ if (event <= as.as_numevent) { exit_error(gettext("Invalid user level audit event " "number specified %hu."), event); } } } static void chk_event_str(int etype, char *event_str) { au_event_ent_t *evp; au_stat_t as; eauditon(A_GETSTAT, (caddr_t)&as, 0); evp = egetauevnam(event_str); if (etype == AC_KERN_EVENT && (evp->ae_number > as.as_numevent)) { exit_error(gettext( "Invalid kernel audit event string specified.\n" "\t\"%s\" appears to be a user level event. " "Check configuration."), event_str); } else if (etype == AC_USER_EVENT && (evp->ae_number < as.as_numevent)) { exit_error(gettext( "Invalid user audit event string specified.\n" "\t\"%s\" appears to be a kernel event. " "Check configuration."), event_str); } } static void chk_known_plugin(char *plugin_str) { if ((strlen(plugin_str) + 1) > PLUGIN_MAXBUF) { exit_error(gettext("Plugin name too long.\n")); } if (!plugin_avail_scf(plugin_str)) { exit_error(gettext("No such plugin configured: %s"), plugin_str); } } static void chk_sorf(char *sorf_str) { if (!strisnum(sorf_str)) exit_error(gettext("Invalid sorf specified: %s"), sorf_str); } static void chk_retval(char *retval_str) { if (!strisnum(retval_str)) exit_error(gettext("Invalid retval specified: %s"), retval_str); } static void execit(char **argv) { char *args, *args_pos; size_t len = 0; size_t n = 0; char **argv_pos; if (*argv) { /* concatenate argument array to be passed to sh -c "..." */ for (argv_pos = argv; *argv_pos; argv_pos++) len += strlen(*argv_pos) + 1; if ((args = malloc(len + 1)) == NULL) exit_error( gettext("Allocation for command/arguments failed")); args_pos = args; for (argv_pos = argv; *argv_pos; argv_pos++) { n += snprintf(args_pos, len - n, "%s ", *argv_pos); args_pos = args + n; } /* strip the last space */ args[strlen(args)] = '\0'; (void) execl("/bin/sh", "sh", "-c", args, NULL); } else { (void) execl("/bin/sh", "sh", NULL); } exit_error(gettext("exec(2) failed")); } static void exit_usage(int status) { FILE *fp; int i; fp = (status ? stderr : stdout); (void) fprintf(fp, gettext("usage: %s option ...\n"), progname); for (i = 0; i < ARG_TBL_SZ; i++) { /* skip the -t option; it's not a standalone option */ if (arg_table[i].auditconfig_cmd == AC_ARG_SET_TEMPORARY) { continue; } (void) fprintf(fp, " %s%s%s\n", arg_table[i].arg_str, arg_table[i].arg_opts, (arg_table[i].temporary_allowed ? " [-t]" : "")); } exit(status); } static void print_asid(au_asid_t asid) { (void) printf(gettext("audit session id = %u\n"), asid); } static void print_auid(au_id_t auid) { struct passwd *pwd; char *username; if ((pwd = getpwuid((uid_t)auid)) != NULL) username = pwd->pw_name; else username = gettext("unknown"); (void) printf(gettext("audit id = %s(%d)\n"), username, auid); } static void print_mask(char *desc, au_mask_t *pmp) { char auflags[512]; if (getauditflagschar(auflags, pmp, 0) < 0) (void) strlcpy(auflags, gettext("unknown"), sizeof (auflags)); (void) printf("%s = %s(0x%x,0x%x)\n", desc, auflags, pmp->am_success, pmp->am_failure); } static void print_plugin(char *plugin_name, kva_t *plugin_kva) { char att_str[PLUGIN_MAXATT]; boolean_t plugin_active; char *active_str; char *qsize_ptr; int qsize; if ((active_str = kva_match(plugin_kva, "active")) == NULL) { (void) printf(gettext("Audit service configuration error: " "\"active\" property not found\n")); return; } plugin_active = (boolean_t)atoi(active_str); qsize_ptr = kva_match(plugin_kva, "qsize"); qsize = atoi(qsize_ptr == NULL ? "-1" : qsize_ptr); (void) printf(gettext("Plugin: %s (%s)\n"), plugin_name, plugin_active ? "active" : "inactive"); free_static_att_kva(plugin_kva); switch (_kva2str(plugin_kva, att_str, PLUGIN_MAXATT, "=", ";")) { case 0: (void) printf(gettext("\tAttributes: %s\n"), att_str); break; case 1: exit_error(gettext("Internal error - buffer size too small.")); break; default: exit_error(gettext("Internal error.")); break; } if (qsize != 0) { (void) printf(gettext("\tQueue size: %d %s\n"), qsize, qsize == -1 ? "(internal error: value not available)" : ""); } } static void print_tid_ex(au_tid_addr_t *tidp) { struct hostent *phe; char *hostname; struct in_addr ia; uint32_t *addr; int err; char buf[INET6_ADDRSTRLEN]; char *bufp; /* IPV6 or IPV4 address */ if (tidp->at_type == AU_IPv4) { if ((phe = gethostbyaddr((char *)&tidp->at_addr[0], sizeof (tidp->at_addr[0]), AF_INET)) != NULL) { hostname = phe->h_name; } else { hostname = gettext("unknown"); } ia.s_addr = tidp->at_addr[0]; (void) printf(gettext( "terminal id (maj,min,host) = %lu,%lu,%s(%s)\n"), major(tidp->at_port), minor(tidp->at_port), hostname, inet_ntoa(ia)); } else { addr = &tidp->at_addr[0]; phe = getipnodebyaddr((const void *)addr, 16, AF_INET6, &err); bzero(buf, sizeof (buf)); (void) inet_ntop(AF_INET6, (void *)addr, buf, sizeof (buf)); if (phe == NULL) { bufp = gettext("unknown"); } else { bufp = phe->h_name; } (void) printf(gettext( "terminal id (maj,min,host) = %lu,%lu,%s(%s)\n"), major(tidp->at_port), minor(tidp->at_port), bufp, buf); if (phe) { freehostent(phe); } } } static int str2ipaddr(char *s, uint32_t *addr, uint32_t type) { int j, sl; char *ss; unsigned int v; bzero(addr, 16); if (strisipaddr(s)) { if (type == AU_IPv4) { if (inet_pton(AF_INET, s, addr)) { return (0); } return (1); } else if (type == AU_IPv6) { if (inet_pton(AF_INET6, s, addr)) return (0); return (1); } return (1); } else { if (type == AU_IPv4) { (void) sscanf(s, "%x", &addr[0]); return (0); } else if (type == AU_IPv6) { sl = strlen(s); ss = s; for (j = 3; j >= 0; j--) { if ((sl - 8) <= 0) { (void) sscanf(s, "%x", &v); addr[j] = v; return (0); } ss = &s[sl-8]; (void) sscanf(ss, "%x", &v); addr[j] = v; sl -= 8; *ss = '\0'; } } return (0); } } static int str2type(char *s, uint_t *type) { if (strcmp(s, "ipv6") == 0) { *type = AU_IPv6; return (0); } if (strcmp(s, "ipv4") == 0) { *type = AU_IPv4; return (0); } return (1); } /* * exit_error() - print an error message along with corresponding system error * number and error message, then exit. Inputs - program error format and * message. */ /*PRINTFLIKE1*/ static void exit_error(char *fmt, ...) { va_list args; va_start(args, fmt); prt_error_va(fmt, args); va_end(args); exit(1); }