1/*- 2 * Copyright (c) 1999-2009 Apple Inc. 3 * Copyright (c) 2005 Robert N. M. Watson 4 * All rights reserved. 5 * 6 * @APPLE_BSD_LICENSE_HEADER_START@ 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of Apple Inc. ("Apple") nor the names of 17 * its contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR 24 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 * @APPLE_BSD_LICENSE_HEADER_END@ 33 */ 34/* 35 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce 36 * support for mandatory and extensible security protections. This notice 37 * is included in support of clause 2.2 (b) of the Apple Public License, 38 * Version 2.0. 39 */ 40 41#include <sys/systm.h> 42#include <sys/sysent.h> 43#include <sys/types.h> 44#include <sys/proc_internal.h> 45#include <sys/vnode_internal.h> 46#include <sys/fcntl.h> 47#include <sys/filedesc.h> 48#include <sys/sem.h> 49 50#include <bsm/audit.h> 51#include <bsm/audit_kevents.h> 52#include <security/audit/audit.h> 53#include <security/audit/audit_bsd.h> 54#include <security/audit/audit_private.h> 55 56#if CONFIG_AUDIT 57/* 58 * Hash table functions for the audit event number to event class mask 59 * mapping. 60 */ 61#define EVCLASSMAP_HASH_TABLE_SIZE 251 62struct evclass_elem { 63 au_event_t event; 64 au_class_t class; 65 LIST_ENTRY(evclass_elem) entry; 66}; 67struct evclass_list { 68 LIST_HEAD(, evclass_elem) head; 69}; 70 71static MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class"); 72static struct rwlock evclass_lock; 73static struct evclass_list evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE]; 74 75#define EVCLASS_LOCK_INIT() rw_init(&evclass_lock, "evclass_lock") 76#define EVCLASS_RLOCK() rw_rlock(&evclass_lock) 77#define EVCLASS_RUNLOCK() rw_runlock(&evclass_lock) 78#define EVCLASS_WLOCK() rw_wlock(&evclass_lock) 79#define EVCLASS_WUNLOCK() rw_wunlock(&evclass_lock) 80 81/* 82 * Look up the class for an audit event in the class mapping table. 83 */ 84au_class_t 85au_event_class(au_event_t event) 86{ 87 struct evclass_list *evcl; 88 struct evclass_elem *evc; 89 au_class_t class; 90 91 EVCLASS_RLOCK(); 92 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 93 class = 0; 94 LIST_FOREACH(evc, &evcl->head, entry) { 95 if (evc->event == event) { 96 class = evc->class; 97 goto out; 98 } 99 } 100out: 101 EVCLASS_RUNLOCK(); 102 return (class); 103} 104 105/* 106 * Insert a event to class mapping. If the event already exists in the 107 * mapping, then replace the mapping with the new one. 108 * 109 * XXX There is currently no constraints placed on the number of mappings. 110 * May want to either limit to a number, or in terms of memory usage. 111 */ 112void 113au_evclassmap_insert(au_event_t event, au_class_t class) 114{ 115 struct evclass_list *evcl; 116 struct evclass_elem *evc, *evc_new; 117 118 /* 119 * If this event requires auditing a system call then add it to our 120 * audit kernel event mask. We use audit_kevent_mask to check to see 121 * if the audit syscalls flag needs to be set when preselection masks 122 * are set. 123 */ 124 if (AUE_IS_A_KEVENT(event)) 125 audit_kevent_mask |= class; 126 127 /* 128 * Pessimistically, always allocate storage before acquiring mutex. 129 * Free if there is already a mapping for this event. 130 */ 131 evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK); 132 133 EVCLASS_WLOCK(); 134 evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE]; 135 LIST_FOREACH(evc, &evcl->head, entry) { 136 if (evc->event == event) { 137 evc->class = class; 138 EVCLASS_WUNLOCK(); 139 free(evc_new, M_AUDITEVCLASS); 140 return; 141 } 142 } 143 evc = evc_new; 144 evc->event = event; 145 evc->class = class; 146 LIST_INSERT_HEAD(&evcl->head, evc, entry); 147 EVCLASS_WUNLOCK(); 148} 149 150void 151au_evclassmap_init(void) 152{ 153 int i; 154 155 EVCLASS_LOCK_INIT(); 156 for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++) 157 LIST_INIT(&evclass_hash[i].head); 158 159 /* 160 * Set up the initial event to class mapping for system calls. 161 */ 162 for (i = 0; i < NUM_SYSENT; i++) { 163 if (sys_au_event[i] != AUE_NULL) 164 au_evclassmap_insert(sys_au_event[i], 0); 165 166 } 167 168 /* 169 * Add the Mach system call events. These are not in sys_au_event[]. 170 */ 171 au_evclassmap_insert(AUE_TASKFORPID, 0); 172 au_evclassmap_insert(AUE_PIDFORTASK, 0); 173 au_evclassmap_insert(AUE_SWAPON, 0); 174 au_evclassmap_insert(AUE_SWAPOFF, 0); 175 au_evclassmap_insert(AUE_MAPFD, 0); 176 au_evclassmap_insert(AUE_INITPROCESS, 0); 177} 178 179/* 180 * Check whether an event is aditable by comparing the mask of classes this 181 * event is part of against the given mask. 182 */ 183int 184au_preselect(__unused au_event_t event, au_class_t class, au_mask_t *mask_p, 185 int sorf) 186{ 187 au_class_t effmask = 0; 188 189 if (mask_p == NULL) 190 return (-1); 191 192 /* 193 * Perform the actual check of the masks against the event. 194 */ 195 if (sorf & AU_PRS_SUCCESS) 196 effmask |= (mask_p->am_success & class); 197 198 if (sorf & AU_PRS_FAILURE) 199 effmask |= (mask_p->am_failure & class); 200 201 if (effmask) 202 return (1); 203 else 204 return (0); 205} 206 207/* 208 * Convert sysctl names and present arguments to events. 209 */ 210au_event_t 211audit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg) 212{ 213 214 /* can't parse it - so return the worst case */ 215 if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN)) 216 return (AUE_SYSCTL); 217 218 switch (name[0]) { 219 /* non-admin "lookups" treat them special */ 220 case KERN_OSTYPE: 221 case KERN_OSRELEASE: 222 case KERN_OSREV: 223 case KERN_VERSION: 224 case KERN_ARGMAX: 225 case KERN_CLOCKRATE: 226 case KERN_BOOTTIME: 227 case KERN_POSIX1: 228 case KERN_NGROUPS: 229 case KERN_JOB_CONTROL: 230 case KERN_SAVED_IDS: 231 case KERN_OSRELDATE: 232 case KERN_NETBOOT: 233 case KERN_SYMFILE: 234 case KERN_SHREG_PRIVATIZABLE: 235 case KERN_OSVERSION: 236 return (AUE_SYSCTL_NONADMIN); 237 238 /* only treat the changeable controls as admin */ 239 case KERN_MAXVNODES: 240 case KERN_MAXPROC: 241 case KERN_MAXFILES: 242 case KERN_MAXPROCPERUID: 243 case KERN_MAXFILESPERPROC: 244 case KERN_HOSTID: 245 case KERN_AIOMAX: 246 case KERN_AIOPROCMAX: 247 case KERN_AIOTHREADS: 248 case KERN_COREDUMP: 249 case KERN_SUGID_COREDUMP: 250 case KERN_NX_PROTECTION: 251 return ((valid_arg & ARG_VALUE32) ? 252 AUE_SYSCTL : AUE_SYSCTL_NONADMIN); 253 254 default: 255 return (AUE_SYSCTL); 256 } 257 /* NOTREACHED */ 258} 259 260/* 261 * Convert an open flags specifier into a specific type of open event for 262 * auditing purposes. 263 */ 264au_event_t 265audit_flags_and_error_to_openevent(int oflags, int error) 266{ 267 au_event_t aevent; 268 269 /* 270 * Need to check only those flags we care about. 271 */ 272 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 273 274 /* 275 * These checks determine what flags are on with the condition that 276 * ONLY that combination is on, and no other flags are on. 277 */ 278 switch (oflags) { 279 case O_RDONLY: 280 aevent = AUE_OPEN_R; 281 break; 282 283 case (O_RDONLY | O_CREAT): 284 aevent = AUE_OPEN_RC; 285 break; 286 287 case (O_RDONLY | O_CREAT | O_TRUNC): 288 aevent = AUE_OPEN_RTC; 289 break; 290 291 case (O_RDONLY | O_TRUNC): 292 aevent = AUE_OPEN_RT; 293 break; 294 295 case O_RDWR: 296 aevent = AUE_OPEN_RW; 297 break; 298 299 case (O_RDWR | O_CREAT): 300 aevent = AUE_OPEN_RWC; 301 break; 302 303 case (O_RDWR | O_CREAT | O_TRUNC): 304 aevent = AUE_OPEN_RWTC; 305 break; 306 307 case (O_RDWR | O_TRUNC): 308 aevent = AUE_OPEN_RWT; 309 break; 310 311 case O_WRONLY: 312 aevent = AUE_OPEN_W; 313 break; 314 315 case (O_WRONLY | O_CREAT): 316 aevent = AUE_OPEN_WC; 317 break; 318 319 case (O_WRONLY | O_CREAT | O_TRUNC): 320 aevent = AUE_OPEN_WTC; 321 break; 322 323 case (O_WRONLY | O_TRUNC): 324 aevent = AUE_OPEN_WT; 325 break; 326 327 default: 328 aevent = AUE_OPEN; 329 break; 330 } 331 332 /* 333 * Convert chatty errors to better matching events. Failures to 334 * find a file are really just attribute events -- so recast them as 335 * such. 336 * 337 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it 338 * is just a placeholder. However, in Darwin we return that in 339 * preference to other events. 340 * 341 * XXXRW: This behavior differs from FreeBSD, so possibly revise this 342 * code or this comment. 343 */ 344 switch (aevent) { 345 case AUE_OPEN_R: 346 case AUE_OPEN_RT: 347 case AUE_OPEN_RW: 348 case AUE_OPEN_RWT: 349 case AUE_OPEN_W: 350 case AUE_OPEN_WT: 351 if (error == ENOENT) 352 aevent = AUE_OPEN; 353 } 354 return (aevent); 355} 356 357/* 358 * Convert an open flags specifier into a specific type of open_extended event 359 * for auditing purposes. 360 */ 361au_event_t 362audit_flags_and_error_to_openextendedevent(int oflags, int error) 363{ 364 au_event_t aevent; 365 366 /* 367 * Need to check only those flags we care about. 368 */ 369 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 370 371 /* 372 * These checks determine what flags are on with the condition that 373 * ONLY that combination is on, and no other flags are on. 374 */ 375 switch (oflags) { 376 case O_RDONLY: 377 aevent = AUE_OPEN_EXTENDED_R; 378 break; 379 380 case (O_RDONLY | O_CREAT): 381 aevent = AUE_OPEN_EXTENDED_RC; 382 break; 383 384 case (O_RDONLY | O_CREAT | O_TRUNC): 385 aevent = AUE_OPEN_EXTENDED_RTC; 386 break; 387 388 case (O_RDONLY | O_TRUNC): 389 aevent = AUE_OPEN_EXTENDED_RT; 390 break; 391 392 case O_RDWR: 393 aevent = AUE_OPEN_EXTENDED_RW; 394 break; 395 396 case (O_RDWR | O_CREAT): 397 aevent = AUE_OPEN_EXTENDED_RWC; 398 break; 399 400 case (O_RDWR | O_CREAT | O_TRUNC): 401 aevent = AUE_OPEN_EXTENDED_RWTC; 402 break; 403 404 case (O_RDWR | O_TRUNC): 405 aevent = AUE_OPEN_EXTENDED_RWT; 406 break; 407 408 case O_WRONLY: 409 aevent = AUE_OPEN_EXTENDED_W; 410 break; 411 412 case (O_WRONLY | O_CREAT): 413 aevent = AUE_OPEN_EXTENDED_WC; 414 break; 415 416 case (O_WRONLY | O_CREAT | O_TRUNC): 417 aevent = AUE_OPEN_EXTENDED_WTC; 418 break; 419 420 case (O_WRONLY | O_TRUNC): 421 aevent = AUE_OPEN_EXTENDED_WT; 422 break; 423 424 default: 425 aevent = AUE_OPEN_EXTENDED; 426 break; 427 } 428 429 /* 430 * Convert chatty errors to better matching events. Failures to 431 * find a file are really just attribute events -- so recast them as 432 * such. 433 * 434 * XXXAUDIT: Solaris defines that AUE_OPEN will never be returned, it 435 * is just a placeholder. However, in Darwin we return that in 436 * preference to other events. 437 * 438 * XXXRW: This behavior differs from FreeBSD, so possibly revise this 439 * code or this comment. 440 */ 441 switch (aevent) { 442 case AUE_OPEN_EXTENDED_R: 443 case AUE_OPEN_EXTENDED_RT: 444 case AUE_OPEN_EXTENDED_RW: 445 case AUE_OPEN_EXTENDED_RWT: 446 case AUE_OPEN_EXTENDED_W: 447 case AUE_OPEN_EXTENDED_WT: 448 if (error == ENOENT) 449 aevent = AUE_OPEN_EXTENDED; 450 } 451 return (aevent); 452} 453 454/* 455 * Convert an open flags specifier into a specific type of open_extended event 456 * for auditing purposes. 457 */ 458au_event_t 459audit_flags_and_error_to_openatevent(int oflags, int error) 460{ 461 au_event_t aevent; 462 463 /* 464 * Need to check only those flags we care about. 465 */ 466 oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY); 467 468 /* 469 * These checks determine what flags are on with the condition that 470 * ONLY that combination is on, and no other flags are on. 471 */ 472 switch (oflags) { 473 case O_RDONLY: 474 aevent = AUE_OPENAT_R; 475 break; 476 477 case (O_RDONLY | O_CREAT): 478 aevent = AUE_OPENAT_RC; 479 break; 480 481 case (O_RDONLY | O_CREAT | O_TRUNC): 482 aevent = AUE_OPENAT_RTC; 483 break; 484 485 case (O_RDONLY | O_TRUNC): 486 aevent = AUE_OPENAT_RT; 487 break; 488 489 case O_RDWR: 490 aevent = AUE_OPENAT_RW; 491 break; 492 493 case (O_RDWR | O_CREAT): 494 aevent = AUE_OPENAT_RWC; 495 break; 496 497 case (O_RDWR | O_CREAT | O_TRUNC): 498 aevent = AUE_OPENAT_RWTC; 499 break; 500 501 case (O_RDWR | O_TRUNC): 502 aevent = AUE_OPENAT_RWT; 503 break; 504 505 case O_WRONLY: 506 aevent = AUE_OPENAT_W; 507 break; 508 509 case (O_WRONLY | O_CREAT): 510 aevent = AUE_OPENAT_WC; 511 break; 512 513 case (O_WRONLY | O_CREAT | O_TRUNC): 514 aevent = AUE_OPENAT_WTC; 515 break; 516 517 case (O_WRONLY | O_TRUNC): 518 aevent = AUE_OPENAT_WT; 519 break; 520 521 default: 522 aevent = AUE_OPENAT; 523 break; 524 } 525 526 /* 527 * Convert chatty errors to better matching events. Failures to 528 * find a file are really just attribute events -- so recast them as 529 * such. 530 * 531 * XXXAUDIT: Solaris defines that AUE_OPENAT will never be returned, it 532 * is just a placeholder. However, in Darwin we return that in 533 * preference to other events. 534 * 535 * XXXRW: This behavior differs from FreeBSD, so possibly revise this 536 * code or this comment. 537 */ 538 switch (aevent) { 539 case AUE_OPENAT_R: 540 case AUE_OPENAT_RT: 541 case AUE_OPENAT_RW: 542 case AUE_OPENAT_RWT: 543 case AUE_OPENAT_W: 544 case AUE_OPENAT_WT: 545 if (error == ENOENT) 546 aevent = AUE_OPENAT; 547 } 548 return (aevent); 549} 550 551/* 552 * Convert an open flags specifier into a specific type of openbyid event 553 * for auditing purposes. 554 */ 555au_event_t 556audit_flags_and_error_to_openbyidevent(int oflags, int error) 557{ 558 au_event_t aevent; 559 560 /* 561 * Need to check only those flags we care about. 562 */ 563 oflags = oflags & (O_RDONLY | O_TRUNC | O_RDWR | O_WRONLY); 564 565 /* 566 * These checks determine what flags are on with the condition that 567 * ONLY that combination is on, and no other flags are on. 568 */ 569 switch (oflags) { 570 case O_RDONLY: 571 aevent = AUE_OPENBYID_R; 572 break; 573 574 case (O_RDONLY | O_TRUNC): 575 aevent = AUE_OPENBYID_RT; 576 break; 577 578 case O_RDWR: 579 aevent = AUE_OPENBYID_RW; 580 break; 581 582 case (O_RDWR | O_TRUNC): 583 aevent = AUE_OPENBYID_RWT; 584 break; 585 586 case O_WRONLY: 587 aevent = AUE_OPENBYID_W; 588 break; 589 590 case (O_WRONLY | O_TRUNC): 591 aevent = AUE_OPENBYID_WT; 592 break; 593 594 default: 595 aevent = AUE_OPENBYID; 596 break; 597 } 598 599 /* 600 * Convert chatty errors to better matching events. Failures to 601 * find a file are really just attribute events -- so recast them as 602 * such. 603 */ 604 switch (aevent) { 605 case AUE_OPENBYID_R: 606 case AUE_OPENBYID_RT: 607 case AUE_OPENBYID_RW: 608 case AUE_OPENBYID_RWT: 609 case AUE_OPENBYID_W: 610 case AUE_OPENBYID_WT: 611 if (error == ENOENT) 612 aevent = AUE_OPENBYID; 613 } 614 return (aevent); 615} 616 617/* 618 * Convert a MSGCTL command to a specific event. 619 */ 620au_event_t 621audit_msgctl_to_event(int cmd) 622{ 623 624 switch (cmd) { 625 case IPC_RMID: 626 return (AUE_MSGCTL_RMID); 627 628 case IPC_SET: 629 return (AUE_MSGCTL_SET); 630 631 case IPC_STAT: 632 return (AUE_MSGCTL_STAT); 633 634 default: 635 /* We will audit a bad command. */ 636 return (AUE_MSGCTL); 637 } 638} 639 640/* 641 * Convert a SEMCTL command to a specific event. 642 */ 643au_event_t 644audit_semctl_to_event(int cmd) 645{ 646 647 switch (cmd) { 648 case GETALL: 649 return (AUE_SEMCTL_GETALL); 650 651 case GETNCNT: 652 return (AUE_SEMCTL_GETNCNT); 653 654 case GETPID: 655 return (AUE_SEMCTL_GETPID); 656 657 case GETVAL: 658 return (AUE_SEMCTL_GETVAL); 659 660 case GETZCNT: 661 return (AUE_SEMCTL_GETZCNT); 662 663 case IPC_RMID: 664 return (AUE_SEMCTL_RMID); 665 666 case IPC_SET: 667 return (AUE_SEMCTL_SET); 668 669 case SETALL: 670 return (AUE_SEMCTL_SETALL); 671 672 case SETVAL: 673 return (AUE_SEMCTL_SETVAL); 674 675 case IPC_STAT: 676 return (AUE_SEMCTL_STAT); 677 678 default: 679 /* We will audit a bad command. */ 680 return (AUE_SEMCTL); 681 } 682} 683 684/* 685 * Convert a command for the auditon() system call to a audit event. 686 */ 687au_event_t 688auditon_command_event(int cmd) 689{ 690 691 switch(cmd) { 692 case A_GETPOLICY: 693 return (AUE_AUDITON_GPOLICY); 694 695 case A_SETPOLICY: 696 return (AUE_AUDITON_SPOLICY); 697 698 case A_GETKMASK: 699 return (AUE_AUDITON_GETKMASK); 700 701 case A_SETKMASK: 702 return (AUE_AUDITON_SETKMASK); 703 704 case A_GETQCTRL: 705 return (AUE_AUDITON_GQCTRL); 706 707 case A_SETQCTRL: 708 return (AUE_AUDITON_SQCTRL); 709 710 case A_GETCWD: 711 return (AUE_AUDITON_GETCWD); 712 713 case A_GETCAR: 714 return (AUE_AUDITON_GETCAR); 715 716 case A_GETSTAT: 717 return (AUE_AUDITON_GETSTAT); 718 719 case A_SETSTAT: 720 return (AUE_AUDITON_SETSTAT); 721 722 case A_SETUMASK: 723 return (AUE_AUDITON_SETUMASK); 724 725 case A_SETSMASK: 726 return (AUE_AUDITON_SETSMASK); 727 728 case A_GETCOND: 729 return (AUE_AUDITON_GETCOND); 730 731 case A_SETCOND: 732 return (AUE_AUDITON_SETCOND); 733 734 case A_GETCLASS: 735 return (AUE_AUDITON_GETCLASS); 736 737 case A_SETCLASS: 738 return (AUE_AUDITON_SETCLASS); 739 740 case A_GETPINFO: 741 case A_SETPMASK: 742 case A_SETFSIZE: 743 case A_GETFSIZE: 744 case A_GETPINFO_ADDR: 745 case A_GETKAUDIT: 746 case A_SETKAUDIT: 747 case A_GETSINFO_ADDR: 748 default: 749 return (AUE_AUDITON); /* No special record */ 750 } 751} 752 753/* 754 * For darwin we rewrite events generated by fcntl(F_OPENFROM,...) and 755 * fcntl(F_UNLINKFROM,...) system calls to AUE_OPENAT_* and AUE_UNLINKAT audit 756 * events. 757 */ 758au_event_t 759audit_fcntl_command_event(int cmd, int oflags, int error) 760{ 761 switch(cmd) { 762 case F_OPENFROM: 763 return (audit_flags_and_error_to_openatevent(oflags, error)); 764 765 case F_UNLINKFROM: 766 return (AUE_UNLINKAT); 767 768 default: 769 return (AUE_FCNTL); /* Don't change from AUE_FCNTL. */ 770 } 771} 772 773/* 774 * Create a canonical path from given path by prefixing either the root 775 * directory, or the current working directory. 776 */ 777int 778audit_canon_path(struct vnode *cwd_vp, char *path, char *cpath) 779{ 780 int len; 781 int ret; 782 char *bufp = path; 783 784 /* 785 * Convert multiple leading '/' into a single '/' if the cwd_vp is 786 * NULL (i.e. an absolute path), and strip them entirely if the 787 * cwd_vp represents a chroot directory (i.e. the caller checked for 788 * an initial '/' character itself, saw one, and passed fdp->fd_rdir). 789 * Somewhat complicated, but it places the onus for locking structs 790 * involved on the caller, and makes proxy operations explicit rather 791 * than implicit. 792 */ 793 if (*(path) == '/') { 794 while (*(bufp) == '/') 795 bufp++; /* skip leading '/'s */ 796 if (cwd_vp == NULL) 797 bufp--; /* restore one '/' */ 798 } 799 if (cwd_vp != NULL) { 800 len = MAXPATHLEN; 801 ret = vn_getpath(cwd_vp, cpath, &len); 802 if (ret != 0) { 803 cpath[0] = '\0'; 804 return (ret); 805 } 806 if (len < MAXPATHLEN) 807 cpath[len-1] = '/'; 808 strlcpy(cpath + len, bufp, MAXPATHLEN - len); 809 } else { 810 strlcpy(cpath, bufp, MAXPATHLEN); 811 } 812 return (0); 813} 814#endif /* CONFIG_AUDIT */ 815