audit_syscalls.c revision 191296
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 191296 2009-04-19 23:28:08Z 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 case A_GETPOLICY: 220 if (uap->length == sizeof(udata.au_policy64)) { 221 if (!audit_fail_stop) 222 udata.au_policy64 |= AUDIT_CNT; 223 if (audit_panic_on_write_fail) 224 udata.au_policy64 |= AUDIT_AHLT; 225 if (audit_argv) 226 udata.au_policy64 |= AUDIT_ARGV; 227 if (audit_arge) 228 udata.au_policy64 |= AUDIT_ARGE; 229 break; 230 } 231 if (uap->length != sizeof(udata.au_policy)) 232 return (EINVAL); 233 if (!audit_fail_stop) 234 udata.au_policy |= AUDIT_CNT; 235 if (audit_panic_on_write_fail) 236 udata.au_policy |= AUDIT_AHLT; 237 if (audit_argv) 238 udata.au_policy |= AUDIT_ARGV; 239 if (audit_arge) 240 udata.au_policy |= AUDIT_ARGE; 241 break; 242 243 case A_OLDSETPOLICY: 244 case A_SETPOLICY: 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 if (uap->length != sizeof(udata.au_policy)) 258 return (EINVAL); 259 if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 260 AUDIT_ARGE)) 261 return (EINVAL); 262 /* 263 * XXX - Need to wake up waiters if the policy relaxes? 264 */ 265 audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 266 audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 267 audit_argv = (udata.au_policy & AUDIT_ARGV); 268 audit_arge = (udata.au_policy & AUDIT_ARGE); 269 break; 270 271 case A_GETKMASK: 272 if (uap->length != sizeof(udata.au_mask)) 273 return (EINVAL); 274 udata.au_mask = audit_nae_mask; 275 break; 276 277 case A_SETKMASK: 278 if (uap->length != sizeof(udata.au_mask)) 279 return (EINVAL); 280 audit_nae_mask = udata.au_mask; 281 break; 282 283 case A_OLDGETQCTRL: 284 case A_GETQCTRL: 285 if (uap->length == sizeof(udata.au_qctrl64)) { 286 udata.au_qctrl64.aq64_hiwater = 287 (u_int64_t)audit_qctrl.aq_hiwater; 288 udata.au_qctrl64.aq64_lowater = 289 (u_int64_t)audit_qctrl.aq_lowater; 290 udata.au_qctrl64.aq64_bufsz = 291 (u_int64_t)audit_qctrl.aq_bufsz; 292 udata.au_qctrl64.aq64_minfree = 293 (u_int64_t)audit_qctrl.aq_minfree; 294 break; 295 } 296 if (uap->length != sizeof(udata.au_qctrl)) 297 return (EINVAL); 298 udata.au_qctrl = audit_qctrl; 299 break; 300 301 case A_OLDSETQCTRL: 302 case A_SETQCTRL: 303 if (uap->length == sizeof(udata.au_qctrl64)) { 304 if ((udata.au_qctrl64.aq64_hiwater > AQ_MAXHIGH) || 305 (udata.au_qctrl64.aq64_lowater >= 306 udata.au_qctrl.aq_hiwater) || 307 (udata.au_qctrl64.aq64_bufsz > AQ_MAXBUFSZ) || 308 (udata.au_qctrl64.aq64_minfree < 0) || 309 (udata.au_qctrl64.aq64_minfree > 100)) 310 return (EINVAL); 311 audit_qctrl.aq_hiwater = 312 (int)udata.au_qctrl64.aq64_hiwater; 313 audit_qctrl.aq_lowater = 314 (int)udata.au_qctrl64.aq64_lowater; 315 audit_qctrl.aq_bufsz = 316 (int)udata.au_qctrl64.aq64_bufsz; 317 audit_qctrl.aq_minfree = 318 (int)udata.au_qctrl64.aq64_minfree; 319 audit_qctrl.aq_delay = -1; /* Not used. */ 320 break; 321 } 322 if (uap->length != sizeof(udata.au_qctrl)) 323 return (EINVAL); 324 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 325 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 326 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 327 (udata.au_qctrl.aq_minfree < 0) || 328 (udata.au_qctrl.aq_minfree > 100)) 329 return (EINVAL); 330 331 audit_qctrl = udata.au_qctrl; 332 /* XXX The queue delay value isn't used with the kernel. */ 333 audit_qctrl.aq_delay = -1; 334 break; 335 336 case A_GETCWD: 337 return (ENOSYS); 338 break; 339 340 case A_GETCAR: 341 return (ENOSYS); 342 break; 343 344 case A_GETSTAT: 345 return (ENOSYS); 346 break; 347 348 case A_SETSTAT: 349 return (ENOSYS); 350 break; 351 352 case A_SETUMASK: 353 return (ENOSYS); 354 break; 355 356 case A_SETSMASK: 357 return (ENOSYS); 358 break; 359 360 case A_OLDGETCOND: 361 case A_GETCOND: 362 if (uap->length == sizeof(udata.au_cond64)) { 363 if (audit_enabled && !audit_suspended) 364 udata.au_cond64 = AUC_AUDITING; 365 else 366 udata.au_cond64 = AUC_NOAUDIT; 367 break; 368 } 369 if (uap->length != sizeof(udata.au_cond)) 370 return (EINVAL); 371 if (audit_enabled && !audit_suspended) 372 udata.au_cond = AUC_AUDITING; 373 else 374 udata.au_cond = AUC_NOAUDIT; 375 break; 376 377 case A_OLDSETCOND: 378 case A_SETCOND: 379 if (uap->length == sizeof(udata.au_cond64)) { 380 if (udata.au_cond64 == AUC_NOAUDIT) 381 audit_suspended = 1; 382 if (udata.au_cond64 == AUC_AUDITING) 383 audit_suspended = 0; 384 if (udata.au_cond64 == AUC_DISABLED) { 385 audit_suspended = 1; 386 audit_shutdown(NULL, 0); 387 } 388 break; 389 } 390 if (uap->length != sizeof(udata.au_cond)) 391 return (EINVAL); 392 if (udata.au_cond == AUC_NOAUDIT) 393 audit_suspended = 1; 394 if (udata.au_cond == AUC_AUDITING) 395 audit_suspended = 0; 396 if (udata.au_cond == AUC_DISABLED) { 397 audit_suspended = 1; 398 audit_shutdown(NULL, 0); 399 } 400 break; 401 402 case A_GETCLASS: 403 if (uap->length != sizeof(udata.au_evclass)) 404 return (EINVAL); 405 udata.au_evclass.ec_class = au_event_class( 406 udata.au_evclass.ec_number); 407 break; 408 409 case A_SETCLASS: 410 if (uap->length != sizeof(udata.au_evclass)) 411 return (EINVAL); 412 au_evclassmap_insert(udata.au_evclass.ec_number, 413 udata.au_evclass.ec_class); 414 break; 415 416 case A_GETPINFO: 417 if (uap->length != sizeof(udata.au_aupinfo)) 418 return (EINVAL); 419 if (udata.au_aupinfo.ap_pid < 1) 420 return (ESRCH); 421 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 422 return (ESRCH); 423 if ((error = p_cansee(td, tp)) != 0) { 424 PROC_UNLOCK(tp); 425 return (error); 426 } 427 cred = tp->p_ucred; 428 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) { 429 PROC_UNLOCK(tp); 430 return (EINVAL); 431 } 432 udata.au_aupinfo.ap_auid = cred->cr_audit.ai_auid; 433 udata.au_aupinfo.ap_mask.am_success = 434 cred->cr_audit.ai_mask.am_success; 435 udata.au_aupinfo.ap_mask.am_failure = 436 cred->cr_audit.ai_mask.am_failure; 437 udata.au_aupinfo.ap_termid.machine = 438 cred->cr_audit.ai_termid.at_addr[0]; 439 udata.au_aupinfo.ap_termid.port = 440 (dev_t)cred->cr_audit.ai_termid.at_port; 441 udata.au_aupinfo.ap_asid = cred->cr_audit.ai_asid; 442 PROC_UNLOCK(tp); 443 break; 444 445 case A_SETPMASK: 446 if (uap->length != sizeof(udata.au_aupinfo)) 447 return (EINVAL); 448 if (udata.au_aupinfo.ap_pid < 1) 449 return (ESRCH); 450 newcred = crget(); 451 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { 452 crfree(newcred); 453 return (ESRCH); 454 } 455 if ((error = p_cansee(td, tp)) != 0) { 456 PROC_UNLOCK(tp); 457 crfree(newcred); 458 return (error); 459 } 460 oldcred = tp->p_ucred; 461 crcopy(newcred, oldcred); 462 newcred->cr_audit.ai_mask.am_success = 463 udata.au_aupinfo.ap_mask.am_success; 464 newcred->cr_audit.ai_mask.am_failure = 465 udata.au_aupinfo.ap_mask.am_failure; 466 td->td_proc->p_ucred = newcred; 467 PROC_UNLOCK(tp); 468 crfree(oldcred); 469 break; 470 471 case A_SETFSIZE: 472 if (uap->length != sizeof(udata.au_fstat)) 473 return (EINVAL); 474 if ((udata.au_fstat.af_filesz != 0) && 475 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 476 return (EINVAL); 477 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 478 break; 479 480 case A_GETFSIZE: 481 if (uap->length != sizeof(udata.au_fstat)) 482 return (EINVAL); 483 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 484 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 485 break; 486 487 case A_GETPINFO_ADDR: 488 if (uap->length != sizeof(udata.au_aupinfo_addr)) 489 return (EINVAL); 490 if (udata.au_aupinfo_addr.ap_pid < 1) 491 return (ESRCH); 492 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) 493 return (ESRCH); 494 cred = tp->p_ucred; 495 udata.au_aupinfo_addr.ap_auid = cred->cr_audit.ai_auid; 496 udata.au_aupinfo_addr.ap_mask.am_success = 497 cred->cr_audit.ai_mask.am_success; 498 udata.au_aupinfo_addr.ap_mask.am_failure = 499 cred->cr_audit.ai_mask.am_failure; 500 udata.au_aupinfo_addr.ap_termid = cred->cr_audit.ai_termid; 501 udata.au_aupinfo_addr.ap_asid = cred->cr_audit.ai_asid; 502 PROC_UNLOCK(tp); 503 break; 504 505 case A_GETKAUDIT: 506 if (uap->length != sizeof(udata.au_kau_info)) 507 return (EINVAL); 508 audit_get_kinfo(&udata.au_kau_info); 509 break; 510 511 case A_SETKAUDIT: 512 if (uap->length != sizeof(udata.au_kau_info)) 513 return (EINVAL); 514 if (udata.au_kau_info.ai_termid.at_type != AU_IPv4 && 515 udata.au_kau_info.ai_termid.at_type != AU_IPv6) 516 return (EINVAL); 517 audit_set_kinfo(&udata.au_kau_info); 518 break; 519 520 case A_SENDTRIGGER: 521 if (uap->length != sizeof(udata.au_trigger)) 522 return (EINVAL); 523 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 524 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 525 return (EINVAL); 526 return (audit_send_trigger(udata.au_trigger)); 527 528 default: 529 return (EINVAL); 530 } 531 532 /* 533 * Copy data back to userspace for the GET comands. 534 */ 535 switch (uap->cmd) { 536 case A_GETPOLICY: 537 case A_OLDGETPOLICY: 538 case A_GETKMASK: 539 case A_GETQCTRL: 540 case A_OLDGETQCTRL: 541 case A_GETCWD: 542 case A_GETCAR: 543 case A_GETSTAT: 544 case A_GETCOND: 545 case A_OLDGETCOND: 546 case A_GETCLASS: 547 case A_GETPINFO: 548 case A_GETFSIZE: 549 case A_GETPINFO_ADDR: 550 case A_GETKAUDIT: 551 error = copyout((void *)&udata, uap->data, uap->length); 552 if (error) 553 return (error); 554 break; 555 } 556 557 return (0); 558} 559 560/* 561 * System calls to manage the user audit information. 562 */ 563/* ARGSUSED */ 564int 565getauid(struct thread *td, struct getauid_args *uap) 566{ 567 int error; 568 569 if (jailed(td->td_ucred)) 570 return (ENOSYS); 571 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 572 if (error) 573 return (error); 574 return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid, 575 sizeof(td->td_ucred->cr_audit.ai_auid))); 576} 577 578/* ARGSUSED */ 579int 580setauid(struct thread *td, struct setauid_args *uap) 581{ 582 struct ucred *newcred, *oldcred; 583 au_id_t id; 584 int error; 585 586 if (jailed(td->td_ucred)) 587 return (ENOSYS); 588 error = copyin(uap->auid, &id, sizeof(id)); 589 if (error) 590 return (error); 591 audit_arg_auid(id); 592 newcred = crget(); 593 PROC_LOCK(td->td_proc); 594 oldcred = td->td_proc->p_ucred; 595 crcopy(newcred, oldcred); 596#ifdef MAC 597 error = mac_cred_check_setauid(oldcred, id); 598 if (error) 599 goto fail; 600#endif 601 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 602 if (error) 603 goto fail; 604 newcred->cr_audit.ai_auid = id; 605 td->td_proc->p_ucred = newcred; 606 PROC_UNLOCK(td->td_proc); 607 crfree(oldcred); 608 return (0); 609fail: 610 PROC_UNLOCK(td->td_proc); 611 crfree(newcred); 612 return (error); 613} 614 615/* 616 * System calls to get and set process audit information. 617 */ 618/* ARGSUSED */ 619int 620getaudit(struct thread *td, struct getaudit_args *uap) 621{ 622 struct auditinfo ai; 623 struct ucred *cred; 624 int error; 625 626 cred = td->td_ucred; 627 if (jailed(cred)) 628 return (ENOSYS); 629 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 630 if (error) 631 return (error); 632 if (cred->cr_audit.ai_termid.at_type == AU_IPv6) 633 return (E2BIG); 634 bzero(&ai, sizeof(ai)); 635 ai.ai_auid = cred->cr_audit.ai_auid; 636 ai.ai_mask = cred->cr_audit.ai_mask; 637 ai.ai_asid = cred->cr_audit.ai_asid; 638 ai.ai_termid.machine = cred->cr_audit.ai_termid.at_addr[0]; 639 ai.ai_termid.port = cred->cr_audit.ai_termid.at_port; 640 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 641} 642 643/* ARGSUSED */ 644int 645setaudit(struct thread *td, struct setaudit_args *uap) 646{ 647 struct ucred *newcred, *oldcred; 648 struct auditinfo ai; 649 int error; 650 651 if (jailed(td->td_ucred)) 652 return (ENOSYS); 653 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 654 if (error) 655 return (error); 656 audit_arg_auditinfo(&ai); 657 newcred = crget(); 658 PROC_LOCK(td->td_proc); 659 oldcred = td->td_proc->p_ucred; 660 crcopy(newcred, oldcred); 661#ifdef MAC 662 error = mac_cred_check_setaudit(oldcred, &ai); 663 if (error) 664 goto fail; 665#endif 666 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 667 if (error) 668 goto fail; 669 bzero(&newcred->cr_audit, sizeof(newcred->cr_audit)); 670 newcred->cr_audit.ai_auid = ai.ai_auid; 671 newcred->cr_audit.ai_mask = ai.ai_mask; 672 newcred->cr_audit.ai_asid = ai.ai_asid; 673 newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; 674 newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; 675 newcred->cr_audit.ai_termid.at_type = AU_IPv4; 676 td->td_proc->p_ucred = newcred; 677 PROC_UNLOCK(td->td_proc); 678 crfree(oldcred); 679 return (0); 680fail: 681 PROC_UNLOCK(td->td_proc); 682 crfree(newcred); 683 return (error); 684} 685 686/* ARGSUSED */ 687int 688getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 689{ 690 int error; 691 692 if (jailed(td->td_ucred)) 693 return (ENOSYS); 694 if (uap->length < sizeof(*uap->auditinfo_addr)) 695 return (EOVERFLOW); 696 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 697 if (error) 698 return (error); 699 return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr, 700 sizeof(*uap->auditinfo_addr))); 701} 702 703/* ARGSUSED */ 704int 705setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 706{ 707 struct ucred *newcred, *oldcred; 708 struct auditinfo_addr aia; 709 int error; 710 711 if (jailed(td->td_ucred)) 712 return (ENOSYS); 713 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); 714 if (error) 715 return (error); 716 audit_arg_auditinfo_addr(&aia); 717 if (aia.ai_termid.at_type != AU_IPv6 && 718 aia.ai_termid.at_type != AU_IPv4) 719 return (EINVAL); 720 newcred = crget(); 721 PROC_LOCK(td->td_proc); 722 oldcred = td->td_proc->p_ucred; 723 crcopy(newcred, oldcred); 724#ifdef MAC 725 error = mac_cred_check_setaudit_addr(oldcred, &aia); 726 if (error) 727 goto fail; 728#endif 729 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 730 if (error) 731 goto fail; 732 newcred->cr_audit = aia; 733 td->td_proc->p_ucred = newcred; 734 PROC_UNLOCK(td->td_proc); 735 crfree(oldcred); 736 return (0); 737fail: 738 PROC_UNLOCK(td->td_proc); 739 crfree(newcred); 740 return (error); 741} 742 743/* 744 * Syscall to manage audit files. 745 */ 746/* ARGSUSED */ 747int 748auditctl(struct thread *td, struct auditctl_args *uap) 749{ 750 struct nameidata nd; 751 struct ucred *cred; 752 struct vnode *vp; 753 int error = 0; 754 int flags, vfslocked; 755 756 if (jailed(td->td_ucred)) 757 return (ENOSYS); 758 error = priv_check(td, PRIV_AUDIT_CONTROL); 759 if (error) 760 return (error); 761 762 vp = NULL; 763 cred = NULL; 764 765 /* 766 * If a path is specified, open the replacement vnode, perform 767 * validity checks, and grab another reference to the current 768 * credential. 769 * 770 * On Darwin, a NULL path argument is also used to disable audit. 771 */ 772 if (uap->path == NULL) 773 return (EINVAL); 774 775 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, 776 UIO_USERSPACE, uap->path, td); 777 flags = AUDIT_OPEN_FLAGS; 778 error = vn_open(&nd, &flags, 0, NULL); 779 if (error) 780 return (error); 781 vfslocked = NDHASGIANT(&nd); 782 vp = nd.ni_vp; 783#ifdef MAC 784 error = mac_system_check_auditctl(td->td_ucred, vp); 785 VOP_UNLOCK(vp, 0); 786 if (error) { 787 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 788 VFS_UNLOCK_GIANT(vfslocked); 789 return (error); 790 } 791#else 792 VOP_UNLOCK(vp, 0); 793#endif 794 NDFREE(&nd, NDF_ONLY_PNBUF); 795 if (vp->v_type != VREG) { 796 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 797 VFS_UNLOCK_GIANT(vfslocked); 798 return (EINVAL); 799 } 800 VFS_UNLOCK_GIANT(vfslocked); 801 cred = td->td_ucred; 802 crhold(cred); 803 804 /* 805 * XXXAUDIT: Should audit_suspended actually be cleared by 806 * audit_worker? 807 */ 808 audit_suspended = 0; 809 810 audit_rotate_vnode(cred, vp); 811 812 return (error); 813} 814 815#else /* !AUDIT */ 816 817int 818audit(struct thread *td, struct audit_args *uap) 819{ 820 821 return (ENOSYS); 822} 823 824int 825auditon(struct thread *td, struct auditon_args *uap) 826{ 827 828 return (ENOSYS); 829} 830 831int 832getauid(struct thread *td, struct getauid_args *uap) 833{ 834 835 return (ENOSYS); 836} 837 838int 839setauid(struct thread *td, struct setauid_args *uap) 840{ 841 842 return (ENOSYS); 843} 844 845int 846getaudit(struct thread *td, struct getaudit_args *uap) 847{ 848 849 return (ENOSYS); 850} 851 852int 853setaudit(struct thread *td, struct setaudit_args *uap) 854{ 855 856 return (ENOSYS); 857} 858 859int 860getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 861{ 862 863 return (ENOSYS); 864} 865 866int 867setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 868{ 869 870 return (ENOSYS); 871} 872 873int 874auditctl(struct thread *td, struct auditctl_args *uap) 875{ 876 877 return (ENOSYS); 878} 879#endif /* AUDIT */ 880