1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1999-2009 Apple Inc. 5 * Copyright (c) 2016 Robert N. M. Watson 6 * All rights reserved. 7 * 8 * Portions of this software were developed by BAE Systems, the University of 9 * Cambridge Computer Laboratory, and Memorial University under DARPA/AFRL 10 * contract FA8650-15-C-7558 ("CADETS"), as part of the DARPA Transparent 11 * Computing (TC) research program. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 22 * its contributors may be used to endorse or promote products derived 23 * from this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 29 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 34 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 * POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/cdefs.h> 39 __FBSDID("$FreeBSD$"); 40 41 #include <sys/param.h> 42 #include <sys/mount.h> 43 #include <sys/namei.h> 44 #include <sys/priv.h> 45 #include <sys/proc.h> 46 #include <sys/sysproto.h> 47 #include <sys/systm.h> 48 #include <sys/vnode.h> 49 #include <sys/jail.h> 50 51 #include <bsm/audit.h> 52 #include <bsm/audit_kevents.h> 53 54 #include <security/audit/audit.h> 55 #include <security/audit/audit_private.h> 56 #include <security/mac/mac_framework.h> 57 58 #ifdef AUDIT 59 60 /* 61 * System call to allow a user space application to submit a BSM audit record 62 * to the kernel for inclusion in the audit log. This function does little 63 * verification on the audit record that is submitted. 64 * 65 * XXXAUDIT: Audit preselection for user records does not currently work, 66 * since we pre-select only based on the AUE_audit event type, not the event 67 * type submitted as part of the user audit data. 68 */ 69 /* ARGSUSED */ 70 int 71 sys_audit(struct thread *td, struct audit_args *uap) 72 { 73 int error; 74 void * rec; 75 struct kaudit_record *ar; 76 77 if (jailed(td->td_ucred)) 78 return (ENOSYS); 79 error = priv_check(td, PRIV_AUDIT_SUBMIT); 80 if (error) 81 return (error); 82 83 if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) 84 return (EINVAL); 85 86 ar = currecord(); 87 88 /* 89 * If there's no current audit record (audit() itself not audited) 90 * commit the user audit record. 91 */ 92 if (ar == NULL) { 93 94 /* 95 * This is not very efficient; we're required to allocate a 96 * complete kernel audit record just so the user record can 97 * tag along. 98 * 99 * XXXAUDIT: Maybe AUE_AUDIT in the system call context and 100 * special pre-select handling? 101 */ 102 td->td_ar = audit_new(AUE_NULL, td); 103 if (td->td_ar == NULL) 104 return (ENOTSUP); 105 td->td_pflags |= TDP_AUDITREC; 106 ar = td->td_ar; 107 } 108 109 if (uap->length > MAX_AUDIT_RECORD_SIZE) 110 return (EINVAL); 111 112 rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); 113 114 error = copyin(uap->record, rec, uap->length); 115 if (error) 116 goto free_out; 117 118 /* Verify the record. */ 119 if (bsm_rec_verify(rec) == 0) { 120 error = EINVAL; 121 goto free_out; 122 } 123 124 #ifdef MAC 125 error = mac_system_check_audit(td->td_ucred, rec, uap->length); 126 if (error) 127 goto free_out; 128 #endif 129 130 /* 131 * Attach the user audit record to the kernel audit record. Because 132 * this system call is an auditable event, we will write the user 133 * record along with the record for this audit event. 134 * 135 * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, 136 * k_ar_commit & AR_COMMIT_USER? 137 */ 138 ar->k_udata = rec; 139 ar->k_ulen = uap->length; 140 ar->k_ar_commit |= AR_COMMIT_USER; 141 142 /* 143 * Currently we assume that all preselection has been performed in 144 * userspace. We unconditionally set these masks so that the records 145 * get committed both to the trail and pipe. In the future we will 146 * want to setup kernel based preselection. 147 */ 148 ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); 149 return (0); 150 151 free_out: 152 /* 153 * audit_syscall_exit() will free the audit record on the thread even 154 * if we allocated it above. 155 */ 156 free(rec, M_AUDITDATA); 157 return (error); 158 } 159 160 /* 161 * System call to manipulate auditing. 162 */ 163 /* ARGSUSED */ 164 int 165 sys_auditon(struct thread *td, struct auditon_args *uap) 166 { 167 struct ucred *cred, *newcred, *oldcred; 168 int error; 169 union auditon_udata udata; 170 struct proc *tp; 171 172 if (jailed(td->td_ucred)) 173 return (ENOSYS); 174 AUDIT_ARG_CMD(uap->cmd); 175 176 #ifdef MAC 177 error = mac_system_check_auditon(td->td_ucred, uap->cmd); 178 if (error) 179 return (error); 180 #endif 181 182 error = priv_check(td, PRIV_AUDIT_CONTROL); 183 if (error) 184 return (error); 185 186 if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata))) 187 return (EINVAL); 188 189 memset((void *)&udata, 0, sizeof(udata)); 190 191 /* 192 * Some of the GET commands use the arguments too. 193 */ 194 switch (uap->cmd) { 195 case A_SETPOLICY: 196 case A_OLDSETPOLICY: 197 case A_SETKMASK: 198 case A_SETQCTRL: 199 case A_OLDSETQCTRL: 200 case A_SETSTAT: 201 case A_SETUMASK: 202 case A_SETSMASK: 203 case A_SETCOND: 204 case A_OLDSETCOND: 205 case A_SETCLASS: 206 case A_SETEVENT: 207 case A_SETPMASK: 208 case A_SETFSIZE: 209 case A_SETKAUDIT: 210 case A_GETCLASS: 211 case A_GETEVENT: 212 case A_GETPINFO: 213 case A_GETPINFO_ADDR: 214 case A_SENDTRIGGER: 215 error = copyin(uap->data, (void *)&udata, uap->length); 216 if (error) 217 return (error); 218 AUDIT_ARG_AUDITON(&udata); 219 break; 220 } 221 222 /* 223 * XXXAUDIT: Locking? 224 */ 225 switch (uap->cmd) { 226 case A_OLDGETPOLICY: 227 case A_GETPOLICY: 228 if (uap->length == sizeof(udata.au_policy64)) { 229 if (!audit_fail_stop) 230 udata.au_policy64 |= AUDIT_CNT; 231 if (audit_panic_on_write_fail) 232 udata.au_policy64 |= AUDIT_AHLT; 233 if (audit_argv) 234 udata.au_policy64 |= AUDIT_ARGV; 235 if (audit_arge) 236 udata.au_policy64 |= AUDIT_ARGE; 237 break; 238 } 239 if (uap->length != sizeof(udata.au_policy)) 240 return (EINVAL); 241 if (!audit_fail_stop) 242 udata.au_policy |= AUDIT_CNT; 243 if (audit_panic_on_write_fail) 244 udata.au_policy |= AUDIT_AHLT; 245 if (audit_argv) 246 udata.au_policy |= AUDIT_ARGV; 247 if (audit_arge) 248 udata.au_policy |= AUDIT_ARGE; 249 break; 250 251 case A_OLDSETPOLICY: 252 case A_SETPOLICY: 253 if (uap->length == sizeof(udata.au_policy64)) { 254 if (udata.au_policy & (~AUDIT_CNT|AUDIT_AHLT| 255 AUDIT_ARGV|AUDIT_ARGE)) 256 return (EINVAL); 257 audit_fail_stop = ((udata.au_policy64 & AUDIT_CNT) == 258 0); 259 audit_panic_on_write_fail = (udata.au_policy64 & 260 AUDIT_AHLT); 261 audit_argv = (udata.au_policy64 & AUDIT_ARGV); 262 audit_arge = (udata.au_policy64 & AUDIT_ARGE); 263 break; 264 } 265 if (uap->length != sizeof(udata.au_policy)) 266 return (EINVAL); 267 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 268 AUDIT_ARGE)) 269 return (EINVAL); 270 /* 271 * XXX - Need to wake up waiters if the policy relaxes? 272 */ 273 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 274 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 275 audit_argv = (udata.au_policy & AUDIT_ARGV); 276 audit_arge = (udata.au_policy & AUDIT_ARGE); 277 break; 278 279 case A_GETKMASK: 280 if (uap->length != sizeof(udata.au_mask)) 281 return (EINVAL); 282 udata.au_mask = audit_nae_mask; 283 break; 284 285 case A_SETKMASK: 286 if (uap->length != sizeof(udata.au_mask)) 287 return (EINVAL); 288 audit_nae_mask = udata.au_mask; 289 break; 290 291 case A_OLDGETQCTRL: 292 case A_GETQCTRL: 293 if (uap->length == sizeof(udata.au_qctrl64)) { 294 udata.au_qctrl64.aq64_hiwater = 295 (u_int64_t)audit_qctrl.aq_hiwater; 296 udata.au_qctrl64.aq64_lowater = 297 (u_int64_t)audit_qctrl.aq_lowater; 298 udata.au_qctrl64.aq64_bufsz = 299 (u_int64_t)audit_qctrl.aq_bufsz; 300 udata.au_qctrl64.aq64_minfree = 301 (u_int64_t)audit_qctrl.aq_minfree; 302 break; 303 } 304 if (uap->length != sizeof(udata.au_qctrl)) 305 return (EINVAL); 306 udata.au_qctrl = audit_qctrl; 307 break; 308 309 case A_OLDSETQCTRL: 310 case A_SETQCTRL: 311 if (uap->length == sizeof(udata.au_qctrl64)) { 312 /* NB: aq64_minfree is unsigned unlike aq_minfree. */ 313 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || 314 (udata.au_qctrl64.aq64_lowater >= 315 udata.au_qctrl.aq_hiwater) || 316 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || 317 (udata.au_qctrl64.aq64_minfree > 100)) 318 return (EINVAL); 319 audit_qctrl.aq_hiwater = 320 (int)udata.au_qctrl64.aq64_hiwater; 321 audit_qctrl.aq_lowater = 322 (int)udata.au_qctrl64.aq64_lowater; 323 audit_qctrl.aq_bufsz = 324 (int)udata.au_qctrl64.aq64_bufsz; 325 audit_qctrl.aq_minfree = 326 (int)udata.au_qctrl64.aq64_minfree; 327 audit_qctrl.aq_delay = -1; /* Not used. */ 328 break; 329 } 330 if (uap->length != sizeof(udata.au_qctrl)) 331 return (EINVAL); 332 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 333 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 334 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 335 (udata.au_qctrl.aq_minfree < 0) || 336 (udata.au_qctrl.aq_minfree > 100)) 337 return (EINVAL); 338 339 audit_qctrl = udata.au_qctrl; 340 /* XXX The queue delay value isn't used with the kernel. */ 341 audit_qctrl.aq_delay = -1; 342 break; 343 344 case A_GETCWD: 345 return (ENOSYS); 346 break; 347 348 case A_GETCAR: 349 return (ENOSYS); 350 break; 351 352 case A_GETSTAT: 353 return (ENOSYS); 354 break; 355 356 case A_SETSTAT: 357 return (ENOSYS); 358 break; 359 360 case A_SETUMASK: 361 return (ENOSYS); 362 break; 363 364 case A_SETSMASK: 365 return (ENOSYS); 366 break; 367 368 case A_OLDGETCOND: 369 case A_GETCOND: 370 if (uap->length == sizeof(udata.au_cond64)) { 371 if (audit_enabled && !audit_suspended) 372 udata.au_cond64 = AUC_AUDITING; 373 else 374 udata.au_cond64 = AUC_NOAUDIT; 375 break; 376 } 377 if (uap->length != sizeof(udata.au_cond)) 378 return (EINVAL); 379 if (audit_enabled && !audit_suspended) 380 udata.au_cond = AUC_AUDITING; 381 else 382 udata.au_cond = AUC_NOAUDIT; 383 break; 384 385 case A_OLDSETCOND: 386 case A_SETCOND: 387 if (uap->length == sizeof(udata.au_cond64)) { 388 if (udata.au_cond64 == AUC_NOAUDIT) 389 audit_suspended = 1; 390 if (udata.au_cond64 == AUC_AUDITING) 391 audit_suspended = 0; 392 if (udata.au_cond64 == AUC_DISABLED) { 393 audit_suspended = 1; 394 audit_shutdown(NULL, 0); 395 } 396 break; 397 } 398 if (uap->length != sizeof(udata.au_cond)) 399 return (EINVAL); 400 if (udata.au_cond == AUC_NOAUDIT) 401 audit_suspended = 1; 402 if (udata.au_cond == AUC_AUDITING) 403 audit_suspended = 0; 404 if (udata.au_cond == AUC_DISABLED) { 405 audit_suspended = 1; 406 audit_shutdown(NULL, 0); 407 } 408 break; 409 410 case A_GETCLASS: 411 if (uap->length != sizeof(udata.au_evclass)) 412 return (EINVAL); 413 udata.au_evclass.ec_class = au_event_class( 414 udata.au_evclass.ec_number); 415 break; 416 417 case A_GETEVENT: 418 if (uap->length != sizeof(udata.au_evname)) 419 return (EINVAL); 420 error = au_event_name(udata.au_evname.en_number, 421 udata.au_evname.en_name); 422 if (error != 0) 423 return (error); 424 break; 425 426 case A_SETCLASS: 427 if (uap->length != sizeof(udata.au_evclass)) 428 return (EINVAL); 429 au_evclassmap_insert(udata.au_evclass.ec_number, 430 udata.au_evclass.ec_class); 431 break; 432 433 case A_SETEVENT: 434 if (uap->length != sizeof(udata.au_evname)) 435 return (EINVAL); 436 437 /* Ensure nul termination from userspace. */ 438 udata.au_evname.en_name[sizeof(udata.au_evname.en_name) - 1] 439 = 0; 440 au_evnamemap_insert(udata.au_evname.en_number, 441 udata.au_evname.en_name); 442 break; 443 444 case A_GETPINFO: 445 if (uap->length != sizeof(udata.au_aupinfo)) 446 return (EINVAL); 447 if (udata.au_aupinfo.ap_pid < 1) 448 return (ESRCH); 449 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 450 return (ESRCH); 451 if ((error = p_cansee(td, tp)) != 0) { 452 PROC_UNLOCK(tp); 453 return (error); 454 } 455 cred = tp->p_ucred; 456 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) { 457 PROC_UNLOCK(tp); 458 return (EINVAL); 459 } 460 udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid; 461 udata.au_aupinfo.ap_mask.am_success = 462 cred->cr_audit.ai_mask.am_success; 463 udata.au_aupinfo.ap_mask.am_failure = 464 cred->cr_audit.ai_mask.am_failure; 465 udata.au_aupinfo.ap_termid.machine = 466 cred->cr_audit.ai_termid.at_addr[0]; 467 udata.au_aupinfo.ap_termid.port = 468 (dev_t)cred->cr_audit.ai_termid.at_port; 469 udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid; 470 PROC_UNLOCK(tp); 471 break; 472 473 case A_SETPMASK: 474 if (uap->length != sizeof(udata.au_aupinfo)) 475 return (EINVAL); 476 if (udata.au_aupinfo.ap_pid < 1) 477 return (ESRCH); 478 newcred = crget(); 479 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { 480 crfree(newcred); 481 return (ESRCH); 482 } 483 if ((error = p_cansee(td, tp)) != 0) { 484 PROC_UNLOCK(tp); 485 crfree(newcred); 486 return (error); 487 } 488 oldcred = tp->p_ucred; 489 crcopy(newcred, oldcred); 490 newcred->cr_audit.ai_mask.am_success = 491 udata.au_aupinfo.ap_mask.am_success; 492 newcred->cr_audit.ai_mask.am_failure = 493 udata.au_aupinfo.ap_mask.am_failure; 494 proc_set_cred(tp, newcred); 495 PROC_UNLOCK(tp); 496 crfree(oldcred); 497 break; 498 499 case A_SETFSIZE: 500 if (uap->length != sizeof(udata.au_fstat)) 501 return (EINVAL); 502 if ((udata.au_fstat.af_filesz != 0) && 503 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 504 return (EINVAL); 505 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 506 break; 507 508 case A_GETFSIZE: 509 if (uap->length != sizeof(udata.au_fstat)) 510 return (EINVAL); 511 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 512 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 513 break; 514 515 case A_GETPINFO_ADDR: 516 if (uap->length != sizeof(udata.au_aupinfo_addr)) 517 return (EINVAL); 518 if (udata.au_aupinfo_addr.ap_pid < 1) 519 return (ESRCH); 520 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) 521 return (ESRCH); 522 cred = tp->p_ucred; 523 udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid; 524 udata.au_aupinfo_addr.ap_mask.am_success = 525 cred->cr_audit.ai_mask.am_success; 526 udata.au_aupinfo_addr.ap_mask.am_failure = 527 cred->cr_audit.ai_mask.am_failure; 528 udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid; 529 udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid; 530 PROC_UNLOCK(tp); 531 break; 532 533 case A_GETKAUDIT: 534 if (uap->length != sizeof(udata.au_kau_info)) 535 return (EINVAL); 536 audit_get_kinfo(&udata.au_kau_info); 537 break; 538 539 case A_SETKAUDIT: 540 if (uap->length != sizeof(udata.au_kau_info)) 541 return (EINVAL); 542 if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && 543 udata.au_kau_info.ai_termid.at_type != AU_IPv6) 544 return (EINVAL); 545 audit_set_kinfo(&udata.au_kau_info); 546 break; 547 548 case A_SENDTRIGGER: 549 if (uap->length != sizeof(udata.au_trigger)) 550 return (EINVAL); 551 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 552 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 553 return (EINVAL); 554 return (audit_send_trigger(udata.au_trigger)); 555 556 default: 557 return (EINVAL); 558 } 559 560 /* 561 * Copy data back to userspace for the GET comands. 562 */ 563 switch (uap->cmd) { 564 case A_GETPOLICY: 565 case A_OLDGETPOLICY: 566 case A_GETKMASK: 567 case A_GETQCTRL: 568 case A_OLDGETQCTRL: 569 case A_GETCWD: 570 case A_GETCAR: 571 case A_GETSTAT: 572 case A_GETCOND: 573 case A_OLDGETCOND: 574 case A_GETCLASS: 575 case A_GETPINFO: 576 case A_GETFSIZE: 577 case A_GETPINFO_ADDR: 578 case A_GETKAUDIT: 579 error = copyout((void *)&udata, uap->data, uap->length); 580 if (error) 581 return (error); 582 break; 583 } 584 585 return (0); 586 } 587 588 /* 589 * System calls to manage the user audit information. 590 */ 591 /* ARGSUSED */ 592 int 593 sys_getauid(struct thread *td, struct getauid_args *uap) 594 { 595 int error; 596 597 if (jailed(td->td_ucred)) 598 return (ENOSYS); 599 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 600 if (error) 601 return (error); 602 return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid, 603 sizeof(td->td_ucred->cr_audit.ai_auid))); 604 } 605 606 /* ARGSUSED */ 607 int 608 sys_setauid(struct thread *td, struct setauid_args *uap) 609 { 610 struct ucred *newcred, *oldcred; 611 au_id_t id; 612 int error; 613 614 if (jailed(td->td_ucred)) 615 return (ENOSYS); 616 error = copyin(uap->auid, &id, sizeof(id)); 617 if (error) 618 return (error); 619 audit_arg_auid(id); 620 newcred = crget(); 621 PROC_LOCK(td->td_proc); 622 oldcred = td->td_proc->p_ucred; 623 crcopy(newcred, oldcred); 624 #ifdef MAC 625 error = mac_cred_check_setauid(oldcred, id); 626 if (error) 627 goto fail; 628 #endif 629 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 630 if (error) 631 goto fail; 632 newcred->cr_audit.ai_auid = id; 633 proc_set_cred(td->td_proc, newcred); 634 PROC_UNLOCK(td->td_proc); 635 crfree(oldcred); 636 return (0); 637 fail: 638 PROC_UNLOCK(td->td_proc); 639 crfree(newcred); 640 return (error); 641 } 642 643 /* 644 * System calls to get and set process audit information. 645 */ 646 /* ARGSUSED */ 647 int 648 sys_getaudit(struct thread *td, struct getaudit_args *uap) 649 { 650 struct auditinfo ai; 651 struct ucred *cred; 652 int error; 653 654 cred = td->td_ucred; 655 if (jailed(cred)) 656 return (ENOSYS); 657 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 658 if (error) 659 return (error); 660 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) 661 return (E2BIG); 662 bzero(&ai, sizeof(ai)); 663 ai.ai_auid = cred->cr_audit.ai_auid; 664 ai.ai_mask = cred->cr_audit.ai_mask; 665 ai.ai_asid = cred->cr_audit.ai_asid; 666 ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0]; 667 ai.ai_termid.port = cred->cr_audit.ai_termid.at_port; 668 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 669 } 670 671 /* ARGSUSED */ 672 int 673 sys_setaudit(struct thread *td, struct setaudit_args *uap) 674 { 675 struct ucred *newcred, *oldcred; 676 struct auditinfo ai; 677 int error; 678 679 if (jailed(td->td_ucred)) 680 return (ENOSYS); 681 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 682 if (error) 683 return (error); 684 audit_arg_auditinfo(&ai); 685 newcred = crget(); 686 PROC_LOCK(td->td_proc); 687 oldcred = td->td_proc->p_ucred; 688 crcopy(newcred, oldcred); 689 #ifdef MAC 690 error = mac_cred_check_setaudit(oldcred, &ai); 691 if (error) 692 goto fail; 693 #endif 694 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 695 if (error) 696 goto fail; 697 bzero(&newcred->cr_audit, sizeof(newcred->cr_audit)); 698 newcred->cr_audit.ai_auid = ai.ai_auid; 699 newcred->cr_audit.ai_mask = ai.ai_mask; 700 newcred->cr_audit.ai_asid = ai.ai_asid; 701 newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; 702 newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; 703 newcred->cr_audit.ai_termid.at_type = AU_IPv4; 704 proc_set_cred(td->td_proc, newcred); 705 PROC_UNLOCK(td->td_proc); 706 crfree(oldcred); 707 return (0); 708 fail: 709 PROC_UNLOCK(td->td_proc); 710 crfree(newcred); 711 return (error); 712 } 713 714 /* ARGSUSED */ 715 int 716 sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 717 { 718 int error; 719 720 if (jailed(td->td_ucred)) 721 return (ENOSYS); 722 if (uap->length < sizeof(*uap->auditinfo_addr)) 723 return (EOVERFLOW); 724 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 725 if (error) 726 return (error); 727 return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr, 728 sizeof(*uap->auditinfo_addr))); 729 } 730 731 /* ARGSUSED */ 732 int 733 sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 734 { 735 struct ucred *newcred, *oldcred; 736 struct auditinfo_addr aia; 737 int error; 738 739 if (jailed(td->td_ucred)) 740 return (ENOSYS); 741 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); 742 if (error) 743 return (error); 744 audit_arg_auditinfo_addr(&aia); 745 if (aia.ai_termid.at_type != AU_IPv6 && 746 aia.ai_termid.at_type != AU_IPv4) 747 return (EINVAL); 748 newcred = crget(); 749 PROC_LOCK(td->td_proc); 750 oldcred = td->td_proc->p_ucred; 751 crcopy(newcred, oldcred); 752 #ifdef MAC 753 error = mac_cred_check_setaudit_addr(oldcred, &aia); 754 if (error) 755 goto fail; 756 #endif 757 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 758 if (error) 759 goto fail; 760 newcred->cr_audit = aia; 761 proc_set_cred(td->td_proc, newcred); 762 PROC_UNLOCK(td->td_proc); 763 crfree(oldcred); 764 return (0); 765 fail: 766 PROC_UNLOCK(td->td_proc); 767 crfree(newcred); 768 return (error); 769 } 770 771 /* 772 * Syscall to manage audit files. 773 */ 774 /* ARGSUSED */ 775 int 776 sys_auditctl(struct thread *td, struct auditctl_args *uap) 777 { 778 struct nameidata nd; 779 struct ucred *cred; 780 struct vnode *vp; 781 int error = 0; 782 int flags; 783 784 if (jailed(td->td_ucred)) 785 return (ENOSYS); 786 error = priv_check(td, PRIV_AUDIT_CONTROL); 787 if (error) 788 return (error); 789 790 vp = NULL; 791 cred = NULL; 792 793 /* 794 * If a path is specified, open the replacement vnode, perform 795 * validity checks, and grab another reference to the current 796 * credential. 797 * 798 * On Darwin, a NULL path argument is also used to disable audit. 799 */ 800 if (uap->path == NULL) 801 return (EINVAL); 802 803 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNODE1, 804 UIO_USERSPACE, uap->path, td); 805 flags = AUDIT_OPEN_FLAGS; 806 error = vn_open(&nd, &flags, 0, NULL); 807 if (error) 808 return (error); 809 vp = nd.ni_vp; 810 #ifdef MAC 811 error = mac_system_check_auditctl(td->td_ucred, vp); 812 VOP_UNLOCK(vp, 0); 813 if (error) { 814 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 815 return (error); 816 } 817 #else 818 VOP_UNLOCK(vp, 0); 819 #endif 820 NDFREE(&nd, NDF_ONLY_PNBUF); 821 if (vp->v_type != VREG) { 822 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 823 return (EINVAL); 824 } 825 cred = td->td_ucred; 826 crhold(cred); 827 828 /* 829 * XXXAUDIT: Should audit_suspended actually be cleared by 830 * audit_worker? 831 */ 832 audit_suspended = 0; 833 834 audit_rotate_vnode(cred, vp); 835 836 return (error); 837 } 838 839 #else /* !AUDIT */ 840 841 int 842 sys_audit(struct thread *td, struct audit_args *uap) 843 { 844 845 return (ENOSYS); 846 } 847 848 int 849 sys_auditon(struct thread *td, struct auditon_args *uap) 850 { 851 852 return (ENOSYS); 853 } 854 855 int 856 sys_getauid(struct thread *td, struct getauid_args *uap) 857 { 858 859 return (ENOSYS); 860 } 861 862 int 863 sys_setauid(struct thread *td, struct setauid_args *uap) 864 { 865 866 return (ENOSYS); 867 } 868 869 int 870 sys_getaudit(struct thread *td, struct getaudit_args *uap) 871 { 872 873 return (ENOSYS); 874 } 875 876 int 877 sys_setaudit(struct thread *td, struct setaudit_args *uap) 878 { 879 880 return (ENOSYS); 881 } 882 883 int 884 sys_getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 885 { 886 887 return (ENOSYS); 888 } 889 890 int 891 sys_setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 892 { 893 894 return (ENOSYS); 895 } 896 897 int 898 sys_auditctl(struct thread *td, struct auditctl_args *uap) 899 { 900 901 return (ENOSYS); 902 } 903 #endif /* AUDIT */ 904