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