1181053Srwatson/*- 2191270Srwatson * Copyright (c) 1999-2009 Apple Inc. 3155192Srwatson * All rights reserved. 4155192Srwatson * 5155192Srwatson * Redistribution and use in source and binary forms, with or without 6155192Srwatson * modification, are permitted provided that the following conditions 7155192Srwatson * are met: 8155192Srwatson * 1. Redistributions of source code must retain the above copyright 9155192Srwatson * notice, this list of conditions and the following disclaimer. 10155192Srwatson * 2. Redistributions in binary form must reproduce the above copyright 11155192Srwatson * notice, this list of conditions and the following disclaimer in the 12155192Srwatson * documentation and/or other materials provided with the distribution. 13180701Srwatson * 3. Neither the name of Apple Inc. ("Apple") nor the names of 14155192Srwatson * its contributors may be used to endorse or promote products derived 15155192Srwatson * from this software without specific prior written permission. 16155192Srwatson * 17155192Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 18155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20155192Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 21155192Srwatson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 25155192Srwatson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 26155192Srwatson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27155192Srwatson * POSSIBILITY OF SUCH DAMAGE. 28155192Srwatson */ 29155192Srwatson 30178186Srwatson#include <sys/cdefs.h> 31178186Srwatson__FBSDID("$FreeBSD$"); 32178186Srwatson 33155192Srwatson#include <sys/param.h> 34159318Srwatson#include <sys/mount.h> 35155192Srwatson#include <sys/namei.h> 36164033Srwatson#include <sys/priv.h> 37155192Srwatson#include <sys/proc.h> 38155192Srwatson#include <sys/sysproto.h> 39155192Srwatson#include <sys/systm.h> 40155192Srwatson#include <sys/vnode.h> 41163207Scsjp#include <sys/jail.h> 42155192Srwatson 43155192Srwatson#include <bsm/audit.h> 44155192Srwatson#include <bsm/audit_kevents.h> 45168933Srwatson 46155192Srwatson#include <security/audit/audit.h> 47155192Srwatson#include <security/audit/audit_private.h> 48168933Srwatson#include <security/mac/mac_framework.h> 49155192Srwatson 50155192Srwatson#ifdef AUDIT 51155192Srwatson 52155192Srwatson/* 53156889Srwatson * System call to allow a user space application to submit a BSM audit record 54170127Srwatson * to the kernel for inclusion in the audit log. This function does little 55156889Srwatson * verification on the audit record that is submitted. 56155192Srwatson * 57156889Srwatson * XXXAUDIT: Audit preselection for user records does not currently work, 58156889Srwatson * since we pre-select only based on the AUE_audit event type, not the event 59156889Srwatson * type submitted as part of the user audit data. 60155192Srwatson */ 61155192Srwatson/* ARGSUSED */ 62155192Srwatsonint 63225617Skmacysys_audit(struct thread *td, struct audit_args *uap) 64155192Srwatson{ 65155192Srwatson int error; 66155192Srwatson void * rec; 67155192Srwatson struct kaudit_record *ar; 68155192Srwatson 69163207Scsjp if (jailed(td->td_ucred)) 70163207Scsjp return (ENOSYS); 71164033Srwatson error = priv_check(td, PRIV_AUDIT_SUBMIT); 72155192Srwatson if (error) 73155192Srwatson return (error); 74155192Srwatson 75155192Srwatson if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) 76155192Srwatson return (EINVAL); 77155192Srwatson 78155192Srwatson ar = currecord(); 79155192Srwatson 80156889Srwatson /* 81156889Srwatson * If there's no current audit record (audit() itself not audited) 82155192Srwatson * commit the user audit record. 83155192Srwatson */ 84155192Srwatson if (ar == NULL) { 85155192Srwatson 86156889Srwatson /* 87156889Srwatson * This is not very efficient; we're required to allocate a 88156889Srwatson * complete kernel audit record just so the user record can 89156889Srwatson * tag along. 90155192Srwatson * 91155192Srwatson * XXXAUDIT: Maybe AUE_AUDIT in the system call context and 92155192Srwatson * special pre-select handling? 93155192Srwatson */ 94155192Srwatson td->td_ar = audit_new(AUE_NULL, td); 95155192Srwatson if (td->td_ar == NULL) 96155192Srwatson return (ENOTSUP); 97189570Srwatson td->td_pflags |= TDP_AUDITREC; 98155192Srwatson ar = td->td_ar; 99155192Srwatson } 100155192Srwatson 101156889Srwatson if (uap->length > MAX_AUDIT_RECORD_SIZE) 102155192Srwatson return (EINVAL); 103155192Srwatson 104155192Srwatson rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); 105155192Srwatson 106155192Srwatson error = copyin(uap->record, rec, uap->length); 107155192Srwatson if (error) 108155192Srwatson goto free_out; 109155192Srwatson 110156889Srwatson /* Verify the record. */ 111155192Srwatson if (bsm_rec_verify(rec) == 0) { 112155192Srwatson error = EINVAL; 113155192Srwatson goto free_out; 114155192Srwatson } 115155192Srwatson 116168933Srwatson#ifdef MAC 117172930Srwatson error = mac_system_check_audit(td->td_ucred, rec, uap->length); 118168933Srwatson if (error) 119168933Srwatson goto free_out; 120168933Srwatson#endif 121168933Srwatson 122156889Srwatson /* 123170127Srwatson * Attach the user audit record to the kernel audit record. Because 124155192Srwatson * this system call is an auditable event, we will write the user 125155192Srwatson * record along with the record for this audit event. 126155192Srwatson * 127155192Srwatson * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, 128155192Srwatson * k_ar_commit & AR_COMMIT_USER? 129155192Srwatson */ 130155192Srwatson ar->k_udata = rec; 131155192Srwatson ar->k_ulen = uap->length; 132155192Srwatson ar->k_ar_commit |= AR_COMMIT_USER; 133162380Scsjp 134162380Scsjp /* 135162380Scsjp * Currently we assume that all preselection has been performed in 136170127Srwatson * userspace. We unconditionally set these masks so that the records 137162380Scsjp * get committed both to the trail and pipe. In the future we will 138162380Scsjp * want to setup kernel based preselection. 139162380Scsjp */ 140162380Scsjp ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); 141155192Srwatson return (0); 142155192Srwatson 143155192Srwatsonfree_out: 144156889Srwatson /* 145156889Srwatson * audit_syscall_exit() will free the audit record on the thread even 146156889Srwatson * if we allocated it above. 147155192Srwatson */ 148155192Srwatson free(rec, M_AUDITDATA); 149155192Srwatson return (error); 150155192Srwatson} 151155192Srwatson 152155192Srwatson/* 153155192Srwatson * System call to manipulate auditing. 154155192Srwatson */ 155155192Srwatson/* ARGSUSED */ 156155192Srwatsonint 157225617Skmacysys_auditon(struct thread *td, struct auditon_args *uap) 158155192Srwatson{ 159184948Srwatson struct ucred *cred, *newcred, *oldcred; 160155192Srwatson int error; 161155192Srwatson union auditon_udata udata; 162155192Srwatson struct proc *tp; 163155192Srwatson 164163207Scsjp if (jailed(td->td_ucred)) 165163207Scsjp return (ENOSYS); 166195104Srwatson AUDIT_ARG_CMD(uap->cmd); 167168933Srwatson 168168933Srwatson#ifdef MAC 169172930Srwatson error = mac_system_check_auditon(td->td_ucred, uap->cmd); 170168933Srwatson if (error) 171168933Srwatson return (error); 172168933Srwatson#endif 173168933Srwatson 174164033Srwatson error = priv_check(td, PRIV_AUDIT_CONTROL); 175155192Srwatson if (error) 176155192Srwatson return (error); 177155192Srwatson 178155192Srwatson if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata))) 179155192Srwatson return (EINVAL); 180155192Srwatson 181155192Srwatson memset((void *)&udata, 0, sizeof(udata)); 182155192Srwatson 183156889Srwatson /* 184156889Srwatson * Some of the GET commands use the arguments too. 185156889Srwatson */ 186155192Srwatson switch (uap->cmd) { 187155192Srwatson case A_SETPOLICY: 188191270Srwatson case A_OLDSETPOLICY: 189155192Srwatson case A_SETKMASK: 190155192Srwatson case A_SETQCTRL: 191191270Srwatson case A_OLDSETQCTRL: 192155192Srwatson case A_SETSTAT: 193155192Srwatson case A_SETUMASK: 194155192Srwatson case A_SETSMASK: 195155192Srwatson case A_SETCOND: 196191270Srwatson case A_OLDSETCOND: 197155192Srwatson case A_SETCLASS: 198155192Srwatson case A_SETPMASK: 199155192Srwatson case A_SETFSIZE: 200155192Srwatson case A_SETKAUDIT: 201155192Srwatson case A_GETCLASS: 202155192Srwatson case A_GETPINFO: 203155192Srwatson case A_GETPINFO_ADDR: 204155192Srwatson case A_SENDTRIGGER: 205155192Srwatson error = copyin(uap->data, (void *)&udata, uap->length); 206155192Srwatson if (error) 207155192Srwatson return (error); 208195104Srwatson AUDIT_ARG_AUDITON(&udata); 209155192Srwatson break; 210155192Srwatson } 211155192Srwatson 212156889Srwatson /* 213155192Srwatson * XXXAUDIT: Locking? 214155192Srwatson */ 215155192Srwatson switch (uap->cmd) { 216191270Srwatson case A_OLDGETPOLICY: 217191296Srwatson case A_GETPOLICY: 218191270Srwatson if (uap->length == sizeof(udata.au_policy64)) { 219191270Srwatson if (!audit_fail_stop) 220191270Srwatson udata.au_policy64 |= AUDIT_CNT; 221191270Srwatson if (audit_panic_on_write_fail) 222191270Srwatson udata.au_policy64 |= AUDIT_AHLT; 223191270Srwatson if (audit_argv) 224191270Srwatson udata.au_policy64 |= AUDIT_ARGV; 225191270Srwatson if (audit_arge) 226191270Srwatson udata.au_policy64 |= AUDIT_ARGE; 227191270Srwatson break; 228191270Srwatson } 229191270Srwatson if (uap->length != sizeof(udata.au_policy)) 230191270Srwatson return (EINVAL); 231155192Srwatson if (!audit_fail_stop) 232155192Srwatson udata.au_policy |= AUDIT_CNT; 233155192Srwatson if (audit_panic_on_write_fail) 234155192Srwatson udata.au_policy |= AUDIT_AHLT; 235161813Swsalamon if (audit_argv) 236161813Swsalamon udata.au_policy |= AUDIT_ARGV; 237161813Swsalamon if (audit_arge) 238161813Swsalamon udata.au_policy |= AUDIT_ARGE; 239155192Srwatson break; 240155192Srwatson 241191270Srwatson case A_OLDSETPOLICY: 242191296Srwatson case A_SETPOLICY: 243191270Srwatson if (uap->length == sizeof(udata.au_policy64)) { 244191270Srwatson if (udata.au_policy & (~AUDIT_CNT|AUDIT_AHLT| 245191270Srwatson AUDIT_ARGV|AUDIT_ARGE)) 246191270Srwatson return (EINVAL); 247191270Srwatson audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) == 248191270Srwatson 0); 249191270Srwatson audit_panic_on_write_fail = (udata.au_policy64 & 250191270Srwatson AUDIT_AHLT); 251191270Srwatson audit_argv = (udata.au_policy64 & AUDIT_ARGV); 252191270Srwatson audit_arge = (udata.au_policy64 & AUDIT_ARGE); 253191270Srwatson break; 254191270Srwatson } 255191270Srwatson if (uap->length != sizeof(udata.au_policy)) 256191270Srwatson return (EINVAL); 257161813Swsalamon if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 258161813Swsalamon AUDIT_ARGE)) 259155192Srwatson return (EINVAL); 260155192Srwatson /* 261155192Srwatson * XXX - Need to wake up waiters if the policy relaxes? 262155192Srwatson */ 263155192Srwatson audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 264155192Srwatson audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 265161813Swsalamon audit_argv = (udata.au_policy & AUDIT_ARGV); 266161813Swsalamon audit_arge = (udata.au_policy & AUDIT_ARGE); 267155192Srwatson break; 268155192Srwatson 269155192Srwatson case A_GETKMASK: 270191270Srwatson if (uap->length != sizeof(udata.au_mask)) 271191270Srwatson return (EINVAL); 272155192Srwatson udata.au_mask = audit_nae_mask; 273155192Srwatson break; 274155192Srwatson 275155192Srwatson case A_SETKMASK: 276191270Srwatson if (uap->length != sizeof(udata.au_mask)) 277191270Srwatson return (EINVAL); 278155192Srwatson audit_nae_mask = udata.au_mask; 279155192Srwatson break; 280155192Srwatson 281191270Srwatson case A_OLDGETQCTRL: 282191296Srwatson case A_GETQCTRL: 283191270Srwatson if (uap->length == sizeof(udata.au_qctrl64)) { 284191270Srwatson udata.au_qctrl64.aq64_hiwater = 285191270Srwatson (u_int64_t)audit_qctrl.aq_hiwater; 286191270Srwatson udata.au_qctrl64.aq64_lowater = 287191270Srwatson (u_int64_t)audit_qctrl.aq_lowater; 288191270Srwatson udata.au_qctrl64.aq64_bufsz = 289191270Srwatson (u_int64_t)audit_qctrl.aq_bufsz; 290191270Srwatson udata.au_qctrl64.aq64_minfree = 291191270Srwatson (u_int64_t)audit_qctrl.aq_minfree; 292191270Srwatson break; 293191270Srwatson } 294191270Srwatson if (uap->length != sizeof(udata.au_qctrl)) 295191270Srwatson return (EINVAL); 296155192Srwatson udata.au_qctrl = audit_qctrl; 297155192Srwatson break; 298155192Srwatson 299191270Srwatson case A_OLDSETQCTRL: 300191296Srwatson case A_SETQCTRL: 301191270Srwatson if (uap->length == sizeof(udata.au_qctrl64)) { 302191270Srwatson if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || 303191270Srwatson (udata.au_qctrl64.aq64_lowater >= 304191270Srwatson udata.au_qctrl.aq_hiwater) || 305191270Srwatson (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || 306191270Srwatson (udata.au_qctrl64.aq64_minfree < 0) || 307191270Srwatson (udata.au_qctrl64.aq64_minfree > 100)) 308191270Srwatson return (EINVAL); 309191270Srwatson audit_qctrl.aq_hiwater = 310191270Srwatson (int)udata.au_qctrl64.aq64_hiwater; 311191270Srwatson audit_qctrl.aq_lowater = 312191270Srwatson (int)udata.au_qctrl64.aq64_lowater; 313191270Srwatson audit_qctrl.aq_bufsz = 314191270Srwatson (int)udata.au_qctrl64.aq64_bufsz; 315191270Srwatson audit_qctrl.aq_minfree = 316191270Srwatson (int)udata.au_qctrl64.aq64_minfree; 317191270Srwatson audit_qctrl.aq_delay = -1; /* Not used. */ 318191270Srwatson break; 319191270Srwatson } 320191270Srwatson if (uap->length != sizeof(udata.au_qctrl)) 321191270Srwatson return (EINVAL); 322155192Srwatson if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 323155192Srwatson (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 324155192Srwatson (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 325155192Srwatson (udata.au_qctrl.aq_minfree < 0) || 326155192Srwatson (udata.au_qctrl.aq_minfree > 100)) 327155192Srwatson return (EINVAL); 328155192Srwatson 329155192Srwatson audit_qctrl = udata.au_qctrl; 330155192Srwatson /* XXX The queue delay value isn't used with the kernel. */ 331155192Srwatson audit_qctrl.aq_delay = -1; 332155192Srwatson break; 333155192Srwatson 334155192Srwatson case A_GETCWD: 335155192Srwatson return (ENOSYS); 336155192Srwatson break; 337155192Srwatson 338155192Srwatson case A_GETCAR: 339155192Srwatson return (ENOSYS); 340155192Srwatson break; 341155192Srwatson 342155192Srwatson case A_GETSTAT: 343155192Srwatson return (ENOSYS); 344155192Srwatson break; 345155192Srwatson 346155192Srwatson case A_SETSTAT: 347155192Srwatson return (ENOSYS); 348155192Srwatson break; 349155192Srwatson 350155192Srwatson case A_SETUMASK: 351155192Srwatson return (ENOSYS); 352155192Srwatson break; 353155192Srwatson 354155192Srwatson case A_SETSMASK: 355155192Srwatson return (ENOSYS); 356155192Srwatson break; 357155192Srwatson 358191270Srwatson case A_OLDGETCOND: 359191296Srwatson case A_GETCOND: 360191270Srwatson if (uap->length == sizeof(udata.au_cond64)) { 361191270Srwatson if (audit_enabled && !audit_suspended) 362191270Srwatson udata.au_cond64 = AUC_AUDITING; 363191270Srwatson else 364191270Srwatson udata.au_cond64 = AUC_NOAUDIT; 365191270Srwatson break; 366191270Srwatson } 367191270Srwatson if (uap->length != sizeof(udata.au_cond)) 368191270Srwatson return (EINVAL); 369155192Srwatson if (audit_enabled && !audit_suspended) 370155192Srwatson udata.au_cond = AUC_AUDITING; 371155192Srwatson else 372155192Srwatson udata.au_cond = AUC_NOAUDIT; 373155192Srwatson break; 374155192Srwatson 375191270Srwatson case A_OLDSETCOND: 376191296Srwatson case A_SETCOND: 377191270Srwatson if (uap->length == sizeof(udata.au_cond64)) { 378191270Srwatson if (udata.au_cond64 == AUC_NOAUDIT) 379191270Srwatson audit_suspended = 1; 380191270Srwatson if (udata.au_cond64 == AUC_AUDITING) 381191270Srwatson audit_suspended = 0; 382191270Srwatson if (udata.au_cond64 == AUC_DISABLED) { 383191270Srwatson audit_suspended = 1; 384191270Srwatson audit_shutdown(NULL, 0); 385191270Srwatson } 386191270Srwatson break; 387191270Srwatson } 388191270Srwatson if (uap->length != sizeof(udata.au_cond)) 389191270Srwatson return (EINVAL); 390156889Srwatson if (udata.au_cond == AUC_NOAUDIT) 391155192Srwatson audit_suspended = 1; 392156889Srwatson if (udata.au_cond == AUC_AUDITING) 393155192Srwatson audit_suspended = 0; 394155192Srwatson if (udata.au_cond == AUC_DISABLED) { 395155192Srwatson audit_suspended = 1; 396155192Srwatson audit_shutdown(NULL, 0); 397155192Srwatson } 398155192Srwatson break; 399155192Srwatson 400155192Srwatson case A_GETCLASS: 401191270Srwatson if (uap->length != sizeof(udata.au_evclass)) 402191270Srwatson return (EINVAL); 403156889Srwatson udata.au_evclass.ec_class = au_event_class( 404156889Srwatson udata.au_evclass.ec_number); 405155192Srwatson break; 406155192Srwatson 407155192Srwatson case A_SETCLASS: 408191270Srwatson if (uap->length != sizeof(udata.au_evclass)) 409191270Srwatson return (EINVAL); 410155192Srwatson au_evclassmap_insert(udata.au_evclass.ec_number, 411156889Srwatson udata.au_evclass.ec_class); 412155192Srwatson break; 413155192Srwatson 414155192Srwatson case A_GETPINFO: 415191270Srwatson if (uap->length != sizeof(udata.au_aupinfo)) 416191270Srwatson return (EINVAL); 417156889Srwatson if (udata.au_aupinfo.ap_pid < 1) 418182750Skevlo return (ESRCH); 419155192Srwatson if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 420182750Skevlo return (ESRCH); 421182754Sdes if ((error = p_cansee(td, tp)) != 0) { 422165624Srwatson PROC_UNLOCK(tp); 423182750Skevlo return (error); 424165624Srwatson } 425184948Srwatson cred = tp->p_ucred; 426184948Srwatson if (cred->cr_audit.ai_termid.at_type == AU_IPv6) { 427168688Scsjp PROC_UNLOCK(tp); 428168688Scsjp return (EINVAL); 429168688Scsjp } 430184948Srwatson udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid; 431156889Srwatson udata.au_aupinfo.ap_mask.am_success = 432184948Srwatson cred->cr_audit.ai_mask.am_success; 433156889Srwatson udata.au_aupinfo.ap_mask.am_failure = 434184948Srwatson cred->cr_audit.ai_mask.am_failure; 435156889Srwatson udata.au_aupinfo.ap_termid.machine = 436184948Srwatson cred->cr_audit.ai_termid.at_addr[0]; 437168688Scsjp udata.au_aupinfo.ap_termid.port = 438184948Srwatson (dev_t)cred->cr_audit.ai_termid.at_port; 439184948Srwatson udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid; 440155192Srwatson PROC_UNLOCK(tp); 441155192Srwatson break; 442155192Srwatson 443155192Srwatson case A_SETPMASK: 444191270Srwatson if (uap->length != sizeof(udata.au_aupinfo)) 445191270Srwatson return (EINVAL); 446156889Srwatson if (udata.au_aupinfo.ap_pid < 1) 447182750Skevlo return (ESRCH); 448170407Srwatson newcred = crget(); 449170407Srwatson if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { 450170407Srwatson crfree(newcred); 451182750Skevlo return (ESRCH); 452170407Srwatson } 453182754Sdes if ((error = p_cansee(td, tp)) != 0) { 454165624Srwatson PROC_UNLOCK(tp); 455170407Srwatson crfree(newcred); 456182750Skevlo return (error); 457165624Srwatson } 458170407Srwatson oldcred = tp->p_ucred; 459170407Srwatson crcopy(newcred, oldcred); 460170407Srwatson newcred->cr_audit.ai_mask.am_success = 461156889Srwatson udata.au_aupinfo.ap_mask.am_success; 462170407Srwatson newcred->cr_audit.ai_mask.am_failure = 463156889Srwatson udata.au_aupinfo.ap_mask.am_failure; 464170407Srwatson td->td_proc->p_ucred = newcred; 465155192Srwatson PROC_UNLOCK(tp); 466170407Srwatson crfree(oldcred); 467155192Srwatson break; 468155192Srwatson 469155192Srwatson case A_SETFSIZE: 470191270Srwatson if (uap->length != sizeof(udata.au_fstat)) 471191270Srwatson return (EINVAL); 472155192Srwatson if ((udata.au_fstat.af_filesz != 0) && 473155192Srwatson (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 474155192Srwatson return (EINVAL); 475155192Srwatson audit_fstat.af_filesz = udata.au_fstat.af_filesz; 476155192Srwatson break; 477155192Srwatson 478155192Srwatson case A_GETFSIZE: 479191270Srwatson if (uap->length != sizeof(udata.au_fstat)) 480191270Srwatson return (EINVAL); 481155192Srwatson udata.au_fstat.af_filesz = audit_fstat.af_filesz; 482155192Srwatson udata.au_fstat.af_currsz = audit_fstat.af_currsz; 483155192Srwatson break; 484155192Srwatson 485155192Srwatson case A_GETPINFO_ADDR: 486191270Srwatson if (uap->length != sizeof(udata.au_aupinfo_addr)) 487191270Srwatson return (EINVAL); 488168688Scsjp if (udata.au_aupinfo_addr.ap_pid < 1) 489182750Skevlo return (ESRCH); 490168688Scsjp if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) 491182750Skevlo return (ESRCH); 492184948Srwatson cred = tp->p_ucred; 493184948Srwatson udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid; 494168688Scsjp udata.au_aupinfo_addr.ap_mask.am_success = 495184948Srwatson cred->cr_audit.ai_mask.am_success; 496168688Scsjp udata.au_aupinfo_addr.ap_mask.am_failure = 497184948Srwatson cred->cr_audit.ai_mask.am_failure; 498184948Srwatson udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid; 499184948Srwatson udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid; 500168688Scsjp PROC_UNLOCK(tp); 501155192Srwatson break; 502155192Srwatson 503155192Srwatson case A_GETKAUDIT: 504191270Srwatson if (uap->length != sizeof(udata.au_kau_info)) 505191270Srwatson return (EINVAL); 506184856Scsjp audit_get_kinfo(&udata.au_kau_info); 507155192Srwatson break; 508155192Srwatson 509155192Srwatson case A_SETKAUDIT: 510191270Srwatson if (uap->length != sizeof(udata.au_kau_info)) 511191270Srwatson return (EINVAL); 512184856Scsjp if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && 513184856Scsjp udata.au_kau_info.ai_termid.at_type != AU_IPv6) 514184856Scsjp return (EINVAL); 515184856Scsjp audit_set_kinfo(&udata.au_kau_info); 516155192Srwatson break; 517155192Srwatson 518155192Srwatson case A_SENDTRIGGER: 519191270Srwatson if (uap->length != sizeof(udata.au_trigger)) 520191270Srwatson return (EINVAL); 521155192Srwatson if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 522155192Srwatson (udata.au_trigger > AUDIT_TRIGGER_MAX)) 523155192Srwatson return (EINVAL); 524176686Srwatson return (audit_send_trigger(udata.au_trigger)); 525176887Scsjp 526176887Scsjp default: 527176887Scsjp return (EINVAL); 528155192Srwatson } 529156889Srwatson 530156889Srwatson /* 531156889Srwatson * Copy data back to userspace for the GET comands. 532156889Srwatson */ 533155192Srwatson switch (uap->cmd) { 534155192Srwatson case A_GETPOLICY: 535191270Srwatson case A_OLDGETPOLICY: 536155192Srwatson case A_GETKMASK: 537155192Srwatson case A_GETQCTRL: 538191270Srwatson case A_OLDGETQCTRL: 539155192Srwatson case A_GETCWD: 540155192Srwatson case A_GETCAR: 541155192Srwatson case A_GETSTAT: 542155192Srwatson case A_GETCOND: 543191270Srwatson case A_OLDGETCOND: 544155192Srwatson case A_GETCLASS: 545155192Srwatson case A_GETPINFO: 546155192Srwatson case A_GETFSIZE: 547155192Srwatson case A_GETPINFO_ADDR: 548155192Srwatson case A_GETKAUDIT: 549155192Srwatson error = copyout((void *)&udata, uap->data, uap->length); 550155192Srwatson if (error) 551155192Srwatson return (error); 552155192Srwatson break; 553155192Srwatson } 554155192Srwatson 555155192Srwatson return (0); 556155192Srwatson} 557155192Srwatson 558156889Srwatson/* 559155192Srwatson * System calls to manage the user audit information. 560155192Srwatson */ 561155192Srwatson/* ARGSUSED */ 562155192Srwatsonint 563225617Skmacysys_getauid(struct thread *td, struct getauid_args *uap) 564155192Srwatson{ 565155192Srwatson int error; 566155192Srwatson 567163207Scsjp if (jailed(td->td_ucred)) 568163207Scsjp return (ENOSYS); 569164033Srwatson error = priv_check(td, PRIV_AUDIT_GETAUDIT); 570155192Srwatson if (error) 571155192Srwatson return (error); 572170407Srwatson return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid, 573170407Srwatson sizeof(td->td_ucred->cr_audit.ai_auid))); 574155192Srwatson} 575155192Srwatson 576155192Srwatson/* ARGSUSED */ 577155192Srwatsonint 578225617Skmacysys_setauid(struct thread *td, struct setauid_args *uap) 579155192Srwatson{ 580170407Srwatson struct ucred *newcred, *oldcred; 581170407Srwatson au_id_t id; 582155192Srwatson int error; 583155192Srwatson 584163207Scsjp if (jailed(td->td_ucred)) 585163207Scsjp return (ENOSYS); 586155192Srwatson error = copyin(uap->auid, &id, sizeof(id)); 587155192Srwatson if (error) 588155192Srwatson return (error); 589155192Srwatson audit_arg_auid(id); 590170407Srwatson newcred = crget(); 591170407Srwatson PROC_LOCK(td->td_proc); 592170407Srwatson oldcred = td->td_proc->p_ucred; 593170407Srwatson crcopy(newcred, oldcred); 594168933Srwatson#ifdef MAC 595189529Srwatson error = mac_cred_check_setauid(oldcred, id); 596168933Srwatson if (error) 597170407Srwatson goto fail; 598168933Srwatson#endif 599170407Srwatson error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 600170407Srwatson if (error) 601170407Srwatson goto fail; 602170407Srwatson newcred->cr_audit.ai_auid = id; 603170407Srwatson td->td_proc->p_ucred = newcred; 604155192Srwatson PROC_UNLOCK(td->td_proc); 605170407Srwatson crfree(oldcred); 606155192Srwatson return (0); 607170407Srwatsonfail: 608170407Srwatson PROC_UNLOCK(td->td_proc); 609170407Srwatson crfree(newcred); 610170407Srwatson return (error); 611155192Srwatson} 612155192Srwatson 613155192Srwatson/* 614156889Srwatson * System calls to get and set process audit information. 615155192Srwatson */ 616155192Srwatson/* ARGSUSED */ 617155192Srwatsonint 618225617Skmacysys_getaudit(struct thread *td, struct getaudit_args *uap) 619155192Srwatson{ 620155192Srwatson struct auditinfo ai; 621184948Srwatson struct ucred *cred; 622155192Srwatson int error; 623155192Srwatson 624184948Srwatson cred = td->td_ucred; 625184948Srwatson if (jailed(cred)) 626163207Scsjp return (ENOSYS); 627164033Srwatson error = priv_check(td, PRIV_AUDIT_GETAUDIT); 628155192Srwatson if (error) 629155192Srwatson return (error); 630184948Srwatson if (cred->cr_audit.ai_termid.at_type == AU_IPv6) 631185484Scsjp return (E2BIG); 632168688Scsjp bzero(&ai, sizeof(ai)); 633184948Srwatson ai.ai_auid = cred->cr_audit.ai_auid; 634184948Srwatson ai.ai_mask = cred->cr_audit.ai_mask; 635184948Srwatson ai.ai_asid = cred->cr_audit.ai_asid; 636184948Srwatson ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0]; 637184948Srwatson ai.ai_termid.port = cred->cr_audit.ai_termid.at_port; 638171066Scsjp return (copyout(&ai, uap->auditinfo, sizeof(ai))); 639155192Srwatson} 640155192Srwatson 641155192Srwatson/* ARGSUSED */ 642155192Srwatsonint 643225617Skmacysys_setaudit(struct thread *td, struct setaudit_args *uap) 644155192Srwatson{ 645170407Srwatson struct ucred *newcred, *oldcred; 646155192Srwatson struct auditinfo ai; 647155192Srwatson int error; 648155192Srwatson 649163207Scsjp if (jailed(td->td_ucred)) 650163207Scsjp return (ENOSYS); 651155192Srwatson error = copyin(uap->auditinfo, &ai, sizeof(ai)); 652155192Srwatson if (error) 653155192Srwatson return (error); 654155192Srwatson audit_arg_auditinfo(&ai); 655170407Srwatson newcred = crget(); 656170407Srwatson PROC_LOCK(td->td_proc); 657170407Srwatson oldcred = td->td_proc->p_ucred; 658170407Srwatson crcopy(newcred, oldcred); 659168933Srwatson#ifdef MAC 660189529Srwatson error = mac_cred_check_setaudit(oldcred, &ai); 661168933Srwatson if (error) 662170407Srwatson goto fail; 663168933Srwatson#endif 664170407Srwatson error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 665170407Srwatson if (error) 666170407Srwatson goto fail; 667170407Srwatson bzero(&newcred->cr_audit, sizeof(newcred->cr_audit)); 668170407Srwatson newcred->cr_audit.ai_auid = ai.ai_auid; 669170407Srwatson newcred->cr_audit.ai_mask = ai.ai_mask; 670170407Srwatson newcred->cr_audit.ai_asid = ai.ai_asid; 671170407Srwatson newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; 672170407Srwatson newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; 673170407Srwatson newcred->cr_audit.ai_termid.at_type = AU_IPv4; 674170407Srwatson td->td_proc->p_ucred = newcred; 675155192Srwatson PROC_UNLOCK(td->td_proc); 676170407Srwatson crfree(oldcred); 677155192Srwatson return (0); 678170407Srwatsonfail: 679170407Srwatson PROC_UNLOCK(td->td_proc); 680170407Srwatson crfree(newcred); 681170407Srwatson return (error); 682155192Srwatson} 683155192Srwatson 684155192Srwatson/* ARGSUSED */ 685155192Srwatsonint 686225617Skmacysys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 687155192Srwatson{ 688155192Srwatson int error; 689155192Srwatson 690163207Scsjp if (jailed(td->td_ucred)) 691163207Scsjp return (ENOSYS); 692170407Srwatson if (uap->length < sizeof(*uap->auditinfo_addr)) 693170407Srwatson return (EOVERFLOW); 694164033Srwatson error = priv_check(td, PRIV_AUDIT_GETAUDIT); 695155192Srwatson if (error) 696155192Srwatson return (error); 697170407Srwatson return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr, 698170407Srwatson sizeof(*uap->auditinfo_addr))); 699155192Srwatson} 700155192Srwatson 701155192Srwatson/* ARGSUSED */ 702155192Srwatsonint 703225617Skmacysys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 704155192Srwatson{ 705170407Srwatson struct ucred *newcred, *oldcred; 706168688Scsjp struct auditinfo_addr aia; 707155192Srwatson int error; 708155192Srwatson 709163207Scsjp if (jailed(td->td_ucred)) 710163207Scsjp return (ENOSYS); 711170407Srwatson error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); 712155192Srwatson if (error) 713155192Srwatson return (error); 714171066Scsjp audit_arg_auditinfo_addr(&aia); 715171066Scsjp if (aia.ai_termid.at_type != AU_IPv6 && 716171066Scsjp aia.ai_termid.at_type != AU_IPv4) 717171066Scsjp return (EINVAL); 718170407Srwatson newcred = crget(); 719170407Srwatson PROC_LOCK(td->td_proc); 720170407Srwatson oldcred = td->td_proc->p_ucred; 721170407Srwatson crcopy(newcred, oldcred); 722168933Srwatson#ifdef MAC 723189529Srwatson error = mac_cred_check_setaudit_addr(oldcred, &aia); 724168933Srwatson if (error) 725170407Srwatson goto fail; 726168933Srwatson#endif 727170407Srwatson error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 728168688Scsjp if (error) 729170407Srwatson goto fail; 730170407Srwatson newcred->cr_audit = aia; 731170407Srwatson td->td_proc->p_ucred = newcred; 732168688Scsjp PROC_UNLOCK(td->td_proc); 733170407Srwatson crfree(oldcred); 734170407Srwatson return (0); 735170407Srwatsonfail: 736170777Srwatson PROC_UNLOCK(td->td_proc); 737170407Srwatson crfree(newcred); 738168688Scsjp return (error); 739155192Srwatson} 740155192Srwatson 741155192Srwatson/* 742155192Srwatson * Syscall to manage audit files. 743155192Srwatson */ 744155192Srwatson/* ARGSUSED */ 745155192Srwatsonint 746225617Skmacysys_auditctl(struct thread *td, struct auditctl_args *uap) 747155192Srwatson{ 748155192Srwatson struct nameidata nd; 749155192Srwatson struct ucred *cred; 750155192Srwatson struct vnode *vp; 751155192Srwatson int error = 0; 752241896Skib int flags; 753155192Srwatson 754163207Scsjp if (jailed(td->td_ucred)) 755163207Scsjp return (ENOSYS); 756164033Srwatson error = priv_check(td, PRIV_AUDIT_CONTROL); 757155192Srwatson if (error) 758155192Srwatson return (error); 759155192Srwatson 760155192Srwatson vp = NULL; 761155192Srwatson cred = NULL; 762155192Srwatson 763155192Srwatson /* 764155192Srwatson * If a path is specified, open the replacement vnode, perform 765155192Srwatson * validity checks, and grab another reference to the current 766155192Srwatson * credential. 767155192Srwatson * 768165624Srwatson * On Darwin, a NULL path argument is also used to disable audit. 769155192Srwatson */ 770155192Srwatson if (uap->path == NULL) 771155192Srwatson return (EINVAL); 772155192Srwatson 773241896Skib NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, 774162944Srwatson UIO_USERSPACE, uap->path, td); 775155192Srwatson flags = AUDIT_OPEN_FLAGS; 776170183Skib error = vn_open(&nd, &flags, 0, NULL); 777159318Srwatson if (error) 778159318Srwatson return (error); 779155192Srwatson vp = nd.ni_vp; 780168933Srwatson#ifdef MAC 781172930Srwatson error = mac_system_check_auditctl(td->td_ucred, vp); 782175294Sattilio VOP_UNLOCK(vp, 0); 783168933Srwatson if (error) { 784168933Srwatson vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 785168933Srwatson return (error); 786168933Srwatson } 787168933Srwatson#else 788175294Sattilio VOP_UNLOCK(vp, 0); 789168933Srwatson#endif 790162944Srwatson NDFREE(&nd, NDF_ONLY_PNBUF); 791155192Srwatson if (vp->v_type != VREG) { 792155192Srwatson vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 793159318Srwatson return (EINVAL); 794155192Srwatson } 795155192Srwatson cred = td->td_ucred; 796155192Srwatson crhold(cred); 797155192Srwatson 798155192Srwatson /* 799155192Srwatson * XXXAUDIT: Should audit_suspended actually be cleared by 800155192Srwatson * audit_worker? 801155192Srwatson */ 802155192Srwatson audit_suspended = 0; 803155192Srwatson 804155192Srwatson audit_rotate_vnode(cred, vp); 805155192Srwatson 806155192Srwatson return (error); 807155192Srwatson} 808155192Srwatson 809155192Srwatson#else /* !AUDIT */ 810155192Srwatson 811155192Srwatsonint 812225617Skmacysys_audit(struct thread *td, struct audit_args *uap) 813155192Srwatson{ 814155192Srwatson 815155192Srwatson return (ENOSYS); 816155192Srwatson} 817155192Srwatson 818155192Srwatsonint 819225617Skmacysys_auditon(struct thread *td, struct auditon_args *uap) 820155192Srwatson{ 821155192Srwatson 822155192Srwatson return (ENOSYS); 823155192Srwatson} 824155192Srwatson 825155192Srwatsonint 826225617Skmacysys_getauid(struct thread *td, struct getauid_args *uap) 827155192Srwatson{ 828155192Srwatson 829155192Srwatson return (ENOSYS); 830155192Srwatson} 831155192Srwatson 832155192Srwatsonint 833225617Skmacysys_setauid(struct thread *td, struct setauid_args *uap) 834155192Srwatson{ 835155192Srwatson 836155192Srwatson return (ENOSYS); 837155192Srwatson} 838155192Srwatson 839155192Srwatsonint 840225617Skmacysys_getaudit(struct thread *td, struct getaudit_args *uap) 841155192Srwatson{ 842155192Srwatson 843155192Srwatson return (ENOSYS); 844155192Srwatson} 845155192Srwatson 846155192Srwatsonint 847225617Skmacysys_setaudit(struct thread *td, struct setaudit_args *uap) 848155192Srwatson{ 849155192Srwatson 850155192Srwatson return (ENOSYS); 851155192Srwatson} 852155192Srwatson 853155192Srwatsonint 854225617Skmacysys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 855155192Srwatson{ 856155192Srwatson 857155192Srwatson return (ENOSYS); 858155192Srwatson} 859155192Srwatson 860155192Srwatsonint 861225617Skmacysys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 862155192Srwatson{ 863155192Srwatson 864155192Srwatson return (ENOSYS); 865155192Srwatson} 866155192Srwatson 867155192Srwatsonint 868225617Skmacysys_auditctl(struct thread *td, struct auditctl_args *uap) 869155192Srwatson{ 870155192Srwatson 871155192Srwatson return (ENOSYS); 872155192Srwatson} 873155192Srwatson#endif /* AUDIT */ 874