audit_syscalls.c revision 176686
192986Sobrien/* 292986Sobrien * Copyright (c) 1999-2005 Apple Computer, Inc. 392986Sobrien * All rights reserved. 462856Sdcs * 562856Sdcs * Redistribution and use in source and binary forms, with or without 662856Sdcs * modification, are permitted provided that the following conditions 762856Sdcs * are met: 862856Sdcs * 1. Redistributions of source code must retain the above copyright 962856Sdcs * notice, this list of conditions and the following disclaimer. 1062856Sdcs * 2. Redistributions in binary form must reproduce the above copyright 1162856Sdcs * notice, this list of conditions and the following disclaimer in the 1262856Sdcs * documentation and/or other materials provided with the distribution. 1362856Sdcs * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 1462856Sdcs * its contributors may be used to endorse or promote products derived 1562856Sdcs * from this software without specific prior written permission. 1662856Sdcs * 1762856Sdcs * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 1862856Sdcs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1962856Sdcs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2062856Sdcs * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 2162856Sdcs * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2262856Sdcs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2362856Sdcs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2462856Sdcs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2592889Sobrien * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 2692889Sobrien * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2792889Sobrien * POSSIBILITY OF SUCH DAMAGE. 2892889Sobrien * 2962856Sdcs * $FreeBSD: head/sys/security/audit/audit_syscalls.c 176686 2008-03-01 11:04:04Z rwatson $ 3062856Sdcs */ 3162856Sdcs 3262856Sdcs#include "opt_mac.h" 3362856Sdcs 3462856Sdcs#include <sys/param.h> 3562856Sdcs#include <sys/mount.h> 3662856Sdcs#include <sys/namei.h> 3762856Sdcs#include <sys/priv.h> 3862856Sdcs#include <sys/proc.h> 3962856Sdcs#include <sys/sysproto.h> 4062856Sdcs#include <sys/systm.h> 4162856Sdcs#include <sys/vnode.h> 4262856Sdcs#include <sys/jail.h> 4362856Sdcs 4462856Sdcs#include <bsm/audit.h> 4562856Sdcs#include <bsm/audit_kevents.h> 4662856Sdcs 4762856Sdcs#include <security/audit/audit.h> 4862856Sdcs#include <security/audit/audit_private.h> 4962856Sdcs#include <security/mac/mac_framework.h> 5062856Sdcs 5162856Sdcs#ifdef AUDIT 5262856Sdcs 5362856Sdcs/* 5462856Sdcs * System call to allow a user space application to submit a BSM audit record 5562856Sdcs * to the kernel for inclusion in the audit log. This function does little 5662856Sdcs * verification on the audit record that is submitted. 5762856Sdcs * 5862856Sdcs * XXXAUDIT: Audit preselection for user records does not currently work, 5962856Sdcs * since we pre-select only based on the AUE_audit event type, not the event 6062856Sdcs * type submitted as part of the user audit data. 6162856Sdcs */ 6262856Sdcs/* ARGSUSED */ 6362856Sdcsint 6462856Sdcsaudit(struct thread *td, struct audit_args *uap) 6562856Sdcs{ 6662856Sdcs int error; 6762856Sdcs void * rec; 6862856Sdcs struct kaudit_record *ar; 6962856Sdcs 7062856Sdcs if (jailed(td->td_ucred)) 7162856Sdcs return (ENOSYS); 7262856Sdcs error = priv_check(td, PRIV_AUDIT_SUBMIT); 7362856Sdcs if (error) 7462856Sdcs return (error); 7562856Sdcs 7662856Sdcs if ((uap->length <= 0) || (uap->length > audit_qctrl.aq_bufsz)) 7762856Sdcs return (EINVAL); 7862856Sdcs 7962856Sdcs ar = currecord(); 8062856Sdcs 8162856Sdcs /* 8262856Sdcs * If there's no current audit record (audit() itself not audited) 8362856Sdcs * commit the user audit record. 8462856Sdcs */ 8562856Sdcs if (ar == NULL) { 8662856Sdcs 8762856Sdcs /* 8862856Sdcs * This is not very efficient; we're required to allocate a 8962856Sdcs * complete kernel audit record just so the user record can 9062856Sdcs * tag along. 9192889Sobrien * 9262856Sdcs * XXXAUDIT: Maybe AUE_AUDIT in the system call context and 9362856Sdcs * special pre-select handling? 9462856Sdcs */ 9592889Sobrien td->td_ar = audit_new(AUE_NULL, td); 9662856Sdcs if (td->td_ar == NULL) 9762856Sdcs return (ENOTSUP); 9892889Sobrien ar = td->td_ar; 9992889Sobrien } 10092889Sobrien 10192889Sobrien if (uap->length > MAX_AUDIT_RECORD_SIZE) 10292889Sobrien return (EINVAL); 10392889Sobrien 10492889Sobrien rec = malloc(uap->length, M_AUDITDATA, M_WAITOK); 10592889Sobrien 10662856Sdcs error = copyin(uap->record, rec, uap->length); 10762856Sdcs if (error) 10862856Sdcs goto free_out; 10962856Sdcs 11062856Sdcs /* Verify the record. */ 11162856Sdcs if (bsm_rec_verify(rec) == 0) { 11262856Sdcs error = EINVAL; 11362856Sdcs goto free_out; 11462856Sdcs } 11562856Sdcs 11662856Sdcs#ifdef MAC 11762856Sdcs error = mac_system_check_audit(td->td_ucred, rec, uap->length); 11862856Sdcs if (error) 11962856Sdcs goto free_out; 12062856Sdcs#endif 12162856Sdcs 12262856Sdcs /* 12362856Sdcs * Attach the user audit record to the kernel audit record. Because 12462856Sdcs * this system call is an auditable event, we will write the user 12562856Sdcs * record along with the record for this audit event. 12662856Sdcs * 12762856Sdcs * XXXAUDIT: KASSERT appropriate starting values of k_udata, k_ulen, 12862856Sdcs * k_ar_commit & AR_COMMIT_USER? 12962856Sdcs */ 13062856Sdcs ar->k_udata = rec; 13162856Sdcs ar->k_ulen = uap->length; 13262856Sdcs ar->k_ar_commit |= AR_COMMIT_USER; 13362856Sdcs 13462856Sdcs /* 13562856Sdcs * Currently we assume that all preselection has been performed in 13662856Sdcs * userspace. We unconditionally set these masks so that the records 13762856Sdcs * get committed both to the trail and pipe. In the future we will 13862856Sdcs * want to setup kernel based preselection. 13962856Sdcs */ 14062856Sdcs ar->k_ar_commit |= (AR_PRESELECT_USER_TRAIL | AR_PRESELECT_USER_PIPE); 14162856Sdcs return (0); 14262856Sdcs 14362856Sdcsfree_out: 14462856Sdcs /* 14562856Sdcs * audit_syscall_exit() will free the audit record on the thread even 14662856Sdcs * if we allocated it above. 14762856Sdcs */ 14862856Sdcs free(rec, M_AUDITDATA); 14962856Sdcs return (error); 15062856Sdcs} 15162856Sdcs 15262856Sdcs/* 15362856Sdcs * System call to manipulate auditing. 15462856Sdcs */ 15562856Sdcs/* ARGSUSED */ 15662856Sdcsint 15762856Sdcsauditon(struct thread *td, struct auditon_args *uap) 15862856Sdcs{ 15962856Sdcs struct ucred *newcred, *oldcred; 16062856Sdcs int error; 16162856Sdcs union auditon_udata udata; 16262856Sdcs struct proc *tp; 16362856Sdcs 16462856Sdcs if (jailed(td->td_ucred)) 16562856Sdcs return (ENOSYS); 16662856Sdcs AUDIT_ARG(cmd, uap->cmd); 16762856Sdcs 16862856Sdcs#ifdef MAC 16962856Sdcs error = mac_system_check_auditon(td->td_ucred, uap->cmd); 17062856Sdcs if (error) 17162856Sdcs return (error); 17262856Sdcs#endif 17362856Sdcs 17462856Sdcs error = priv_check(td, PRIV_AUDIT_CONTROL); 17562856Sdcs if (error) 17662856Sdcs return (error); 17762856Sdcs 17862856Sdcs if ((uap->length <= 0) || (uap->length > sizeof(union auditon_udata))) 17962856Sdcs return (EINVAL); 18062856Sdcs 18162856Sdcs memset((void *)&udata, 0, sizeof(udata)); 18262856Sdcs 18362856Sdcs /* 18462856Sdcs * Some of the GET commands use the arguments too. 18562856Sdcs */ 18662856Sdcs switch (uap->cmd) { 18762856Sdcs case A_SETPOLICY: 18862856Sdcs case A_SETKMASK: 18962856Sdcs case A_SETQCTRL: 19062856Sdcs case A_SETSTAT: 19162856Sdcs case A_SETUMASK: 19262856Sdcs case A_SETSMASK: 19362856Sdcs case A_SETCOND: 19462856Sdcs case A_SETCLASS: 19562856Sdcs case A_SETPMASK: 19662856Sdcs case A_SETFSIZE: 19762856Sdcs case A_SETKAUDIT: 19862856Sdcs case A_GETCLASS: 19962856Sdcs case A_GETPINFO: 20062856Sdcs case A_GETPINFO_ADDR: 20162856Sdcs case A_SENDTRIGGER: 20262856Sdcs error = copyin(uap->data, (void *)&udata, uap->length); 20362856Sdcs if (error) 20462856Sdcs return (error); 20562856Sdcs AUDIT_ARG(auditon, &udata); 20662856Sdcs break; 20762856Sdcs } 20862856Sdcs 20962856Sdcs /* 21062856Sdcs * XXXAUDIT: Locking? 21162856Sdcs */ 21262856Sdcs switch (uap->cmd) { 21362856Sdcs case A_GETPOLICY: 21462856Sdcs if (!audit_fail_stop) 21562856Sdcs udata.au_policy |= AUDIT_CNT; 21662856Sdcs if (audit_panic_on_write_fail) 21762856Sdcs udata.au_policy |= AUDIT_AHLT; 21862856Sdcs if (audit_argv) 21962856Sdcs udata.au_policy |= AUDIT_ARGV; 22062856Sdcs if (audit_arge) 22162856Sdcs udata.au_policy |= AUDIT_ARGE; 22262856Sdcs break; 22362856Sdcs 22462856Sdcs case A_SETPOLICY: 22562856Sdcs if (udata.au_policy & ~(AUDIT_CNT|AUDIT_AHLT|AUDIT_ARGV| 22662856Sdcs AUDIT_ARGE)) 22762856Sdcs return (EINVAL); 22862856Sdcs /* 22962856Sdcs * XXX - Need to wake up waiters if the policy relaxes? 23062856Sdcs */ 23162856Sdcs audit_fail_stop = ((udata.au_policy & AUDIT_CNT) == 0); 23262856Sdcs audit_panic_on_write_fail = (udata.au_policy & AUDIT_AHLT); 23362856Sdcs audit_argv = (udata.au_policy & AUDIT_ARGV); 23462856Sdcs audit_arge = (udata.au_policy & AUDIT_ARGE); 23562856Sdcs break; 23662856Sdcs 23762856Sdcs case A_GETKMASK: 23862856Sdcs udata.au_mask = audit_nae_mask; 23962856Sdcs break; 24062856Sdcs 24162856Sdcs case A_SETKMASK: 24262856Sdcs audit_nae_mask = udata.au_mask; 24362856Sdcs break; 24462856Sdcs 24562856Sdcs case A_GETQCTRL: 246 udata.au_qctrl = audit_qctrl; 247 break; 248 249 case A_SETQCTRL: 250 if ((udata.au_qctrl.aq_hiwater > AQ_MAXHIGH) || 251 (udata.au_qctrl.aq_lowater >= udata.au_qctrl.aq_hiwater) || 252 (udata.au_qctrl.aq_bufsz > AQ_MAXBUFSZ) || 253 (udata.au_qctrl.aq_minfree < 0) || 254 (udata.au_qctrl.aq_minfree > 100)) 255 return (EINVAL); 256 257 audit_qctrl = udata.au_qctrl; 258 /* XXX The queue delay value isn't used with the kernel. */ 259 audit_qctrl.aq_delay = -1; 260 break; 261 262 case A_GETCWD: 263 return (ENOSYS); 264 break; 265 266 case A_GETCAR: 267 return (ENOSYS); 268 break; 269 270 case A_GETSTAT: 271 return (ENOSYS); 272 break; 273 274 case A_SETSTAT: 275 return (ENOSYS); 276 break; 277 278 case A_SETUMASK: 279 return (ENOSYS); 280 break; 281 282 case A_SETSMASK: 283 return (ENOSYS); 284 break; 285 286 case A_GETCOND: 287 if (audit_enabled && !audit_suspended) 288 udata.au_cond = AUC_AUDITING; 289 else 290 udata.au_cond = AUC_NOAUDIT; 291 break; 292 293 case A_SETCOND: 294 if (udata.au_cond == AUC_NOAUDIT) 295 audit_suspended = 1; 296 if (udata.au_cond == AUC_AUDITING) 297 audit_suspended = 0; 298 if (udata.au_cond == AUC_DISABLED) { 299 audit_suspended = 1; 300 audit_shutdown(NULL, 0); 301 } 302 break; 303 304 case A_GETCLASS: 305 udata.au_evclass.ec_class = au_event_class( 306 udata.au_evclass.ec_number); 307 break; 308 309 case A_SETCLASS: 310 au_evclassmap_insert(udata.au_evclass.ec_number, 311 udata.au_evclass.ec_class); 312 break; 313 314 case A_GETPINFO: 315 if (udata.au_aupinfo.ap_pid < 1) 316 return (EINVAL); 317 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) 318 return (EINVAL); 319 if (p_cansee(td, tp) != 0) { 320 PROC_UNLOCK(tp); 321 return (EINVAL); 322 } 323 if (tp->p_ucred->cr_audit.ai_termid.at_type == AU_IPv6) { 324 PROC_UNLOCK(tp); 325 return (EINVAL); 326 } 327 udata.au_aupinfo.ap_auid = 328 tp->p_ucred->cr_audit.ai_auid; 329 udata.au_aupinfo.ap_mask.am_success = 330 tp->p_ucred->cr_audit.ai_mask.am_success; 331 udata.au_aupinfo.ap_mask.am_failure = 332 tp->p_ucred->cr_audit.ai_mask.am_failure; 333 udata.au_aupinfo.ap_termid.machine = 334 tp->p_ucred->cr_audit.ai_termid.at_addr[0]; 335 udata.au_aupinfo.ap_termid.port = 336 (dev_t)tp->p_ucred->cr_audit.ai_termid.at_port; 337 udata.au_aupinfo.ap_asid = 338 tp->p_ucred->cr_audit.ai_asid; 339 PROC_UNLOCK(tp); 340 break; 341 342 case A_SETPMASK: 343 if (udata.au_aupinfo.ap_pid < 1) 344 return (EINVAL); 345 newcred = crget(); 346 if ((tp = pfind(udata.au_aupinfo.ap_pid)) == NULL) { 347 crfree(newcred); 348 return (EINVAL); 349 } 350 if (p_cansee(td, tp) != 0) { 351 PROC_UNLOCK(tp); 352 crfree(newcred); 353 return (EINVAL); 354 } 355 oldcred = tp->p_ucred; 356 crcopy(newcred, oldcred); 357 newcred->cr_audit.ai_mask.am_success = 358 udata.au_aupinfo.ap_mask.am_success; 359 newcred->cr_audit.ai_mask.am_failure = 360 udata.au_aupinfo.ap_mask.am_failure; 361 td->td_proc->p_ucred = newcred; 362 PROC_UNLOCK(tp); 363 crfree(oldcred); 364 break; 365 366 case A_SETFSIZE: 367 if ((udata.au_fstat.af_filesz != 0) && 368 (udata.au_fstat.af_filesz < MIN_AUDIT_FILE_SIZE)) 369 return (EINVAL); 370 audit_fstat.af_filesz = udata.au_fstat.af_filesz; 371 break; 372 373 case A_GETFSIZE: 374 udata.au_fstat.af_filesz = audit_fstat.af_filesz; 375 udata.au_fstat.af_currsz = audit_fstat.af_currsz; 376 break; 377 378 case A_GETPINFO_ADDR: 379 if (udata.au_aupinfo_addr.ap_pid < 1) 380 return (EINVAL); 381 if ((tp = pfind(udata.au_aupinfo_addr.ap_pid)) == NULL) 382 return (EINVAL); 383 udata.au_aupinfo_addr.ap_auid = 384 tp->p_ucred->cr_audit.ai_auid; 385 udata.au_aupinfo_addr.ap_mask.am_success = 386 tp->p_ucred->cr_audit.ai_mask.am_success; 387 udata.au_aupinfo_addr.ap_mask.am_failure = 388 tp->p_ucred->cr_audit.ai_mask.am_failure; 389 udata.au_aupinfo_addr.ap_termid = 390 tp->p_ucred->cr_audit.ai_termid; 391 udata.au_aupinfo_addr.ap_asid = 392 tp->p_ucred->cr_audit.ai_asid; 393 PROC_UNLOCK(tp); 394 break; 395 396 case A_GETKAUDIT: 397 return (ENOSYS); 398 break; 399 400 case A_SETKAUDIT: 401 return (ENOSYS); 402 break; 403 404 case A_SENDTRIGGER: 405 if ((udata.au_trigger < AUDIT_TRIGGER_MIN) || 406 (udata.au_trigger > AUDIT_TRIGGER_MAX)) 407 return (EINVAL); 408 return (audit_send_trigger(udata.au_trigger)); 409 } 410 411 /* 412 * Copy data back to userspace for the GET comands. 413 */ 414 switch (uap->cmd) { 415 case A_GETPOLICY: 416 case A_GETKMASK: 417 case A_GETQCTRL: 418 case A_GETCWD: 419 case A_GETCAR: 420 case A_GETSTAT: 421 case A_GETCOND: 422 case A_GETCLASS: 423 case A_GETPINFO: 424 case A_GETFSIZE: 425 case A_GETPINFO_ADDR: 426 case A_GETKAUDIT: 427 error = copyout((void *)&udata, uap->data, uap->length); 428 if (error) 429 return (error); 430 break; 431 } 432 433 return (0); 434} 435 436/* 437 * System calls to manage the user audit information. 438 */ 439/* ARGSUSED */ 440int 441getauid(struct thread *td, struct getauid_args *uap) 442{ 443 int error; 444 445 if (jailed(td->td_ucred)) 446 return (ENOSYS); 447 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 448 if (error) 449 return (error); 450 return (copyout(&td->td_ucred->cr_audit.ai_auid, uap->auid, 451 sizeof(td->td_ucred->cr_audit.ai_auid))); 452} 453 454/* ARGSUSED */ 455int 456setauid(struct thread *td, struct setauid_args *uap) 457{ 458 struct ucred *newcred, *oldcred; 459 au_id_t id; 460 int error; 461 462 if (jailed(td->td_ucred)) 463 return (ENOSYS); 464 error = copyin(uap->auid, &id, sizeof(id)); 465 if (error) 466 return (error); 467 audit_arg_auid(id); 468 newcred = crget(); 469 PROC_LOCK(td->td_proc); 470 oldcred = td->td_proc->p_ucred; 471 crcopy(newcred, oldcred); 472#ifdef MAC 473 error = mac_proc_check_setauid(oldcred, id); 474 if (error) 475 goto fail; 476#endif 477 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 478 if (error) 479 goto fail; 480 newcred->cr_audit.ai_auid = id; 481 td->td_proc->p_ucred = newcred; 482 PROC_UNLOCK(td->td_proc); 483 crfree(oldcred); 484 return (0); 485fail: 486 PROC_UNLOCK(td->td_proc); 487 crfree(newcred); 488 return (error); 489} 490 491/* 492 * System calls to get and set process audit information. 493 */ 494/* ARGSUSED */ 495int 496getaudit(struct thread *td, struct getaudit_args *uap) 497{ 498 struct auditinfo ai; 499 int error; 500 501 if (jailed(td->td_ucred)) 502 return (ENOSYS); 503 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 504 if (error) 505 return (error); 506 if (td->td_ucred->cr_audit.ai_termid.at_type == AU_IPv6) 507 return (E2BIG); 508 bzero(&ai, sizeof(ai)); 509 ai.ai_auid = td->td_ucred->cr_audit.ai_auid; 510 ai.ai_mask = td->td_ucred->cr_audit.ai_mask; 511 ai.ai_asid = td->td_ucred->cr_audit.ai_asid; 512 ai.ai_termid.machine = td->td_ucred->cr_audit.ai_termid.at_addr[0]; 513 ai.ai_termid.port = td->td_ucred->cr_audit.ai_termid.at_port; 514 return (copyout(&ai, uap->auditinfo, sizeof(ai))); 515} 516 517/* ARGSUSED */ 518int 519setaudit(struct thread *td, struct setaudit_args *uap) 520{ 521 struct ucred *newcred, *oldcred; 522 struct auditinfo ai; 523 int error; 524 525 if (jailed(td->td_ucred)) 526 return (ENOSYS); 527 error = copyin(uap->auditinfo, &ai, sizeof(ai)); 528 if (error) 529 return (error); 530 audit_arg_auditinfo(&ai); 531 newcred = crget(); 532 PROC_LOCK(td->td_proc); 533 oldcred = td->td_proc->p_ucred; 534 crcopy(newcred, oldcred); 535#ifdef MAC 536 error = mac_proc_check_setaudit(oldcred, &ai); 537 if (error) 538 goto fail; 539#endif 540 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 541 if (error) 542 goto fail; 543 bzero(&newcred->cr_audit, sizeof(newcred->cr_audit)); 544 newcred->cr_audit.ai_auid = ai.ai_auid; 545 newcred->cr_audit.ai_mask = ai.ai_mask; 546 newcred->cr_audit.ai_asid = ai.ai_asid; 547 newcred->cr_audit.ai_termid.at_addr[0] = ai.ai_termid.machine; 548 newcred->cr_audit.ai_termid.at_port = ai.ai_termid.port; 549 newcred->cr_audit.ai_termid.at_type = AU_IPv4; 550 td->td_proc->p_ucred = newcred; 551 PROC_UNLOCK(td->td_proc); 552 crfree(oldcred); 553 return (0); 554fail: 555 PROC_UNLOCK(td->td_proc); 556 crfree(newcred); 557 return (error); 558} 559 560/* ARGSUSED */ 561int 562getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 563{ 564 int error; 565 566 if (jailed(td->td_ucred)) 567 return (ENOSYS); 568 if (uap->length < sizeof(*uap->auditinfo_addr)) 569 return (EOVERFLOW); 570 error = priv_check(td, PRIV_AUDIT_GETAUDIT); 571 if (error) 572 return (error); 573 return (copyout(&td->td_ucred->cr_audit, uap->auditinfo_addr, 574 sizeof(*uap->auditinfo_addr))); 575} 576 577/* ARGSUSED */ 578int 579setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 580{ 581 struct ucred *newcred, *oldcred; 582 struct auditinfo_addr aia; 583 int error; 584 585 if (jailed(td->td_ucred)) 586 return (ENOSYS); 587 error = copyin(uap->auditinfo_addr, &aia, sizeof(aia)); 588 if (error) 589 return (error); 590 audit_arg_auditinfo_addr(&aia); 591 if (aia.ai_termid.at_type != AU_IPv6 && 592 aia.ai_termid.at_type != AU_IPv4) 593 return (EINVAL); 594 newcred = crget(); 595 PROC_LOCK(td->td_proc); 596 oldcred = td->td_proc->p_ucred; 597 crcopy(newcred, oldcred); 598#ifdef MAC 599 error = mac_proc_check_setaudit_addr(oldcred, &aia); 600 if (error) 601 goto fail; 602#endif 603 error = priv_check_cred(oldcred, PRIV_AUDIT_SETAUDIT, 0); 604 if (error) 605 goto fail; 606 newcred->cr_audit = aia; 607 td->td_proc->p_ucred = newcred; 608 PROC_UNLOCK(td->td_proc); 609 crfree(oldcred); 610 return (0); 611fail: 612 PROC_UNLOCK(td->td_proc); 613 crfree(newcred); 614 return (error); 615} 616 617/* 618 * Syscall to manage audit files. 619 */ 620/* ARGSUSED */ 621int 622auditctl(struct thread *td, struct auditctl_args *uap) 623{ 624 struct nameidata nd; 625 struct ucred *cred; 626 struct vnode *vp; 627 int error = 0; 628 int flags, vfslocked; 629 630 if (jailed(td->td_ucred)) 631 return (ENOSYS); 632 error = priv_check(td, PRIV_AUDIT_CONTROL); 633 if (error) 634 return (error); 635 636 vp = NULL; 637 cred = NULL; 638 639 /* 640 * If a path is specified, open the replacement vnode, perform 641 * validity checks, and grab another reference to the current 642 * credential. 643 * 644 * On Darwin, a NULL path argument is also used to disable audit. 645 */ 646 if (uap->path == NULL) 647 return (EINVAL); 648 649 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | MPSAFE | AUDITVNODE1, 650 UIO_USERSPACE, uap->path, td); 651 flags = AUDIT_OPEN_FLAGS; 652 error = vn_open(&nd, &flags, 0, NULL); 653 if (error) 654 return (error); 655 vfslocked = NDHASGIANT(&nd); 656 vp = nd.ni_vp; 657#ifdef MAC 658 error = mac_system_check_auditctl(td->td_ucred, vp); 659 VOP_UNLOCK(vp, 0); 660 if (error) { 661 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 662 VFS_UNLOCK_GIANT(vfslocked); 663 return (error); 664 } 665#else 666 VOP_UNLOCK(vp, 0); 667#endif 668 NDFREE(&nd, NDF_ONLY_PNBUF); 669 if (vp->v_type != VREG) { 670 vn_close(vp, AUDIT_CLOSE_FLAGS, td->td_ucred, td); 671 VFS_UNLOCK_GIANT(vfslocked); 672 return (EINVAL); 673 } 674 VFS_UNLOCK_GIANT(vfslocked); 675 cred = td->td_ucred; 676 crhold(cred); 677 678 /* 679 * XXXAUDIT: Should audit_suspended actually be cleared by 680 * audit_worker? 681 */ 682 audit_suspended = 0; 683 684 audit_rotate_vnode(cred, vp); 685 686 return (error); 687} 688 689#else /* !AUDIT */ 690 691int 692audit(struct thread *td, struct audit_args *uap) 693{ 694 695 return (ENOSYS); 696} 697 698int 699auditon(struct thread *td, struct auditon_args *uap) 700{ 701 702 return (ENOSYS); 703} 704 705int 706getauid(struct thread *td, struct getauid_args *uap) 707{ 708 709 return (ENOSYS); 710} 711 712int 713setauid(struct thread *td, struct setauid_args *uap) 714{ 715 716 return (ENOSYS); 717} 718 719int 720getaudit(struct thread *td, struct getaudit_args *uap) 721{ 722 723 return (ENOSYS); 724} 725 726int 727setaudit(struct thread *td, struct setaudit_args *uap) 728{ 729 730 return (ENOSYS); 731} 732 733int 734getaudit_addr(struct thread *td, struct getaudit_addr_args *uap) 735{ 736 737 return (ENOSYS); 738} 739 740int 741setaudit_addr(struct thread *td, struct setaudit_addr_args *uap) 742{ 743 744 return (ENOSYS); 745} 746 747int 748auditctl(struct thread *td, struct auditctl_args *uap) 749{ 750 751 return (ENOSYS); 752} 753#endif /* AUDIT */ 754