17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 54e5fbfedStz204579 * Common Development and Distribution License (the "License"). 64e5fbfedStz204579 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*005d3febSMarek Pospisil * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * This file contains the auditing system call code. 287c478bd9Sstevel@tonic-gate * 297c478bd9Sstevel@tonic-gate */ 307c478bd9Sstevel@tonic-gate 317c478bd9Sstevel@tonic-gate #include <sys/param.h> 327c478bd9Sstevel@tonic-gate #include <sys/systm.h> 337c478bd9Sstevel@tonic-gate #include <sys/user.h> 347c478bd9Sstevel@tonic-gate #include <sys/vnode.h> 357c478bd9Sstevel@tonic-gate #include <sys/vfs.h> 367c478bd9Sstevel@tonic-gate #include <sys/session.h> /* for session structure (auditctl(2) */ 377c478bd9Sstevel@tonic-gate #include <sys/kmem.h> /* for KM_SLEEP */ 3867dbe2beSCasper H.S. Dik #include <sys/cred.h> 397c478bd9Sstevel@tonic-gate #include <sys/types.h> 407c478bd9Sstevel@tonic-gate #include <sys/proc.h> 417c478bd9Sstevel@tonic-gate #include <sys/uio.h> 427c478bd9Sstevel@tonic-gate #include <sys/file.h> 437c478bd9Sstevel@tonic-gate #include <sys/stat.h> 447c478bd9Sstevel@tonic-gate #include <sys/pathname.h> 457c478bd9Sstevel@tonic-gate #include <sys/acct.h> 467c478bd9Sstevel@tonic-gate #include <sys/stropts.h> 477c478bd9Sstevel@tonic-gate #include <sys/exec.h> 487c478bd9Sstevel@tonic-gate #include <sys/thread.h> 497c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 507c478bd9Sstevel@tonic-gate #include <sys/debug.h> 517c478bd9Sstevel@tonic-gate #include <sys/disp.h> 527c478bd9Sstevel@tonic-gate #include <sys/kobj.h> 537c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 547c478bd9Sstevel@tonic-gate #include <sys/policy.h> 557c478bd9Sstevel@tonic-gate #include <sys/taskq.h> 567c478bd9Sstevel@tonic-gate #include <sys/zone.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #include <c2/audit.h> 597c478bd9Sstevel@tonic-gate #include <c2/audit_kernel.h> 607c478bd9Sstevel@tonic-gate #include <c2/audit_record.h> 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate #define HEADER_SIZE64 1; 637c478bd9Sstevel@tonic-gate #define HEADER_SIZE32 0; 647c478bd9Sstevel@tonic-gate #define AU_MIN_FILE_SZ 0x80000 /* minumum audit file size */ 657c478bd9Sstevel@tonic-gate #define AUDIT_REC_SIZE 0x8000 /* maximum user audit record size */ 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate extern pri_t minclsyspri; /* priority for taskq */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate static clock_t au_resid = 15; /* wait .15 sec before droping a rec */ 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate static void au_output_thread(); 72*005d3febSMarek Pospisil 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * This is the loadable module wrapper. 757c478bd9Sstevel@tonic-gate */ 767c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 777c478bd9Sstevel@tonic-gate 787c478bd9Sstevel@tonic-gate /* 797c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 807c478bd9Sstevel@tonic-gate */ 81*005d3febSMarek Pospisil static struct modlmisc modlmisc = { 82*005d3febSMarek Pospisil &mod_miscops, "Solaris Auditing (C2)" 837c478bd9Sstevel@tonic-gate }; 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 86*005d3febSMarek Pospisil MODREV_1, (void *)&modlmisc, 0 877c478bd9Sstevel@tonic-gate }; 887c478bd9Sstevel@tonic-gate 897c478bd9Sstevel@tonic-gate int 907c478bd9Sstevel@tonic-gate _init() 917c478bd9Sstevel@tonic-gate { 92*005d3febSMarek Pospisil return (mod_install(&modlinkage)); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate int 967c478bd9Sstevel@tonic-gate _fini() 977c478bd9Sstevel@tonic-gate { 987c478bd9Sstevel@tonic-gate return (EBUSY); 997c478bd9Sstevel@tonic-gate } 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate int 1027c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 1037c478bd9Sstevel@tonic-gate { 1047c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * The audit system call. Trust what the user has sent down and save it 1097c478bd9Sstevel@tonic-gate * away in the audit file. User passes a complete audit record and its 1107c478bd9Sstevel@tonic-gate * length. We will fill in the time stamp, check the header and the length 1117c478bd9Sstevel@tonic-gate * Put a trailer and a sequence token if policy requires. 1127c478bd9Sstevel@tonic-gate * In the future length might become size_t instead of an int. 1137c478bd9Sstevel@tonic-gate * 1147c478bd9Sstevel@tonic-gate * The call is valid whether or not AUDIT_PERZONE is set (think of 1157c478bd9Sstevel@tonic-gate * login to a zone). When the local audit state (auk_auditstate) is 1167c478bd9Sstevel@tonic-gate * AUC_INIT_AUDIT, records are accepted even though auditd isn't 1177c478bd9Sstevel@tonic-gate * running. 1187c478bd9Sstevel@tonic-gate */ 1197c478bd9Sstevel@tonic-gate int 1207c478bd9Sstevel@tonic-gate audit(caddr_t record, int length) 1217c478bd9Sstevel@tonic-gate { 1227c478bd9Sstevel@tonic-gate char c; 1237c478bd9Sstevel@tonic-gate int count, l; 1247c478bd9Sstevel@tonic-gate token_t *m, *n, *s, *ad; 1257c478bd9Sstevel@tonic-gate int hdrlen, delta; 1267c478bd9Sstevel@tonic-gate adr_t hadr; 1277c478bd9Sstevel@tonic-gate adr_t sadr; 1287c478bd9Sstevel@tonic-gate int size; /* 0: 32 bit utility 1: 64 bit utility */ 1297c478bd9Sstevel@tonic-gate int host_len; 1307c478bd9Sstevel@tonic-gate size_t zlen; 1319e9e6ab8Spaulson au_kcontext_t *kctx = GET_KCTX_PZ; 132*005d3febSMarek Pospisil uint32_t auditing; 1337c478bd9Sstevel@tonic-gate 1347c478bd9Sstevel@tonic-gate /* if auditing not enabled, then don't generate an audit record */ 135*005d3febSMarek Pospisil auditing = (U2A(u)->tad_audit != AUC_UNSET) ? 136*005d3febSMarek Pospisil U2A(u)->tad_audit : kctx->auk_auditstate; 137*005d3febSMarek Pospisil if (auditing & ~(AUC_AUDITING | AUC_INIT_AUDIT)) 1387c478bd9Sstevel@tonic-gate return (0); 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* Only privileged processes can audit */ 1417c478bd9Sstevel@tonic-gate if (secpolicy_audit_modify(CRED()) != 0) 1427c478bd9Sstevel@tonic-gate return (EPERM); 1437c478bd9Sstevel@tonic-gate 1447c478bd9Sstevel@tonic-gate /* Max user record size is 32K */ 1457c478bd9Sstevel@tonic-gate if (length > AUDIT_REC_SIZE) 1467c478bd9Sstevel@tonic-gate return (E2BIG); 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * The specified length must be at least as big as the smallest 1507c478bd9Sstevel@tonic-gate * possible header token. Later after beginning to scan the 1517c478bd9Sstevel@tonic-gate * header we'll determine the true minimum length according to 1527c478bd9Sstevel@tonic-gate * the header type and attributes. 1537c478bd9Sstevel@tonic-gate */ 1547c478bd9Sstevel@tonic-gate #define AU_MIN_HEADER_LEN (sizeof (char) + sizeof (int32_t) + \ 1557c478bd9Sstevel@tonic-gate sizeof (char) + sizeof (short) + sizeof (short) + \ 1567c478bd9Sstevel@tonic-gate (sizeof (int32_t) * 2)) 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate if (length < AU_MIN_HEADER_LEN) 1597c478bd9Sstevel@tonic-gate return (EINVAL); 1607c478bd9Sstevel@tonic-gate 1617c478bd9Sstevel@tonic-gate /* Read in user's audit record */ 1627c478bd9Sstevel@tonic-gate count = length; 1637c478bd9Sstevel@tonic-gate m = n = s = ad = NULL; 1647c478bd9Sstevel@tonic-gate while (count) { 1657c478bd9Sstevel@tonic-gate m = au_getclr(); 1667c478bd9Sstevel@tonic-gate if (!s) 1677c478bd9Sstevel@tonic-gate s = n = m; 1687c478bd9Sstevel@tonic-gate else { 1697c478bd9Sstevel@tonic-gate n->next_buf = m; 1707c478bd9Sstevel@tonic-gate n = m; 1717c478bd9Sstevel@tonic-gate } 1727c478bd9Sstevel@tonic-gate l = MIN(count, AU_BUFSIZE); 173787b48eaSgww if (copyin(record, memtod(m, caddr_t), (size_t)l)) { 1747c478bd9Sstevel@tonic-gate /* copyin failed release au_membuf */ 1757c478bd9Sstevel@tonic-gate au_free_rec(s); 1767c478bd9Sstevel@tonic-gate return (EFAULT); 1777c478bd9Sstevel@tonic-gate } 1787c478bd9Sstevel@tonic-gate record += l; 1797c478bd9Sstevel@tonic-gate count -= l; 1807c478bd9Sstevel@tonic-gate m->len = (uchar_t)l; 1817c478bd9Sstevel@tonic-gate } 1827c478bd9Sstevel@tonic-gate 1837c478bd9Sstevel@tonic-gate /* Now attach the entire thing to ad */ 1847c478bd9Sstevel@tonic-gate au_write((caddr_t *)&(ad), s); 1857c478bd9Sstevel@tonic-gate 1867c478bd9Sstevel@tonic-gate /* validate header token type. trust everything following it */ 1877c478bd9Sstevel@tonic-gate adr_start(&hadr, memtod(s, char *)); 1887c478bd9Sstevel@tonic-gate (void) adr_getchar(&hadr, &c); 1897c478bd9Sstevel@tonic-gate switch (c) { 1907c478bd9Sstevel@tonic-gate case AUT_HEADER32: 1917c478bd9Sstevel@tonic-gate /* size vers+event_ID+event_modifier fields */ 1927c478bd9Sstevel@tonic-gate delta = 1 + 2 + 2; 1937c478bd9Sstevel@tonic-gate hdrlen = 1 + 4 + delta + (sizeof (int32_t) * 2); 1947c478bd9Sstevel@tonic-gate size = HEADER_SIZE32; 1957c478bd9Sstevel@tonic-gate break; 1967c478bd9Sstevel@tonic-gate 1977c478bd9Sstevel@tonic-gate #ifdef _LP64 1987c478bd9Sstevel@tonic-gate case AUT_HEADER64: 1997c478bd9Sstevel@tonic-gate /* size vers+event_ID+event_modifier fields */ 2007c478bd9Sstevel@tonic-gate delta = 1 + 2 + 2; 2017c478bd9Sstevel@tonic-gate hdrlen = 1 + 4 + delta + (sizeof (int64_t) * 2); 2027c478bd9Sstevel@tonic-gate size = HEADER_SIZE64; 2037c478bd9Sstevel@tonic-gate break; 2047c478bd9Sstevel@tonic-gate #endif 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate case AUT_HEADER32_EX: 2077c478bd9Sstevel@tonic-gate /* 2087c478bd9Sstevel@tonic-gate * Skip over the length/version/type/mod fields and 2097c478bd9Sstevel@tonic-gate * grab the host address type (length), then rewind. 2107c478bd9Sstevel@tonic-gate * This is safe per the previous minimum length check. 2117c478bd9Sstevel@tonic-gate */ 2127c478bd9Sstevel@tonic-gate hadr.adr_now += 9; 2137c478bd9Sstevel@tonic-gate (void) adr_getint32(&hadr, &host_len); 2147c478bd9Sstevel@tonic-gate hadr.adr_now -= 9 + sizeof (int32_t); 2157c478bd9Sstevel@tonic-gate 2167c478bd9Sstevel@tonic-gate /* size: vers+event_ID+event_modifier+IP_type+IP_addr_array */ 2177c478bd9Sstevel@tonic-gate delta = 1 + 2 + 2 + 4 + host_len; 2187c478bd9Sstevel@tonic-gate hdrlen = 1 + 4 + delta + (sizeof (int32_t) * 2); 2197c478bd9Sstevel@tonic-gate size = HEADER_SIZE32; 2207c478bd9Sstevel@tonic-gate break; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate #ifdef _LP64 2237c478bd9Sstevel@tonic-gate case AUT_HEADER64_EX: 2247c478bd9Sstevel@tonic-gate /* 2257c478bd9Sstevel@tonic-gate * Skip over the length/version/type/mod fields and grab 2267c478bd9Sstevel@tonic-gate * the host address type (length), then rewind. 2277c478bd9Sstevel@tonic-gate * This is safe per the previous minimum length check. 2287c478bd9Sstevel@tonic-gate */ 2297c478bd9Sstevel@tonic-gate hadr.adr_now += 9; 2307c478bd9Sstevel@tonic-gate (void) adr_getint32(&hadr, &host_len); 2317c478bd9Sstevel@tonic-gate hadr.adr_now -= 9 + sizeof (int32_t); 2327c478bd9Sstevel@tonic-gate 2337c478bd9Sstevel@tonic-gate /* size: vers+event_ID+event_modifier+IP_type+IP_addr_array */ 2347c478bd9Sstevel@tonic-gate delta = 1 + 2 + 2 + 4 + host_len; 2357c478bd9Sstevel@tonic-gate hdrlen = 1 + 4 + delta + (sizeof (int64_t) * 2); 2367c478bd9Sstevel@tonic-gate size = HEADER_SIZE64; 2377c478bd9Sstevel@tonic-gate break; 2387c478bd9Sstevel@tonic-gate #endif 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate default: 2417c478bd9Sstevel@tonic-gate /* Header is wrong, reject message */ 2427c478bd9Sstevel@tonic-gate au_free_rec(s); 2437c478bd9Sstevel@tonic-gate return (EINVAL); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate if (length < hdrlen) { 2477c478bd9Sstevel@tonic-gate au_free_rec(s); 2487c478bd9Sstevel@tonic-gate return (0); 2497c478bd9Sstevel@tonic-gate } 2507c478bd9Sstevel@tonic-gate 2517c478bd9Sstevel@tonic-gate /* advance over header token length field */ 2527c478bd9Sstevel@tonic-gate hadr.adr_now += 4; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate /* validate version */ 2557c478bd9Sstevel@tonic-gate (void) adr_getchar(&hadr, &c); 2567c478bd9Sstevel@tonic-gate if (c != TOKEN_VERSION) { 2577c478bd9Sstevel@tonic-gate /* version is wrong, reject message */ 2587c478bd9Sstevel@tonic-gate au_free_rec(s); 2597c478bd9Sstevel@tonic-gate return (EINVAL); 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate 2627c478bd9Sstevel@tonic-gate /* backup to header length field (including version field) */ 2637c478bd9Sstevel@tonic-gate hadr.adr_now -= 5; 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* 2667c478bd9Sstevel@tonic-gate * add on the zonename token if policy AUDIT_ZONENAME is set 2677c478bd9Sstevel@tonic-gate */ 2687c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_ZONENAME) { 2691d7bfecdStz204579 zlen = au_zonename_length(NULL); 2707c478bd9Sstevel@tonic-gate if (zlen > 0) { 2717c478bd9Sstevel@tonic-gate length += zlen; 2721d7bfecdStz204579 m = au_to_zonename(zlen, NULL); 2737c478bd9Sstevel@tonic-gate (void) au_append_rec(ad, m, AU_PACK); 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate /* Add an (optional) sequence token. NULL offset if none */ 2777c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_SEQ) { 2787c478bd9Sstevel@tonic-gate /* get the sequnce token */ 2797c478bd9Sstevel@tonic-gate m = au_to_seq(); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate /* sequence token 5 bytes long */ 2827c478bd9Sstevel@tonic-gate length += 5; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* link to audit record (i.e. don't pack the data) */ 2857c478bd9Sstevel@tonic-gate (void) au_append_rec(ad, m, AU_LINK); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* advance to count field of token */ 2887c478bd9Sstevel@tonic-gate adr_start(&sadr, memtod(m, char *)); 2897c478bd9Sstevel@tonic-gate sadr.adr_now += 1; 2907c478bd9Sstevel@tonic-gate } else 2917c478bd9Sstevel@tonic-gate sadr.adr_now = (char *)NULL; 2927c478bd9Sstevel@tonic-gate 2937c478bd9Sstevel@tonic-gate /* add the (optional) trailer token */ 2947c478bd9Sstevel@tonic-gate if (kctx->auk_policy & AUDIT_TRAIL) { 2957c478bd9Sstevel@tonic-gate /* trailer token is 7 bytes long */ 2967c478bd9Sstevel@tonic-gate length += 7; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate /* append to audit record */ 2997c478bd9Sstevel@tonic-gate (void) au_append_rec(ad, au_to_trailer(length), AU_PACK); 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate 3027c478bd9Sstevel@tonic-gate /* audit record completely assembled. set the length */ 3037c478bd9Sstevel@tonic-gate adr_int32(&hadr, (int32_t *)&length, 1); 3047c478bd9Sstevel@tonic-gate 3057c478bd9Sstevel@tonic-gate /* advance to date/time field of header */ 3067c478bd9Sstevel@tonic-gate hadr.adr_now += delta; 3077c478bd9Sstevel@tonic-gate 3087c478bd9Sstevel@tonic-gate /* We are done put it on the queue */ 3097c478bd9Sstevel@tonic-gate AS_INC(as_generated, 1, kctx); 3107c478bd9Sstevel@tonic-gate AS_INC(as_audit, 1, kctx); 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate au_enqueue(kctx, s, &hadr, &sadr, size, 0); 3137c478bd9Sstevel@tonic-gate 3147c478bd9Sstevel@tonic-gate AS_INC(as_totalsize, length, kctx); 3157c478bd9Sstevel@tonic-gate 3167c478bd9Sstevel@tonic-gate return (0); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate /* 3207c478bd9Sstevel@tonic-gate * auditdoor starts a kernel thread to generate output from the audit 3217c478bd9Sstevel@tonic-gate * queue. The thread terminates when it detects auditing being turned 3227c478bd9Sstevel@tonic-gate * off, such as when auditd exits with a SIGTERM. If a subsequent 3237c478bd9Sstevel@tonic-gate * auditdoor arrives while the thread is running, the door descriptor 3247c478bd9Sstevel@tonic-gate * of the last auditdoor in will be used for output. auditd is responsible 3257c478bd9Sstevel@tonic-gate * for insuring that multiple copies are not running. 3267c478bd9Sstevel@tonic-gate */ 3277c478bd9Sstevel@tonic-gate 328*005d3febSMarek Pospisil int 3297c478bd9Sstevel@tonic-gate auditdoor(int fd) 3307c478bd9Sstevel@tonic-gate { 3317c478bd9Sstevel@tonic-gate struct file *fp; 3327c478bd9Sstevel@tonic-gate struct vnode *vp; 3337c478bd9Sstevel@tonic-gate int do_create = 0; 3347c478bd9Sstevel@tonic-gate au_kcontext_t *kctx; 3357c478bd9Sstevel@tonic-gate 3367c478bd9Sstevel@tonic-gate if (secpolicy_audit_config(CRED()) != 0) 3377c478bd9Sstevel@tonic-gate return (EPERM); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (!(audit_policy & AUDIT_PERZONE) && !INGLOBALZONE(curproc)) 3407c478bd9Sstevel@tonic-gate return (EINVAL); 3417c478bd9Sstevel@tonic-gate 3429e9e6ab8Spaulson kctx = GET_KCTX_NGZ; 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * convert file pointer to file descriptor 3467c478bd9Sstevel@tonic-gate * Note: fd ref count incremented here. 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate if ((fp = (struct file *)getf(fd)) == NULL) { 349787b48eaSgww return (EBADF); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate vp = fp->f_vnode; 3527c478bd9Sstevel@tonic-gate if (vp->v_type != VDOOR) { 3537c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 3547c478bd9Sstevel@tonic-gate "auditdoor() did not get the expected door descriptor\n"); 3557c478bd9Sstevel@tonic-gate releasef(fd); 356787b48eaSgww return (EINVAL); 3577c478bd9Sstevel@tonic-gate } 3587c478bd9Sstevel@tonic-gate /* 3597c478bd9Sstevel@tonic-gate * If the output thread is already running, then replace the 3607c478bd9Sstevel@tonic-gate * door descriptor with the new one and continue; otherwise 3617c478bd9Sstevel@tonic-gate * create the thread too. Since au_output_thread makes a call 3627c478bd9Sstevel@tonic-gate * to au_doorio() which also does 3637c478bd9Sstevel@tonic-gate * mutex_lock(&(kctx->auk_svc_lock)), the create/dispatch is 3647c478bd9Sstevel@tonic-gate * done after the unlock... 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_svc_lock)); 3677c478bd9Sstevel@tonic-gate 3687c478bd9Sstevel@tonic-gate if (kctx->auk_current_vp != NULL) 3697c478bd9Sstevel@tonic-gate VN_RELE(kctx->auk_current_vp); 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate kctx->auk_current_vp = vp; 3727c478bd9Sstevel@tonic-gate VN_HOLD(kctx->auk_current_vp); 3737c478bd9Sstevel@tonic-gate releasef(fd); 3747c478bd9Sstevel@tonic-gate 3757c478bd9Sstevel@tonic-gate if (!kctx->auk_output_active) { 3767c478bd9Sstevel@tonic-gate kctx->auk_output_active = 1; 3777c478bd9Sstevel@tonic-gate do_create = 1; 3787c478bd9Sstevel@tonic-gate } 3797c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_svc_lock)); 3807c478bd9Sstevel@tonic-gate if (do_create) { 3817c478bd9Sstevel@tonic-gate kctx->auk_taskq = 3827c478bd9Sstevel@tonic-gate taskq_create("output_master", 1, minclsyspri, 1, 1, 0); 3837c478bd9Sstevel@tonic-gate (void) taskq_dispatch(kctx->auk_taskq, 3847c478bd9Sstevel@tonic-gate (task_func_t *)au_output_thread, 3857c478bd9Sstevel@tonic-gate kctx, TQ_SLEEP); 3867c478bd9Sstevel@tonic-gate } 387787b48eaSgww return (0); 3887c478bd9Sstevel@tonic-gate } 3897c478bd9Sstevel@tonic-gate 390*005d3febSMarek Pospisil static void 391*005d3febSMarek Pospisil audit_dont_stop(void *kctx) 392*005d3febSMarek Pospisil { 393*005d3febSMarek Pospisil 394*005d3febSMarek Pospisil if ((((au_kcontext_t *)kctx)->auk_valid != AUK_VALID) || 395*005d3febSMarek Pospisil (((au_kcontext_t *)kctx)->auk_auditstate == AUC_NOAUDIT)) 396*005d3febSMarek Pospisil return; 397*005d3febSMarek Pospisil 398*005d3febSMarek Pospisil mutex_enter(&(((au_kcontext_t *)kctx)->auk_queue.lock)); 399*005d3febSMarek Pospisil cv_broadcast(&(((au_kcontext_t *)kctx)->auk_queue.write_cv)); 400*005d3febSMarek Pospisil mutex_exit(&(((au_kcontext_t *)kctx)->auk_queue.lock)); 401*005d3febSMarek Pospisil } 402*005d3febSMarek Pospisil 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * au_queue_kick -- wake up the output queue after delay ticks 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate static void 4077c478bd9Sstevel@tonic-gate au_queue_kick(void *kctx) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * wakeup reader if its not running and there is something 4117c478bd9Sstevel@tonic-gate * to do. It also helps that kctx still be valid... 4127c478bd9Sstevel@tonic-gate */ 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate if ((((au_kcontext_t *)kctx)->auk_valid != AUK_VALID) || 4157c478bd9Sstevel@tonic-gate (((au_kcontext_t *)kctx)->auk_auditstate == AUC_NOAUDIT)) 4167c478bd9Sstevel@tonic-gate return; 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate if (((au_kcontext_t *)kctx)->auk_queue.cnt && 4197c478bd9Sstevel@tonic-gate ((au_kcontext_t *)kctx)->auk_queue.rd_block) 4207c478bd9Sstevel@tonic-gate cv_broadcast(&((au_kcontext_t *)kctx)->auk_queue.read_cv); 4217c478bd9Sstevel@tonic-gate 4227c478bd9Sstevel@tonic-gate /* fire off timeout event to kick audit queue awake */ 4237c478bd9Sstevel@tonic-gate (void) timeout(au_queue_kick, kctx, 4247c478bd9Sstevel@tonic-gate ((au_kcontext_t *)kctx)->auk_queue.delay); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * output thread 4297c478bd9Sstevel@tonic-gate * 4307c478bd9Sstevel@tonic-gate * this runs "forever" where "forever" means until either auk_auditstate 4317c478bd9Sstevel@tonic-gate * changes from AUC_AUDITING or if the door descriptor becomes invalid. 4327c478bd9Sstevel@tonic-gate * 4337c478bd9Sstevel@tonic-gate * there is one thread per active zone if AUC_PERZONE is set. Since 4347c478bd9Sstevel@tonic-gate * there is the possibility that a zone may go down without auditd 4357c478bd9Sstevel@tonic-gate * terminating properly, a zone shutdown kills its au_output_thread() 4367c478bd9Sstevel@tonic-gate * via taskq_destroy(). 4377c478bd9Sstevel@tonic-gate */ 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate static void 4407c478bd9Sstevel@tonic-gate au_output_thread(au_kcontext_t *kctx) 4417c478bd9Sstevel@tonic-gate { 4427c478bd9Sstevel@tonic-gate int error = 0; 4437c478bd9Sstevel@tonic-gate 4447c478bd9Sstevel@tonic-gate (void) timeout(au_queue_kick, kctx, kctx->auk_queue.delay); 4457c478bd9Sstevel@tonic-gate 4467c478bd9Sstevel@tonic-gate /* 4477c478bd9Sstevel@tonic-gate * Wait for work, until a signal arrives, 4487c478bd9Sstevel@tonic-gate * or until auditing is disabled. 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate while (!error) { 4527c478bd9Sstevel@tonic-gate if (kctx->auk_auditstate == AUC_AUDITING) { 4537c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_queue.lock)); 4547c478bd9Sstevel@tonic-gate while (kctx->auk_queue.head == NULL) { 4557c478bd9Sstevel@tonic-gate /* safety check. kick writer awake */ 456787b48eaSgww if (kctx->auk_queue.wt_block) { 457787b48eaSgww cv_broadcast(&(kctx-> 458787b48eaSgww auk_queue.write_cv)); 459787b48eaSgww } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate kctx->auk_queue.rd_block = 1; 4627c478bd9Sstevel@tonic-gate AS_INC(as_rblocked, 1, kctx); 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate cv_wait(&(kctx->auk_queue.read_cv), 4657c478bd9Sstevel@tonic-gate &(kctx->auk_queue.lock)); 4667c478bd9Sstevel@tonic-gate kctx->auk_queue.rd_block = 0; 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate if (kctx->auk_auditstate != AUC_AUDITING) { 4697c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 470787b48eaSgww (void) timeout(audit_dont_stop, kctx, 471787b48eaSgww au_resid); 4727c478bd9Sstevel@tonic-gate goto output_exit; 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate kctx->auk_queue.rd_block = 0; 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_queue.lock)); 4777c478bd9Sstevel@tonic-gate /* 478787b48eaSgww * au_doorio() calls au_door_upcall which holds 479787b48eaSgww * auk_svc_lock; au_doorio empties the queue before 480787b48eaSgww * returning. 4817c478bd9Sstevel@tonic-gate */ 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate error = au_doorio(kctx); 484787b48eaSgww } else { 485787b48eaSgww /* auditing turned off while we slept */ 4867c478bd9Sstevel@tonic-gate break; 4877c478bd9Sstevel@tonic-gate } 488787b48eaSgww } 4897c478bd9Sstevel@tonic-gate output_exit: 4907c478bd9Sstevel@tonic-gate mutex_enter(&(kctx->auk_svc_lock)); 4917c478bd9Sstevel@tonic-gate 4927c478bd9Sstevel@tonic-gate VN_RELE(kctx->auk_current_vp); 4937c478bd9Sstevel@tonic-gate kctx->auk_current_vp = NULL; 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate kctx->auk_output_active = 0; 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate mutex_exit(&(kctx->auk_svc_lock)); 4987c478bd9Sstevel@tonic-gate } 499