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