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