]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_bsm_klib.c
ee69ec02efff102959904806015df1ea633d4d7a
2 * Copyright (c) 2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 #include <sys/types.h>
27 #include <sys/vnode.h>
28 #include <sys/fcntl.h>
29 #include <sys/filedesc.h>
31 #include <sys/audit.h>
32 #include <sys/kern_audit.h>
33 #include <sys/bsm_kevents.h>
34 #include <sys/bsm_klib.h>
37 * Initialize the system call to audit event mapping table. This table
38 * must be kept in sync with the system call table. This table is meant to
39 * be directly accessed.
40 * XXX This should be improved, though, to make it independent of the syscall
41 * table (but we don't want to traverse a large table for every system call
42 * to find a match). Ultimately, it would be best to place the audit event
43 * number in the system call table.
45 au_event_t sys_au_event
[] = {
46 AUE_NULL
, /* 0 = indir */
47 AUE_EXIT
, /* 1 = exit */
48 AUE_NULL
, /* 2 = fork */
49 AUE_NULL
, /* 3 = read */
50 AUE_NULL
, /* 4 = write */
51 AUE_OPEN_R
, /* 5 = open */
52 AUE_NULL
, /* 6 = close */
53 AUE_NULL
, /* 7 = wait4 */
54 AUE_NULL
, /* 8 = old creat */
55 AUE_LINK
, /* 9 = link */
56 AUE_UNLINK
, /* 10 = unlink */
57 AUE_NULL
, /* 11 was obsolete execv */
58 AUE_CHDIR
, /* 12 = chdir */
59 AUE_FCHDIR
, /* 13 = fchdir */
60 AUE_MKNOD
, /* 14 = mknod */
61 AUE_CHMOD
, /* 15 = chmod */
62 AUE_CHOWN
, /* 16 = chown; now 3 args */
63 AUE_NULL
, /* 17 = old break */
65 AUE_NULL
, /* 18 = ogetfsstat */
67 AUE_GETFSSTAT
, /* 18 = getfsstat */
69 AUE_NULL
, /* 19 = old lseek */
70 AUE_NULL
, /* 20 = getpid */
71 AUE_NULL
, /* 21 was obsolete mount */
72 AUE_NULL
, /* 22 was obsolete umount */
73 AUE_SETUID
, /* 23 = setuid */
74 AUE_NULL
, /* 24 = getuid */
75 AUE_NULL
, /* 25 = geteuid */
76 AUE_NULL
, /* 26 = ptrace */
77 AUE_RECVMSG
, /* 27 = recvmsg */
78 AUE_SENDMSG
, /* 28 = sendmsg */
79 AUE_RECVFROM
, /* 29 = recvfrom */
80 AUE_ACCEPT
, /* 30 = accept */
81 AUE_NULL
, /* 31 = getpeername */
82 AUE_NULL
, /* 32 = getsockname */
83 AUE_ACCESS
, /* 33 = access */
84 AUE_CHFLAGS
, /* 34 = chflags */
85 AUE_FCHFLAGS
, /* 35 = fchflags */
86 AUE_NULL
, /* 36 = sync */
87 AUE_NULL
, /* 37 = kill */
88 AUE_NULL
, /* 38 = old stat */
89 AUE_NULL
, /* 39 = getppid */
90 AUE_NULL
, /* 40 = old lstat */
91 AUE_NULL
, /* 41 = dup */
92 AUE_PIPE
, /* 42 = pipe */
93 AUE_NULL
, /* 43 = getegid */
94 AUE_NULL
, /* 44 = profil */
95 AUE_NULL
, /* 45 = ktrace */
96 AUE_NULL
, /* 46 = sigaction */
97 AUE_NULL
, /* 47 = getgid */
98 AUE_NULL
, /* 48 = sigprocmask */
99 AUE_NULL
, /* 49 = getlogin */
100 AUE_NULL
, /* 50 = setlogin */
101 AUE_NULL
, /* 51 = turn acct off/on */
102 AUE_NULL
, /* 52 = sigpending */
103 AUE_NULL
, /* 53 = sigaltstack */
104 AUE_NULL
, /* 54 = ioctl */
105 AUE_NULL
, /* 55 = reboot */
106 AUE_REVOKE
, /* 56 = revoke */
107 AUE_SYMLINK
, /* 57 = symlink */
108 AUE_READLINK
, /* 58 = readlink */
109 AUE_EXECVE
, /* 59 = execve */
110 AUE_UMASK
, /* 60 = umask */
111 AUE_CHROOT
, /* 61 = chroot */
112 AUE_NULL
, /* 62 = old fstat */
113 AUE_NULL
, /* 63 = used internally, reserved */
114 AUE_NULL
, /* 64 = old getpagesize */
115 AUE_NULL
, /* 65 = msync */
116 AUE_NULL
, /* 66 = vfork */
117 AUE_NULL
, /* 67 was obsolete vread */
118 AUE_NULL
, /* 68 was obsolete vwrite */
119 AUE_NULL
, /* 69 = sbrk */
120 AUE_NULL
, /* 70 = sstk */
121 AUE_NULL
, /* 71 = old mmap */
122 AUE_NULL
, /* 72 = old vadvise */
123 AUE_NULL
, /* 73 = munmap */
124 AUE_NULL
, /* 74 = mprotect */
125 AUE_NULL
, /* 75 = madvise */
126 AUE_NULL
, /* 76 was obsolete vhangup */
127 AUE_NULL
, /* 77 was obsolete vlimit */
128 AUE_NULL
, /* 78 = mincore */
129 AUE_NULL
, /* 79 = getgroups */
130 AUE_SETGROUPS
, /* 80 = setgroups */
131 AUE_NULL
, /* 81 = getpgrp */
132 AUE_SETPGRP
, /* 82 = setpgid */
133 AUE_NULL
, /* 83 = setitimer */
134 AUE_NULL
, /* 84 = old wait */
135 AUE_NULL
, /* 85 = swapon */
136 AUE_NULL
, /* 86 = getitimer */
137 AUE_NULL
, /* 87 = old gethostname */
138 AUE_NULL
, /* 88 = old sethostname */
139 AUE_NULL
, /* 89 getdtablesize */
140 AUE_NULL
, /* 90 = dup2 */
141 AUE_NULL
, /* 91 was obsolete getdopt */
142 AUE_FCNTL
, /* 92 = fcntl */
143 AUE_NULL
, /* 93 = select */
144 AUE_NULL
, /* 94 was obsolete setdopt */
145 AUE_NULL
, /* 95 = fsync */
146 AUE_NULL
, /* 96 = setpriority */
147 AUE_SOCKET
, /* 97 = socket */
148 AUE_CONNECT
, /* 98 = connect */
149 AUE_NULL
, /* 99 = accept */
150 AUE_NULL
, /* 100 = getpriority */
151 AUE_NULL
, /* 101 = old send */
152 AUE_NULL
, /* 102 = old recv */
153 AUE_NULL
, /* 103 = sigreturn */
154 AUE_BIND
, /* 104 = bind */
155 AUE_SETSOCKOPT
, /* 105 = setsockopt */
156 AUE_NULL
, /* 106 = listen */
157 AUE_NULL
, /* 107 was vtimes */
158 AUE_NULL
, /* 108 = sigvec */
159 AUE_NULL
, /* 109 = sigblock */
160 AUE_NULL
, /* 110 = sigsetmask */
161 AUE_NULL
, /* 111 = sigpause */
162 AUE_NULL
, /* 112 = sigstack */
163 AUE_NULL
, /* 113 = recvmsg */
164 AUE_NULL
, /* 114 = sendmsg */
165 AUE_NULL
, /* 115 = old vtrace */
166 AUE_NULL
, /* 116 = gettimeofday */
167 AUE_NULL
, /* 117 = getrusage */
168 AUE_NULL
, /* 118 = getsockopt */
169 AUE_NULL
, /* 119 = old resuba */
170 AUE_NULL
, /* 120 = readv */
171 AUE_NULL
, /* 121 = writev */
172 AUE_NULL
, /* 122 = settimeofday */
173 AUE_FCHOWN
, /* 123 = fchown */
174 AUE_FCHMOD
, /* 124 = fchmod */
175 AUE_NULL
, /* 125 = recvfrom */
176 AUE_NULL
, /* 126 = setreuid */
177 AUE_NULL
, /* 127 = setregid */
178 AUE_RENAME
, /* 128 = rename */
179 AUE_NULL
, /* 129 = old truncate */
180 AUE_NULL
, /* 130 = old ftruncate */
181 AUE_FLOCK
, /* 131 = flock */
182 AUE_MKFIFO
, /* 132 = mkfifo */
183 AUE_SENDTO
, /* 133 = sendto */
184 AUE_SHUTDOWN
, /* 134 = shutdown */
185 AUE_SOCKETPAIR
, /* 135 = socketpair */
186 AUE_MKDIR
, /* 136 = mkdir */
187 AUE_RMDIR
, /* 137 = rmdir */
188 AUE_UTIMES
, /* 138 = utimes */
189 AUE_FUTIMES
, /* 139 = futimes */
190 AUE_ADJTIME
, /* 140 = adjtime */
191 AUE_NULL
, /* 141 = getpeername */
192 AUE_NULL
, /* 142 = old gethostid */
193 AUE_NULL
, /* 143 = old sethostid */
194 AUE_NULL
, /* 144 = old getrlimit */
195 AUE_NULL
, /* 145 = old setrlimit */
196 AUE_NULL
, /* 146 = old killpg */
197 AUE_NULL
, /* 147 = setsid */
198 AUE_NULL
, /* 148 was setquota */
199 AUE_NULL
, /* 149 was qquota */
200 AUE_NULL
, /* 150 = getsockname */
201 AUE_NULL
, /* 151 = getpgid */
202 AUE_NULL
, /* 152 = setprivexec */
203 AUE_NULL
, /* 153 = pread */
204 AUE_NULL
, /* 154 = pwrite */
205 AUE_NULL
, /* 155 = nfs_svc */
206 AUE_NULL
, /* 156 = old getdirentries */
207 AUE_STATFS
, /* 157 = statfs */
208 AUE_FSTATFS
, /* 158 = fstatfs */
209 AUE_UMOUNT
, /* 159 = unmount */
210 AUE_NULL
, /* 160 was async_daemon */
211 AUE_GETFH
, /* 161 = get file handle */
212 AUE_NULL
, /* 162 = getdomainname */
213 AUE_NULL
, /* 163 = setdomainname */
216 AUE_QUOTACTL
, /* 165 = quotactl */
218 AUE_NULL
, /* 165 = not configured */
220 AUE_NULL
, /* 166 was exportfs */
221 AUE_MOUNT
, /* 167 = mount */
222 AUE_NULL
, /* 168 was ustat */
223 AUE_NULL
, /* 169 = nosys */
224 AUE_NULL
, /* 170 was table */
225 AUE_NULL
, /* 171 = old wait3 */
226 AUE_NULL
, /* 172 was rpause */
227 AUE_NULL
, /* 173 = nosys */
228 AUE_NULL
, /* 174 was getdents */
229 AUE_NULL
, /* 175 was gc_control */
230 AUE_NULL
, /* 176 = add_profil */
235 AUE_SETGID
, /* 181 */
236 AUE_SETEGID
, /* 182 */
237 AUE_SETEUID
, /* 183 */
238 AUE_NULL
, /* 184 = nosys */
239 AUE_NULL
, /* 185 = nosys */
240 AUE_NULL
, /* 186 = nosys */
241 AUE_NULL
, /* 187 = nosys */
242 AUE_STAT
, /* 188 = stat */
243 AUE_FSTAT
, /* 189 = fstat */
244 AUE_LSTAT
, /* 190 = lstat */
245 AUE_PATHCONF
, /* 191 = pathconf */
246 AUE_FPATHCONF
, /* 192 = fpathconf */
249 AUE_GETFSSTAT
, /* 193 = getfsstat */
251 AUE_NULL
, /* 193 is unused */
253 AUE_NULL
, /* 194 = getrlimit */
254 AUE_SETRLIMIT
, /* 195 = setrlimit */
255 AUE_GETDIRENTRIES
, /* 196 = getdirentries */
256 AUE_NULL
, /* 197 = mmap */
257 AUE_NULL
, /* 198 = __syscall */
258 AUE_NULL
, /* 199 = lseek */
259 AUE_TRUNCATE
, /* 200 = truncate */
260 AUE_FTRUNCATE
, /* 201 = ftruncate */
261 AUE_NULL
, /* 202 = __sysctl */
262 AUE_NULL
, /* 203 = mlock */
263 AUE_NULL
, /* 204 = munlock */
264 AUE_UNDELETE
, /* 205 = undelete */
265 AUE_NULL
, /* 206 = ATsocket */
266 AUE_NULL
, /* 207 = ATgetmsg*/
267 AUE_NULL
, /* 208 = ATputmsg*/
268 AUE_NULL
, /* 209 = ATPsndreq*/
269 AUE_NULL
, /* 210 = ATPsndrsp*/
270 AUE_NULL
, /* 211 = ATPgetreq*/
271 AUE_NULL
, /* 212 = ATPgetrsp*/
272 AUE_NULL
, /* 213 = Reserved for AppleTalk */
273 AUE_NULL
, /* 214 = Reserved for AppleTalk */
274 AUE_NULL
, /* 215 = Reserved for AppleTalk */
276 AUE_NULL
, /* 216 = HFS make complex file call (multipel forks */
277 AUE_NULL
, /* 217 = HFS statv extended stat call for HFS */
278 AUE_NULL
, /* 218 = HFS lstatv extended lstat call for HFS */
279 AUE_NULL
, /* 219 = HFS fstatv extended fstat call for HFS */
280 AUE_GETATTRLIST
,/* 220 = HFS getarrtlist get attribute list cal */
281 AUE_SETATTRLIST
,/* 221 = HFS setattrlist set attribute list */
282 AUE_GETDIRENTRIESATTR
,/* 222 = HFS getdirentriesattr get directory attributes */
283 AUE_EXCHANGEDATA
,/* 223 = HFS exchangedata exchange file contents */
284 AUE_NULL
,/* 224 = HFS checkuseraccess check access to a file */
285 AUE_SEARCHFS
, /* 225 = HFS searchfs to implement catalog searching */
286 AUE_NULL
, /* 226 = private delete (Carbon semantics) */
287 AUE_NULL
, /* 227 = copyfile - orignally for AFP */
302 AUE_NULL
, /* 242 = fsctl */
307 AUE_NULL
, /* 247 = nfsclnt*/
308 AUE_NULL
, /* 248 = fhopen */
310 AUE_NULL
, /* 250 = minherit */
311 AUE_NULL
, /* 251 = semsys */
312 AUE_NULL
, /* 252 = msgsys */
313 AUE_NULL
, /* 253 = shmsys */
314 AUE_SEMCTL
, /* 254 = semctl */
315 AUE_SEMGET
, /* 255 = semget */
316 AUE_SEMOP
, /* 256 = semop */
317 AUE_NULL
, /* 257 = semconfig */
318 AUE_MSGCTL
, /* 258 = msgctl */
319 AUE_MSGGET
, /* 259 = msgget */
320 AUE_MSGSND
, /* 260 = msgsnd */
321 AUE_MSGRCV
, /* 261 = msgrcv */
322 AUE_SHMAT
, /* 262 = shmat */
323 AUE_SHMCTL
, /* 263 = shmctl */
324 AUE_SHMDT
, /* 264 = shmdt */
325 AUE_SHMGET
, /* 265 = shmget */
326 AUE_NULL
, /* 266 = shm_open */
327 AUE_NULL
, /* 267 = shm_unlink */
328 AUE_NULL
, /* 268 = sem_open */
329 AUE_NULL
, /* 269 = sem_close */
330 AUE_NULL
, /* 270 = sem_unlink */
331 AUE_NULL
, /* 271 = sem_wait */
332 AUE_NULL
, /* 272 = sem_trywait */
333 AUE_NULL
, /* 273 = sem_post */
334 AUE_NULL
, /* 274 = sem_getvalue */
335 AUE_NULL
, /* 275 = sem_init */
336 AUE_NULL
, /* 276 = sem_destroy */
356 AUE_NULL
, /* 296 = load_shared_file */
357 AUE_NULL
, /* 297 = reset_shared_file */
358 AUE_NULL
, /* 298 = new_system_shared_regions */
370 AUE_NULL
, /* 310 = getsid */
384 AUE_NULL
, /* 324 = mlockall*/
385 AUE_NULL
, /* 325 = munlockall*/
387 AUE_NULL
, /* 327 = issetugid */
395 AUE_NULL
, /* 335 = utrace */
413 AUE_GETAUID
, /* 353 */
414 AUE_SETAUID
, /* 354 */
422 AUE_NULL
, /* 362 = kqueue */
423 AUE_NULL
, /* 363 = kevent */
431 int nsys_au_event
= sizeof(sys_au_event
) / sizeof(sys_au_event
[0]);
434 * Check whether an event is aditable by comparing the mask of classes this
435 * event is part of against the kernel's preselection mask the given mask
436 * which will be the process event mask.
438 * XXX This needs to eventually implement the selection based on the
439 * event->class mapping that is controlled by a configuration file.
441 int au_preselect(au_event_t event
, au_mask_t
*mask_p
, int sorf
)
444 au_class_t effmask
= 0;
450 * XXX Set the event class using a big ugly switch statement. This
451 * will change to use the mapping defined by a configuration file.
456 /* mmap() and pipe() are AU_NULL in some systems; we'll
457 * place them in AU_IPC for now.
459 ae_class
= AU_IPC
; break;
461 case AUE_GETDIRENTRIES
:
462 ae_class
= AU_FREAD
; break;
472 case AUE_GETATTRLIST
:
474 case AUE_GETDIRENTRIESATTR
:
476 ae_class
= AU_FACCESS
; break;
487 case AUE_SETATTRLIST
:
491 case AUE_EXCHANGEDATA
:
492 ae_class
= AU_FMODIFY
; break;
498 ae_class
= AU_FCREATE
; break;
501 ae_class
= AU_FDELETE
; break;
505 ae_class
= AU_CLOSE
; break;
520 ae_class
= AU_PROCESS
; break;
532 ae_class
= AU_NET
; break;
544 ae_class
= AU_IPC
; break;
552 ae_class
= AU_ADMIN
; break;
554 ae_class
= AU_IOCTL
; break;
556 ae_class
= AU_PROCESS
|AU_EXEC
; break;
558 ae_class
= AU_FREAD
; break;
560 ae_class
= AU_FREAD
|AU_FCREATE
; break;
562 ae_class
= AU_FREAD
|AU_FCREATE
|AU_FDELETE
; break;
564 ae_class
= AU_FREAD
|AU_FDELETE
; break;
566 ae_class
= AU_FREAD
|AU_FWRITE
; break;
568 ae_class
= AU_FREAD
|AU_FWRITE
|AU_FCREATE
; break;
570 ae_class
= AU_FREAD
|AU_FWRITE
|AU_FCREATE
|AU_FDELETE
; break;
572 ae_class
= AU_FREAD
|AU_FWRITE
|AU_FDELETE
; break;
574 ae_class
= AU_FWRITE
; break;
576 ae_class
= AU_FWRITE
|AU_FCREATE
; break;
578 ae_class
= AU_FWRITE
|AU_FCREATE
|AU_FDELETE
; break;
580 ae_class
= AU_FWRITE
|AU_FDELETE
; break;
582 ae_class
= AU_FCREATE
|AU_FDELETE
; break;
583 default: /* Assign the event to all classes */
584 ae_class
= AU_ALL
; break;
588 * Perform the actual check of the masks against the event.
591 * XXX Need to compare against the kernel mask??? Or do we not do
592 * that by default and let the client code just call this function
593 * with the kernel preselection mask as the mask parameter?
595 if(sorf
& AU_PRS_SUCCESS
) {
596 effmask
|= (mask_p
->am_success
& ae_class
);
599 if(sorf
& AU_PRS_FAILURE
) {
600 effmask
|= (mask_p
->am_failure
& ae_class
);
610 * Convert an open flags specifier into a specific type of open event for
613 au_event_t
flags_to_openevent(int oflags
) {
615 /* Need to check only those flags we care about. */
616 oflags
= oflags
& (O_RDONLY
| O_CREAT
| O_TRUNC
| O_RDWR
| O_WRONLY
);
618 /* These checks determine what flags are on with the condition
619 * that ONLY that combination is on, and no other flags are on.
621 if (!(oflags
^ O_RDONLY
))
623 if (!(oflags
^ (O_RDONLY
| O_CREAT
)))
625 if (!(oflags
^ (O_RDONLY
| O_CREAT
| O_TRUNC
)))
627 if (!(oflags
^ (O_RDONLY
| O_TRUNC
)))
629 if (!(oflags
^ O_RDWR
))
631 if (!(oflags
^ (O_RDWR
| O_CREAT
)))
633 if (!(oflags
^ (O_RDWR
| O_CREAT
| O_TRUNC
)))
634 return AUE_OPEN_RWTC
;
635 if (!(oflags
^ (O_RDWR
| O_TRUNC
)))
637 if (!(oflags
^ O_WRONLY
))
639 if (!(oflags
^ (O_WRONLY
| O_CREAT
)))
641 if (!(oflags
^ (O_WRONLY
| O_CREAT
| O_TRUNC
)))
643 if (!(oflags
^ (O_WRONLY
| O_TRUNC
)))
650 * Fill in a vattr struct from kernel audit record fields. This function
651 * would be unecessary if we store a vattr in the kernel audit record
654 void fill_vattr(struct vattr
*v
, struct vnode_au_info
*vn_info
)
656 v
->va_mode
= vn_info
->vn_mode
;
657 v
->va_uid
= vn_info
->vn_uid
;
658 v
->va_gid
= vn_info
->vn_gid
;
659 v
->va_fsid
= vn_info
->vn_fsid
;
660 v
->va_fileid
= vn_info
->vn_fileid
;
661 v
->va_rdev
= vn_info
->vn_dev
;
664 /* Convert a MSGCTL command to a specific event. */
665 int msgctl_to_event(int cmd
)
669 return AUE_MSGCTL_RMID
;
671 return AUE_MSGCTL_SET
;
673 return AUE_MSGCTL_STAT
;
676 /* We will audit a bad command */
680 /* Convert a SEMCTL command to a specific event. */
681 int semctl_to_event(int cmd
)
685 return AUE_SEMCTL_GETALL
;
687 return AUE_SEMCTL_GETNCNT
;
689 return AUE_SEMCTL_GETPID
;
691 return AUE_SEMCTL_GETVAL
;
693 return AUE_SEMCTL_GETZCNT
;
695 return AUE_SEMCTL_RMID
;
697 return AUE_SEMCTL_SET
;
699 return AUE_SEMCTL_SETALL
;
701 return AUE_SEMCTL_SETVAL
;
703 return AUE_SEMCTL_STAT
;
706 /* We will audit a bad command */
711 * Create a canonical path from given path by prefixing either the
712 * root directory, or the current working directory.
713 * If the process working directory is NULL, we could use 'rootvnode'
714 * to obtain the root directoty, but this results in a volfs name
715 * written to the audit log. So we will leave the filename starting
716 * with '/' in the audit log in this case.
718 void canon_path(struct proc
*p
, char *path
, char *cpath
)
723 struct filedesc
*fdp
;
727 if (*(path
) == '/') {
728 while (*(bufp
) == '/')
729 bufp
++; /* skip leading '/'s */
730 /* If no process root, or it is the same as the system root,
731 * audit the path as passed in with a single '/'.
733 if ((fdp
->fd_rdir
== NULL
) ||
734 (fdp
->fd_rdir
== rootvnode
)) {
736 bufp
--; /* restore one '/' */
738 vnp
= fdp
->fd_rdir
; /* use process root */
741 vnp
= fdp
->fd_cdir
; /* prepend the current dir */
746 vn_getpath(vnp
, cpath
, &len
);
747 /* The length returned by vn_getpath() is two greater than the
748 * number of characters in the string.
750 if (len
< MAXPATHLEN
)
752 strncpy(cpath
+ len
-1, bufp
, MAXPATHLEN
- len
);
754 strncpy(cpath
, bufp
, MAXPATHLEN
);