audit_bsm_klib.c revision 212425
1155192Srwatson/*
2188313Srwatson * Copyright (c) 1999-2009 Apple Inc.
3155192Srwatson * Copyright (c) 2005 Robert N. M. Watson
4155192Srwatson * All rights reserved.
5155192Srwatson *
6155192Srwatson * Redistribution and use in source and binary forms, with or without
7155192Srwatson * modification, are permitted provided that the following conditions
8155192Srwatson * are met:
9155192Srwatson * 1.  Redistributions of source code must retain the above copyright
10155192Srwatson *     notice, this list of conditions and the following disclaimer.
11155192Srwatson * 2.  Redistributions in binary form must reproduce the above copyright
12155192Srwatson *     notice, this list of conditions and the following disclaimer in the
13155192Srwatson *     documentation and/or other materials provided with the distribution.
14180701Srwatson * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
15155192Srwatson *     its contributors may be used to endorse or promote products derived
16155192Srwatson *     from this software without specific prior written permission.
17155192Srwatson *
18155192Srwatson * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND
19155192Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20155192Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21155192Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR
22155192Srwatson * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23155192Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24155192Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25155192Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
26155192Srwatson * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
27155192Srwatson * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28155192Srwatson * POSSIBILITY OF SUCH DAMAGE.
29155192Srwatson */
30155192Srwatson
31178186Srwatson#include <sys/cdefs.h>
32178186Srwatson__FBSDID("$FreeBSD: head/sys/security/audit/audit_bsm_klib.c 212425 2010-09-10 16:42:16Z mdf $");
33178186Srwatson
34155192Srwatson#include <sys/param.h>
35155192Srwatson#include <sys/fcntl.h>
36155192Srwatson#include <sys/filedesc.h>
37155192Srwatson#include <sys/libkern.h>
38155192Srwatson#include <sys/malloc.h>
39155192Srwatson#include <sys/mount.h>
40155192Srwatson#include <sys/proc.h>
41184482Srwatson#include <sys/rwlock.h>
42155192Srwatson#include <sys/sem.h>
43181060Scsjp#include <sys/sbuf.h>
44155192Srwatson#include <sys/syscall.h>
45155192Srwatson#include <sys/sysctl.h>
46155192Srwatson#include <sys/sysent.h>
47155192Srwatson#include <sys/vnode.h>
48155192Srwatson
49155192Srwatson#include <bsm/audit.h>
50155192Srwatson#include <bsm/audit_kevents.h>
51155192Srwatson#include <security/audit/audit.h>
52155192Srwatson#include <security/audit/audit_private.h>
53155192Srwatson
54155192Srwatson/*
55155192Srwatson * Hash table functions for the audit event number to event class mask
56155192Srwatson * mapping.
57155192Srwatson */
58180735Srwatson#define	EVCLASSMAP_HASH_TABLE_SIZE	251
59155192Srwatsonstruct evclass_elem {
60155192Srwatson	au_event_t event;
61155192Srwatson	au_class_t class;
62155192Srwatson	LIST_ENTRY(evclass_elem) entry;
63155192Srwatson};
64155192Srwatsonstruct evclass_list {
65155192Srwatson	LIST_HEAD(, evclass_elem) head;
66155192Srwatson};
67155192Srwatson
68155192Srwatsonstatic MALLOC_DEFINE(M_AUDITEVCLASS, "audit_evclass", "Audit event class");
69184482Srwatsonstatic struct rwlock		evclass_lock;
70156889Srwatsonstatic struct evclass_list	evclass_hash[EVCLASSMAP_HASH_TABLE_SIZE];
71155192Srwatson
72184482Srwatson#define	EVCLASS_LOCK_INIT()	rw_init(&evclass_lock, "evclass_lock")
73184482Srwatson#define	EVCLASS_RLOCK()		rw_rlock(&evclass_lock)
74184482Srwatson#define	EVCLASS_RUNLOCK()	rw_runlock(&evclass_lock)
75184482Srwatson#define	EVCLASS_WLOCK()		rw_wlock(&evclass_lock)
76184482Srwatson#define	EVCLASS_WUNLOCK()	rw_wunlock(&evclass_lock)
77184482Srwatson
78195925Srwatsonstruct aue_open_event {
79195925Srwatson	int		aoe_flags;
80195925Srwatson	au_event_t	aoe_event;
81195925Srwatson};
82195925Srwatson
83195925Srwatsonstatic const struct aue_open_event aue_open[] = {
84195925Srwatson	{ O_RDONLY,					AUE_OPEN_R },
85195925Srwatson	{ (O_RDONLY | O_CREAT),				AUE_OPEN_RC },
86195925Srwatson	{ (O_RDONLY | O_CREAT | O_TRUNC),		AUE_OPEN_RTC },
87195925Srwatson	{ (O_RDONLY | O_TRUNC),				AUE_OPEN_RT },
88195925Srwatson	{ O_RDWR,					AUE_OPEN_RW },
89195925Srwatson	{ (O_RDWR | O_CREAT),				AUE_OPEN_RWC },
90195925Srwatson	{ (O_RDWR | O_CREAT | O_TRUNC),			AUE_OPEN_RWTC },
91195925Srwatson	{ (O_RDWR | O_TRUNC),				AUE_OPEN_RWT },
92195925Srwatson	{ O_WRONLY,					AUE_OPEN_W },
93195925Srwatson	{ (O_WRONLY | O_CREAT),				AUE_OPEN_WC },
94195925Srwatson	{ (O_WRONLY | O_CREAT | O_TRUNC),		AUE_OPEN_WTC },
95195925Srwatson	{ (O_WRONLY | O_TRUNC),				AUE_OPEN_WT },
96195925Srwatson};
97195925Srwatsonstatic const int aue_open_count = sizeof(aue_open) / sizeof(aue_open[0]);
98195925Srwatson
99195925Srwatsonstatic const struct aue_open_event aue_openat[] = {
100195925Srwatson	{ O_RDONLY,					AUE_OPENAT_R },
101195925Srwatson	{ (O_RDONLY | O_CREAT),				AUE_OPENAT_RC },
102195925Srwatson	{ (O_RDONLY | O_CREAT | O_TRUNC),		AUE_OPENAT_RTC },
103195925Srwatson	{ (O_RDONLY | O_TRUNC),				AUE_OPENAT_RT },
104195925Srwatson	{ O_RDWR,					AUE_OPENAT_RW },
105195925Srwatson	{ (O_RDWR | O_CREAT),				AUE_OPENAT_RWC },
106195925Srwatson	{ (O_RDWR | O_CREAT | O_TRUNC),			AUE_OPENAT_RWTC },
107195925Srwatson	{ (O_RDWR | O_TRUNC),				AUE_OPENAT_RWT },
108195925Srwatson	{ O_WRONLY,					AUE_OPENAT_W },
109195925Srwatson	{ (O_WRONLY | O_CREAT),				AUE_OPENAT_WC },
110195925Srwatson	{ (O_WRONLY | O_CREAT | O_TRUNC),		AUE_OPENAT_WTC },
111195925Srwatson	{ (O_WRONLY | O_TRUNC),				AUE_OPENAT_WT },
112195925Srwatson};
113195925Srwatsonstatic const int aue_openat_count = sizeof(aue_openat) / sizeof(aue_openat[0]);
114195925Srwatson
115155192Srwatson/*
116155192Srwatson * Look up the class for an audit event in the class mapping table.
117155192Srwatson */
118155192Srwatsonau_class_t
119155192Srwatsonau_event_class(au_event_t event)
120155192Srwatson{
121155192Srwatson	struct evclass_list *evcl;
122155192Srwatson	struct evclass_elem *evc;
123155192Srwatson	au_class_t class;
124155192Srwatson
125184482Srwatson	EVCLASS_RLOCK();
126155192Srwatson	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
127173142Srwatson	class = 0;
128155192Srwatson	LIST_FOREACH(evc, &evcl->head, entry) {
129155192Srwatson		if (evc->event == event) {
130155192Srwatson			class = evc->class;
131155192Srwatson			goto out;
132155192Srwatson		}
133155192Srwatson	}
134155192Srwatsonout:
135184482Srwatson	EVCLASS_RUNLOCK();
136155192Srwatson	return (class);
137155192Srwatson}
138155192Srwatson
139156889Srwatson/*
140155192Srwatson * Insert a event to class mapping. If the event already exists in the
141155192Srwatson * mapping, then replace the mapping with the new one.
142156889Srwatson *
143155192Srwatson * XXX There is currently no constraints placed on the number of mappings.
144156889Srwatson * May want to either limit to a number, or in terms of memory usage.
145155192Srwatson */
146155192Srwatsonvoid
147156889Srwatsonau_evclassmap_insert(au_event_t event, au_class_t class)
148155192Srwatson{
149155192Srwatson	struct evclass_list *evcl;
150155192Srwatson	struct evclass_elem *evc, *evc_new;
151155192Srwatson
152155192Srwatson	/*
153155192Srwatson	 * Pessimistically, always allocate storage before acquiring mutex.
154155192Srwatson	 * Free if there is already a mapping for this event.
155155192Srwatson	 */
156155192Srwatson	evc_new = malloc(sizeof(*evc), M_AUDITEVCLASS, M_WAITOK);
157155192Srwatson
158184482Srwatson	EVCLASS_WLOCK();
159155192Srwatson	evcl = &evclass_hash[event % EVCLASSMAP_HASH_TABLE_SIZE];
160155192Srwatson	LIST_FOREACH(evc, &evcl->head, entry) {
161155192Srwatson		if (evc->event == event) {
162155192Srwatson			evc->class = class;
163184482Srwatson			EVCLASS_WUNLOCK();
164155192Srwatson			free(evc_new, M_AUDITEVCLASS);
165155192Srwatson			return;
166155192Srwatson		}
167155192Srwatson	}
168155192Srwatson	evc = evc_new;
169155192Srwatson	evc->event = event;
170155192Srwatson	evc->class = class;
171155192Srwatson	LIST_INSERT_HEAD(&evcl->head, evc, entry);
172184482Srwatson	EVCLASS_WUNLOCK();
173155192Srwatson}
174155192Srwatson
175155192Srwatsonvoid
176156889Srwatsonau_evclassmap_init(void)
177155192Srwatson{
178155192Srwatson	int i;
179155192Srwatson
180184482Srwatson	EVCLASS_LOCK_INIT();
181155192Srwatson	for (i = 0; i < EVCLASSMAP_HASH_TABLE_SIZE; i++)
182155192Srwatson		LIST_INIT(&evclass_hash[i].head);
183155192Srwatson
184155192Srwatson	/*
185155192Srwatson	 * Set up the initial event to class mapping for system calls.
186155192Srwatson	 *
187155192Srwatson	 * XXXRW: Really, this should walk all possible audit events, not all
188155192Srwatson	 * native ABI system calls, as there may be audit events reachable
189155192Srwatson	 * only through non-native system calls.  It also seems a shame to
190155192Srwatson	 * frob the mutex this early.
191156889Srwatson	 */
192155192Srwatson	for (i = 0; i < SYS_MAXSYSCALL; i++) {
193155192Srwatson		if (sysent[i].sy_auevent != AUE_NULL)
194173142Srwatson			au_evclassmap_insert(sysent[i].sy_auevent, 0);
195155192Srwatson	}
196155192Srwatson}
197155192Srwatson
198155192Srwatson/*
199155192Srwatson * Check whether an event is aditable by comparing the mask of classes this
200155192Srwatson * event is part of against the given mask.
201155192Srwatson */
202155192Srwatsonint
203159269Srwatsonau_preselect(au_event_t event, au_class_t class, au_mask_t *mask_p, int sorf)
204155192Srwatson{
205155192Srwatson	au_class_t effmask = 0;
206155192Srwatson
207155192Srwatson	if (mask_p == NULL)
208155192Srwatson		return (-1);
209155192Srwatson
210156889Srwatson	/*
211155192Srwatson	 * Perform the actual check of the masks against the event.
212155192Srwatson	 */
213155192Srwatson	if (sorf & AU_PRS_SUCCESS)
214159269Srwatson		effmask |= (mask_p->am_success & class);
215156889Srwatson
216155192Srwatson	if (sorf & AU_PRS_FAILURE)
217159269Srwatson		effmask |= (mask_p->am_failure & class);
218156889Srwatson
219155192Srwatson	if (effmask)
220155192Srwatson		return (1);
221156889Srwatson	else
222155192Srwatson		return (0);
223155192Srwatson}
224155192Srwatson
225155192Srwatson/*
226156889Srwatson * Convert sysctl names and present arguments to events.
227155192Srwatson */
228155192Srwatsonau_event_t
229176690Srwatsonaudit_ctlname_to_sysctlevent(int name[], uint64_t valid_arg)
230155192Srwatson{
231155192Srwatson
232155192Srwatson	/* can't parse it - so return the worst case */
233156889Srwatson	if ((valid_arg & (ARG_CTLNAME | ARG_LEN)) != (ARG_CTLNAME | ARG_LEN))
234155192Srwatson		return (AUE_SYSCTL);
235155192Srwatson
236155192Srwatson	switch (name[0]) {
237155192Srwatson	/* non-admin "lookups" treat them special */
238155192Srwatson	case KERN_OSTYPE:
239155192Srwatson	case KERN_OSRELEASE:
240155192Srwatson	case KERN_OSREV:
241155192Srwatson	case KERN_VERSION:
242155192Srwatson	case KERN_ARGMAX:
243155192Srwatson	case KERN_CLOCKRATE:
244155192Srwatson	case KERN_BOOTTIME:
245155192Srwatson	case KERN_POSIX1:
246155192Srwatson	case KERN_NGROUPS:
247155192Srwatson	case KERN_JOB_CONTROL:
248155192Srwatson	case KERN_SAVED_IDS:
249155192Srwatson	case KERN_OSRELDATE:
250155192Srwatson	case KERN_DUMMY:
251155192Srwatson		return (AUE_SYSCTL_NONADMIN);
252155192Srwatson
253155192Srwatson	/* only treat the changeable controls as admin */
254155192Srwatson	case KERN_MAXVNODES:
255155192Srwatson	case KERN_MAXPROC:
256155192Srwatson	case KERN_MAXFILES:
257155192Srwatson	case KERN_MAXPROCPERUID:
258155192Srwatson	case KERN_MAXFILESPERPROC:
259155192Srwatson	case KERN_HOSTID:
260155192Srwatson	case KERN_SECURELVL:
261155192Srwatson	case KERN_HOSTNAME:
262155192Srwatson	case KERN_VNODE:
263155192Srwatson	case KERN_PROC:
264155192Srwatson	case KERN_FILE:
265155192Srwatson	case KERN_PROF:
266155192Srwatson	case KERN_NISDOMAINNAME:
267155192Srwatson	case KERN_UPDATEINTERVAL:
268155192Srwatson	case KERN_NTP_PLL:
269155192Srwatson	case KERN_BOOTFILE:
270155192Srwatson	case KERN_DUMPDEV:
271155192Srwatson	case KERN_IPC:
272155192Srwatson	case KERN_PS_STRINGS:
273155192Srwatson	case KERN_USRSTACK:
274155192Srwatson	case KERN_LOGSIGEXIT:
275155192Srwatson	case KERN_IOV_MAX:
276155192Srwatson	case KERN_MAXID:
277155192Srwatson		return ((valid_arg & ARG_VALUE) ?
278181053Srwatson		    AUE_SYSCTL : AUE_SYSCTL_NONADMIN);
279155192Srwatson
280155192Srwatson	default:
281155192Srwatson		return (AUE_SYSCTL);
282155192Srwatson	}
283155192Srwatson	/* NOTREACHED */
284155192Srwatson}
285155192Srwatson
286155192Srwatson/*
287156889Srwatson * Convert an open flags specifier into a specific type of open event for
288155192Srwatson * auditing purposes.
289155192Srwatson */
290155192Srwatsonau_event_t
291176690Srwatsonaudit_flags_and_error_to_openevent(int oflags, int error)
292156889Srwatson{
293195925Srwatson	int i;
294155192Srwatson
295156889Srwatson	/*
296156889Srwatson	 * Need to check only those flags we care about.
297156889Srwatson	 */
298155192Srwatson	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
299195925Srwatson	for (i = 0; i < aue_open_count; i++) {
300195925Srwatson		if (aue_open[i].aoe_flags == oflags)
301195925Srwatson			return (aue_open[i].aoe_event);
302195925Srwatson	}
303195925Srwatson	return (AUE_OPEN);
304195925Srwatson}
305155192Srwatson
306195925Srwatsonau_event_t
307195925Srwatsonaudit_flags_and_error_to_openatevent(int oflags, int error)
308195925Srwatson{
309195925Srwatson	int i;
310155192Srwatson
311156889Srwatson	/*
312195925Srwatson	 * Need to check only those flags we care about.
313155192Srwatson	 */
314195925Srwatson	oflags = oflags & (O_RDONLY | O_CREAT | O_TRUNC | O_RDWR | O_WRONLY);
315195925Srwatson	for (i = 0; i < aue_openat_count; i++) {
316195925Srwatson		if (aue_openat[i].aoe_flags == oflags)
317195925Srwatson			return (aue_openat[i].aoe_event);
318155192Srwatson	}
319195925Srwatson	return (AUE_OPENAT);
320155192Srwatson}
321155192Srwatson
322155192Srwatson/*
323155192Srwatson * Convert a MSGCTL command to a specific event.
324155192Srwatson */
325188313Srwatsonau_event_t
326176565Srwatsonaudit_msgctl_to_event(int cmd)
327155192Srwatson{
328155192Srwatson
329155192Srwatson	switch (cmd) {
330155192Srwatson	case IPC_RMID:
331155192Srwatson		return (AUE_MSGCTL_RMID);
332155192Srwatson
333155192Srwatson	case IPC_SET:
334155192Srwatson		return (AUE_MSGCTL_SET);
335155192Srwatson
336155192Srwatson	case IPC_STAT:
337155192Srwatson		return (AUE_MSGCTL_STAT);
338155192Srwatson
339155192Srwatson	default:
340170196Srwatson		/* We will audit a bad command. */
341155192Srwatson		return (AUE_MSGCTL);
342155192Srwatson	}
343155192Srwatson}
344155192Srwatson
345155192Srwatson/*
346155192Srwatson * Convert a SEMCTL command to a specific event.
347155192Srwatson */
348188313Srwatsonau_event_t
349176565Srwatsonaudit_semctl_to_event(int cmd)
350155192Srwatson{
351155192Srwatson
352155192Srwatson	switch (cmd) {
353155192Srwatson	case GETALL:
354155192Srwatson		return (AUE_SEMCTL_GETALL);
355155192Srwatson
356155192Srwatson	case GETNCNT:
357155192Srwatson		return (AUE_SEMCTL_GETNCNT);
358155192Srwatson
359155192Srwatson	case GETPID:
360155192Srwatson		return (AUE_SEMCTL_GETPID);
361155192Srwatson
362155192Srwatson	case GETVAL:
363155192Srwatson		return (AUE_SEMCTL_GETVAL);
364155192Srwatson
365155192Srwatson	case GETZCNT:
366155192Srwatson		return (AUE_SEMCTL_GETZCNT);
367155192Srwatson
368155192Srwatson	case IPC_RMID:
369155192Srwatson		return (AUE_SEMCTL_RMID);
370155192Srwatson
371155192Srwatson	case IPC_SET:
372155192Srwatson		return (AUE_SEMCTL_SET);
373155192Srwatson
374155192Srwatson	case SETALL:
375155192Srwatson		return (AUE_SEMCTL_SETALL);
376155192Srwatson
377155192Srwatson	case SETVAL:
378155192Srwatson		return (AUE_SEMCTL_SETVAL);
379155192Srwatson
380155192Srwatson	case IPC_STAT:
381155192Srwatson		return (AUE_SEMCTL_STAT);
382155192Srwatson
383155192Srwatson	default:
384181053Srwatson		/* We will audit a bad command. */
385155192Srwatson		return (AUE_SEMCTL);
386155192Srwatson	}
387155192Srwatson}
388155192Srwatson
389155192Srwatson/*
390155192Srwatson * Convert a command for the auditon() system call to a audit event.
391155192Srwatson */
392188313Srwatsonau_event_t
393155192Srwatsonauditon_command_event(int cmd)
394155192Srwatson{
395155192Srwatson
396155192Srwatson	switch(cmd) {
397155192Srwatson	case A_GETPOLICY:
398155192Srwatson		return (AUE_AUDITON_GPOLICY);
399155192Srwatson
400155192Srwatson	case A_SETPOLICY:
401155192Srwatson		return (AUE_AUDITON_SPOLICY);
402155192Srwatson
403155192Srwatson	case A_GETKMASK:
404155192Srwatson		return (AUE_AUDITON_GETKMASK);
405155192Srwatson
406155192Srwatson	case A_SETKMASK:
407155192Srwatson		return (AUE_AUDITON_SETKMASK);
408155192Srwatson
409155192Srwatson	case A_GETQCTRL:
410155192Srwatson		return (AUE_AUDITON_GQCTRL);
411155192Srwatson
412155192Srwatson	case A_SETQCTRL:
413155192Srwatson		return (AUE_AUDITON_SQCTRL);
414155192Srwatson
415155192Srwatson	case A_GETCWD:
416155192Srwatson		return (AUE_AUDITON_GETCWD);
417155192Srwatson
418155192Srwatson	case A_GETCAR:
419155192Srwatson		return (AUE_AUDITON_GETCAR);
420155192Srwatson
421155192Srwatson	case A_GETSTAT:
422155192Srwatson		return (AUE_AUDITON_GETSTAT);
423155192Srwatson
424155192Srwatson	case A_SETSTAT:
425155192Srwatson		return (AUE_AUDITON_SETSTAT);
426155192Srwatson
427155192Srwatson	case A_SETUMASK:
428155192Srwatson		return (AUE_AUDITON_SETUMASK);
429155192Srwatson
430155192Srwatson	case A_SETSMASK:
431155192Srwatson		return (AUE_AUDITON_SETSMASK);
432155192Srwatson
433155192Srwatson	case A_GETCOND:
434155192Srwatson		return (AUE_AUDITON_GETCOND);
435155192Srwatson
436155192Srwatson	case A_SETCOND:
437155192Srwatson		return (AUE_AUDITON_SETCOND);
438155192Srwatson
439155192Srwatson	case A_GETCLASS:
440155192Srwatson		return (AUE_AUDITON_GETCLASS);
441155192Srwatson
442155192Srwatson	case A_SETCLASS:
443155192Srwatson		return (AUE_AUDITON_SETCLASS);
444155192Srwatson
445155192Srwatson	case A_GETPINFO:
446155192Srwatson	case A_SETPMASK:
447155192Srwatson	case A_SETFSIZE:
448155192Srwatson	case A_GETFSIZE:
449155192Srwatson	case A_GETPINFO_ADDR:
450155192Srwatson	case A_GETKAUDIT:
451155192Srwatson	case A_SETKAUDIT:
452155192Srwatson	default:
453155192Srwatson		return (AUE_AUDITON);	/* No special record */
454155192Srwatson	}
455155192Srwatson}
456155192Srwatson
457156889Srwatson/*
458156889Srwatson * Create a canonical path from given path by prefixing either the root
459156889Srwatson * directory, or the current working directory.  If the process working
460170196Srwatson * directory is NULL, we could use 'rootvnode' to obtain the root directory,
461156889Srwatson * but this results in a volfs name written to the audit log. So we will
462156889Srwatson * leave the filename starting with '/' in the audit log in this case.
463155192Srwatson */
464155192Srwatsonvoid
465176565Srwatsonaudit_canon_path(struct thread *td, char *path, char *cpath)
466155192Srwatson{
467181060Scsjp	struct vnode *cvnp, *rvnp;
468181060Scsjp	char *rbuf, *fbuf, *copy;
469155192Srwatson	struct filedesc *fdp;
470181060Scsjp	struct sbuf sbf;
471184660Sjhb	int error, cwir;
472155192Srwatson
473181060Scsjp	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, "%s: at %s:%d",
474181060Scsjp	    __func__,  __FILE__, __LINE__);
475165621Srwatson
476181060Scsjp	copy = path;
477181060Scsjp	rvnp = cvnp = NULL;
478155192Srwatson	fdp = td->td_proc->p_fd;
479168355Srwatson	FILEDESC_SLOCK(fdp);
480181060Scsjp	/*
481181060Scsjp	 * Make sure that we handle the chroot(2) case.  If there is an
482181060Scsjp	 * alternate root directory, prepend it to the audited pathname.
483181060Scsjp	 */
484181060Scsjp	if (fdp->fd_rdir != NULL && fdp->fd_rdir != rootvnode) {
485181060Scsjp		rvnp = fdp->fd_rdir;
486181060Scsjp		vhold(rvnp);
487155192Srwatson	}
488181060Scsjp	/*
489181060Scsjp	 * If the supplied path is relative, make sure we capture the current
490181060Scsjp	 * working directory so we can prepend it to the supplied relative
491181060Scsjp	 * path.
492181060Scsjp	 */
493181060Scsjp	if (*path != '/') {
494181060Scsjp		cvnp = fdp->fd_cdir;
495181060Scsjp		vhold(cvnp);
496181060Scsjp	}
497181060Scsjp	cwir = (fdp->fd_rdir == fdp->fd_cdir);
498168355Srwatson	FILEDESC_SUNLOCK(fdp);
499181060Scsjp	/*
500181060Scsjp	 * NB: We require that the supplied array be at least MAXPATHLEN bytes
501181060Scsjp	 * long.  If this is not the case, then we can run into serious trouble.
502181060Scsjp	 */
503181060Scsjp	(void) sbuf_new(&sbf, cpath, MAXPATHLEN, SBUF_FIXEDLEN);
504181060Scsjp	/*
505181060Scsjp	 * Strip leading forward slashes.
506181060Scsjp	 */
507181060Scsjp	while (*copy == '/')
508181060Scsjp		copy++;
509181060Scsjp	/*
510181060Scsjp	 * Make sure we handle chroot(2) and prepend the global path to these
511181060Scsjp	 * environments.
512181060Scsjp	 *
513181060Scsjp	 * NB: vn_fullpath(9) on FreeBSD is less reliable than vn_getpath(9)
514181060Scsjp	 * on Darwin.  As a result, this may need some additional attention
515181060Scsjp	 * in the future.
516181060Scsjp	 */
517181060Scsjp	if (rvnp != NULL) {
518184660Sjhb		error = vn_fullpath_global(td, rvnp, &rbuf, &fbuf);
519181060Scsjp		vdrop(rvnp);
520181060Scsjp		if (error) {
521155192Srwatson			cpath[0] = '\0';
522181060Scsjp			if (cvnp != NULL)
523181060Scsjp				vdrop(cvnp);
524181060Scsjp			return;
525181060Scsjp		}
526181060Scsjp		(void) sbuf_cat(&sbf, rbuf);
527181060Scsjp		free(fbuf, M_TEMP);
528181060Scsjp	}
529181060Scsjp	if (cvnp != NULL) {
530184660Sjhb		error = vn_fullpath(td, cvnp, &rbuf, &fbuf);
531181060Scsjp		vdrop(cvnp);
532181060Scsjp		if (error) {
533181060Scsjp			cpath[0] = '\0';
534181060Scsjp			return;
535181060Scsjp		}
536181060Scsjp		(void) sbuf_cat(&sbf, rbuf);
537181060Scsjp		free(fbuf, M_TEMP);
538181060Scsjp	}
539181060Scsjp	if (cwir == 0 || (cwir != 0 && cvnp == NULL))
540182090Scsjp		(void) sbuf_putc(&sbf, '/');
541181060Scsjp	/*
542181060Scsjp	 * Now that we have processed any alternate root and relative path
543181060Scsjp	 * names, add the supplied pathname.
544181060Scsjp	 */
545181060Scsjp        (void) sbuf_cat(&sbf, copy);
546181060Scsjp	/*
547181060Scsjp	 * One or more of the previous sbuf operations could have resulted in
548181060Scsjp	 * the supplied buffer being overflowed.  Check to see if this is the
549181060Scsjp	 * case.
550181060Scsjp	 */
551212425Smdf	if (sbuf_error(&sbf) != 0) {
552181060Scsjp		cpath[0] = '\0';
553181060Scsjp		return;
554181060Scsjp	}
555181060Scsjp	sbuf_finish(&sbf);
556155192Srwatson}
557