]> git.saurik.com Git - apple/xnu.git/blob - bsd/vfs/vfs_syscalls.c
be9bfe17a6c3fbd5aac65ca2c40b23d265b6115b
[apple/xnu.git] / bsd / vfs / vfs_syscalls.c
1 /*
2 * Copyright (c) 1995-2008 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * Copyright (c) 1989, 1993
30 * The Regents of the University of California. All rights reserved.
31 * (c) UNIX System Laboratories, Inc.
32 * All or some portions of this file are derived from material licensed
33 * to the University of California by American Telephone and Telegraph
34 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
35 * the permission of UNIX System Laboratories, Inc.
36 *
37 * Redistribution and use in source and binary forms, with or without
38 * modification, are permitted provided that the following conditions
39 * are met:
40 * 1. Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * 2. Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in the
44 * documentation and/or other materials provided with the distribution.
45 * 3. All advertising materials mentioning features or use of this software
46 * must display the following acknowledgement:
47 * This product includes software developed by the University of
48 * California, Berkeley and its contributors.
49 * 4. Neither the name of the University nor the names of its contributors
50 * may be used to endorse or promote products derived from this software
51 * without specific prior written permission.
52 *
53 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63 * SUCH DAMAGE.
64 *
65 * @(#)vfs_syscalls.c 8.41 (Berkeley) 6/15/95
66 */
67 /*
68 * NOTICE: This file was modified by SPARTA, Inc. in 2005 to introduce
69 * support for mandatory and extensible security protections. This notice
70 * is included in support of clause 2.2 (b) of the Apple Public License,
71 * Version 2.0.
72 */
73
74 #include <sys/param.h>
75 #include <sys/systm.h>
76 #include <sys/namei.h>
77 #include <sys/filedesc.h>
78 #include <sys/kernel.h>
79 #include <sys/file_internal.h>
80 #include <sys/stat.h>
81 #include <sys/vnode_internal.h>
82 #include <sys/mount_internal.h>
83 #include <sys/proc_internal.h>
84 #include <sys/kauth.h>
85 #include <sys/uio_internal.h>
86 #include <sys/malloc.h>
87 #include <sys/mman.h>
88 #include <sys/dirent.h>
89 #include <sys/attr.h>
90 #include <sys/sysctl.h>
91 #include <sys/ubc.h>
92 #include <sys/quota.h>
93 #include <sys/kdebug.h>
94 #include <sys/fsevents.h>
95 #include <sys/sysproto.h>
96 #include <sys/xattr.h>
97 #include <sys/ubc_internal.h>
98 #include <sys/disk.h>
99 #include <machine/cons.h>
100 #include <machine/limits.h>
101 #include <miscfs/specfs/specdev.h>
102 #include <miscfs/union/union.h>
103
104 #include <bsm/audit_kernel.h>
105 #include <bsm/audit_kevents.h>
106
107 #include <mach/mach_types.h>
108 #include <kern/kern_types.h>
109 #include <kern/kalloc.h>
110
111 #include <vm/vm_pageout.h>
112
113 #include <libkern/OSAtomic.h>
114
115 #if CONFIG_MACF
116 #include <security/mac.h>
117 #include <security/mac_framework.h>
118 #endif
119
120 #if CONFIG_FSE
121 #define GET_PATH(x) \
122 (x) = get_pathbuff();
123 #define RELEASE_PATH(x) \
124 release_pathbuff(x);
125 #else
126 #define GET_PATH(x) \
127 MALLOC_ZONE((x), char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
128 #define RELEASE_PATH(x) \
129 FREE_ZONE((x), MAXPATHLEN, M_NAMEI);
130 #endif /* CONFIG_FSE */
131
132 /* struct for checkdirs iteration */
133 struct cdirargs {
134 vnode_t olddp;
135 vnode_t newdp;
136 };
137 /* callback for checkdirs iteration */
138 static int checkdirs_callback(proc_t p, void * arg);
139
140 static int change_dir(struct nameidata *ndp, vfs_context_t ctx);
141 static int checkdirs(vnode_t olddp, vfs_context_t ctx);
142 void enablequotas(struct mount *mp, vfs_context_t ctx);
143 static int getfsstat_callback(mount_t mp, void * arg);
144 static int getutimes(user_addr_t usrtvp, struct timespec *tsp);
145 static int setutimes(vfs_context_t ctx, vnode_t vp, const struct timespec *ts, int nullflag);
146 static int sync_callback(mount_t, void *);
147 static int munge_statfs(struct mount *mp, struct vfsstatfs *sfsp,
148 user_addr_t bufp, int *sizep, boolean_t is_64_bit,
149 boolean_t partial_copy);
150 static int statfs64_common(struct mount *mp, struct vfsstatfs *sfsp, user_addr_t bufp);
151 int (*union_dircheckp)(struct vnode **, struct fileproc *, vfs_context_t);
152
153 __private_extern__
154 int sync_internal(void);
155
156 __private_extern__
157 int open1(vfs_context_t, struct nameidata *, int, struct vnode_attr *, register_t *);
158
159 __private_extern__
160 int unlink1(vfs_context_t, struct nameidata *, int);
161
162
163 #ifdef __APPLE_API_OBSOLETE
164 struct fstatv_args {
165 int fd; /* file descriptor of the target file */
166 struct vstat *vsb; /* vstat structure for returned info */
167 };
168 struct lstatv_args {
169 const char *path; /* pathname of the target file */
170 struct vstat *vsb; /* vstat structure for returned info */
171 };
172 struct mkcomplex_args {
173 const char *path; /* pathname of the file to be created */
174 mode_t mode; /* access mode for the newly created file */
175 u_long type; /* format of the complex file */
176 };
177 struct statv_args {
178 const char *path; /* pathname of the target file */
179 struct vstat *vsb; /* vstat structure for returned info */
180 };
181
182 int fstatv(proc_t p, struct fstatv_args *uap, register_t *retval);
183 int lstatv(proc_t p, struct lstatv_args *uap, register_t *retval);
184 int mkcomplex(proc_t p, struct mkcomplex_args *uap, register_t *retval);
185 int statv(proc_t p, struct statv_args *uap, register_t *retval);
186
187 #endif /* __APPLE_API_OBSOLETE */
188
189 /*
190 * incremented each time a mount or unmount operation occurs
191 * used to invalidate the cached value of the rootvp in the
192 * mount structure utilized by cache_lookup_path
193 */
194 int mount_generation = 0;
195
196 /* counts number of mount and unmount operations */
197 unsigned int vfs_nummntops=0;
198
199 extern struct fileops vnops;
200 extern errno_t rmdir_remove_orphaned_appleDouble(vnode_t, vfs_context_t, int *);
201
202
203 /*
204 * Virtual File System System Calls
205 */
206
207 /*
208 * Mount a file system.
209 */
210 /* ARGSUSED */
211 int
212 mount(proc_t p, struct mount_args *uap, __unused register_t *retval)
213 {
214 struct __mac_mount_args muap;
215
216 muap.type = uap->type;
217 muap.path = uap->path;
218 muap.flags = uap->flags;
219 muap.data = uap->data;
220 muap.mac_p = USER_ADDR_NULL;
221 return (__mac_mount(p, &muap, retval));
222 }
223
224 int
225 __mac_mount(struct proc *p, register struct __mac_mount_args *uap, __unused register_t *retval)
226 {
227 struct vnode *vp;
228 struct vnode *devvp = NULLVP;
229 struct vnode *device_vnode = NULLVP;
230 #if CONFIG_MACF
231 struct vnode *rvp;
232 #endif
233 struct mount *mp;
234 struct vfstable *vfsp = (struct vfstable *)0;
235 int error, flag = 0;
236 struct vnode_attr va;
237 vfs_context_t ctx = vfs_context_current();
238 struct nameidata nd;
239 struct nameidata nd1;
240 char fstypename[MFSNAMELEN];
241 size_t dummy=0;
242 user_addr_t devpath = USER_ADDR_NULL;
243 user_addr_t fsmountargs = uap->data;
244 int ronly = 0;
245 int mntalloc = 0;
246 mode_t accessmode;
247 boolean_t is_64bit;
248 boolean_t is_rwlock_locked = FALSE;
249
250 AUDIT_ARG(fflags, uap->flags);
251
252 is_64bit = proc_is64bit(p);
253
254 /*
255 * Get vnode to be covered
256 */
257 NDINIT(&nd, LOOKUP, NOTRIGGER | FOLLOW | AUDITVNPATH1,
258 UIO_USERSPACE, uap->path, ctx);
259 error = namei(&nd);
260 if (error)
261 return (error);
262 vp = nd.ni_vp;
263
264 if ((vp->v_flag & VROOT) &&
265 (vp->v_mount->mnt_flag & MNT_ROOTFS))
266 uap->flags |= MNT_UPDATE;
267
268 error = copyinstr(uap->type, fstypename, MFSNAMELEN, &dummy);
269 if (error)
270 goto out1;
271
272 if (uap->flags & MNT_UPDATE) {
273 if ((vp->v_flag & VROOT) == 0) {
274 error = EINVAL;
275 goto out1;
276 }
277 mp = vp->v_mount;
278
279 /* unmount in progress return error */
280 mount_lock(mp);
281 if (mp->mnt_lflag & MNT_LUNMOUNT) {
282 mount_unlock(mp);
283 error = EBUSY;
284 goto out1;
285 }
286 mount_unlock(mp);
287 lck_rw_lock_exclusive(&mp->mnt_rwlock);
288 is_rwlock_locked = TRUE;
289 /*
290 * We only allow the filesystem to be reloaded if it
291 * is currently mounted read-only.
292 */
293 if ((uap->flags & MNT_RELOAD) &&
294 ((mp->mnt_flag & MNT_RDONLY) == 0)) {
295 error = ENOTSUP;
296 goto out1;
297 }
298 /*
299 * Only root, or the user that did the original mount is
300 * permitted to update it.
301 */
302 if (mp->mnt_vfsstat.f_owner != kauth_cred_getuid(vfs_context_ucred(ctx)) &&
303 (error = suser(vfs_context_ucred(ctx), &p->p_acflag))) {
304 goto out1;
305 }
306 #if CONFIG_MACF
307 error = mac_mount_check_remount(ctx, mp);
308 if (error != 0) {
309 lck_rw_done(&mp->mnt_rwlock);
310 goto out1;
311 }
312 #endif
313 /*
314 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV,
315 * and MNT_NOEXEC if mount point is already MNT_NOEXEC.
316 */
317 if (suser(vfs_context_ucred(ctx), NULL)) {
318 uap->flags |= MNT_NOSUID | MNT_NODEV;
319 if (mp->mnt_flag & MNT_NOEXEC)
320 uap->flags |= MNT_NOEXEC;
321 }
322 flag = mp->mnt_flag;
323
324 mp->mnt_flag |=
325 uap->flags & (MNT_RELOAD | MNT_FORCE | MNT_UPDATE);
326
327 vfsp = mp->mnt_vtable;
328 goto update;
329 }
330 /*
331 * If the user is not root, ensure that they own the directory
332 * onto which we are attempting to mount.
333 */
334 VATTR_INIT(&va);
335 VATTR_WANTED(&va, va_uid);
336 if ((error = vnode_getattr(vp, &va, ctx)) ||
337 (va.va_uid != kauth_cred_getuid(vfs_context_ucred(ctx)) &&
338 (error = suser(vfs_context_ucred(ctx), &p->p_acflag)))) {
339 goto out1;
340 }
341 /*
342 * For non-root users, silently enforce MNT_NOSUID and MNT_NODEV, and
343 * MNT_NOEXEC if mount point is already MNT_NOEXEC.
344 */
345 if (suser(vfs_context_ucred(ctx), NULL)) {
346 uap->flags |= MNT_NOSUID | MNT_NODEV;
347 if (vp->v_mount->mnt_flag & MNT_NOEXEC)
348 uap->flags |= MNT_NOEXEC;
349 }
350 if ( (error = VNOP_FSYNC(vp, MNT_WAIT, ctx)) )
351 goto out1;
352
353 if ( (error = buf_invalidateblks(vp, BUF_WRITE_DATA, 0, 0)) )
354 goto out1;
355
356 if (vp->v_type != VDIR) {
357 error = ENOTDIR;
358 goto out1;
359 }
360
361 /* XXXAUDIT: Should we capture the type on the error path as well? */
362 AUDIT_ARG(text, fstypename);
363 mount_list_lock();
364 for (vfsp = vfsconf; vfsp; vfsp = vfsp->vfc_next)
365 if (!strncmp(vfsp->vfc_name, fstypename, MFSNAMELEN))
366 break;
367 mount_list_unlock();
368 if (vfsp == NULL) {
369 error = ENODEV;
370 goto out1;
371 }
372 #if CONFIG_MACF
373 error = mac_mount_check_mount(ctx, vp,
374 &nd.ni_cnd, vfsp->vfc_name);
375 if (error != 0)
376 goto out1;
377 #endif
378 if (ISSET(vp->v_flag, VMOUNT) && (vp->v_mountedhere != NULL)) {
379 error = EBUSY;
380 goto out1;
381 }
382 vnode_lock_spin(vp);
383 SET(vp->v_flag, VMOUNT);
384 vnode_unlock(vp);
385
386 /*
387 * Allocate and initialize the filesystem.
388 */
389 MALLOC_ZONE(mp, struct mount *, (u_long)sizeof(struct mount),
390 M_MOUNT, M_WAITOK);
391 bzero((char *)mp, (u_long)sizeof(struct mount));
392 mntalloc = 1;
393
394 /* Initialize the default IO constraints */
395 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
396 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
397 mp->mnt_maxsegreadsize = mp->mnt_maxreadcnt;
398 mp->mnt_maxsegwritesize = mp->mnt_maxwritecnt;
399 mp->mnt_devblocksize = DEV_BSIZE;
400 mp->mnt_alignmentmask = PAGE_MASK;
401 mp->mnt_ioflags = 0;
402 mp->mnt_realrootvp = NULLVP;
403 mp->mnt_authcache_ttl = CACHED_LOOKUP_RIGHT_TTL;
404
405 TAILQ_INIT(&mp->mnt_vnodelist);
406 TAILQ_INIT(&mp->mnt_workerqueue);
407 TAILQ_INIT(&mp->mnt_newvnodes);
408 mount_lock_init(mp);
409 lck_rw_lock_exclusive(&mp->mnt_rwlock);
410 is_rwlock_locked = TRUE;
411 mp->mnt_op = vfsp->vfc_vfsops;
412 mp->mnt_vtable = vfsp;
413 mount_list_lock();
414 vfsp->vfc_refcount++;
415 mount_list_unlock();
416 //mp->mnt_stat.f_type = vfsp->vfc_typenum;
417 mp->mnt_flag |= vfsp->vfc_flags & MNT_VISFLAGMASK;
418 strncpy(mp->mnt_vfsstat.f_fstypename, vfsp->vfc_name, MFSTYPENAMELEN);
419 strncpy(mp->mnt_vfsstat.f_mntonname, nd.ni_cnd.cn_pnbuf, MAXPATHLEN);
420 mp->mnt_vnodecovered = vp;
421 mp->mnt_vfsstat.f_owner = kauth_cred_getuid(vfs_context_ucred(ctx));
422 mp->mnt_devbsdunit = LOWPRI_MAX_NUM_DEV - 1;
423
424 /* XXX 3762912 hack to support HFS filesystem 'owner' - filesystem may update later */
425 vfs_setowner(mp, KAUTH_UID_NONE, KAUTH_GID_NONE);
426
427 update:
428 /*
429 * Set the mount level flags.
430 */
431 if (uap->flags & MNT_RDONLY)
432 mp->mnt_flag |= MNT_RDONLY;
433 else if (mp->mnt_flag & MNT_RDONLY)
434 mp->mnt_kern_flag |= MNTK_WANTRDWR;
435 mp->mnt_flag &= ~(MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
436 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC |
437 MNT_UNKNOWNPERMISSIONS | MNT_DONTBROWSE | MNT_AUTOMOUNTED |
438 MNT_DEFWRITE | MNT_NOATIME | MNT_QUARANTINE);
439 mp->mnt_flag |= uap->flags & (MNT_NOSUID | MNT_NOEXEC | MNT_NODEV |
440 MNT_SYNCHRONOUS | MNT_UNION | MNT_ASYNC |
441 MNT_UNKNOWNPERMISSIONS | MNT_DONTBROWSE | MNT_AUTOMOUNTED |
442 MNT_DEFWRITE | MNT_NOATIME | MNT_QUARANTINE);
443
444 #if CONFIG_MACF
445 if (uap->flags & MNT_MULTILABEL) {
446 if (vfsp->vfc_vfsflags & VFC_VFSNOMACLABEL) {
447 error = EINVAL;
448 goto out1;
449 }
450 mp->mnt_flag |= MNT_MULTILABEL;
451 }
452 #endif
453
454 if (vfsp->vfc_vfsflags & VFC_VFSLOCALARGS) {
455 if (is_64bit) {
456 if ( (error = copyin(fsmountargs, (caddr_t)&devpath, sizeof(devpath))) )
457 goto out1;
458 fsmountargs += sizeof(devpath);
459 } else {
460 char *tmp;
461 if ( (error = copyin(fsmountargs, (caddr_t)&tmp, sizeof(tmp))) )
462 goto out1;
463 /* munge into LP64 addr */
464 devpath = CAST_USER_ADDR_T(tmp);
465 fsmountargs += sizeof(tmp);
466 }
467
468 /* if it is not update and device name needs to be parsed */
469 if ((devpath)) {
470 NDINIT(&nd1, LOOKUP, FOLLOW, UIO_USERSPACE, devpath, ctx);
471 if ( (error = namei(&nd1)) )
472 goto out1;
473
474 strncpy(mp->mnt_vfsstat.f_mntfromname, nd1.ni_cnd.cn_pnbuf, MAXPATHLEN);
475 devvp = nd1.ni_vp;
476
477 nameidone(&nd1);
478
479 if (devvp->v_type != VBLK) {
480 error = ENOTBLK;
481 goto out2;
482 }
483 if (major(devvp->v_rdev) >= nblkdev) {
484 error = ENXIO;
485 goto out2;
486 }
487 /*
488 * If mount by non-root, then verify that user has necessary
489 * permissions on the device.
490 */
491 if (suser(vfs_context_ucred(ctx), NULL) != 0) {
492 accessmode = KAUTH_VNODE_READ_DATA;
493 if ((mp->mnt_flag & MNT_RDONLY) == 0)
494 accessmode |= KAUTH_VNODE_WRITE_DATA;
495 if ((error = vnode_authorize(devvp, NULL, accessmode, ctx)) != 0)
496 goto out2;
497 }
498 }
499 if (devpath && ((uap->flags & MNT_UPDATE) == 0)) {
500 if ( (error = vnode_ref(devvp)) )
501 goto out2;
502 /*
503 * Disallow multiple mounts of the same device.
504 * Disallow mounting of a device that is currently in use
505 * (except for root, which might share swap device for miniroot).
506 * Flush out any old buffers remaining from a previous use.
507 */
508 if ( (error = vfs_mountedon(devvp)) )
509 goto out3;
510
511 if (vcount(devvp) > 1 && !(vfs_flags(mp) & MNT_ROOTFS)) {
512 error = EBUSY;
513 goto out3;
514 }
515 if ( (error = VNOP_FSYNC(devvp, MNT_WAIT, ctx)) ) {
516 error = ENOTBLK;
517 goto out3;
518 }
519 if ( (error = buf_invalidateblks(devvp, BUF_WRITE_DATA, 0, 0)) )
520 goto out3;
521
522 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
523 #if CONFIG_MACF
524 error = mac_vnode_check_open(ctx,
525 devvp,
526 ronly ? FREAD : FREAD|FWRITE);
527 if (error)
528 goto out3;
529 #endif /* MAC */
530 if ( (error = VNOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, ctx)) )
531 goto out3;
532
533 mp->mnt_devvp = devvp;
534 device_vnode = devvp;
535 } else {
536 if ((mp->mnt_flag & MNT_RDONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
537 /*
538 * If upgrade to read-write by non-root, then verify
539 * that user has necessary permissions on the device.
540 */
541 device_vnode = mp->mnt_devvp;
542 if (device_vnode && suser(vfs_context_ucred(ctx), NULL)) {
543 if ((error = vnode_authorize(device_vnode, NULL,
544 KAUTH_VNODE_READ_DATA | KAUTH_VNODE_WRITE_DATA, ctx)) != 0)
545 goto out2;
546 }
547 }
548 device_vnode = NULLVP;
549 }
550 }
551 #if CONFIG_MACF
552 if ((uap->flags & MNT_UPDATE) == 0) {
553 mac_mount_label_init(mp);
554 mac_mount_label_associate(ctx, mp);
555 }
556 if (uap->mac_p != USER_ADDR_NULL) {
557 struct user_mac mac;
558 char *labelstr = NULL;
559 size_t ulen = 0;
560
561 if ((uap->flags & MNT_UPDATE) != 0) {
562 error = mac_mount_check_label_update(
563 ctx, mp);
564 if (error != 0)
565 goto out3;
566 }
567 if (is_64bit) {
568 error = copyin(uap->mac_p, &mac, sizeof(mac));
569 } else {
570 struct mac mac32;
571 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
572 mac.m_buflen = mac32.m_buflen;
573 mac.m_string = CAST_USER_ADDR_T(mac32.m_string);
574 }
575 if (error != 0)
576 goto out3;
577 if ((mac.m_buflen > MAC_MAX_LABEL_BUF_LEN) ||
578 (mac.m_buflen < 2)) {
579 error = EINVAL;
580 goto out3;
581 }
582 MALLOC(labelstr, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
583 error = copyinstr(mac.m_string, labelstr, mac.m_buflen, &ulen);
584 if (error != 0) {
585 FREE(labelstr, M_MACTEMP);
586 goto out3;
587 }
588 AUDIT_ARG(mac_string, labelstr);
589 error = mac_mount_label_internalize(mp->mnt_mntlabel, labelstr);
590 FREE(labelstr, M_MACTEMP);
591 if (error != 0)
592 goto out3;
593 }
594 #endif
595 if (device_vnode != NULL) {
596 VNOP_IOCTL(device_vnode, DKIOCGETBSDUNIT, (caddr_t)&mp->mnt_devbsdunit, 0, NULL);
597 mp->mnt_devbsdunit %= LOWPRI_MAX_NUM_DEV;
598 }
599
600 /*
601 * Mount the filesystem.
602 */
603 error = VFS_MOUNT(mp, device_vnode, fsmountargs, ctx);
604
605 if (uap->flags & MNT_UPDATE) {
606 if (mp->mnt_kern_flag & MNTK_WANTRDWR)
607 mp->mnt_flag &= ~MNT_RDONLY;
608 mp->mnt_flag &=~
609 (MNT_UPDATE | MNT_RELOAD | MNT_FORCE);
610 mp->mnt_kern_flag &=~ MNTK_WANTRDWR;
611 if (error)
612 mp->mnt_flag = flag;
613 vfs_event_signal(NULL, VQ_UPDATE, (intptr_t)NULL);
614 lck_rw_done(&mp->mnt_rwlock);
615 is_rwlock_locked = FALSE;
616 if (!error)
617 enablequotas(mp, ctx);
618 goto out2;
619 }
620 /*
621 * Put the new filesystem on the mount list after root.
622 */
623 if (error == 0) {
624 struct vfs_attr vfsattr;
625 #if CONFIG_MACF
626 if (vfs_flags(mp) & MNT_MULTILABEL) {
627 error = VFS_ROOT(mp, &rvp, ctx);
628 if (error) {
629 printf("%s() VFS_ROOT returned %d\n", __func__, error);
630 goto out3;
631 }
632
633 /* VFS_ROOT provides reference so needref = 0 */
634 error = vnode_label(mp, NULL, rvp, NULL, 0, ctx);
635 if (error)
636 goto out3;
637 }
638 #endif /* MAC */
639
640 vnode_lock_spin(vp);
641 CLR(vp->v_flag, VMOUNT);
642 vp->v_mountedhere = mp;
643 vnode_unlock(vp);
644
645 /*
646 * taking the name_cache_lock exclusively will
647 * insure that everyone is out of the fast path who
648 * might be trying to use a now stale copy of
649 * vp->v_mountedhere->mnt_realrootvp
650 * bumping mount_generation causes the cached values
651 * to be invalidated
652 */
653 name_cache_lock();
654 mount_generation++;
655 name_cache_unlock();
656
657 vnode_ref(vp);
658
659 error = checkdirs(vp, ctx);
660 if (error != 0) {
661 /* Unmount the filesystem as cdir/rdirs cannot be updated */
662 goto out4;
663 }
664 /*
665 * there is no cleanup code here so I have made it void
666 * we need to revisit this
667 */
668 (void)VFS_START(mp, 0, ctx);
669
670 mount_list_add(mp);
671 lck_rw_done(&mp->mnt_rwlock);
672 is_rwlock_locked = FALSE;
673
674 /* Check if this mounted file system supports EAs or named streams. */
675 /* Skip WebDAV file systems for now since they hang in VFS_GETATTR here. */
676 VFSATTR_INIT(&vfsattr);
677 VFSATTR_WANTED(&vfsattr, f_capabilities);
678 if (strncmp(mp->mnt_vfsstat.f_fstypename, "webdav", sizeof("webdav")) != 0 &&
679 vfs_getattr(mp, &vfsattr, ctx) == 0 &&
680 VFSATTR_IS_SUPPORTED(&vfsattr, f_capabilities)) {
681 if ((vfsattr.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_EXTENDED_ATTR) &&
682 (vfsattr.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_EXTENDED_ATTR)) {
683 mp->mnt_kern_flag |= MNTK_EXTENDED_ATTRS;
684 }
685 #if NAMEDSTREAMS
686 if ((vfsattr.f_capabilities.capabilities[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_NAMEDSTREAMS) &&
687 (vfsattr.f_capabilities.valid[VOL_CAPABILITIES_INTERFACES] & VOL_CAP_INT_NAMEDSTREAMS)) {
688 mp->mnt_kern_flag |= MNTK_NAMED_STREAMS;
689 }
690 #endif
691 /* Check if this file system supports path from id lookups. */
692 if ((vfsattr.f_capabilities.capabilities[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_PATH_FROM_ID) &&
693 (vfsattr.f_capabilities.valid[VOL_CAPABILITIES_FORMAT] & VOL_CAP_FMT_PATH_FROM_ID)) {
694 mp->mnt_kern_flag |= MNTK_PATH_FROM_ID;
695 } else if (mp->mnt_flag & MNT_DOVOLFS) {
696 /* Legacy MNT_DOVOLFS flag also implies path from id lookups. */
697 mp->mnt_kern_flag |= MNTK_PATH_FROM_ID;
698 }
699 }
700 if (mp->mnt_vtable->vfc_vfsflags & VFC_VFSNATIVEXATTR) {
701 mp->mnt_kern_flag |= MNTK_EXTENDED_ATTRS;
702 }
703 if (mp->mnt_vtable->vfc_vfsflags & VFC_VFSPREFLIGHT) {
704 mp->mnt_kern_flag |= MNTK_UNMOUNT_PREFLIGHT;
705 }
706 /* increment the operations count */
707 OSAddAtomic(1, (SInt32 *)&vfs_nummntops);
708 enablequotas(mp, ctx);
709
710 if (device_vnode) {
711 device_vnode->v_specflags |= SI_MOUNTEDON;
712
713 /*
714 * cache the IO attributes for the underlying physical media...
715 * an error return indicates the underlying driver doesn't
716 * support all the queries necessary... however, reasonable
717 * defaults will have been set, so no reason to bail or care
718 */
719 vfs_init_io_attributes(device_vnode, mp);
720 }
721
722 /* Now that mount is setup, notify the listeners */
723 vfs_event_signal(NULL, VQ_MOUNT, (intptr_t)NULL);
724 } else {
725 vnode_lock_spin(vp);
726 CLR(vp->v_flag, VMOUNT);
727 vnode_unlock(vp);
728 mount_list_lock();
729 mp->mnt_vtable->vfc_refcount--;
730 mount_list_unlock();
731
732 if (device_vnode ) {
733 VNOP_CLOSE(device_vnode, ronly ? FREAD : FREAD|FWRITE, ctx);
734 vnode_rele(device_vnode);
735 }
736 lck_rw_done(&mp->mnt_rwlock);
737 is_rwlock_locked = FALSE;
738 mount_lock_destroy(mp);
739 #if CONFIG_MACF
740 mac_mount_label_destroy(mp);
741 #endif
742 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
743 }
744 nameidone(&nd);
745
746 /*
747 * drop I/O count on covered 'vp' and
748 * on the device vp if there was one
749 */
750 if (devpath && devvp)
751 vnode_put(devvp);
752 vnode_put(vp);
753
754 return(error);
755 out4:
756 (void)VFS_UNMOUNT(mp, MNT_FORCE, ctx);
757 if (device_vnode != NULLVP) {
758 VNOP_CLOSE(device_vnode, mp->mnt_flag & MNT_RDONLY ? FREAD : FREAD|FWRITE,
759 ctx);
760
761 }
762 vnode_lock_spin(vp);
763 vp->v_mountedhere = (mount_t) 0;
764 vnode_unlock(vp);
765 vnode_rele(vp);
766 out3:
767 if (devpath && ((uap->flags & MNT_UPDATE) == 0))
768 vnode_rele(devvp);
769 out2:
770 if (devpath && devvp)
771 vnode_put(devvp);
772 out1:
773 /* Release mnt_rwlock only when it was taken */
774 if (is_rwlock_locked == TRUE) {
775 lck_rw_done(&mp->mnt_rwlock);
776 }
777 if (mntalloc) {
778 #if CONFIG_MACF
779 mac_mount_label_destroy(mp);
780 #endif
781 mount_list_lock();
782 vfsp->vfc_refcount--;
783 mount_list_unlock();
784 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
785 }
786 vnode_put(vp);
787 nameidone(&nd);
788
789 return(error);
790 }
791
792 void
793 enablequotas(struct mount *mp, vfs_context_t ctx)
794 {
795 struct nameidata qnd;
796 int type;
797 char qfpath[MAXPATHLEN];
798 const char *qfname = QUOTAFILENAME;
799 const char *qfopsname = QUOTAOPSNAME;
800 const char *qfextension[] = INITQFNAMES;
801
802 /* XXX Shoulkd be an MNTK_ flag, instead of strncmp()'s */
803 if ((strncmp(mp->mnt_vfsstat.f_fstypename, "hfs", sizeof("hfs")) != 0 )
804 && (strncmp( mp->mnt_vfsstat.f_fstypename, "ufs", sizeof("ufs")) != 0))
805 return;
806
807 /*
808 * Enable filesystem disk quotas if necessary.
809 * We ignore errors as this should not interfere with final mount
810 */
811 for (type=0; type < MAXQUOTAS; type++) {
812 snprintf(qfpath, sizeof(qfpath), "%s/%s.%s", mp->mnt_vfsstat.f_mntonname, qfopsname, qfextension[type]);
813 NDINIT(&qnd, LOOKUP, FOLLOW, UIO_SYSSPACE32, CAST_USER_ADDR_T(qfpath), ctx);
814 if (namei(&qnd) != 0)
815 continue; /* option file to trigger quotas is not present */
816 vnode_put(qnd.ni_vp);
817 nameidone(&qnd);
818 snprintf(qfpath, sizeof(qfpath), "%s/%s.%s", mp->mnt_vfsstat.f_mntonname, qfname, qfextension[type]);
819
820 (void) VFS_QUOTACTL(mp, QCMD(Q_QUOTAON, type), 0, qfpath, ctx);
821 }
822 return;
823 }
824
825
826 static int
827 checkdirs_callback(proc_t p, void * arg)
828 {
829 struct cdirargs * cdrp = (struct cdirargs * )arg;
830 vnode_t olddp = cdrp->olddp;
831 vnode_t newdp = cdrp->newdp;
832 struct filedesc *fdp;
833 vnode_t tvp;
834 vnode_t fdp_cvp;
835 vnode_t fdp_rvp;
836 int cdir_changed = 0;
837 int rdir_changed = 0;
838
839 /*
840 * XXX Also needs to iterate each thread in the process to see if it
841 * XXX is using a per-thread current working directory, and, if so,
842 * XXX update that as well.
843 */
844
845 proc_fdlock(p);
846 fdp = p->p_fd;
847 if (fdp == (struct filedesc *)0) {
848 proc_fdunlock(p);
849 return(PROC_RETURNED);
850 }
851 fdp_cvp = fdp->fd_cdir;
852 fdp_rvp = fdp->fd_rdir;
853 proc_fdunlock(p);
854
855 if (fdp_cvp == olddp) {
856 vnode_ref(newdp);
857 tvp = fdp->fd_cdir;
858 fdp_cvp = newdp;
859 cdir_changed = 1;
860 vnode_rele(tvp);
861 }
862 if (fdp_rvp == olddp) {
863 vnode_ref(newdp);
864 tvp = fdp->fd_rdir;
865 fdp_rvp = newdp;
866 rdir_changed = 1;
867 vnode_rele(tvp);
868 }
869 if (cdir_changed || rdir_changed) {
870 proc_fdlock(p);
871 fdp->fd_cdir = fdp_cvp;
872 fdp->fd_rdir = fdp_rvp;
873 proc_fdunlock(p);
874 }
875 return(PROC_RETURNED);
876 }
877
878
879
880 /*
881 * Scan all active processes to see if any of them have a current
882 * or root directory onto which the new filesystem has just been
883 * mounted. If so, replace them with the new mount point.
884 */
885 static int
886 checkdirs(vnode_t olddp, vfs_context_t ctx)
887 {
888 vnode_t newdp;
889 vnode_t tvp;
890 int err;
891 struct cdirargs cdr;
892 struct uthread * uth = get_bsdthread_info(current_thread());
893
894 if (olddp->v_usecount == 1)
895 return(0);
896 if (uth != (struct uthread *)0)
897 uth->uu_notrigger = 1;
898 err = VFS_ROOT(olddp->v_mountedhere, &newdp, ctx);
899 if (uth != (struct uthread *)0)
900 uth->uu_notrigger = 0;
901
902 if (err != 0) {
903 #if DIAGNOSTIC
904 panic("mount: lost mount: error %d", err);
905 #endif
906 return(err);
907 }
908
909 cdr.olddp = olddp;
910 cdr.newdp = newdp;
911 /* do not block for exec/fork trans as the vp in cwd & rootdir are not changing */
912 proc_iterate(PROC_ALLPROCLIST | PROC_NOWAITTRANS, checkdirs_callback, (void *)&cdr, NULL, NULL);
913
914 if (rootvnode == olddp) {
915 vnode_ref(newdp);
916 tvp = rootvnode;
917 rootvnode = newdp;
918 vnode_rele(tvp);
919 }
920
921 vnode_put(newdp);
922 return(0);
923 }
924
925 /*
926 * Unmount a file system.
927 *
928 * Note: unmount takes a path to the vnode mounted on as argument,
929 * not special file (as before).
930 */
931 /* ARGSUSED */
932 int
933 unmount(__unused proc_t p, struct unmount_args *uap, __unused register_t *retval)
934 {
935 vnode_t vp;
936 struct mount *mp;
937 int error;
938 struct nameidata nd;
939 vfs_context_t ctx = vfs_context_current();
940
941 NDINIT(&nd, LOOKUP, NOTRIGGER | FOLLOW | AUDITVNPATH1,
942 UIO_USERSPACE, uap->path, ctx);
943 error = namei(&nd);
944 if (error)
945 return (error);
946 vp = nd.ni_vp;
947 mp = vp->v_mount;
948 nameidone(&nd);
949
950 #if CONFIG_MACF
951 error = mac_mount_check_umount(ctx, mp);
952 if (error != 0) {
953 vnode_put(vp);
954 return (error);
955 }
956 #endif
957 /*
958 * Must be the root of the filesystem
959 */
960 if ((vp->v_flag & VROOT) == 0) {
961 vnode_put(vp);
962 return (EINVAL);
963 }
964 mount_ref(mp, 0);
965 vnode_put(vp);
966 /* safedounmount consumes the mount ref */
967 return (safedounmount(mp, uap->flags, ctx));
968 }
969
970 int
971 vfs_unmountbyfsid(fsid_t * fsid, int flags, vfs_context_t ctx)
972 {
973 mount_t mp;
974
975 mp = mount_list_lookupby_fsid(fsid, 0, 1);
976 if (mp == (mount_t)0) {
977 return(ENOENT);
978 }
979 mount_ref(mp, 0);
980 mount_iterdrop(mp);
981 /* safedounmount consumes the mount ref */
982 return(safedounmount(mp, flags, ctx));
983 }
984
985
986 /*
987 * The mount struct comes with a mount ref which will be consumed.
988 * Do the actual file system unmount, prevent some common foot shooting.
989 */
990 int
991 safedounmount(struct mount *mp, int flags, vfs_context_t ctx)
992 {
993 int error;
994 proc_t p = vfs_context_proc(ctx);
995
996 /*
997 * Only root, or the user that did the original mount is
998 * permitted to unmount this filesystem.
999 */
1000 if ((mp->mnt_vfsstat.f_owner != kauth_cred_getuid(kauth_cred_get())) &&
1001 (error = suser(kauth_cred_get(), &p->p_acflag)))
1002 goto out;
1003
1004 /*
1005 * Don't allow unmounting the root file system.
1006 */
1007 if (mp->mnt_flag & MNT_ROOTFS) {
1008 error = EBUSY; /* the root is always busy */
1009 goto out;
1010 }
1011
1012 return (dounmount(mp, flags, 1, ctx));
1013
1014 out:
1015 mount_drop(mp, 0);
1016 return(error);
1017 }
1018
1019 /*
1020 * Do the actual file system unmount.
1021 */
1022 int
1023 dounmount(struct mount *mp, int flags, int withref, vfs_context_t ctx)
1024 {
1025 vnode_t coveredvp = (vnode_t)0;
1026 int error;
1027 int needwakeup = 0;
1028 int forcedunmount = 0;
1029 int lflags = 0;
1030 struct vnode *devvp = NULLVP;
1031
1032 if (flags & MNT_FORCE)
1033 forcedunmount = 1;
1034 mount_lock(mp);
1035 /* XXX post jaguar fix LK_DRAIN - then clean this up */
1036 if ((flags & MNT_FORCE)) {
1037 mp->mnt_kern_flag |= MNTK_FRCUNMOUNT;
1038 mp->mnt_lflag |= MNT_LFORCE;
1039 }
1040 if (mp->mnt_lflag & MNT_LUNMOUNT) {
1041 mp->mnt_lflag |= MNT_LWAIT;
1042 if(withref != 0)
1043 mount_drop(mp, 1);
1044 msleep((caddr_t)mp, &mp->mnt_mlock, (PVFS | PDROP), "dounmount", NULL);
1045 /*
1046 * The prior unmount attempt has probably succeeded.
1047 * Do not dereference mp here - returning EBUSY is safest.
1048 */
1049 return (EBUSY);
1050 }
1051 mp->mnt_kern_flag |= MNTK_UNMOUNT;
1052 mp->mnt_lflag |= MNT_LUNMOUNT;
1053 mp->mnt_flag &=~ MNT_ASYNC;
1054 /*
1055 * anyone currently in the fast path that
1056 * trips over the cached rootvp will be
1057 * dumped out and forced into the slow path
1058 * to regenerate a new cached value
1059 */
1060 mp->mnt_realrootvp = NULLVP;
1061 mount_unlock(mp);
1062
1063 /*
1064 * taking the name_cache_lock exclusively will
1065 * insure that everyone is out of the fast path who
1066 * might be trying to use a now stale copy of
1067 * vp->v_mountedhere->mnt_realrootvp
1068 * bumping mount_generation causes the cached values
1069 * to be invalidated
1070 */
1071 name_cache_lock();
1072 mount_generation++;
1073 name_cache_unlock();
1074
1075
1076 lck_rw_lock_exclusive(&mp->mnt_rwlock);
1077 if (withref != 0)
1078 mount_drop(mp, 0);
1079 #if CONFIG_FSE
1080 fsevent_unmount(mp); /* has to come first! */
1081 #endif
1082 error = 0;
1083 if (forcedunmount == 0) {
1084 ubc_umount(mp); /* release cached vnodes */
1085 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1086 error = VFS_SYNC(mp, MNT_WAIT, ctx);
1087 if (error) {
1088 mount_lock(mp);
1089 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
1090 mp->mnt_lflag &= ~MNT_LUNMOUNT;
1091 mp->mnt_lflag &= ~MNT_LFORCE;
1092 goto out;
1093 }
1094 }
1095 }
1096
1097 if (forcedunmount)
1098 lflags |= FORCECLOSE;
1099 error = vflush(mp, NULLVP, SKIPSWAP | SKIPSYSTEM | SKIPROOT | lflags);
1100 if ((forcedunmount == 0) && error) {
1101 mount_lock(mp);
1102 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
1103 mp->mnt_lflag &= ~MNT_LUNMOUNT;
1104 mp->mnt_lflag &= ~MNT_LFORCE;
1105 goto out;
1106 }
1107
1108 /* make sure there are no one in the mount iterations or lookup */
1109 mount_iterdrain(mp);
1110
1111 error = VFS_UNMOUNT(mp, flags, ctx);
1112 if (error) {
1113 mount_iterreset(mp);
1114 mount_lock(mp);
1115 mp->mnt_kern_flag &= ~MNTK_UNMOUNT;
1116 mp->mnt_lflag &= ~MNT_LUNMOUNT;
1117 mp->mnt_lflag &= ~MNT_LFORCE;
1118 goto out;
1119 }
1120
1121 /* increment the operations count */
1122 if (!error)
1123 OSAddAtomic(1, (SInt32 *)&vfs_nummntops);
1124
1125 if ( mp->mnt_devvp && mp->mnt_vtable->vfc_vfsflags & VFC_VFSLOCALARGS) {
1126 /* hold an io reference and drop the usecount before close */
1127 devvp = mp->mnt_devvp;
1128 vnode_clearmountedon(devvp);
1129 vnode_getalways(devvp);
1130 vnode_rele(devvp);
1131 VNOP_CLOSE(devvp, mp->mnt_flag & MNT_RDONLY ? FREAD : FREAD|FWRITE,
1132 ctx);
1133 vnode_put(devvp);
1134 }
1135 lck_rw_done(&mp->mnt_rwlock);
1136 mount_list_remove(mp);
1137 lck_rw_lock_exclusive(&mp->mnt_rwlock);
1138
1139 /* mark the mount point hook in the vp but not drop the ref yet */
1140 if ((coveredvp = mp->mnt_vnodecovered) != NULLVP) {
1141 vnode_getwithref(coveredvp);
1142 vnode_lock_spin(coveredvp);
1143 coveredvp->v_mountedhere = (struct mount *)0;
1144 vnode_unlock(coveredvp);
1145 vnode_put(coveredvp);
1146 }
1147
1148 mount_list_lock();
1149 mp->mnt_vtable->vfc_refcount--;
1150 mount_list_unlock();
1151
1152 cache_purgevfs(mp); /* remove cache entries for this file sys */
1153 vfs_event_signal(NULL, VQ_UNMOUNT, (intptr_t)NULL);
1154 mount_lock(mp);
1155 mp->mnt_lflag |= MNT_LDEAD;
1156
1157 if (mp->mnt_lflag & MNT_LWAIT) {
1158 /*
1159 * do the wakeup here
1160 * in case we block in mount_refdrain
1161 * which will drop the mount lock
1162 * and allow anyone blocked in vfs_busy
1163 * to wakeup and see the LDEAD state
1164 */
1165 mp->mnt_lflag &= ~MNT_LWAIT;
1166 wakeup((caddr_t)mp);
1167 }
1168 mount_refdrain(mp);
1169 out:
1170 if (mp->mnt_lflag & MNT_LWAIT) {
1171 mp->mnt_lflag &= ~MNT_LWAIT;
1172 needwakeup = 1;
1173 }
1174 mount_unlock(mp);
1175 lck_rw_done(&mp->mnt_rwlock);
1176
1177 if (needwakeup)
1178 wakeup((caddr_t)mp);
1179 if (!error) {
1180 if ((coveredvp != NULLVP)) {
1181 vnode_getwithref(coveredvp);
1182 vnode_rele(coveredvp);
1183 vnode_lock_spin(coveredvp);
1184 if(mp->mnt_crossref == 0) {
1185 vnode_unlock(coveredvp);
1186 mount_lock_destroy(mp);
1187 #if CONFIG_MACF
1188 mac_mount_label_destroy(mp);
1189 #endif
1190 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
1191 } else {
1192 coveredvp->v_lflag |= VL_MOUNTDEAD;
1193 vnode_unlock(coveredvp);
1194 }
1195 vnode_put(coveredvp);
1196 } else if (mp->mnt_flag & MNT_ROOTFS) {
1197 mount_lock_destroy(mp);
1198 #if CONFIG_MACF
1199 mac_mount_label_destroy(mp);
1200 #endif
1201 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
1202 } else
1203 panic("dounmount: no coveredvp");
1204 }
1205 return (error);
1206 }
1207
1208 void
1209 mount_dropcrossref(mount_t mp, vnode_t dp, int need_put)
1210 {
1211 vnode_lock(dp);
1212 mp->mnt_crossref--;
1213 if (mp->mnt_crossref < 0)
1214 panic("mount cross refs -ve");
1215 if (((dp->v_lflag & VL_MOUNTDEAD) == VL_MOUNTDEAD) && (mp->mnt_crossref == 0)) {
1216 dp->v_lflag &= ~VL_MOUNTDEAD;
1217 if (need_put)
1218 vnode_put_locked(dp);
1219 vnode_unlock(dp);
1220 mount_lock_destroy(mp);
1221 #if CONFIG_MACF
1222 mac_mount_label_destroy(mp);
1223 #endif
1224 FREE_ZONE((caddr_t)mp, sizeof (struct mount), M_MOUNT);
1225 return;
1226 }
1227 if (need_put)
1228 vnode_put_locked(dp);
1229 vnode_unlock(dp);
1230 }
1231
1232
1233 /*
1234 * Sync each mounted filesystem.
1235 */
1236 #if DIAGNOSTIC
1237 int syncprt = 0;
1238 struct ctldebug debug0 = { "syncprt", &syncprt };
1239 #endif
1240
1241 int print_vmpage_stat=0;
1242
1243 static int
1244 sync_callback(mount_t mp, __unused void * arg)
1245 {
1246 int asyncflag;
1247
1248 if ((mp->mnt_flag & MNT_RDONLY) == 0) {
1249 asyncflag = mp->mnt_flag & MNT_ASYNC;
1250 mp->mnt_flag &= ~MNT_ASYNC;
1251 VFS_SYNC(mp, MNT_NOWAIT, vfs_context_current());
1252 if (asyncflag)
1253 mp->mnt_flag |= MNT_ASYNC;
1254 }
1255 return(VFS_RETURNED);
1256 }
1257
1258
1259 extern unsigned int vp_pagein, vp_pgodirty, vp_pgoclean;
1260 extern unsigned int dp_pgins, dp_pgouts;
1261
1262 /* ARGSUSED */
1263 int
1264 sync(__unused proc_t p, __unused struct sync_args *uap, __unused register_t *retval)
1265 {
1266
1267 vfs_iterate(LK_NOWAIT, sync_callback, (void *)0);
1268 {
1269 if(print_vmpage_stat) {
1270 vm_countdirtypages();
1271 printf("VP: %d: %d: %d: %d: %d\n", vp_pgodirty, vp_pgoclean, vp_pagein,
1272 dp_pgins, dp_pgouts);
1273 }
1274 }
1275 #if DIAGNOSTIC
1276 if (syncprt)
1277 vfs_bufstats();
1278 #endif /* DIAGNOSTIC */
1279 return (0);
1280 }
1281
1282 /*
1283 * Change filesystem quotas.
1284 */
1285 #if QUOTA
1286 static int quotactl_funneled(proc_t p, struct quotactl_args *uap, register_t *retval);
1287
1288 int
1289 quotactl(proc_t p, struct quotactl_args *uap, register_t *retval)
1290 {
1291 boolean_t funnel_state;
1292 int error;
1293
1294 funnel_state = thread_funnel_set(kernel_flock, TRUE);
1295 error = quotactl_funneled(p, uap, retval);
1296 thread_funnel_set(kernel_flock, funnel_state);
1297 return(error);
1298 }
1299
1300 static int
1301 quotactl_funneled(proc_t p, struct quotactl_args *uap, __unused register_t *retval)
1302 {
1303 struct mount *mp;
1304 int error, quota_cmd, quota_status;
1305 caddr_t datap;
1306 size_t fnamelen;
1307 struct nameidata nd;
1308 vfs_context_t ctx = vfs_context_current();
1309 struct dqblk my_dqblk;
1310
1311 AUDIT_ARG(uid, uap->uid, 0, 0, 0);
1312 AUDIT_ARG(cmd, uap->cmd);
1313 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1314 UIO_USERSPACE, uap->path, ctx);
1315 error = namei(&nd);
1316 if (error)
1317 return (error);
1318 mp = nd.ni_vp->v_mount;
1319 vnode_put(nd.ni_vp);
1320 nameidone(&nd);
1321
1322 /* copyin any data we will need for downstream code */
1323 quota_cmd = uap->cmd >> SUBCMDSHIFT;
1324
1325 switch (quota_cmd) {
1326 case Q_QUOTAON:
1327 /* uap->arg specifies a file from which to take the quotas */
1328 fnamelen = MAXPATHLEN;
1329 datap = kalloc(MAXPATHLEN);
1330 error = copyinstr(uap->arg, datap, MAXPATHLEN, &fnamelen);
1331 break;
1332 case Q_GETQUOTA:
1333 /* uap->arg is a pointer to a dqblk structure. */
1334 datap = (caddr_t) &my_dqblk;
1335 break;
1336 case Q_SETQUOTA:
1337 case Q_SETUSE:
1338 /* uap->arg is a pointer to a dqblk structure. */
1339 datap = (caddr_t) &my_dqblk;
1340 if (proc_is64bit(p)) {
1341 struct user_dqblk my_dqblk64;
1342 error = copyin(uap->arg, (caddr_t)&my_dqblk64, sizeof (my_dqblk64));
1343 if (error == 0) {
1344 munge_dqblk(&my_dqblk, &my_dqblk64, FALSE);
1345 }
1346 }
1347 else {
1348 error = copyin(uap->arg, (caddr_t)&my_dqblk, sizeof (my_dqblk));
1349 }
1350 break;
1351 case Q_QUOTASTAT:
1352 /* uap->arg is a pointer to an integer */
1353 datap = (caddr_t) &quota_status;
1354 break;
1355 default:
1356 datap = NULL;
1357 break;
1358 } /* switch */
1359
1360 if (error == 0) {
1361 error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, datap, ctx);
1362 }
1363
1364 switch (quota_cmd) {
1365 case Q_QUOTAON:
1366 if (datap != NULL)
1367 kfree(datap, MAXPATHLEN);
1368 break;
1369 case Q_GETQUOTA:
1370 /* uap->arg is a pointer to a dqblk structure we need to copy out to */
1371 if (error == 0) {
1372 if (proc_is64bit(p)) {
1373 struct user_dqblk my_dqblk64;
1374 munge_dqblk(&my_dqblk, &my_dqblk64, TRUE);
1375 error = copyout((caddr_t)&my_dqblk64, uap->arg, sizeof (my_dqblk64));
1376 }
1377 else {
1378 error = copyout(datap, uap->arg, sizeof (struct dqblk));
1379 }
1380 }
1381 break;
1382 case Q_QUOTASTAT:
1383 /* uap->arg is a pointer to an integer */
1384 if (error == 0) {
1385 error = copyout(datap, uap->arg, sizeof(quota_status));
1386 }
1387 break;
1388 default:
1389 break;
1390 } /* switch */
1391
1392 return (error);
1393 }
1394 #else
1395 int
1396 quotactl(__unused proc_t p, __unused struct quotactl_args *uap, __unused register_t *retval)
1397 {
1398 return (EOPNOTSUPP);
1399 }
1400 #endif /* QUOTA */
1401
1402 /*
1403 * Get filesystem statistics.
1404 *
1405 * Returns: 0 Success
1406 * namei:???
1407 * vfs_update_vfsstat:???
1408 * munge_statfs:EFAULT
1409 */
1410 /* ARGSUSED */
1411 int
1412 statfs(__unused proc_t p, struct statfs_args *uap, __unused register_t *retval)
1413 {
1414 struct mount *mp;
1415 struct vfsstatfs *sp;
1416 int error;
1417 struct nameidata nd;
1418 vfs_context_t ctx = vfs_context_current();
1419 vnode_t vp;
1420
1421 NDINIT(&nd, LOOKUP, NOTRIGGER | FOLLOW | AUDITVNPATH1,
1422 UIO_USERSPACE, uap->path, ctx);
1423 error = namei(&nd);
1424 if (error)
1425 return (error);
1426 vp = nd.ni_vp;
1427 mp = vp->v_mount;
1428 sp = &mp->mnt_vfsstat;
1429 nameidone(&nd);
1430
1431 error = vfs_update_vfsstat(mp, ctx, VFS_USER_EVENT);
1432 vnode_put(vp);
1433 if (error != 0)
1434 return (error);
1435
1436 error = munge_statfs(mp, sp, uap->buf, NULL, IS_64BIT_PROCESS(p), TRUE);
1437 return (error);
1438 }
1439
1440 /*
1441 * Get filesystem statistics.
1442 */
1443 /* ARGSUSED */
1444 int
1445 fstatfs(__unused proc_t p, struct fstatfs_args *uap, __unused register_t *retval)
1446 {
1447 vnode_t vp;
1448 struct mount *mp;
1449 struct vfsstatfs *sp;
1450 int error;
1451
1452 AUDIT_ARG(fd, uap->fd);
1453
1454 if ( (error = file_vnode(uap->fd, &vp)) )
1455 return (error);
1456
1457 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
1458
1459 mp = vp->v_mount;
1460 if (!mp) {
1461 file_drop(uap->fd);
1462 return (EBADF);
1463 }
1464 sp = &mp->mnt_vfsstat;
1465 if ((error = vfs_update_vfsstat(mp,vfs_context_current(),VFS_USER_EVENT)) != 0) {
1466 file_drop(uap->fd);
1467 return (error);
1468 }
1469 file_drop(uap->fd);
1470
1471 error = munge_statfs(mp, sp, uap->buf, NULL, IS_64BIT_PROCESS(p), TRUE);
1472
1473 return (error);
1474 }
1475
1476 /*
1477 * Common routine to handle copying of statfs64 data to user space
1478 */
1479 static int
1480 statfs64_common(struct mount *mp, struct vfsstatfs *sfsp, user_addr_t bufp)
1481 {
1482 int error;
1483 struct statfs64 sfs;
1484
1485 bzero(&sfs, sizeof(sfs));
1486
1487 sfs.f_bsize = sfsp->f_bsize;
1488 sfs.f_iosize = (int32_t)sfsp->f_iosize;
1489 sfs.f_blocks = sfsp->f_blocks;
1490 sfs.f_bfree = sfsp->f_bfree;
1491 sfs.f_bavail = sfsp->f_bavail;
1492 sfs.f_files = sfsp->f_files;
1493 sfs.f_ffree = sfsp->f_ffree;
1494 sfs.f_fsid = sfsp->f_fsid;
1495 sfs.f_owner = sfsp->f_owner;
1496 sfs.f_type = mp->mnt_vtable->vfc_typenum;
1497 sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
1498 sfs.f_fssubtype = sfsp->f_fssubtype;
1499 strlcpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSTYPENAMELEN);
1500 strlcpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MAXPATHLEN);
1501 strlcpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MAXPATHLEN);
1502
1503 error = copyout((caddr_t)&sfs, bufp, sizeof(sfs));
1504
1505 return(error);
1506 }
1507
1508 /*
1509 * Get file system statistics in 64-bit mode
1510 */
1511 int
1512 statfs64(__unused struct proc *p, struct statfs64_args *uap, __unused register_t *retval)
1513 {
1514 struct mount *mp;
1515 struct vfsstatfs *sp;
1516 int error;
1517 struct nameidata nd;
1518 vfs_context_t ctxp = vfs_context_current();
1519 vnode_t vp;
1520
1521 NDINIT(&nd, LOOKUP, NOTRIGGER | FOLLOW | AUDITVNPATH1,
1522 UIO_USERSPACE, uap->path, ctxp);
1523 error = namei(&nd);
1524 if (error)
1525 return (error);
1526 vp = nd.ni_vp;
1527 mp = vp->v_mount;
1528 sp = &mp->mnt_vfsstat;
1529 nameidone(&nd);
1530
1531 error = vfs_update_vfsstat(mp, ctxp, VFS_USER_EVENT);
1532 vnode_put(vp);
1533 if (error != 0)
1534 return (error);
1535
1536 error = statfs64_common(mp, sp, uap->buf);
1537
1538 return (error);
1539 }
1540
1541 /*
1542 * Get file system statistics in 64-bit mode
1543 */
1544 int
1545 fstatfs64(__unused struct proc *p, struct fstatfs64_args *uap, __unused register_t *retval)
1546 {
1547 struct vnode *vp;
1548 struct mount *mp;
1549 struct vfsstatfs *sp;
1550 int error;
1551
1552 AUDIT_ARG(fd, uap->fd);
1553
1554 if ( (error = file_vnode(uap->fd, &vp)) )
1555 return (error);
1556
1557 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
1558
1559 mp = vp->v_mount;
1560 if (!mp) {
1561 file_drop(uap->fd);
1562 return (EBADF);
1563 }
1564 sp = &mp->mnt_vfsstat;
1565 if ((error = vfs_update_vfsstat(mp, vfs_context_current(), VFS_USER_EVENT)) != 0) {
1566 file_drop(uap->fd);
1567 return (error);
1568 }
1569 file_drop(uap->fd);
1570
1571 error = statfs64_common(mp, sp, uap->buf);
1572
1573 return (error);
1574 }
1575
1576 struct getfsstat_struct {
1577 user_addr_t sfsp;
1578 user_addr_t *mp;
1579 int count;
1580 int maxcount;
1581 int flags;
1582 int error;
1583 };
1584
1585
1586 static int
1587 getfsstat_callback(mount_t mp, void * arg)
1588 {
1589
1590 struct getfsstat_struct *fstp = (struct getfsstat_struct *)arg;
1591 struct vfsstatfs *sp;
1592 int error, my_size;
1593 vfs_context_t ctx = vfs_context_current();
1594
1595 if (fstp->sfsp && fstp->count < fstp->maxcount) {
1596 sp = &mp->mnt_vfsstat;
1597 /*
1598 * If MNT_NOWAIT is specified, do not refresh the
1599 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1600 */
1601 if (((fstp->flags & MNT_NOWAIT) == 0 || (fstp->flags & MNT_WAIT)) &&
1602 (error = vfs_update_vfsstat(mp, ctx,
1603 VFS_USER_EVENT))) {
1604 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error);
1605 return(VFS_RETURNED);
1606 }
1607
1608 /*
1609 * Need to handle LP64 version of struct statfs
1610 */
1611 error = munge_statfs(mp, sp, fstp->sfsp, &my_size, IS_64BIT_PROCESS(vfs_context_proc(ctx)), FALSE);
1612 if (error) {
1613 fstp->error = error;
1614 return(VFS_RETURNED_DONE);
1615 }
1616 fstp->sfsp += my_size;
1617
1618 if (fstp->mp) {
1619 error = mac_mount_label_get(mp, *fstp->mp);
1620 if (error) {
1621 fstp->error = error;
1622 return(VFS_RETURNED_DONE);
1623 }
1624 fstp->mp++;
1625 }
1626 }
1627 fstp->count++;
1628 return(VFS_RETURNED);
1629 }
1630
1631 /*
1632 * Get statistics on all filesystems.
1633 */
1634 int
1635 getfsstat(__unused proc_t p, struct getfsstat_args *uap, int *retval)
1636 {
1637 struct __mac_getfsstat_args muap;
1638
1639 muap.buf = uap->buf;
1640 muap.bufsize = uap->bufsize;
1641 muap.mac = USER_ADDR_NULL;
1642 muap.macsize = 0;
1643 muap.flags = uap->flags;
1644
1645 return (__mac_getfsstat(p, &muap, retval));
1646 }
1647
1648 int
1649 __mac_getfsstat(__unused proc_t p, struct __mac_getfsstat_args *uap, int *retval)
1650 {
1651 user_addr_t sfsp;
1652 user_addr_t *mp;
1653 int count, maxcount;
1654 struct getfsstat_struct fst;
1655
1656 if (IS_64BIT_PROCESS(p)) {
1657 maxcount = uap->bufsize / sizeof(struct user_statfs);
1658 }
1659 else {
1660 maxcount = uap->bufsize / sizeof(struct statfs);
1661 }
1662 sfsp = uap->buf;
1663 count = 0;
1664
1665 mp = NULL;
1666
1667 #if CONFIG_MACF
1668 if (uap->mac != USER_ADDR_NULL) {
1669 u_int32_t *mp0;
1670 int error;
1671 int i;
1672
1673 count = (int)(uap->macsize / (IS_64BIT_PROCESS(p) ? 8 : 4));
1674 if (count != maxcount)
1675 return (EINVAL);
1676
1677 /* Copy in the array */
1678 MALLOC(mp0, u_int32_t *, uap->macsize, M_MACTEMP, M_WAITOK);
1679 error = copyin(uap->mac, mp0, uap->macsize);
1680 if (error)
1681 return (error);
1682
1683 /* Normalize to an array of user_addr_t */
1684 MALLOC(mp, user_addr_t *, count * sizeof(user_addr_t), M_MACTEMP, M_WAITOK);
1685 for (i = 0; i < count; i++) {
1686 if (IS_64BIT_PROCESS(p))
1687 mp[i] = ((user_addr_t *)mp0)[i];
1688 else
1689 mp[i] = (user_addr_t)mp0[i];
1690 }
1691 FREE(mp0, M_MACTEMP);
1692 }
1693 #endif
1694
1695
1696 fst.sfsp = sfsp;
1697 fst.mp = mp;
1698 fst.flags = uap->flags;
1699 fst.count = 0;
1700 fst.error = 0;
1701 fst.maxcount = maxcount;
1702
1703
1704 vfs_iterate(0, getfsstat_callback, &fst);
1705
1706 if (mp)
1707 FREE(mp, M_MACTEMP);
1708
1709 if (fst.error ) {
1710 KAUTH_DEBUG("ERROR - %s gets %d", p->p_comm, fst.error);
1711 return(fst.error);
1712 }
1713
1714 if (fst.sfsp && fst.count > fst.maxcount)
1715 *retval = fst.maxcount;
1716 else
1717 *retval = fst.count;
1718 return (0);
1719 }
1720
1721 static int
1722 getfsstat64_callback(mount_t mp, void * arg)
1723 {
1724 struct getfsstat_struct *fstp = (struct getfsstat_struct *)arg;
1725 struct vfsstatfs *sp;
1726 int error;
1727
1728 if (fstp->sfsp && fstp->count < fstp->maxcount) {
1729 sp = &mp->mnt_vfsstat;
1730 /*
1731 * If MNT_NOWAIT is specified, do not refresh the
1732 * fsstat cache. MNT_WAIT overrides MNT_NOWAIT.
1733 */
1734 if (((fstp->flags & MNT_NOWAIT) == 0 || (fstp->flags & MNT_WAIT)) &&
1735 (error = vfs_update_vfsstat(mp, vfs_context_current(), VFS_USER_EVENT))) {
1736 KAUTH_DEBUG("vfs_update_vfsstat returned %d", error);
1737 return(VFS_RETURNED);
1738 }
1739
1740 error = statfs64_common(mp, sp, fstp->sfsp);
1741 if (error) {
1742 fstp->error = error;
1743 return(VFS_RETURNED_DONE);
1744 }
1745 fstp->sfsp += sizeof(struct statfs64);
1746 }
1747 fstp->count++;
1748 return(VFS_RETURNED);
1749 }
1750
1751 /*
1752 * Get statistics on all file systems in 64 bit mode.
1753 */
1754 int
1755 getfsstat64(__unused proc_t p, struct getfsstat64_args *uap, int *retval)
1756 {
1757 user_addr_t sfsp;
1758 int count, maxcount;
1759 struct getfsstat_struct fst;
1760
1761 maxcount = uap->bufsize / sizeof(struct statfs64);
1762
1763 sfsp = uap->buf;
1764 count = 0;
1765
1766 fst.sfsp = sfsp;
1767 fst.flags = uap->flags;
1768 fst.count = 0;
1769 fst.error = 0;
1770 fst.maxcount = maxcount;
1771
1772 vfs_iterate(0, getfsstat64_callback, &fst);
1773
1774 if (fst.error ) {
1775 KAUTH_DEBUG("ERROR - %s gets %d", p->p_comm, fst.error);
1776 return(fst.error);
1777 }
1778
1779 if (fst.sfsp && fst.count > fst.maxcount)
1780 *retval = fst.maxcount;
1781 else
1782 *retval = fst.count;
1783
1784 return (0);
1785 }
1786
1787 #if COMPAT_GETFSSTAT
1788 ogetfsstat(proc_t p, struct getfsstat_args *uap, register_t *retval)
1789 {
1790 return (ENOTSUP);
1791 }
1792 #endif
1793
1794 /*
1795 * Change current working directory to a given file descriptor.
1796 */
1797 /* ARGSUSED */
1798 static int
1799 common_fchdir(proc_t p, struct fchdir_args *uap, int per_thread)
1800 {
1801 struct filedesc *fdp = p->p_fd;
1802 vnode_t vp;
1803 vnode_t tdp;
1804 vnode_t tvp;
1805 struct mount *mp;
1806 int error;
1807 vfs_context_t ctx = vfs_context_current();
1808
1809 if (per_thread && uap->fd == -1) {
1810 /*
1811 * Switching back from per-thread to per process CWD; verify we
1812 * in fact have one before proceeding. The only success case
1813 * for this code path is to return 0 preemptively after zapping
1814 * the thread structure contents.
1815 */
1816 thread_t th = vfs_context_thread(ctx);
1817 if (th) {
1818 uthread_t uth = get_bsdthread_info(th);
1819 tvp = uth->uu_cdir;
1820 uth->uu_cdir = NULLVP;
1821 if (tvp != NULLVP) {
1822 vnode_rele(tvp);
1823 return (0);
1824 }
1825 }
1826 return (EBADF);
1827 }
1828
1829 if ( (error = file_vnode(uap->fd, &vp)) )
1830 return(error);
1831 if ( (error = vnode_getwithref(vp)) ) {
1832 file_drop(uap->fd);
1833 return(error);
1834 }
1835
1836 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
1837
1838 if (vp->v_type != VDIR) {
1839 error = ENOTDIR;
1840 goto out;
1841 }
1842
1843 #if CONFIG_MACF
1844 error = mac_vnode_check_chdir(ctx, vp);
1845 if (error)
1846 goto out;
1847 #endif
1848 error = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, ctx);
1849 if (error)
1850 goto out;
1851
1852 while (!error && (mp = vp->v_mountedhere) != NULL) {
1853 if (vfs_busy(mp, LK_NOWAIT)) {
1854 error = EACCES;
1855 goto out;
1856 }
1857 error = VFS_ROOT(mp, &tdp, ctx);
1858 vfs_unbusy(mp);
1859 if (error)
1860 break;
1861 vnode_put(vp);
1862 vp = tdp;
1863 }
1864 if (error)
1865 goto out;
1866 if ( (error = vnode_ref(vp)) )
1867 goto out;
1868 vnode_put(vp);
1869
1870 if (per_thread) {
1871 thread_t th = vfs_context_thread(ctx);
1872 if (th) {
1873 uthread_t uth = get_bsdthread_info(th);
1874 tvp = uth->uu_cdir;
1875 uth->uu_cdir = vp;
1876 OSBitOrAtomic(P_THCWD, (UInt32 *)&p->p_flag);
1877 } else {
1878 vnode_rele(vp);
1879 return (ENOENT);
1880 }
1881 } else {
1882 proc_fdlock(p);
1883 tvp = fdp->fd_cdir;
1884 fdp->fd_cdir = vp;
1885 proc_fdunlock(p);
1886 }
1887
1888 if (tvp)
1889 vnode_rele(tvp);
1890 file_drop(uap->fd);
1891
1892 return (0);
1893 out:
1894 vnode_put(vp);
1895 file_drop(uap->fd);
1896
1897 return(error);
1898 }
1899
1900 int
1901 fchdir(proc_t p, struct fchdir_args *uap, __unused register_t *retval)
1902 {
1903 return common_fchdir(p, uap, 0);
1904 }
1905
1906 int
1907 __pthread_fchdir(proc_t p, struct __pthread_fchdir_args *uap, __unused register_t *retval)
1908 {
1909 return common_fchdir(p, (void *)uap, 1);
1910 }
1911
1912 /*
1913 * Change current working directory (``.'').
1914 *
1915 * Returns: 0 Success
1916 * change_dir:ENOTDIR
1917 * change_dir:???
1918 * vnode_ref:ENOENT No such file or directory
1919 */
1920 /* ARGSUSED */
1921 static int
1922 common_chdir(proc_t p, struct chdir_args *uap, int per_thread)
1923 {
1924 struct filedesc *fdp = p->p_fd;
1925 int error;
1926 struct nameidata nd;
1927 vnode_t tvp;
1928 vfs_context_t ctx = vfs_context_current();
1929
1930 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1931 UIO_USERSPACE, uap->path, ctx);
1932 error = change_dir(&nd, ctx);
1933 if (error)
1934 return (error);
1935 if ( (error = vnode_ref(nd.ni_vp)) ) {
1936 vnode_put(nd.ni_vp);
1937 return (error);
1938 }
1939 /*
1940 * drop the iocount we picked up in change_dir
1941 */
1942 vnode_put(nd.ni_vp);
1943
1944 if (per_thread) {
1945 thread_t th = vfs_context_thread(ctx);
1946 if (th) {
1947 uthread_t uth = get_bsdthread_info(th);
1948 tvp = uth->uu_cdir;
1949 uth->uu_cdir = nd.ni_vp;
1950 OSBitOrAtomic(P_THCWD, (UInt32 *)&p->p_flag);
1951 } else {
1952 vnode_rele(nd.ni_vp);
1953 return (ENOENT);
1954 }
1955 } else {
1956 proc_fdlock(p);
1957 tvp = fdp->fd_cdir;
1958 fdp->fd_cdir = nd.ni_vp;
1959 proc_fdunlock(p);
1960 }
1961
1962 if (tvp)
1963 vnode_rele(tvp);
1964
1965 return (0);
1966 }
1967
1968 int
1969 chdir(proc_t p, struct chdir_args *uap, __unused register_t *retval)
1970 {
1971 return common_chdir(p, (void *)uap, 0);
1972 }
1973
1974 int
1975 __pthread_chdir(proc_t p, struct __pthread_chdir_args *uap, __unused register_t *retval)
1976 {
1977 return common_chdir(p, (void *)uap, 1);
1978 }
1979
1980
1981 /*
1982 * Change notion of root (``/'') directory.
1983 */
1984 /* ARGSUSED */
1985 int
1986 chroot(proc_t p, struct chroot_args *uap, __unused register_t *retval)
1987 {
1988 struct filedesc *fdp = p->p_fd;
1989 int error;
1990 struct nameidata nd;
1991 vnode_t tvp;
1992 vfs_context_t ctx = vfs_context_current();
1993
1994 if ((error = suser(kauth_cred_get(), &p->p_acflag)))
1995 return (error);
1996
1997 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
1998 UIO_USERSPACE, uap->path, ctx);
1999 error = change_dir(&nd, ctx);
2000 if (error)
2001 return (error);
2002
2003 #if CONFIG_MACF
2004 error = mac_vnode_check_chroot(ctx, nd.ni_vp,
2005 &nd.ni_cnd);
2006 if (error) {
2007 vnode_put(nd.ni_vp);
2008 return (error);
2009 }
2010 #endif
2011
2012 if ( (error = vnode_ref(nd.ni_vp)) ) {
2013 vnode_put(nd.ni_vp);
2014 return (error);
2015 }
2016 vnode_put(nd.ni_vp);
2017
2018 proc_fdlock(p);
2019 tvp = fdp->fd_rdir;
2020 fdp->fd_rdir = nd.ni_vp;
2021 fdp->fd_flags |= FD_CHROOT;
2022 proc_fdunlock(p);
2023
2024 if (tvp != NULL)
2025 vnode_rele(tvp);
2026
2027 return (0);
2028 }
2029
2030 /*
2031 * Common routine for chroot and chdir.
2032 *
2033 * Returns: 0 Success
2034 * ENOTDIR Not a directory
2035 * namei:??? [anything namei can return]
2036 * vnode_authorize:??? [anything vnode_authorize can return]
2037 */
2038 static int
2039 change_dir(struct nameidata *ndp, vfs_context_t ctx)
2040 {
2041 vnode_t vp;
2042 int error;
2043
2044 if ((error = namei(ndp)))
2045 return (error);
2046 nameidone(ndp);
2047 vp = ndp->ni_vp;
2048
2049 if (vp->v_type != VDIR) {
2050 vnode_put(vp);
2051 return (ENOTDIR);
2052 }
2053
2054 #if CONFIG_MACF
2055 error = mac_vnode_check_chdir(ctx, vp);
2056 if (error) {
2057 vnode_put(vp);
2058 return (error);
2059 }
2060 #endif
2061
2062 error = vnode_authorize(vp, NULL, KAUTH_VNODE_SEARCH, ctx);
2063 if (error) {
2064 vnode_put(vp);
2065 return (error);
2066 }
2067
2068 return (error);
2069 }
2070
2071 /*
2072 * Check permissions, allocate an open file structure,
2073 * and call the device open routine if any.
2074 *
2075 * Returns: 0 Success
2076 * EINVAL
2077 * EINTR
2078 * falloc:ENFILE
2079 * falloc:EMFILE
2080 * falloc:ENOMEM
2081 * vn_open_auth:???
2082 * dupfdopen:???
2083 * VNOP_ADVLOCK:???
2084 * vnode_setsize:???
2085 */
2086 #warning XXX implement uid, gid
2087 int
2088 open1(vfs_context_t ctx, struct nameidata *ndp, int uflags, struct vnode_attr *vap, register_t *retval)
2089 {
2090 proc_t p = vfs_context_proc(ctx);
2091 uthread_t uu = get_bsdthread_info(vfs_context_thread(ctx));
2092 struct filedesc *fdp = p->p_fd;
2093 struct fileproc *fp;
2094 vnode_t vp;
2095 int flags, oflags;
2096 struct fileproc *nfp;
2097 int type, indx, error;
2098 struct flock lf;
2099 int no_controlling_tty = 0;
2100 int deny_controlling_tty = 0;
2101 struct session *sessp = SESSION_NULL;
2102 struct vfs_context context = *vfs_context_current(); /* local copy */
2103
2104 oflags = uflags;
2105
2106 if ((oflags & O_ACCMODE) == O_ACCMODE)
2107 return(EINVAL);
2108 flags = FFLAGS(uflags);
2109
2110 AUDIT_ARG(fflags, oflags);
2111 AUDIT_ARG(mode, vap->va_mode);
2112
2113 if ( (error = falloc(p, &nfp, &indx, ctx)) ) {
2114 return (error);
2115 }
2116 fp = nfp;
2117 uu->uu_dupfd = -indx - 1;
2118
2119 if (!(p->p_flag & P_CONTROLT)) {
2120 sessp = proc_session(p);
2121 no_controlling_tty = 1;
2122 /*
2123 * If conditions would warrant getting a controlling tty if
2124 * the device being opened is a tty (see ttyopen in tty.c),
2125 * but the open flags deny it, set a flag in the session to
2126 * prevent it.
2127 */
2128 if (SESS_LEADER(p, sessp) &&
2129 sessp->s_ttyvp == NULL &&
2130 (flags & O_NOCTTY)) {
2131 session_lock(sessp);
2132 sessp->s_flags |= S_NOCTTY;
2133 session_unlock(sessp);
2134 deny_controlling_tty = 1;
2135 }
2136 }
2137
2138 if ((error = vn_open_auth(ndp, &flags, vap))) {
2139 if ((error == ENODEV || error == ENXIO) && (uu->uu_dupfd >= 0)){ /* XXX from fdopen */
2140 if ((error = dupfdopen(fdp, indx, uu->uu_dupfd, flags, error)) == 0) {
2141 fp_drop(p, indx, NULL, 0);
2142 *retval = indx;
2143 if (deny_controlling_tty) {
2144 session_lock(sessp);
2145 sessp->s_flags &= ~S_NOCTTY;
2146 session_unlock(sessp);
2147 }
2148 if (sessp != SESSION_NULL)
2149 session_rele(sessp);
2150 return (0);
2151 }
2152 }
2153 if (error == ERESTART)
2154 error = EINTR;
2155 fp_free(p, indx, fp);
2156
2157 if (deny_controlling_tty) {
2158 session_lock(sessp);
2159 sessp->s_flags &= ~S_NOCTTY;
2160 session_unlock(sessp);
2161 }
2162 if (sessp != SESSION_NULL)
2163 session_rele(sessp);
2164 return (error);
2165 }
2166 uu->uu_dupfd = 0;
2167 vp = ndp->ni_vp;
2168
2169 fp->f_fglob->fg_flag = flags & (FMASK | O_EVTONLY);
2170 fp->f_fglob->fg_type = DTYPE_VNODE;
2171 fp->f_fglob->fg_ops = &vnops;
2172 fp->f_fglob->fg_data = (caddr_t)vp;
2173
2174 if (flags & (O_EXLOCK | O_SHLOCK)) {
2175 lf.l_whence = SEEK_SET;
2176 lf.l_start = 0;
2177 lf.l_len = 0;
2178 if (flags & O_EXLOCK)
2179 lf.l_type = F_WRLCK;
2180 else
2181 lf.l_type = F_RDLCK;
2182 type = F_FLOCK;
2183 if ((flags & FNONBLOCK) == 0)
2184 type |= F_WAIT;
2185 #if CONFIG_MACF
2186 error = mac_file_check_lock(vfs_context_ucred(ctx), fp->f_fglob,
2187 F_SETLK, &lf);
2188 if (error)
2189 goto bad;
2190 #endif
2191 if ((error = VNOP_ADVLOCK(vp, (caddr_t)fp->f_fglob, F_SETLK, &lf, type, ctx)))
2192 goto bad;
2193 fp->f_fglob->fg_flag |= FHASLOCK;
2194 }
2195
2196 /* try to truncate by setting the size attribute */
2197 if ((flags & O_TRUNC) && ((error = vnode_setsize(vp, (off_t)0, 0, ctx)) != 0))
2198 goto bad;
2199
2200 /*
2201 * If the open flags denied the acquisition of a controlling tty,
2202 * clear the flag in the session structure that prevented the lower
2203 * level code from assigning one.
2204 */
2205 if (deny_controlling_tty) {
2206 session_lock(sessp);
2207 sessp->s_flags &= ~S_NOCTTY;
2208 session_unlock(sessp);
2209 }
2210
2211 /*
2212 * If a controlling tty was set by the tty line discipline, then we
2213 * want to set the vp of the tty into the session structure. We have
2214 * a race here because we can't get to the vp for the tp in ttyopen,
2215 * because it's not passed as a parameter in the open path.
2216 */
2217 if (no_controlling_tty && (p->p_flag & P_CONTROLT)) {
2218 vnode_t ttyvp;
2219 vnode_ref(vp);
2220 session_lock(sessp);
2221 ttyvp = sessp->s_ttyvp;
2222 sessp->s_ttyvp = vp;
2223 sessp->s_ttyvid = vnode_vid(vp);
2224 session_unlock(sessp);
2225 if (ttyvp != NULLVP)
2226 vnode_rele(ttyvp);
2227 }
2228
2229 vnode_put(vp);
2230
2231 proc_fdlock(p);
2232 procfdtbl_releasefd(p, indx, NULL);
2233 fp_drop(p, indx, fp, 1);
2234 proc_fdunlock(p);
2235
2236 *retval = indx;
2237
2238 if (sessp != SESSION_NULL)
2239 session_rele(sessp);
2240 return (0);
2241 bad:
2242 if (deny_controlling_tty) {
2243 session_lock(sessp);
2244 sessp->s_flags &= ~S_NOCTTY;
2245 session_unlock(sessp);
2246 }
2247 if (sessp != SESSION_NULL)
2248 session_rele(sessp);
2249
2250 /* Modify local copy (to not damage thread copy) */
2251 context.vc_ucred = fp->f_fglob->fg_cred;
2252
2253 vn_close(vp, fp->f_fglob->fg_flag, &context);
2254 vnode_put(vp);
2255 fp_free(p, indx, fp);
2256
2257 return (error);
2258
2259 }
2260
2261 /*
2262 * An open system call using an extended argument list compared to the regular
2263 * system call 'open'.
2264 *
2265 * Parameters: p Process requesting the open
2266 * uap User argument descriptor (see below)
2267 * retval Pointer to an area to receive the
2268 * return calue from the system call
2269 *
2270 * Indirect: uap->path Path to open (same as 'open')
2271 * uap->flags Flags to open (same as 'open'
2272 * uap->uid UID to set, if creating
2273 * uap->gid GID to set, if creating
2274 * uap->mode File mode, if creating (same as 'open')
2275 * uap->xsecurity ACL to set, if creating
2276 *
2277 * Returns: 0 Success
2278 * !0 errno value
2279 *
2280 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2281 *
2282 * XXX: We should enummerate the possible errno values here, and where
2283 * in the code they originated.
2284 */
2285 int
2286 open_extended(proc_t p, struct open_extended_args *uap, register_t *retval)
2287 {
2288 struct filedesc *fdp = p->p_fd;
2289 int ciferror;
2290 kauth_filesec_t xsecdst;
2291 struct vnode_attr va;
2292 struct nameidata nd;
2293 int cmode;
2294
2295 xsecdst = NULL;
2296 if ((uap->xsecurity != USER_ADDR_NULL) &&
2297 ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0))
2298 return ciferror;
2299
2300 VATTR_INIT(&va);
2301 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
2302 VATTR_SET(&va, va_mode, cmode);
2303 if (uap->uid != KAUTH_UID_NONE)
2304 VATTR_SET(&va, va_uid, uap->uid);
2305 if (uap->gid != KAUTH_GID_NONE)
2306 VATTR_SET(&va, va_gid, uap->gid);
2307 if (xsecdst != NULL)
2308 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
2309
2310 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, vfs_context_current());
2311
2312 ciferror = open1(vfs_context_current(), &nd, uap->flags, &va, retval);
2313 if (xsecdst != NULL)
2314 kauth_filesec_free(xsecdst);
2315
2316 return ciferror;
2317 }
2318
2319 int
2320 open(proc_t p, struct open_args *uap, register_t *retval)
2321 {
2322 __pthread_testcancel(1);
2323 return(open_nocancel(p, (struct open_nocancel_args *)uap, retval));
2324 }
2325
2326
2327 int
2328 open_nocancel(proc_t p, struct open_nocancel_args *uap, register_t *retval)
2329 {
2330 struct filedesc *fdp = p->p_fd;
2331 struct vnode_attr va;
2332 struct nameidata nd;
2333 int cmode;
2334
2335 VATTR_INIT(&va);
2336 /* Mask off all but regular access permissions */
2337 cmode = ((uap->mode &~ fdp->fd_cmask) & ALLPERMS) & ~S_ISTXT;
2338 VATTR_SET(&va, va_mode, cmode & ACCESSPERMS);
2339
2340 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1, UIO_USERSPACE, uap->path, vfs_context_current());
2341
2342 return(open1(vfs_context_current(), &nd, uap->flags, &va, retval));
2343 }
2344
2345
2346 /*
2347 * Create a special file.
2348 */
2349 static int mkfifo1(vfs_context_t ctx, user_addr_t upath, struct vnode_attr *vap);
2350
2351 int
2352 mknod(proc_t p, struct mknod_args *uap, __unused register_t *retval)
2353 {
2354 struct vnode_attr va;
2355 vfs_context_t ctx = vfs_context_current();
2356 int error;
2357 int whiteout = 0;
2358 struct nameidata nd;
2359 vnode_t vp, dvp;
2360
2361 VATTR_INIT(&va);
2362 VATTR_SET(&va, va_mode, (uap->mode & ALLPERMS) & ~p->p_fd->fd_cmask);
2363 VATTR_SET(&va, va_rdev, uap->dev);
2364
2365 /* If it's a mknod() of a FIFO, call mkfifo1() instead */
2366 if ((uap->mode & S_IFMT) == S_IFIFO)
2367 return(mkfifo1(ctx, uap->path, &va));
2368
2369 AUDIT_ARG(mode, uap->mode);
2370 AUDIT_ARG(dev, uap->dev);
2371
2372 if ((error = suser(vfs_context_ucred(ctx), &p->p_acflag)))
2373 return (error);
2374 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
2375 UIO_USERSPACE, uap->path, ctx);
2376 error = namei(&nd);
2377 if (error)
2378 return (error);
2379 dvp = nd.ni_dvp;
2380 vp = nd.ni_vp;
2381
2382 if (vp != NULL) {
2383 error = EEXIST;
2384 goto out;
2385 }
2386
2387 switch (uap->mode & S_IFMT) {
2388 case S_IFMT: /* used by badsect to flag bad sectors */
2389 VATTR_SET(&va, va_type, VBAD);
2390 break;
2391 case S_IFCHR:
2392 VATTR_SET(&va, va_type, VCHR);
2393 break;
2394 case S_IFBLK:
2395 VATTR_SET(&va, va_type, VBLK);
2396 break;
2397 case S_IFWHT:
2398 whiteout = 1;
2399 break;
2400 default:
2401 error = EINVAL;
2402 goto out;
2403 }
2404
2405 #if CONFIG_MACF
2406 if (!whiteout) {
2407 error = mac_vnode_check_create(ctx,
2408 nd.ni_dvp, &nd.ni_cnd, &va);
2409 if (error)
2410 goto out;
2411 }
2412 #endif
2413
2414 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
2415 goto out;
2416
2417 if (whiteout) {
2418 error = VNOP_WHITEOUT(dvp, &nd.ni_cnd, CREATE, ctx);
2419 } else {
2420 error = vn_create(dvp, &vp, &nd.ni_cnd, &va, 0, ctx);
2421 }
2422 if (error)
2423 goto out;
2424
2425 if (vp) {
2426 int update_flags = 0;
2427
2428 // Make sure the name & parent pointers are hooked up
2429 if (vp->v_name == NULL)
2430 update_flags |= VNODE_UPDATE_NAME;
2431 if (vp->v_parent == NULLVP)
2432 update_flags |= VNODE_UPDATE_PARENT;
2433
2434 if (update_flags)
2435 vnode_update_identity(vp, dvp, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, update_flags);
2436
2437 #if CONFIG_FSE
2438 add_fsevent(FSE_CREATE_FILE, ctx,
2439 FSE_ARG_VNODE, vp,
2440 FSE_ARG_DONE);
2441 #endif
2442 }
2443
2444 out:
2445 /*
2446 * nameidone has to happen before we vnode_put(dvp)
2447 * since it may need to release the fs_nodelock on the dvp
2448 */
2449 nameidone(&nd);
2450
2451 if (vp)
2452 vnode_put(vp);
2453 vnode_put(dvp);
2454
2455 return (error);
2456 }
2457
2458 /*
2459 * Create a named pipe.
2460 *
2461 * Returns: 0 Success
2462 * EEXIST
2463 * namei:???
2464 * vnode_authorize:???
2465 * vn_create:???
2466 */
2467 static int
2468 mkfifo1(vfs_context_t ctx, user_addr_t upath, struct vnode_attr *vap)
2469 {
2470 vnode_t vp, dvp;
2471 int error;
2472 struct nameidata nd;
2473
2474 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
2475 UIO_USERSPACE, upath, ctx);
2476 error = namei(&nd);
2477 if (error)
2478 return (error);
2479 dvp = nd.ni_dvp;
2480 vp = nd.ni_vp;
2481
2482 /* check that this is a new file and authorize addition */
2483 if (vp != NULL) {
2484 error = EEXIST;
2485 goto out;
2486 }
2487 VATTR_SET(vap, va_type, VFIFO);
2488
2489 #if CONFIG_MACF
2490 error = mac_vnode_check_create(ctx, nd.ni_dvp,
2491 &nd.ni_cnd, vap);
2492 if (error)
2493 goto out;
2494 #endif
2495
2496
2497 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
2498 goto out;
2499
2500
2501 error = vn_create(dvp, &vp, &nd.ni_cnd, vap, 0, ctx);
2502 out:
2503 /*
2504 * nameidone has to happen before we vnode_put(dvp)
2505 * since it may need to release the fs_nodelock on the dvp
2506 */
2507 nameidone(&nd);
2508
2509 if (vp)
2510 vnode_put(vp);
2511 vnode_put(dvp);
2512
2513 return error;
2514 }
2515
2516
2517 /*
2518 * A mkfifo system call using an extended argument list compared to the regular
2519 * system call 'mkfifo'.
2520 *
2521 * Parameters: p Process requesting the open
2522 * uap User argument descriptor (see below)
2523 * retval (Ignored)
2524 *
2525 * Indirect: uap->path Path to fifo (same as 'mkfifo')
2526 * uap->uid UID to set
2527 * uap->gid GID to set
2528 * uap->mode File mode to set (same as 'mkfifo')
2529 * uap->xsecurity ACL to set, if creating
2530 *
2531 * Returns: 0 Success
2532 * !0 errno value
2533 *
2534 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
2535 *
2536 * XXX: We should enummerate the possible errno values here, and where
2537 * in the code they originated.
2538 */
2539 int
2540 mkfifo_extended(proc_t p, struct mkfifo_extended_args *uap, __unused register_t *retval)
2541 {
2542 int ciferror;
2543 kauth_filesec_t xsecdst;
2544 struct vnode_attr va;
2545
2546 xsecdst = KAUTH_FILESEC_NONE;
2547 if (uap->xsecurity != USER_ADDR_NULL) {
2548 if ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
2549 return ciferror;
2550 }
2551
2552 VATTR_INIT(&va);
2553 VATTR_SET(&va, va_mode, (uap->mode & ALLPERMS) & ~p->p_fd->fd_cmask);
2554 if (uap->uid != KAUTH_UID_NONE)
2555 VATTR_SET(&va, va_uid, uap->uid);
2556 if (uap->gid != KAUTH_GID_NONE)
2557 VATTR_SET(&va, va_gid, uap->gid);
2558 if (xsecdst != KAUTH_FILESEC_NONE)
2559 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
2560
2561 ciferror = mkfifo1(vfs_context_current(), uap->path, &va);
2562
2563 if (xsecdst != KAUTH_FILESEC_NONE)
2564 kauth_filesec_free(xsecdst);
2565 return ciferror;
2566 }
2567
2568 /* ARGSUSED */
2569 int
2570 mkfifo(proc_t p, struct mkfifo_args *uap, __unused register_t *retval)
2571 {
2572 struct vnode_attr va;
2573
2574 VATTR_INIT(&va);
2575 VATTR_SET(&va, va_mode, (uap->mode & ALLPERMS) & ~p->p_fd->fd_cmask);
2576
2577 return(mkfifo1(vfs_context_current(), uap->path, &va));
2578 }
2579
2580 /*
2581 * Make a hard file link.
2582 *
2583 * Returns: 0 Success
2584 * EPERM
2585 * EEXIST
2586 * EXDEV
2587 * namei:???
2588 * vnode_authorize:???
2589 * VNOP_LINK:???
2590 */
2591 /* ARGSUSED */
2592 int
2593 link(__unused proc_t p, struct link_args *uap, __unused register_t *retval)
2594 {
2595 vnode_t vp, dvp, lvp;
2596 struct nameidata nd;
2597 vfs_context_t ctx = vfs_context_current();
2598 int error;
2599 fse_info finfo;
2600 int need_event, has_listeners;
2601 char *target_path = NULL;
2602
2603 vp = dvp = lvp = NULLVP;
2604
2605 /* look up the object we are linking to */
2606 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
2607 UIO_USERSPACE, uap->path, ctx);
2608 error = namei(&nd);
2609 if (error)
2610 return (error);
2611 vp = nd.ni_vp;
2612
2613 nameidone(&nd);
2614
2615 /*
2616 * Normally, linking to directories is not supported.
2617 * However, some file systems may have limited support.
2618 */
2619 if (vp->v_type == VDIR) {
2620 if (!(vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSDIRLINKS)) {
2621 error = EPERM; /* POSIX */
2622 goto out;
2623 }
2624 /* Linking to a directory requires ownership. */
2625 if (!kauth_cred_issuser(vfs_context_ucred(ctx))) {
2626 struct vnode_attr dva;
2627
2628 VATTR_INIT(&dva);
2629 VATTR_WANTED(&dva, va_uid);
2630 if (vnode_getattr(vp, &dva, ctx) != 0 ||
2631 !VATTR_IS_SUPPORTED(&dva, va_uid) ||
2632 (dva.va_uid != kauth_cred_getuid(vfs_context_ucred(ctx)))) {
2633 error = EACCES;
2634 goto out;
2635 }
2636 }
2637 }
2638
2639 /* lookup the target node */
2640 nd.ni_cnd.cn_nameiop = CREATE;
2641 nd.ni_cnd.cn_flags = LOCKPARENT | AUDITVNPATH2 | CN_NBMOUNTLOOK;
2642 nd.ni_dirp = uap->link;
2643 error = namei(&nd);
2644 if (error != 0)
2645 goto out;
2646 dvp = nd.ni_dvp;
2647 lvp = nd.ni_vp;
2648
2649 #if CONFIG_MACF
2650 if ((error = mac_vnode_check_link(ctx, dvp, vp, &nd.ni_cnd)) != 0)
2651 goto out2;
2652 #endif
2653
2654 /* or to anything that kauth doesn't want us to (eg. immutable items) */
2655 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_LINKTARGET, ctx)) != 0)
2656 goto out2;
2657
2658 /* target node must not exist */
2659 if (lvp != NULLVP) {
2660 error = EEXIST;
2661 goto out2;
2662 }
2663 /* cannot link across mountpoints */
2664 if (vnode_mount(vp) != vnode_mount(dvp)) {
2665 error = EXDEV;
2666 goto out2;
2667 }
2668
2669 /* authorize creation of the target note */
2670 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
2671 goto out2;
2672
2673 /* and finally make the link */
2674 error = VNOP_LINK(vp, dvp, &nd.ni_cnd, ctx);
2675 if (error)
2676 goto out2;
2677
2678 #if CONFIG_FSE
2679 need_event = need_fsevent(FSE_CREATE_FILE, dvp);
2680 #else
2681 need_event = 0;
2682 #endif
2683 has_listeners = kauth_authorize_fileop_has_listeners();
2684
2685 if (need_event || has_listeners) {
2686 char *link_to_path = NULL;
2687 int len, link_name_len;
2688
2689 /* build the path to the new link file */
2690 GET_PATH(target_path);
2691 if (target_path == NULL) {
2692 error = ENOMEM;
2693 goto out2;
2694 }
2695
2696 len = MAXPATHLEN;
2697 vn_getpath(dvp, target_path, &len);
2698 if ((len + 1 + nd.ni_cnd.cn_namelen + 1) < MAXPATHLEN) {
2699 target_path[len-1] = '/';
2700 strlcpy(&target_path[len], nd.ni_cnd.cn_nameptr, MAXPATHLEN-len);
2701 len += nd.ni_cnd.cn_namelen;
2702 }
2703
2704 if (has_listeners) {
2705 /* build the path to file we are linking to */
2706 GET_PATH(link_to_path);
2707 if (link_to_path == NULL) {
2708 error = ENOMEM;
2709 goto out2;
2710 }
2711
2712 link_name_len = MAXPATHLEN;
2713 vn_getpath(vp, link_to_path, &link_name_len);
2714
2715 /*
2716 * Call out to allow 3rd party notification of rename.
2717 * Ignore result of kauth_authorize_fileop call.
2718 */
2719 kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_LINK,
2720 (uintptr_t)link_to_path, (uintptr_t)target_path);
2721 if (link_to_path != NULL) {
2722 RELEASE_PATH(link_to_path);
2723 }
2724 }
2725 #if CONFIG_FSE
2726 if (need_event) {
2727 /* construct fsevent */
2728 if (get_fse_info(vp, &finfo, ctx) == 0) {
2729 // build the path to the destination of the link
2730 add_fsevent(FSE_CREATE_FILE, ctx,
2731 FSE_ARG_STRING, len, target_path,
2732 FSE_ARG_FINFO, &finfo,
2733 FSE_ARG_DONE);
2734 }
2735 }
2736 #endif
2737 }
2738 out2:
2739 /*
2740 * nameidone has to happen before we vnode_put(dvp)
2741 * since it may need to release the fs_nodelock on the dvp
2742 */
2743 nameidone(&nd);
2744 if (target_path != NULL) {
2745 RELEASE_PATH(target_path);
2746 }
2747 out:
2748 if (lvp)
2749 vnode_put(lvp);
2750 if (dvp)
2751 vnode_put(dvp);
2752 vnode_put(vp);
2753 return (error);
2754 }
2755
2756 /*
2757 * Make a symbolic link.
2758 *
2759 * We could add support for ACLs here too...
2760 */
2761 /* ARGSUSED */
2762 int
2763 symlink(proc_t p, struct symlink_args *uap, __unused register_t *retval)
2764 {
2765 struct vnode_attr va;
2766 char *path;
2767 int error;
2768 struct nameidata nd;
2769 vfs_context_t ctx = vfs_context_current();
2770 vnode_t vp, dvp;
2771 size_t dummy=0;
2772
2773 MALLOC_ZONE(path, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
2774 error = copyinstr(uap->path, path, MAXPATHLEN, &dummy);
2775 if (error)
2776 goto out;
2777 AUDIT_ARG(text, path); /* This is the link string */
2778
2779 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
2780 UIO_USERSPACE, uap->link, ctx);
2781 error = namei(&nd);
2782 if (error)
2783 goto out;
2784 dvp = nd.ni_dvp;
2785 vp = nd.ni_vp;
2786
2787 VATTR_INIT(&va);
2788 VATTR_SET(&va, va_type, VLNK);
2789 VATTR_SET(&va, va_mode, ACCESSPERMS & ~p->p_fd->fd_cmask);
2790 #if CONFIG_MACF
2791 error = mac_vnode_check_create(ctx,
2792 dvp, &nd.ni_cnd, &va);
2793 #endif
2794 if (error != 0) {
2795 goto skipit;
2796 }
2797
2798 if (vp != NULL) {
2799 error = EEXIST;
2800 goto skipit;
2801 }
2802
2803 /* authorize */
2804 if (error == 0)
2805 error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_FILE, ctx);
2806 /* get default ownership, etc. */
2807 if (error == 0)
2808 error = vnode_authattr_new(dvp, &va, 0, ctx);
2809 if (error == 0)
2810 error = VNOP_SYMLINK(dvp, &vp, &nd.ni_cnd, &va, path, ctx);
2811
2812 /* do fallback attribute handling */
2813 if (error == 0)
2814 error = vnode_setattr_fallback(vp, &va, ctx);
2815
2816 if (error == 0) {
2817 int update_flags = 0;
2818
2819 if (vp == NULL) {
2820 nd.ni_cnd.cn_nameiop = LOOKUP;
2821 nd.ni_cnd.cn_flags = 0;
2822 error = namei(&nd);
2823 vp = nd.ni_vp;
2824
2825 if (vp == NULL)
2826 goto skipit;
2827 }
2828
2829 #if 0 /* XXX - kauth_todo - is KAUTH_FILEOP_SYMLINK needed? */
2830 /* call out to allow 3rd party notification of rename.
2831 * Ignore result of kauth_authorize_fileop call.
2832 */
2833 if (kauth_authorize_fileop_has_listeners() &&
2834 namei(&nd) == 0) {
2835 char *new_link_path = NULL;
2836 int len;
2837
2838 /* build the path to the new link file */
2839 new_link_path = get_pathbuff();
2840 len = MAXPATHLEN;
2841 vn_getpath(dvp, new_link_path, &len);
2842 if ((len + 1 + nd.ni_cnd.cn_namelen + 1) < MAXPATHLEN) {
2843 new_link_path[len - 1] = '/';
2844 strlcpy(&new_link_path[len], nd.ni_cnd.cn_nameptr, MAXPATHLEN-len);
2845 }
2846
2847 kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_SYMLINK,
2848 (uintptr_t)path, (uintptr_t)new_link_path);
2849 if (new_link_path != NULL)
2850 release_pathbuff(new_link_path);
2851 }
2852 #endif
2853 // Make sure the name & parent pointers are hooked up
2854 if (vp->v_name == NULL)
2855 update_flags |= VNODE_UPDATE_NAME;
2856 if (vp->v_parent == NULLVP)
2857 update_flags |= VNODE_UPDATE_PARENT;
2858
2859 if (update_flags)
2860 vnode_update_identity(vp, dvp, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, update_flags);
2861
2862 #if CONFIG_FSE
2863 add_fsevent(FSE_CREATE_FILE, ctx,
2864 FSE_ARG_VNODE, vp,
2865 FSE_ARG_DONE);
2866 #endif
2867 }
2868
2869 skipit:
2870 /*
2871 * nameidone has to happen before we vnode_put(dvp)
2872 * since it may need to release the fs_nodelock on the dvp
2873 */
2874 nameidone(&nd);
2875
2876 if (vp)
2877 vnode_put(vp);
2878 vnode_put(dvp);
2879 out:
2880 FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
2881
2882 return (error);
2883 }
2884
2885 /*
2886 * Delete a whiteout from the filesystem.
2887 */
2888 /* ARGSUSED */
2889 #warning XXX authorization not implmented for whiteouts
2890 int
2891 undelete(__unused proc_t p, struct undelete_args *uap, __unused register_t *retval)
2892 {
2893 int error;
2894 struct nameidata nd;
2895 vfs_context_t ctx = vfs_context_current();
2896 vnode_t vp, dvp;
2897
2898 NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT|AUDITVNPATH1,
2899 UIO_USERSPACE, uap->path, ctx);
2900 error = namei(&nd);
2901 if (error)
2902 return (error);
2903 dvp = nd.ni_dvp;
2904 vp = nd.ni_vp;
2905
2906 if (vp == NULLVP && (nd.ni_cnd.cn_flags & ISWHITEOUT)) {
2907 error = VNOP_WHITEOUT(dvp, &nd.ni_cnd, DELETE, ctx);
2908 } else
2909 error = EEXIST;
2910
2911 /*
2912 * nameidone has to happen before we vnode_put(dvp)
2913 * since it may need to release the fs_nodelock on the dvp
2914 */
2915 nameidone(&nd);
2916
2917 if (vp)
2918 vnode_put(vp);
2919 vnode_put(dvp);
2920
2921 return (error);
2922 }
2923
2924 /*
2925 * Delete a name from the filesystem.
2926 */
2927 /* ARGSUSED */
2928 int
2929 unlink1(vfs_context_t ctx, struct nameidata *ndp, int nodelbusy)
2930 {
2931 vnode_t vp, dvp;
2932 int error;
2933 struct componentname *cnp;
2934 char *path = NULL;
2935 int len;
2936 fse_info finfo;
2937 int flags = 0;
2938 int need_event = 0;
2939 int has_listeners = 0;
2940
2941 ndp->ni_cnd.cn_flags |= LOCKPARENT;
2942 cnp = &ndp->ni_cnd;
2943
2944 error = namei(ndp);
2945 if (error)
2946 return (error);
2947 dvp = ndp->ni_dvp;
2948 vp = ndp->ni_vp;
2949
2950 /* With Carbon delete semantics, busy files cannot be deleted */
2951 if (nodelbusy) {
2952 flags |= VNODE_REMOVE_NODELETEBUSY;
2953 }
2954
2955 /*
2956 * Normally, unlinking of directories is not supported.
2957 * However, some file systems may have limited support.
2958 */
2959 if ((vp->v_type == VDIR) &&
2960 !(vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSDIRLINKS)) {
2961 error = EPERM; /* POSIX */
2962 }
2963
2964 /*
2965 * The root of a mounted filesystem cannot be deleted.
2966 */
2967 if (vp->v_flag & VROOT) {
2968 error = EBUSY;
2969 }
2970 if (error)
2971 goto out;
2972
2973
2974 /* authorize the delete operation */
2975 #if CONFIG_MACF
2976 if (!error)
2977 error = mac_vnode_check_unlink(ctx,
2978 dvp, vp, cnp);
2979 #endif /* MAC */
2980 if (!error)
2981 error = vnode_authorize(vp, ndp->ni_dvp, KAUTH_VNODE_DELETE, ctx);
2982 if (error)
2983 goto out;
2984
2985 #if CONFIG_FSE
2986 need_event = need_fsevent(FSE_DELETE, dvp);
2987 if (need_event) {
2988 if ((vp->v_flag & VISHARDLINK) == 0) {
2989 get_fse_info(vp, &finfo, ctx);
2990 }
2991 }
2992 #endif
2993 has_listeners = kauth_authorize_fileop_has_listeners();
2994 if (need_event || has_listeners) {
2995 GET_PATH(path);
2996 if (path == NULL) {
2997 error = ENOMEM;
2998 goto out;
2999 }
3000 len = MAXPATHLEN;
3001 vn_getpath(vp, path, &len);
3002 }
3003
3004 #if NAMEDRSRCFORK
3005 if (ndp->ni_cnd.cn_flags & CN_WANTSRSRCFORK)
3006 error = vnode_removenamedstream(dvp, vp, XATTR_RESOURCEFORK_NAME, 0, ctx);
3007 else
3008 #endif
3009 error = VNOP_REMOVE(dvp, vp, &ndp->ni_cnd, flags, ctx);
3010
3011 /*
3012 * Call out to allow 3rd party notification of delete.
3013 * Ignore result of kauth_authorize_fileop call.
3014 */
3015 if (!error) {
3016 if (has_listeners) {
3017 kauth_authorize_fileop(vfs_context_ucred(ctx),
3018 KAUTH_FILEOP_DELETE,
3019 (uintptr_t)vp,
3020 (uintptr_t)path);
3021 }
3022
3023 if (vp->v_flag & VISHARDLINK) {
3024 //
3025 // if a hardlink gets deleted we want to blow away the
3026 // v_parent link because the path that got us to this
3027 // instance of the link is no longer valid. this will
3028 // force the next call to get the path to ask the file
3029 // system instead of just following the v_parent link.
3030 //
3031 vnode_update_identity(vp, NULL, NULL, 0, 0, VNODE_UPDATE_PARENT);
3032 }
3033
3034 #if CONFIG_FSE
3035 if (need_event) {
3036 if (vp->v_flag & VISHARDLINK) {
3037 get_fse_info(vp, &finfo, ctx);
3038 }
3039 add_fsevent(FSE_DELETE, ctx,
3040 FSE_ARG_STRING, len, path,
3041 FSE_ARG_FINFO, &finfo,
3042 FSE_ARG_DONE);
3043 }
3044 #endif
3045 }
3046 if (path != NULL)
3047 RELEASE_PATH(path);
3048
3049 /*
3050 * nameidone has to happen before we vnode_put(dvp)
3051 * since it may need to release the fs_nodelock on the dvp
3052 */
3053 out:
3054 nameidone(ndp);
3055 vnode_put(dvp);
3056 vnode_put(vp);
3057 return (error);
3058 }
3059
3060 /*
3061 * Delete a name from the filesystem using POSIX semantics.
3062 */
3063 int
3064 unlink(__unused proc_t p, struct unlink_args *uap, __unused register_t *retval)
3065 {
3066 struct nameidata nd;
3067 vfs_context_t ctx = vfs_context_current();
3068
3069 NDINIT(&nd, DELETE, AUDITVNPATH1, UIO_USERSPACE, uap->path, ctx);
3070 return unlink1(ctx, &nd, 0);
3071 }
3072
3073 /*
3074 * Delete a name from the filesystem using Carbon semantics.
3075 */
3076 int
3077 delete(__unused proc_t p, struct delete_args *uap, __unused register_t *retval)
3078 {
3079 struct nameidata nd;
3080 vfs_context_t ctx = vfs_context_current();
3081
3082 NDINIT(&nd, DELETE, AUDITVNPATH1, UIO_USERSPACE, uap->path, ctx);
3083 return unlink1(ctx, &nd, 1);
3084 }
3085
3086 /*
3087 * Reposition read/write file offset.
3088 */
3089 int
3090 lseek(proc_t p, struct lseek_args *uap, off_t *retval)
3091 {
3092 struct fileproc *fp;
3093 vnode_t vp;
3094 struct vfs_context *ctx;
3095 off_t offset = uap->offset, file_size;
3096 int error;
3097
3098 if ( (error = fp_getfvp(p,uap->fd, &fp, &vp)) ) {
3099 if (error == ENOTSUP)
3100 return (ESPIPE);
3101 return (error);
3102 }
3103 if (vnode_isfifo(vp)) {
3104 file_drop(uap->fd);
3105 return(ESPIPE);
3106 }
3107
3108
3109 ctx = vfs_context_current();
3110 #if CONFIG_MACF
3111 if (uap->whence == L_INCR && uap->offset == 0)
3112 error = mac_file_check_get_offset(vfs_context_ucred(ctx),
3113 fp->f_fglob);
3114 else
3115 error = mac_file_check_change_offset(vfs_context_ucred(ctx),
3116 fp->f_fglob);
3117 if (error) {
3118 file_drop(uap->fd);
3119 return (error);
3120 }
3121 #endif
3122 if ( (error = vnode_getwithref(vp)) ) {
3123 file_drop(uap->fd);
3124 return(error);
3125 }
3126
3127 switch (uap->whence) {
3128 case L_INCR:
3129 offset += fp->f_fglob->fg_offset;
3130 break;
3131 case L_XTND:
3132 if ((error = vnode_size(vp, &file_size, ctx)) != 0)
3133 break;
3134 offset += file_size;
3135 break;
3136 case L_SET:
3137 break;
3138 default:
3139 error = EINVAL;
3140 }
3141 if (error == 0) {
3142 if (uap->offset > 0 && offset < 0) {
3143 /* Incremented/relative move past max size */
3144 error = EOVERFLOW;
3145 } else {
3146 /*
3147 * Allow negative offsets on character devices, per
3148 * POSIX 1003.1-2001. Most likely for writing disk
3149 * labels.
3150 */
3151 if (offset < 0 && vp->v_type != VCHR) {
3152 /* Decremented/relative move before start */
3153 error = EINVAL;
3154 } else {
3155 /* Success */
3156 fp->f_fglob->fg_offset = offset;
3157 *retval = fp->f_fglob->fg_offset;
3158 }
3159 }
3160 }
3161 (void)vnode_put(vp);
3162 file_drop(uap->fd);
3163 return (error);
3164 }
3165
3166
3167 /*
3168 * Check access permissions.
3169 *
3170 * Returns: 0 Success
3171 * vnode_authorize:???
3172 */
3173 static int
3174 access1(vnode_t vp, vnode_t dvp, int uflags, vfs_context_t ctx)
3175 {
3176 kauth_action_t action;
3177 int error;
3178
3179 /*
3180 * If just the regular access bits, convert them to something
3181 * that vnode_authorize will understand.
3182 */
3183 if (!(uflags & _ACCESS_EXTENDED_MASK)) {
3184 action = 0;
3185 if (uflags & R_OK)
3186 action |= KAUTH_VNODE_READ_DATA; /* aka KAUTH_VNODE_LIST_DIRECTORY */
3187 if (uflags & W_OK) {
3188 if (vnode_isdir(vp)) {
3189 action |= KAUTH_VNODE_ADD_FILE |
3190 KAUTH_VNODE_ADD_SUBDIRECTORY;
3191 /* might want delete rights here too */
3192 } else {
3193 action |= KAUTH_VNODE_WRITE_DATA;
3194 }
3195 }
3196 if (uflags & X_OK) {
3197 if (vnode_isdir(vp)) {
3198 action |= KAUTH_VNODE_SEARCH;
3199 } else {
3200 action |= KAUTH_VNODE_EXECUTE;
3201 }
3202 }
3203 } else {
3204 /* take advantage of definition of uflags */
3205 action = uflags >> 8;
3206 }
3207
3208 #if CONFIG_MACF
3209 error = mac_vnode_check_access(ctx, vp, uflags);
3210 if (error)
3211 return (error);
3212 #endif /* MAC */
3213
3214 /* action == 0 means only check for existence */
3215 if (action != 0) {
3216 error = vnode_authorize(vp, dvp, action | KAUTH_VNODE_ACCESS, ctx);
3217 } else {
3218 error = 0;
3219 }
3220
3221 return(error);
3222 }
3223
3224
3225
3226 /*
3227 * access_extended
3228 *
3229 * Description: uap->entries Pointer to argument descriptor
3230 * uap->size Size of the area pointed to by
3231 * the descriptor
3232 * uap->results Pointer to the results array
3233 *
3234 * Returns: 0 Success
3235 * ENOMEM Insufficient memory
3236 * EINVAL Invalid arguments
3237 * namei:EFAULT Bad address
3238 * namei:ENAMETOOLONG Filename too long
3239 * namei:ENOENT No such file or directory
3240 * namei:ELOOP Too many levels of symbolic links
3241 * namei:EBADF Bad file descriptor
3242 * namei:ENOTDIR Not a directory
3243 * namei:???
3244 * access1:
3245 *
3246 * Implicit returns:
3247 * uap->results Array contents modified
3248 *
3249 * Notes: The uap->entries are structured as an arbitrary length array
3250 * of accessx descriptors, followed by one or more NULL terniated
3251 * strings
3252 *
3253 * struct accessx_descriptor[0]
3254 * ...
3255 * struct accessx_descriptor[n]
3256 * char name_data[0];
3257 *
3258 * We determine the entry count by walking the buffer containing
3259 * the uap->entries argument descriptor. For each descrptor we
3260 * see, the valid values for the offset ad_name_offset will be
3261 * in the byte range:
3262 *
3263 * [ uap->entries + sizeof(struct accessx_descriptor) ]
3264 * to
3265 * [ uap->entries + uap->size - 2 ]
3266 *
3267 * since we must have at least one string, and the string must
3268 * be at least one character plus the NUL terminator in length.
3269 *
3270 * XXX: Need to support the check-as uid argument
3271 */
3272 int
3273 access_extended(__unused proc_t p, struct access_extended_args *uap, __unused register_t *retval)
3274 {
3275 struct accessx_descriptor *input = NULL;
3276 errno_t *result = NULL;
3277 errno_t error = 0;
3278 int wantdelete = 0;
3279 unsigned int desc_max, desc_actual, i, j;
3280 struct vfs_context context;
3281 struct nameidata nd;
3282 int niopts;
3283 vnode_t vp = NULL;
3284 vnode_t dvp = NULL;
3285 #define ACCESSX_MAX_DESCR_ON_STACK 10
3286 struct accessx_descriptor stack_input[ACCESSX_MAX_DESCR_ON_STACK];
3287
3288 context.vc_ucred = NULL;
3289
3290 /*
3291 * Validate parameters; if valid, copy the descriptor array and string
3292 * arguments into local memory. Before proceeding, the following
3293 * conditions must have been met:
3294 *
3295 * o The total size is not permitted to exceed ACCESSX_MAX_TABLESIZE
3296 * o There must be sufficient room in the request for at least one
3297 * descriptor and a one yte NUL terminated string.
3298 * o The allocation of local storage must not fail.
3299 */
3300 if (uap->size > ACCESSX_MAX_TABLESIZE)
3301 return(ENOMEM);
3302 if (uap->size < (sizeof(struct accessx_descriptor) + 2))
3303 return(EINVAL);
3304 if (uap->size <= sizeof (stack_input)) {
3305 input = stack_input;
3306 } else {
3307 MALLOC(input, struct accessx_descriptor *, uap->size, M_TEMP, M_WAITOK);
3308 if (input == NULL) {
3309 error = ENOMEM;
3310 goto out;
3311 }
3312 }
3313 error = copyin(uap->entries, input, uap->size);
3314 if (error)
3315 goto out;
3316
3317 /*
3318 * Force NUL termination of the copyin buffer to avoid nami() running
3319 * off the end. If the caller passes us bogus data, they may get a
3320 * bogus result.
3321 */
3322 ((char *)input)[uap->size - 1] = 0;
3323
3324 /*
3325 * Access is defined as checking against the process' real identity,
3326 * even if operations are checking the effective identity. This
3327 * requires that we use a local vfs context.
3328 */
3329 context.vc_ucred = kauth_cred_copy_real(kauth_cred_get());
3330 context.vc_thread = current_thread();
3331
3332 /*
3333 * Find out how many entries we have, so we can allocate the result
3334 * array by walking the list and adjusting the count downward by the
3335 * earliest string offset we see.
3336 */
3337 desc_max = (uap->size - 2) / sizeof(struct accessx_descriptor);
3338 desc_actual = desc_max;
3339 for (i = 0; i < desc_actual; i++) {
3340 /*
3341 * Take the offset to the name string for this entry and
3342 * convert to an input array index, which would be one off
3343 * the end of the array if this entry was the lowest-addressed
3344 * name string.
3345 */
3346 j = input[i].ad_name_offset / sizeof(struct accessx_descriptor);
3347
3348 /*
3349 * An offset greater than the max allowable offset is an error.
3350 * It is also an error for any valid entry to point
3351 * to a location prior to the end of the current entry, if
3352 * it's not a reference to the string of the previous entry.
3353 */
3354 if (j > desc_max || (j != 0 && j <= i)) {
3355 error = EINVAL;
3356 goto out;
3357 }
3358
3359 /*
3360 * An offset of 0 means use the previous descriptor's offset;
3361 * this is used to chain multiple requests for the same file
3362 * to avoid multiple lookups.
3363 */
3364 if (j == 0) {
3365 /* This is not valid for the first entry */
3366 if (i == 0) {
3367 error = EINVAL;
3368 goto out;
3369 }
3370 continue;
3371 }
3372
3373 /*
3374 * If the offset of the string for this descriptor is before
3375 * what we believe is the current actual last descriptor,
3376 * then we need to adjust our estimate downward; this permits
3377 * the string table following the last descriptor to be out
3378 * of order relative to the descriptor list.
3379 */
3380 if (j < desc_actual)
3381 desc_actual = j;
3382 }
3383
3384 /*
3385 * We limit the actual number of descriptors we are willing to process
3386 * to a hard maximum of ACCESSX_MAX_DESCRIPTORS. If the number being
3387 * requested does not exceed this limit,
3388 */
3389 if (desc_actual > ACCESSX_MAX_DESCRIPTORS) {
3390 error = ENOMEM;
3391 goto out;
3392 }
3393 MALLOC(result, errno_t *, desc_actual * sizeof(errno_t), M_TEMP, M_WAITOK);
3394 if (result == NULL) {
3395 error = ENOMEM;
3396 goto out;
3397 }
3398
3399 /*
3400 * Do the work by iterating over the descriptor entries we know to
3401 * at least appear to contain valid data.
3402 */
3403 error = 0;
3404 for (i = 0; i < desc_actual; i++) {
3405 /*
3406 * If the ad_name_offset is 0, then we use the previous
3407 * results to make the check; otherwise, we are looking up
3408 * a new file name.
3409 */
3410 if (input[i].ad_name_offset != 0) {
3411 /* discard old vnodes */
3412 if (vp) {
3413 vnode_put(vp);
3414 vp = NULL;
3415 }
3416 if (dvp) {
3417 vnode_put(dvp);
3418 dvp = NULL;
3419 }
3420
3421 /*
3422 * Scan forward in the descriptor list to see if we
3423 * need the parent vnode. We will need it if we are
3424 * deleting, since we must have rights to remove
3425 * entries in the parent directory, as well as the
3426 * rights to delete the object itself.
3427 */
3428 wantdelete = input[i].ad_flags & _DELETE_OK;
3429 for (j = i + 1; (j < desc_actual) && (input[j].ad_name_offset == 0); j++)
3430 if (input[j].ad_flags & _DELETE_OK)
3431 wantdelete = 1;
3432
3433 niopts = FOLLOW | AUDITVNPATH1;
3434
3435 /* need parent for vnode_authorize for deletion test */
3436 if (wantdelete)
3437 niopts |= WANTPARENT;
3438
3439 /* do the lookup */
3440 NDINIT(&nd, LOOKUP, niopts, UIO_SYSSPACE, CAST_USER_ADDR_T(((const char *)input) + input[i].ad_name_offset), &context);
3441 error = namei(&nd);
3442 if (!error) {
3443 vp = nd.ni_vp;
3444 if (wantdelete)
3445 dvp = nd.ni_dvp;
3446 }
3447 nameidone(&nd);
3448 }
3449
3450 /*
3451 * Handle lookup errors.
3452 */
3453 switch(error) {
3454 case ENOENT:
3455 case EACCES:
3456 case EPERM:
3457 case ENOTDIR:
3458 result[i] = error;
3459 break;
3460 case 0:
3461 /* run this access check */
3462 result[i] = access1(vp, dvp, input[i].ad_flags, &context);
3463 break;
3464 default:
3465 /* fatal lookup error */
3466
3467 goto out;
3468 }
3469 }
3470
3471 /* copy out results */
3472 error = copyout(result, uap->results, desc_actual * sizeof(errno_t));
3473
3474 out:
3475 if (input && input != stack_input)
3476 FREE(input, M_TEMP);
3477 if (result)
3478 FREE(result, M_TEMP);
3479 if (vp)
3480 vnode_put(vp);
3481 if (dvp)
3482 vnode_put(dvp);
3483 if (IS_VALID_CRED(context.vc_ucred))
3484 kauth_cred_unref(&context.vc_ucred);
3485 return(error);
3486 }
3487
3488
3489 /*
3490 * Returns: 0 Success
3491 * namei:EFAULT Bad address
3492 * namei:ENAMETOOLONG Filename too long
3493 * namei:ENOENT No such file or directory
3494 * namei:ELOOP Too many levels of symbolic links
3495 * namei:EBADF Bad file descriptor
3496 * namei:ENOTDIR Not a directory
3497 * namei:???
3498 * access1:
3499 */
3500 int
3501 access(__unused proc_t p, struct access_args *uap, __unused register_t *retval)
3502 {
3503 int error;
3504 struct nameidata nd;
3505 int niopts;
3506 struct vfs_context context;
3507
3508 #if NAMEDRSRCFORK
3509 int is_namedstream = 0;
3510 #endif
3511
3512 /*
3513 * Access is defined as checking against the process'
3514 * real identity, even if operations are checking the
3515 * effective identity. So we need to tweak the credential
3516 * in the context.
3517 */
3518 context.vc_ucred = kauth_cred_copy_real(kauth_cred_get());
3519 context.vc_thread = current_thread();
3520
3521 niopts = FOLLOW | AUDITVNPATH1;
3522 /* need parent for vnode_authorize for deletion test */
3523 if (uap->flags & _DELETE_OK)
3524 niopts |= WANTPARENT;
3525 NDINIT(&nd, LOOKUP, niopts, UIO_USERSPACE, uap->path, &context);
3526
3527 #if NAMEDRSRCFORK
3528 /* access(F_OK) calls are allowed for resource forks. */
3529 if (uap->flags == F_OK)
3530 nd.ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
3531 #endif
3532 error = namei(&nd);
3533 if (error)
3534 goto out;
3535
3536 #if NAMEDRSRCFORK
3537 /* Grab reference on the shadow stream file vnode to
3538 * force an inactive on release which will mark it for
3539 * recycle
3540 */
3541 if (vnode_isnamedstream(nd.ni_vp) &&
3542 (nd.ni_vp->v_parent != NULLVP) &&
3543 ((nd.ni_vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0)) {
3544 is_namedstream = 1;
3545 vnode_ref(nd.ni_vp);
3546 }
3547 #endif
3548
3549 error = access1(nd.ni_vp, nd.ni_dvp, uap->flags, &context);
3550
3551 #if NAMEDRSRCFORK
3552 if (is_namedstream) {
3553 vnode_rele(nd.ni_vp);
3554 }
3555 #endif
3556
3557 vnode_put(nd.ni_vp);
3558 if (uap->flags & _DELETE_OK)
3559 vnode_put(nd.ni_dvp);
3560 nameidone(&nd);
3561
3562 out:
3563 kauth_cred_unref(&context.vc_ucred);
3564 return(error);
3565 }
3566
3567
3568 /*
3569 * Returns: 0 Success
3570 * EFAULT
3571 * copyout:EFAULT
3572 * namei:???
3573 * vn_stat:???
3574 */
3575 static int
3576 stat2(vfs_context_t ctx, struct nameidata *ndp, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size, int isstat64)
3577 {
3578 struct stat sb;
3579 struct stat64 sb64;
3580 struct user_stat user_sb;
3581 struct user_stat64 user_sb64;
3582 caddr_t sbp;
3583 int error, my_size;
3584 kauth_filesec_t fsec;
3585 size_t xsecurity_bufsize;
3586 void * statptr;
3587
3588 #if NAMEDRSRCFORK
3589 int is_namedstream = 0;
3590 /* stat calls are allowed for resource forks. */
3591 ndp->ni_cnd.cn_flags |= CN_ALLOWRSRCFORK;
3592 #endif
3593 error = namei(ndp);
3594 if (error)
3595 return (error);
3596 fsec = KAUTH_FILESEC_NONE;
3597 if (isstat64 != 0)
3598 statptr = (void *)&sb64;
3599 else
3600 statptr = (void *)&sb;
3601
3602 #if NAMEDRSRCFORK
3603 /* Grab reference on the shadow stream file vnode to
3604 * force an inactive on release which will mark it for
3605 * recycle.
3606 */
3607 if (vnode_isnamedstream(ndp->ni_vp) &&
3608 (ndp->ni_vp->v_parent != NULLVP) &&
3609 ((ndp->ni_vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) == 0)) {
3610 is_namedstream = 1;
3611 vnode_ref (ndp->ni_vp);
3612 }
3613 #endif
3614
3615 error = vn_stat(ndp->ni_vp, statptr, (xsecurity != USER_ADDR_NULL ? &fsec : NULL), isstat64, ctx);
3616
3617 #if NAMEDRSRCFORK
3618 if (is_namedstream) {
3619 vnode_rele (ndp->ni_vp);
3620 }
3621 #endif
3622
3623 vnode_put(ndp->ni_vp);
3624 nameidone(ndp);
3625
3626 if (error)
3627 return (error);
3628 /* Zap spare fields */
3629 if (isstat64 != 0) {
3630 sb64.st_lspare = 0;
3631 sb64.st_qspare[0] = 0LL;
3632 sb64.st_qspare[1] = 0LL;
3633 if (IS_64BIT_PROCESS(vfs_context_proc(ctx))) {
3634 munge_stat64(&sb64, &user_sb64);
3635 my_size = sizeof(user_sb64);
3636 sbp = (caddr_t)&user_sb64;
3637 } else {
3638 my_size = sizeof(sb64);
3639 sbp = (caddr_t)&sb64;
3640 }
3641 /*
3642 * Check if we raced (post lookup) against the last unlink of a file.
3643 */
3644 if ((sb64.st_nlink == 0) && S_ISREG(sb64.st_mode)) {
3645 sb64.st_nlink = 1;
3646 }
3647 } else {
3648 sb.st_lspare = 0;
3649 sb.st_qspare[0] = 0LL;
3650 sb.st_qspare[1] = 0LL;
3651 if (IS_64BIT_PROCESS(vfs_context_proc(ctx))) {
3652 munge_stat(&sb, &user_sb);
3653 my_size = sizeof(user_sb);
3654 sbp = (caddr_t)&user_sb;
3655 } else {
3656 my_size = sizeof(sb);
3657 sbp = (caddr_t)&sb;
3658 }
3659
3660 /*
3661 * Check if we raced (post lookup) against the last unlink of a file.
3662 */
3663 if ((sb.st_nlink == 0) && S_ISREG(sb.st_mode)) {
3664 sb.st_nlink = 1;
3665 }
3666 }
3667 if ((error = copyout(sbp, ub, my_size)) != 0)
3668 goto out;
3669
3670 /* caller wants extended security information? */
3671 if (xsecurity != USER_ADDR_NULL) {
3672
3673 /* did we get any? */
3674 if (fsec == KAUTH_FILESEC_NONE) {
3675 if (susize(xsecurity_size, 0) != 0) {
3676 error = EFAULT;
3677 goto out;
3678 }
3679 } else {
3680 /* find the user buffer size */
3681 xsecurity_bufsize = fusize(xsecurity_size);
3682
3683 /* copy out the actual data size */
3684 if (susize(xsecurity_size, KAUTH_FILESEC_COPYSIZE(fsec)) != 0) {
3685 error = EFAULT;
3686 goto out;
3687 }
3688
3689 /* if the caller supplied enough room, copy out to it */
3690 if (xsecurity_bufsize >= KAUTH_FILESEC_COPYSIZE(fsec))
3691 error = copyout(fsec, xsecurity, KAUTH_FILESEC_COPYSIZE(fsec));
3692 }
3693 }
3694 out:
3695 if (fsec != KAUTH_FILESEC_NONE)
3696 kauth_filesec_free(fsec);
3697 return (error);
3698 }
3699
3700 /*
3701 * Get file status; this version follows links.
3702 *
3703 * Returns: 0 Success
3704 * stat2:??? [see stat2() in this file]
3705 */
3706 static int
3707 stat1(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size, int isstat64)
3708 {
3709 struct nameidata nd;
3710 vfs_context_t ctx = vfs_context_current();
3711
3712 NDINIT(&nd, LOOKUP, NOTRIGGER | FOLLOW | AUDITVNPATH1,
3713 UIO_USERSPACE, path, ctx);
3714 return(stat2(ctx, &nd, ub, xsecurity, xsecurity_size, isstat64));
3715 }
3716
3717 int
3718 stat_extended(__unused proc_t p, struct stat_extended_args *uap, __unused register_t *retval)
3719 {
3720 return (stat1(uap->path, uap->ub, uap->xsecurity, uap->xsecurity_size, 0));
3721 }
3722
3723 /*
3724 * Returns: 0 Success
3725 * stat1:??? [see stat1() in this file]
3726 */
3727 int
3728 stat(__unused proc_t p, struct stat_args *uap, __unused register_t *retval)
3729 {
3730 return(stat1(uap->path, uap->ub, 0, 0, 0));
3731 }
3732
3733 int
3734 stat64(__unused proc_t p, struct stat64_args *uap, __unused register_t *retval)
3735 {
3736 return(stat1(uap->path, uap->ub, 0, 0, 1));
3737 }
3738
3739 int
3740 stat64_extended(__unused proc_t p, struct stat64_extended_args *uap, __unused register_t *retval)
3741 {
3742 return (stat1(uap->path, uap->ub, uap->xsecurity, uap->xsecurity_size, 1));
3743 }
3744 /*
3745 * Get file status; this version does not follow links.
3746 */
3747 static int
3748 lstat1(user_addr_t path, user_addr_t ub, user_addr_t xsecurity, user_addr_t xsecurity_size, int isstat64)
3749 {
3750 struct nameidata nd;
3751 vfs_context_t ctx = vfs_context_current();
3752
3753 NDINIT(&nd, LOOKUP, NOTRIGGER | NOFOLLOW | AUDITVNPATH1,
3754 UIO_USERSPACE, path, ctx);
3755
3756 return(stat2(ctx, &nd, ub, xsecurity, xsecurity_size, isstat64));
3757 }
3758
3759 int
3760 lstat_extended(__unused proc_t p, struct lstat_extended_args *uap, __unused register_t *retval)
3761 {
3762 return (lstat1(uap->path, uap->ub, uap->xsecurity, uap->xsecurity_size, 0));
3763 }
3764
3765 int
3766 lstat(__unused proc_t p, struct lstat_args *uap, __unused register_t *retval)
3767 {
3768 return(lstat1(uap->path, uap->ub, 0, 0, 0));
3769 }
3770 int
3771 lstat64(__unused proc_t p, struct lstat64_args *uap, __unused register_t *retval)
3772 {
3773 return(lstat1(uap->path, uap->ub, 0, 0, 1));
3774 }
3775
3776 int
3777 lstat64_extended(__unused proc_t p, struct lstat64_extended_args *uap, __unused register_t *retval)
3778 {
3779 return (lstat1(uap->path, uap->ub, uap->xsecurity, uap->xsecurity_size, 1));
3780 }
3781
3782 /*
3783 * Get configurable pathname variables.
3784 *
3785 * Returns: 0 Success
3786 * namei:???
3787 * vn_pathconf:???
3788 *
3789 * Notes: Global implementation constants are intended to be
3790 * implemented in this function directly; all other constants
3791 * are per-FS implementation, and therefore must be handled in
3792 * each respective FS, instead.
3793 *
3794 * XXX We implement some things globally right now that should actually be
3795 * XXX per-FS; we will need to deal with this at some point.
3796 */
3797 /* ARGSUSED */
3798 int
3799 pathconf(__unused proc_t p, struct pathconf_args *uap, register_t *retval)
3800 {
3801 int error;
3802 struct nameidata nd;
3803 vfs_context_t ctx = vfs_context_current();
3804
3805 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
3806 UIO_USERSPACE, uap->path, ctx);
3807 error = namei(&nd);
3808 if (error)
3809 return (error);
3810
3811 error = vn_pathconf(nd.ni_vp, uap->name, retval, ctx);
3812
3813 vnode_put(nd.ni_vp);
3814 nameidone(&nd);
3815 return (error);
3816 }
3817
3818 /*
3819 * Return target name of a symbolic link.
3820 */
3821 /* ARGSUSED */
3822 int
3823 readlink(proc_t p, struct readlink_args *uap, register_t *retval)
3824 {
3825 vnode_t vp;
3826 uio_t auio;
3827 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
3828 int error;
3829 struct nameidata nd;
3830 vfs_context_t ctx = vfs_context_current();
3831 char uio_buf[ UIO_SIZEOF(1) ];
3832
3833 NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNPATH1,
3834 UIO_USERSPACE, uap->path, ctx);
3835 error = namei(&nd);
3836 if (error)
3837 return (error);
3838 vp = nd.ni_vp;
3839
3840 nameidone(&nd);
3841
3842 auio = uio_createwithbuffer(1, 0, spacetype, UIO_READ,
3843 &uio_buf[0], sizeof(uio_buf));
3844 uio_addiov(auio, uap->buf, uap->count);
3845 if (vp->v_type != VLNK)
3846 error = EINVAL;
3847 else {
3848 #if CONFIG_MACF
3849 error = mac_vnode_check_readlink(ctx,
3850 vp);
3851 #endif
3852 if (error == 0)
3853 error = vnode_authorize(vp, NULL, KAUTH_VNODE_READ_DATA, ctx);
3854 if (error == 0)
3855 error = VNOP_READLINK(vp, auio, ctx);
3856 }
3857 vnode_put(vp);
3858 // LP64todo - fix this
3859 *retval = uap->count - (int)uio_resid(auio);
3860 return (error);
3861 }
3862
3863 /*
3864 * Change file flags.
3865 */
3866 static int
3867 chflags1(vnode_t vp, int flags, vfs_context_t ctx)
3868 {
3869 struct vnode_attr va;
3870 kauth_action_t action;
3871 int error;
3872
3873 VATTR_INIT(&va);
3874 VATTR_SET(&va, va_flags, flags);
3875
3876 #if CONFIG_MACF
3877 error = mac_vnode_check_setflags(ctx, vp, flags);
3878 if (error)
3879 goto out;
3880 #endif
3881
3882 /* request authorisation, disregard immutability */
3883 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
3884 goto out;
3885 /*
3886 * Request that the auth layer disregard those file flags it's allowed to when
3887 * authorizing this operation; we need to do this in order to be able to
3888 * clear immutable flags.
3889 */
3890 if (action && ((error = vnode_authorize(vp, NULL, action | KAUTH_VNODE_NOIMMUTABLE, ctx)) != 0))
3891 goto out;
3892 error = vnode_setattr(vp, &va, ctx);
3893
3894 if ((error == 0) && !VATTR_IS_SUPPORTED(&va, va_flags)) {
3895 error = ENOTSUP;
3896 }
3897 out:
3898 vnode_put(vp);
3899 return(error);
3900 }
3901
3902 /*
3903 * Change flags of a file given a path name.
3904 */
3905 /* ARGSUSED */
3906 int
3907 chflags(__unused proc_t p, struct chflags_args *uap, __unused register_t *retval)
3908 {
3909 vnode_t vp;
3910 vfs_context_t ctx = vfs_context_current();
3911 int error;
3912 struct nameidata nd;
3913
3914 AUDIT_ARG(fflags, uap->flags);
3915 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
3916 UIO_USERSPACE, uap->path, ctx);
3917 error = namei(&nd);
3918 if (error)
3919 return (error);
3920 vp = nd.ni_vp;
3921 nameidone(&nd);
3922
3923 error = chflags1(vp, uap->flags, ctx);
3924
3925 return(error);
3926 }
3927
3928 /*
3929 * Change flags of a file given a file descriptor.
3930 */
3931 /* ARGSUSED */
3932 int
3933 fchflags(__unused proc_t p, struct fchflags_args *uap, __unused register_t *retval)
3934 {
3935 vnode_t vp;
3936 int error;
3937
3938 AUDIT_ARG(fd, uap->fd);
3939 AUDIT_ARG(fflags, uap->flags);
3940 if ( (error = file_vnode(uap->fd, &vp)) )
3941 return (error);
3942
3943 if ((error = vnode_getwithref(vp))) {
3944 file_drop(uap->fd);
3945 return(error);
3946 }
3947
3948 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
3949
3950 error = chflags1(vp, uap->flags, vfs_context_current());
3951
3952 file_drop(uap->fd);
3953 return (error);
3954 }
3955
3956 /*
3957 * Change security information on a filesystem object.
3958 *
3959 * Returns: 0 Success
3960 * EPERM Operation not permitted
3961 * vnode_authattr:??? [anything vnode_authattr can return]
3962 * vnode_authorize:??? [anything vnode_authorize can return]
3963 * vnode_setattr:??? [anything vnode_setattr can return]
3964 *
3965 * Notes: If vnode_authattr or vnode_authorize return EACCES, it will be
3966 * translated to EPERM before being returned.
3967 */
3968 static int
3969 chmod2(vfs_context_t ctx, vnode_t vp, struct vnode_attr *vap)
3970 {
3971 kauth_action_t action;
3972 int error;
3973
3974 AUDIT_ARG(mode, (mode_t)vap->va_mode);
3975 #warning XXX audit new args
3976
3977 #if NAMEDSTREAMS
3978 /* chmod calls are not allowed for resource forks. */
3979 if (vp->v_flag & VISNAMEDSTREAM) {
3980 return (EPERM);
3981 }
3982 #endif
3983
3984 #if CONFIG_MACF
3985 error = mac_vnode_check_setmode(ctx, vp, (mode_t)vap->va_mode);
3986 if (error)
3987 return (error);
3988 #endif
3989
3990 /* make sure that the caller is allowed to set this security information */
3991 if (((error = vnode_authattr(vp, vap, &action, ctx)) != 0) ||
3992 ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)) {
3993 if (error == EACCES)
3994 error = EPERM;
3995 return(error);
3996 }
3997
3998 error = vnode_setattr(vp, vap, ctx);
3999
4000 return (error);
4001 }
4002
4003
4004 /*
4005 * Change mode of a file given path name.
4006 *
4007 * Returns: 0 Success
4008 * namei:??? [anything namei can return]
4009 * chmod2:??? [anything chmod2 can return]
4010 */
4011 static int
4012 chmod1(vfs_context_t ctx, user_addr_t path, struct vnode_attr *vap)
4013 {
4014 struct nameidata nd;
4015 int error;
4016
4017 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
4018 UIO_USERSPACE, path, ctx);
4019 if ((error = namei(&nd)))
4020 return (error);
4021 error = chmod2(ctx, nd.ni_vp, vap);
4022 vnode_put(nd.ni_vp);
4023 nameidone(&nd);
4024 return(error);
4025 }
4026
4027 /*
4028 * A chmod system call using an extended argument list compared to the regular
4029 * system call 'mkfifo'.
4030 *
4031 * Parameters: p Process requesting the open
4032 * uap User argument descriptor (see below)
4033 * retval (ignored)
4034 *
4035 * Indirect: uap->path Path to object (same as 'chmod')
4036 * uap->uid UID to set
4037 * uap->gid GID to set
4038 * uap->mode File mode to set (same as 'chmod')
4039 * uap->xsecurity ACL to set (or delete)
4040 *
4041 * Returns: 0 Success
4042 * !0 errno value
4043 *
4044 * Notes: The kauth_filesec_t in 'va', if any, is in host byte order.
4045 *
4046 * XXX: We should enummerate the possible errno values here, and where
4047 * in the code they originated.
4048 */
4049 int
4050 chmod_extended(__unused proc_t p, struct chmod_extended_args *uap, __unused register_t *retval)
4051 {
4052 int error;
4053 struct vnode_attr va;
4054 kauth_filesec_t xsecdst;
4055
4056 VATTR_INIT(&va);
4057 if (uap->mode != -1)
4058 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
4059 if (uap->uid != KAUTH_UID_NONE)
4060 VATTR_SET(&va, va_uid, uap->uid);
4061 if (uap->gid != KAUTH_GID_NONE)
4062 VATTR_SET(&va, va_gid, uap->gid);
4063
4064 xsecdst = NULL;
4065 switch(uap->xsecurity) {
4066 /* explicit remove request */
4067 case CAST_USER_ADDR_T((void *)1): /* _FILESEC_REMOVE_ACL */
4068 VATTR_SET(&va, va_acl, NULL);
4069 break;
4070 /* not being set */
4071 case USER_ADDR_NULL:
4072 break;
4073 default:
4074 if ((error = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
4075 return(error);
4076 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
4077 KAUTH_DEBUG("CHMOD - setting ACL with %d entries", va.va_acl->acl_entrycount);
4078 }
4079
4080 error = chmod1(vfs_context_current(), uap->path, &va);
4081
4082 if (xsecdst != NULL)
4083 kauth_filesec_free(xsecdst);
4084 return(error);
4085 }
4086
4087 /*
4088 * Returns: 0 Success
4089 * chmod1:??? [anything chmod1 can return]
4090 */
4091 int
4092 chmod(__unused proc_t p, struct chmod_args *uap, __unused register_t *retval)
4093 {
4094 struct vnode_attr va;
4095
4096 VATTR_INIT(&va);
4097 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
4098
4099 return(chmod1(vfs_context_current(), uap->path, &va));
4100 }
4101
4102 /*
4103 * Change mode of a file given a file descriptor.
4104 */
4105 static int
4106 fchmod1(__unused proc_t p, int fd, struct vnode_attr *vap)
4107 {
4108 vnode_t vp;
4109 int error;
4110
4111 AUDIT_ARG(fd, fd);
4112
4113 if ((error = file_vnode(fd, &vp)) != 0)
4114 return (error);
4115 if ((error = vnode_getwithref(vp)) != 0) {
4116 file_drop(fd);
4117 return(error);
4118 }
4119 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
4120
4121 error = chmod2(vfs_context_current(), vp, vap);
4122 (void)vnode_put(vp);
4123 file_drop(fd);
4124
4125 return (error);
4126 }
4127
4128 int
4129 fchmod_extended(proc_t p, struct fchmod_extended_args *uap, __unused register_t *retval)
4130 {
4131 int error;
4132 struct vnode_attr va;
4133 kauth_filesec_t xsecdst;
4134
4135 VATTR_INIT(&va);
4136 if (uap->mode != -1)
4137 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
4138 if (uap->uid != KAUTH_UID_NONE)
4139 VATTR_SET(&va, va_uid, uap->uid);
4140 if (uap->gid != KAUTH_GID_NONE)
4141 VATTR_SET(&va, va_gid, uap->gid);
4142
4143 xsecdst = NULL;
4144 switch(uap->xsecurity) {
4145 case USER_ADDR_NULL:
4146 VATTR_SET(&va, va_acl, NULL);
4147 break;
4148 case CAST_USER_ADDR_T(-1):
4149 break;
4150 default:
4151 if ((error = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
4152 return(error);
4153 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
4154 }
4155
4156 error = fchmod1(p, uap->fd, &va);
4157
4158
4159 switch(uap->xsecurity) {
4160 case USER_ADDR_NULL:
4161 case CAST_USER_ADDR_T(-1):
4162 break;
4163 default:
4164 if (xsecdst != NULL)
4165 kauth_filesec_free(xsecdst);
4166 }
4167 return(error);
4168 }
4169
4170 int
4171 fchmod(proc_t p, struct fchmod_args *uap, __unused register_t *retval)
4172 {
4173 struct vnode_attr va;
4174
4175 VATTR_INIT(&va);
4176 VATTR_SET(&va, va_mode, uap->mode & ALLPERMS);
4177
4178 return(fchmod1(p, uap->fd, &va));
4179 }
4180
4181
4182 /*
4183 * Set ownership given a path name.
4184 */
4185 /* ARGSUSED */
4186 static int
4187 chown1(vfs_context_t ctx, struct chown_args *uap, __unused register_t *retval, int follow)
4188 {
4189 vnode_t vp;
4190 struct vnode_attr va;
4191 int error;
4192 struct nameidata nd;
4193 kauth_action_t action;
4194
4195 AUDIT_ARG(owner, uap->uid, uap->gid);
4196
4197 NDINIT(&nd, LOOKUP, (follow ? FOLLOW : 0) | NOTRIGGER | AUDITVNPATH1,
4198 UIO_USERSPACE, uap->path, ctx);
4199 error = namei(&nd);
4200 if (error)
4201 return (error);
4202 vp = nd.ni_vp;
4203
4204 nameidone(&nd);
4205
4206 VATTR_INIT(&va);
4207 if (uap->uid != VNOVAL)
4208 VATTR_SET(&va, va_uid, uap->uid);
4209 if (uap->gid != VNOVAL)
4210 VATTR_SET(&va, va_gid, uap->gid);
4211
4212 #if CONFIG_MACF
4213 error = mac_vnode_check_setowner(ctx, vp, uap->uid, uap->gid);
4214 if (error)
4215 goto out;
4216 #endif
4217
4218 /* preflight and authorize attribute changes */
4219 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
4220 goto out;
4221 if (action && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0))
4222 goto out;
4223 error = vnode_setattr(vp, &va, ctx);
4224
4225 out:
4226 /*
4227 * EACCES is only allowed from namei(); permissions failure should
4228 * return EPERM, so we need to translate the error code.
4229 */
4230 if (error == EACCES)
4231 error = EPERM;
4232
4233 vnode_put(vp);
4234 return (error);
4235 }
4236
4237 int
4238 chown(__unused proc_t p, struct chown_args *uap, register_t *retval)
4239 {
4240 return chown1(vfs_context_current(), uap, retval, 1);
4241 }
4242
4243 int
4244 lchown(__unused proc_t p, struct lchown_args *uap, register_t *retval)
4245 {
4246 /* Argument list identical, but machine generated; cast for chown1() */
4247 return chown1(vfs_context_current(), (struct chown_args *)uap, retval, 0);
4248 }
4249
4250 /*
4251 * Set ownership given a file descriptor.
4252 */
4253 /* ARGSUSED */
4254 int
4255 fchown(__unused proc_t p, struct fchown_args *uap, __unused register_t *retval)
4256 {
4257 struct vnode_attr va;
4258 vfs_context_t ctx = vfs_context_current();
4259 vnode_t vp;
4260 int error;
4261 kauth_action_t action;
4262
4263 AUDIT_ARG(owner, uap->uid, uap->gid);
4264 AUDIT_ARG(fd, uap->fd);
4265
4266 if ( (error = file_vnode(uap->fd, &vp)) )
4267 return (error);
4268
4269 if ( (error = vnode_getwithref(vp)) ) {
4270 file_drop(uap->fd);
4271 return(error);
4272 }
4273 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
4274
4275 VATTR_INIT(&va);
4276 if (uap->uid != VNOVAL)
4277 VATTR_SET(&va, va_uid, uap->uid);
4278 if (uap->gid != VNOVAL)
4279 VATTR_SET(&va, va_gid, uap->gid);
4280
4281 #if NAMEDSTREAMS
4282 /* chown calls are not allowed for resource forks. */
4283 if (vp->v_flag & VISNAMEDSTREAM) {
4284 error = EPERM;
4285 goto out;
4286 }
4287 #endif
4288
4289 #if CONFIG_MACF
4290 error = mac_vnode_check_setowner(ctx, vp, uap->uid, uap->gid);
4291 if (error)
4292 goto out;
4293 #endif
4294
4295 /* preflight and authorize attribute changes */
4296 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
4297 goto out;
4298 if (action && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)) {
4299 if (error == EACCES)
4300 error = EPERM;
4301 goto out;
4302 }
4303 error = vnode_setattr(vp, &va, ctx);
4304
4305 out:
4306 (void)vnode_put(vp);
4307 file_drop(uap->fd);
4308 return (error);
4309 }
4310
4311 static int
4312 getutimes(user_addr_t usrtvp, struct timespec *tsp)
4313 {
4314 struct user_timeval tv[2];
4315 int error;
4316
4317 if (usrtvp == USER_ADDR_NULL) {
4318 struct timeval old_tv;
4319 /* XXX Y2038 bug because of microtime argument */
4320 microtime(&old_tv);
4321 TIMEVAL_TO_TIMESPEC(&old_tv, &tsp[0]);
4322 tsp[1] = tsp[0];
4323 } else {
4324 if (IS_64BIT_PROCESS(current_proc())) {
4325 error = copyin(usrtvp, (void *)tv, sizeof(tv));
4326 } else {
4327 struct timeval old_tv[2];
4328 error = copyin(usrtvp, (void *)old_tv, sizeof(old_tv));
4329 tv[0].tv_sec = old_tv[0].tv_sec;
4330 tv[0].tv_usec = old_tv[0].tv_usec;
4331 tv[1].tv_sec = old_tv[1].tv_sec;
4332 tv[1].tv_usec = old_tv[1].tv_usec;
4333 }
4334 if (error)
4335 return (error);
4336 TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
4337 TIMEVAL_TO_TIMESPEC(&tv[1], &tsp[1]);
4338 }
4339 return 0;
4340 }
4341
4342 static int
4343 setutimes(vfs_context_t ctx, vnode_t vp, const struct timespec *ts,
4344 int nullflag)
4345 {
4346 int error;
4347 struct vnode_attr va;
4348 kauth_action_t action;
4349
4350 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
4351
4352 VATTR_INIT(&va);
4353 VATTR_SET(&va, va_access_time, ts[0]);
4354 VATTR_SET(&va, va_modify_time, ts[1]);
4355 if (nullflag)
4356 va.va_vaflags |= VA_UTIMES_NULL;
4357
4358 #if NAMEDSTREAMS
4359 /* utimes calls are not allowed for resource forks. */
4360 if (vp->v_flag & VISNAMEDSTREAM) {
4361 error = EPERM;
4362 goto out;
4363 }
4364 #endif
4365
4366 #if CONFIG_MACF
4367 error = mac_vnode_check_setutimes(ctx, vp, ts[0], ts[1]);
4368 if (error)
4369 goto out;
4370 #endif
4371 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0) {
4372 if (!nullflag && error == EACCES)
4373 error = EPERM;
4374 goto out;
4375 }
4376
4377 /* since we may not need to auth anything, check here */
4378 if ((action != 0) && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0)) {
4379 if (!nullflag && error == EACCES)
4380 error = EPERM;
4381 goto out;
4382 }
4383 error = vnode_setattr(vp, &va, ctx);
4384
4385 out:
4386 return error;
4387 }
4388
4389 /*
4390 * Set the access and modification times of a file.
4391 */
4392 /* ARGSUSED */
4393 int
4394 utimes(__unused proc_t p, struct utimes_args *uap, __unused register_t *retval)
4395 {
4396 struct timespec ts[2];
4397 user_addr_t usrtvp;
4398 int error;
4399 struct nameidata nd;
4400 vfs_context_t ctx = vfs_context_current();
4401
4402 /*
4403 * AUDIT: Needed to change the order of operations to do the
4404 * name lookup first because auditing wants the path.
4405 */
4406 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
4407 UIO_USERSPACE, uap->path, ctx);
4408 error = namei(&nd);
4409 if (error)
4410 return (error);
4411 nameidone(&nd);
4412
4413 /*
4414 * Fetch the user-supplied time. If usrtvp is USER_ADDR_NULL, we fetch
4415 * the current time instead.
4416 */
4417 usrtvp = uap->tptr;
4418 if ((error = getutimes(usrtvp, ts)) != 0)
4419 goto out;
4420
4421 error = setutimes(ctx, nd.ni_vp, ts, usrtvp == USER_ADDR_NULL);
4422
4423 out:
4424 vnode_put(nd.ni_vp);
4425 return (error);
4426 }
4427
4428 /*
4429 * Set the access and modification times of a file.
4430 */
4431 /* ARGSUSED */
4432 int
4433 futimes(__unused proc_t p, struct futimes_args *uap, __unused register_t *retval)
4434 {
4435 struct timespec ts[2];
4436 vnode_t vp;
4437 user_addr_t usrtvp;
4438 int error;
4439
4440 AUDIT_ARG(fd, uap->fd);
4441 usrtvp = uap->tptr;
4442 if ((error = getutimes(usrtvp, ts)) != 0)
4443 return (error);
4444 if ((error = file_vnode(uap->fd, &vp)) != 0)
4445 return (error);
4446 if((error = vnode_getwithref(vp))) {
4447 file_drop(uap->fd);
4448 return(error);
4449 }
4450
4451 error = setutimes(vfs_context_current(), vp, ts, usrtvp == 0);
4452 vnode_put(vp);
4453 file_drop(uap->fd);
4454 return(error);
4455 }
4456
4457 /*
4458 * Truncate a file given its path name.
4459 */
4460 /* ARGSUSED */
4461 int
4462 truncate(__unused proc_t p, struct truncate_args *uap, __unused register_t *retval)
4463 {
4464 vnode_t vp;
4465 struct vnode_attr va;
4466 vfs_context_t ctx = vfs_context_current();
4467 int error;
4468 struct nameidata nd;
4469 kauth_action_t action;
4470
4471 if (uap->length < 0)
4472 return(EINVAL);
4473 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
4474 UIO_USERSPACE, uap->path, ctx);
4475 if ((error = namei(&nd)))
4476 return (error);
4477 vp = nd.ni_vp;
4478
4479 nameidone(&nd);
4480
4481 VATTR_INIT(&va);
4482 VATTR_SET(&va, va_data_size, uap->length);
4483
4484 #if CONFIG_MACF
4485 error = mac_vnode_check_truncate(ctx, NOCRED, vp);
4486 if (error)
4487 goto out;
4488 #endif
4489
4490 if ((error = vnode_authattr(vp, &va, &action, ctx)) != 0)
4491 goto out;
4492 if ((action != 0) && ((error = vnode_authorize(vp, NULL, action, ctx)) != 0))
4493 goto out;
4494 error = vnode_setattr(vp, &va, ctx);
4495 out:
4496 vnode_put(vp);
4497 return (error);
4498 }
4499
4500 /*
4501 * Truncate a file given a file descriptor.
4502 */
4503 /* ARGSUSED */
4504 int
4505 ftruncate(proc_t p, struct ftruncate_args *uap, register_t *retval)
4506 {
4507 vfs_context_t ctx = vfs_context_current();
4508 struct vnode_attr va;
4509 vnode_t vp;
4510 struct fileproc *fp;
4511 int error ;
4512 int fd = uap->fd;
4513
4514 AUDIT_ARG(fd, uap->fd);
4515 if (uap->length < 0)
4516 return(EINVAL);
4517
4518 if ( (error = fp_lookup(p,fd,&fp,0)) ) {
4519 return(error);
4520 }
4521
4522 if (fp->f_fglob->fg_type == DTYPE_PSXSHM) {
4523 error = pshm_truncate(p, fp, uap->fd, uap->length, retval);
4524 goto out;
4525 }
4526 if (fp->f_fglob->fg_type != DTYPE_VNODE) {
4527 error = EINVAL;
4528 goto out;
4529 }
4530
4531 vp = (vnode_t)fp->f_fglob->fg_data;
4532
4533 if ((fp->f_fglob->fg_flag & FWRITE) == 0) {
4534 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
4535 error = EINVAL;
4536 goto out;
4537 }
4538
4539 if ((error = vnode_getwithref(vp)) != 0) {
4540 goto out;
4541 }
4542
4543 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
4544
4545 #if CONFIG_MACF
4546 error = mac_vnode_check_truncate(ctx,
4547 fp->f_fglob->fg_cred, vp);
4548 if (error) {
4549 (void)vnode_put(vp);
4550 goto out;
4551 }
4552 #endif
4553 VATTR_INIT(&va);
4554 VATTR_SET(&va, va_data_size, uap->length);
4555 error = vnode_setattr(vp, &va, ctx);
4556 (void)vnode_put(vp);
4557 out:
4558 file_drop(fd);
4559 return (error);
4560 }
4561
4562
4563 /*
4564 * Sync an open file.
4565 */
4566 /* ARGSUSED */
4567 int
4568 fsync(proc_t p, struct fsync_args *uap, register_t *retval)
4569 {
4570 __pthread_testcancel(1);
4571 return(fsync_nocancel(p, (struct fsync_nocancel_args *)uap, retval));
4572 }
4573
4574 int
4575 fsync_nocancel(proc_t p, struct fsync_nocancel_args *uap, __unused register_t *retval)
4576 {
4577 vnode_t vp;
4578 struct fileproc *fp;
4579 vfs_context_t ctx = vfs_context_current();
4580 int error;
4581
4582 if ( (error = fp_getfvp(p, uap->fd, &fp, &vp)) )
4583 return (error);
4584 if ( (error = vnode_getwithref(vp)) ) {
4585 file_drop(uap->fd);
4586 return(error);
4587 }
4588
4589 error = VNOP_FSYNC(vp, MNT_WAIT, ctx);
4590
4591 #if NAMEDRSRCFORK
4592 /* Sync resource fork shadow file if necessary. */
4593 if ((error == 0) &&
4594 (vp->v_flag & VISNAMEDSTREAM) &&
4595 (vp->v_parent != NULLVP) &&
4596 !(vp->v_parent->v_mount->mnt_kern_flag & MNTK_NAMED_STREAMS) &&
4597 (fp->f_flags & FP_WRITTEN)) {
4598 (void) vnode_flushnamedstream(vp->v_parent, vp, ctx);
4599 }
4600 #endif
4601
4602 (void)vnode_put(vp);
4603 file_drop(uap->fd);
4604 return (error);
4605 }
4606
4607 /*
4608 * Duplicate files. Source must be a file, target must be a file or
4609 * must not exist.
4610 *
4611 * XXX Copyfile authorisation checking is woefully inadequate, and will not
4612 * perform inheritance correctly.
4613 */
4614 /* ARGSUSED */
4615 int
4616 copyfile(__unused proc_t p, struct copyfile_args *uap, __unused register_t *retval)
4617 {
4618 vnode_t tvp, fvp, tdvp, sdvp;
4619 struct nameidata fromnd, tond;
4620 int error;
4621 vfs_context_t ctx = vfs_context_current();
4622
4623 /* Check that the flags are valid. */
4624
4625 if (uap->flags & ~CPF_MASK) {
4626 return(EINVAL);
4627 }
4628
4629 NDINIT(&fromnd, LOOKUP, SAVESTART | AUDITVNPATH1,
4630 UIO_USERSPACE, uap->from, ctx);
4631 if ((error = namei(&fromnd)))
4632 return (error);
4633 fvp = fromnd.ni_vp;
4634
4635 NDINIT(&tond, CREATE, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART | AUDITVNPATH2 | CN_NBMOUNTLOOK,
4636 UIO_USERSPACE, uap->to, ctx);
4637 if ((error = namei(&tond))) {
4638 goto out1;
4639 }
4640 tdvp = tond.ni_dvp;
4641 tvp = tond.ni_vp;
4642
4643 if (tvp != NULL) {
4644 if (!(uap->flags & CPF_OVERWRITE)) {
4645 error = EEXIST;
4646 goto out;
4647 }
4648 }
4649 if (fvp->v_type == VDIR || (tvp && tvp->v_type == VDIR)) {
4650 error = EISDIR;
4651 goto out;
4652 }
4653
4654 if ((error = vnode_authorize(tdvp, NULL, KAUTH_VNODE_ADD_FILE, ctx)) != 0)
4655 goto out;
4656
4657 if (fvp == tdvp)
4658 error = EINVAL;
4659 /*
4660 * If source is the same as the destination (that is the
4661 * same inode number) then there is nothing to do.
4662 * (fixed to have POSIX semantics - CSM 3/2/98)
4663 */
4664 if (fvp == tvp)
4665 error = -1;
4666 if (!error)
4667 error = VNOP_COPYFILE(fvp, tdvp, tvp, &tond.ni_cnd, uap->mode, uap->flags, ctx);
4668 out:
4669 sdvp = tond.ni_startdir;
4670 /*
4671 * nameidone has to happen before we vnode_put(tdvp)
4672 * since it may need to release the fs_nodelock on the tdvp
4673 */
4674 nameidone(&tond);
4675
4676 if (tvp)
4677 vnode_put(tvp);
4678 vnode_put(tdvp);
4679 vnode_put(sdvp);
4680 out1:
4681 vnode_put(fvp);
4682
4683 if (fromnd.ni_startdir)
4684 vnode_put(fromnd.ni_startdir);
4685 nameidone(&fromnd);
4686
4687 if (error == -1)
4688 return (0);
4689 return (error);
4690 }
4691
4692
4693 /*
4694 * Rename files. Source and destination must either both be directories,
4695 * or both not be directories. If target is a directory, it must be empty.
4696 */
4697 /* ARGSUSED */
4698 int
4699 rename(__unused proc_t p, struct rename_args *uap, __unused register_t *retval)
4700 {
4701 vnode_t tvp, tdvp;
4702 vnode_t fvp, fdvp;
4703 struct nameidata fromnd, tond;
4704 vfs_context_t ctx = vfs_context_current();
4705 int error;
4706 int do_retry;
4707 int mntrename;
4708 int need_event;
4709 const char *oname;
4710 char *from_name = NULL, *to_name = NULL;
4711 int from_len, to_len;
4712 int holding_mntlock;
4713 mount_t locked_mp = NULL;
4714 vnode_t oparent;
4715 fse_info from_finfo, to_finfo;
4716
4717 holding_mntlock = 0;
4718 do_retry = 0;
4719 retry:
4720 fvp = tvp = NULL;
4721 fdvp = tdvp = NULL;
4722 mntrename = FALSE;
4723
4724 NDINIT(&fromnd, DELETE, WANTPARENT | AUDITVNPATH1, UIO_USERSPACE, uap->from, ctx);
4725
4726 if ( (error = namei(&fromnd)) )
4727 goto out1;
4728 fdvp = fromnd.ni_dvp;
4729 fvp = fromnd.ni_vp;
4730
4731 #if CONFIG_MACF
4732 error = mac_vnode_check_rename_from(ctx, fdvp, fvp, &fromnd.ni_cnd);
4733 if (error)
4734 goto out1;
4735 #endif
4736
4737 NDINIT(&tond, RENAME, WANTPARENT | AUDITVNPATH2 | CN_NBMOUNTLOOK , UIO_USERSPACE, uap->to, ctx);
4738 if (fvp->v_type == VDIR)
4739 tond.ni_cnd.cn_flags |= WILLBEDIR;
4740
4741 if ( (error = namei(&tond)) ) {
4742 /*
4743 * Translate error code for rename("dir1", "dir2/.").
4744 */
4745 if (error == EISDIR && fvp->v_type == VDIR)
4746 error = EINVAL;
4747 goto out1;
4748 }
4749 tdvp = tond.ni_dvp;
4750 tvp = tond.ni_vp;
4751
4752 #if CONFIG_MACF
4753 error = mac_vnode_check_rename_to(ctx,
4754 tdvp, tvp, fdvp == tdvp, &tond.ni_cnd);
4755 if (error)
4756 goto out1;
4757 #endif
4758
4759 if (tvp != NULL) {
4760 if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
4761 error = ENOTDIR;
4762 goto out1;
4763 } else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
4764 error = EISDIR;
4765 goto out1;
4766 }
4767 }
4768 if (fvp == tdvp) {
4769 error = EINVAL;
4770 goto out1;
4771 }
4772 /*
4773 * If the source and destination are the same (i.e. they're
4774 * links to the same vnode) and the target file system is
4775 * case sensitive, then there is nothing to do.
4776 */
4777 if (fvp == tvp) {
4778 int pathconf_val;
4779
4780 /*
4781 * Note: if _PC_CASE_SENSITIVE selector isn't supported,
4782 * then assume that this file system is case sensitive.
4783 */
4784 if (VNOP_PATHCONF(fvp, _PC_CASE_SENSITIVE, &pathconf_val, ctx) != 0 ||
4785 pathconf_val != 0) {
4786 goto out1;
4787 }
4788 }
4789
4790 /*
4791 * Authorization.
4792 *
4793 * If tvp is a directory and not the same as fdvp, or tdvp is not
4794 * the same as fdvp, the node is moving between directories and we
4795 * need rights to remove from the old and add to the new.
4796 *
4797 * If tvp already exists and is not a directory, we need to be
4798 * allowed to delete it.
4799 *
4800 * Note that we do not inherit when renaming.
4801 *
4802 * XXX This needs to be revisited to implement the deferred-inherit bit
4803 */
4804 {
4805 int moving = 0;
4806
4807 error = 0;
4808 if ((tvp != NULL) && vnode_isdir(tvp)) {
4809 if (tvp != fdvp)
4810 moving = 1;
4811 } else if (tdvp != fdvp) {
4812 moving = 1;
4813 }
4814 /*
4815 * must have delete rights to remove the old name even in
4816 * the simple case of fdvp == tdvp.
4817 *
4818 * If fvp is a directory, and we are changing it's parent,
4819 * then we also need rights to rewrite its ".." entry as well.
4820 */
4821 if (vnode_isdir(fvp)) {
4822 if ((error = vnode_authorize(fvp, fdvp, KAUTH_VNODE_DELETE | KAUTH_VNODE_ADD_SUBDIRECTORY, ctx)) != 0)
4823 goto auth_exit;
4824 } else {
4825 if ((error = vnode_authorize(fvp, fdvp, KAUTH_VNODE_DELETE, ctx)) != 0)
4826 goto auth_exit;
4827 }
4828 if (moving) {
4829 /* moving into tdvp or tvp, must have rights to add */
4830 if ((error = vnode_authorize(((tvp != NULL) && vnode_isdir(tvp)) ? tvp : tdvp,
4831 NULL,
4832 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE,
4833 ctx)) != 0) {
4834 /*
4835 * We could encounter a race where after doing the namei, tvp stops
4836 * being valid. If so, simply re-drive the rename call from the
4837 * top.
4838 */
4839 if (error == ENOENT) {
4840 do_retry = 1;
4841 }
4842 goto auth_exit;
4843 }
4844 } else {
4845 /* node staying in same directory, must be allowed to add new name */
4846 if ((error = vnode_authorize(fdvp, NULL,
4847 vnode_isdir(fvp) ? KAUTH_VNODE_ADD_SUBDIRECTORY : KAUTH_VNODE_ADD_FILE, ctx)) != 0)
4848 goto auth_exit;
4849 }
4850 /* overwriting tvp */
4851 if ((tvp != NULL) && !vnode_isdir(tvp) &&
4852 ((error = vnode_authorize(tvp, tdvp, KAUTH_VNODE_DELETE, ctx)) != 0)) {
4853 /*
4854 * We could encounter a race where after doing the namei, tvp stops
4855 * being valid. If so, simply re-drive the rename call from the
4856 * top.
4857 */
4858 if (error == ENOENT) {
4859 do_retry = 1;
4860 }
4861 goto auth_exit;
4862 }
4863
4864 /* XXX more checks? */
4865
4866 auth_exit:
4867 /* authorization denied */
4868 if (error != 0)
4869 goto out1;
4870 }
4871 /*
4872 * Allow the renaming of mount points.
4873 * - target must not exist
4874 * - target must reside in the same directory as source
4875 * - union mounts cannot be renamed
4876 * - "/" cannot be renamed
4877 */
4878 if ((fvp->v_flag & VROOT) &&
4879 (fvp->v_type == VDIR) &&
4880 (tvp == NULL) &&
4881 (fvp->v_mountedhere == NULL) &&
4882 (fdvp == tdvp) &&
4883 ((fvp->v_mount->mnt_flag & (MNT_UNION | MNT_ROOTFS)) == 0) &&
4884 (fvp->v_mount->mnt_vnodecovered != NULLVP)) {
4885 vnode_t coveredvp;
4886
4887 /* switch fvp to the covered vnode */
4888 coveredvp = fvp->v_mount->mnt_vnodecovered;
4889 if ( (vnode_getwithref(coveredvp)) ) {
4890 error = ENOENT;
4891 goto out1;
4892 }
4893 vnode_put(fvp);
4894
4895 fvp = coveredvp;
4896 mntrename = TRUE;
4897 }
4898 /*
4899 * Check for cross-device rename.
4900 */
4901 if ((fvp->v_mount != tdvp->v_mount) ||
4902 (tvp && (fvp->v_mount != tvp->v_mount))) {
4903 error = EXDEV;
4904 goto out1;
4905 }
4906 /*
4907 * Avoid renaming "." and "..".
4908 */
4909 if (fvp->v_type == VDIR &&
4910 ((fdvp == fvp) ||
4911 (fromnd.ni_cnd.cn_namelen == 1 && fromnd.ni_cnd.cn_nameptr[0] == '.') ||
4912 ((fromnd.ni_cnd.cn_flags | tond.ni_cnd.cn_flags) & ISDOTDOT)) ) {
4913 error = EINVAL;
4914 goto out1;
4915 }
4916 /*
4917 * The following edge case is caught here:
4918 * (to cannot be a descendent of from)
4919 *
4920 * o fdvp
4921 * /
4922 * /
4923 * o fvp
4924 * \
4925 * \
4926 * o tdvp
4927 * /
4928 * /
4929 * o tvp
4930 */
4931 if (tdvp->v_parent == fvp) {
4932 error = EINVAL;
4933 goto out1;
4934 }
4935
4936 /*
4937 * If source is the same as the destination (that is the
4938 * same inode number) then there is nothing to do...
4939 * EXCEPT if the underlying file system supports case
4940 * insensitivity and is case preserving. In this case
4941 * the file system needs to handle the special case of
4942 * getting the same vnode as target (fvp) and source (tvp).
4943 *
4944 * Only file systems that support pathconf selectors _PC_CASE_SENSITIVE
4945 * and _PC_CASE_PRESERVING can have this exception, and they need to
4946 * handle the special case of getting the same vnode as target and
4947 * source. NOTE: Then the target is unlocked going into vnop_rename,
4948 * so not to cause locking problems. There is a single reference on tvp.
4949 *
4950 * NOTE - that fvp == tvp also occurs if they are hard linked - NOTE
4951 * that correct behaviour then is just to remove the source (link)
4952 */
4953 if (fvp == tvp && fdvp == tdvp) {
4954 if (fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
4955 !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
4956 fromnd.ni_cnd.cn_namelen)) {
4957 goto out1;
4958 }
4959 }
4960
4961 if (holding_mntlock && fvp->v_mount != locked_mp) {
4962 /*
4963 * we're holding a reference and lock
4964 * on locked_mp, but it no longer matches
4965 * what we want to do... so drop our hold
4966 */
4967 mount_unlock_renames(locked_mp);
4968 mount_drop(locked_mp, 0);
4969 holding_mntlock = 0;
4970 }
4971 if (tdvp != fdvp && fvp->v_type == VDIR) {
4972 /*
4973 * serialize renames that re-shape
4974 * the tree... if holding_mntlock is
4975 * set, then we're ready to go...
4976 * otherwise we
4977 * first need to drop the iocounts
4978 * we picked up, second take the
4979 * lock to serialize the access,
4980 * then finally start the lookup
4981 * process over with the lock held
4982 */
4983 if (!holding_mntlock) {
4984 /*
4985 * need to grab a reference on
4986 * the mount point before we
4987 * drop all the iocounts... once
4988 * the iocounts are gone, the mount
4989 * could follow
4990 */
4991 locked_mp = fvp->v_mount;
4992 mount_ref(locked_mp, 0);
4993
4994 /*
4995 * nameidone has to happen before we vnode_put(tvp)
4996 * since it may need to release the fs_nodelock on the tvp
4997 */
4998 nameidone(&tond);
4999
5000 if (tvp)
5001 vnode_put(tvp);
5002 vnode_put(tdvp);
5003
5004 /*
5005 * nameidone has to happen before we vnode_put(fdvp)
5006 * since it may need to release the fs_nodelock on the fvp
5007 */
5008 nameidone(&fromnd);
5009
5010 vnode_put(fvp);
5011 vnode_put(fdvp);
5012
5013 mount_lock_renames(locked_mp);
5014 holding_mntlock = 1;
5015
5016 goto retry;
5017 }
5018 } else {
5019 /*
5020 * when we dropped the iocounts to take
5021 * the lock, we allowed the identity of
5022 * the various vnodes to change... if they did,
5023 * we may no longer be dealing with a rename
5024 * that reshapes the tree... once we're holding
5025 * the iocounts, the vnodes can't change type
5026 * so we're free to drop the lock at this point
5027 * and continue on
5028 */
5029 if (holding_mntlock) {
5030 mount_unlock_renames(locked_mp);
5031 mount_drop(locked_mp, 0);
5032 holding_mntlock = 0;
5033 }
5034 }
5035 // save these off so we can later verify that fvp is the same
5036 oname = fvp->v_name;
5037 oparent = fvp->v_parent;
5038
5039 #if CONFIG_FSE
5040 need_event = need_fsevent(FSE_RENAME, fvp);
5041 if (need_event) {
5042 get_fse_info(fvp, &from_finfo, ctx);
5043
5044 if (tvp) {
5045 get_fse_info(tvp, &to_finfo, ctx);
5046 }
5047 }
5048 #else
5049 need_event = 0;
5050 #endif /* CONFIG_FSE */
5051
5052 if (need_event || kauth_authorize_fileop_has_listeners()) {
5053 GET_PATH(from_name);
5054 if (from_name == NULL) {
5055 error = ENOMEM;
5056 goto out1;
5057 }
5058 from_len = MAXPATHLEN;
5059 vn_getpath(fdvp, from_name, &from_len);
5060 if ((from_len + 1 + fromnd.ni_cnd.cn_namelen + 1) < MAXPATHLEN) {
5061 if (from_len > 2) {
5062 from_name[from_len-1] = '/';
5063 } else {
5064 from_len--;
5065 }
5066 strlcpy(&from_name[from_len], fromnd.ni_cnd.cn_nameptr, MAXPATHLEN-from_len);
5067 from_len += fromnd.ni_cnd.cn_namelen + 1;
5068 from_name[from_len] = '\0';
5069 }
5070
5071 GET_PATH(to_name);
5072 if (to_name == NULL) {
5073 error = ENOMEM;
5074 goto out1;
5075 }
5076
5077 to_len = MAXPATHLEN;
5078 vn_getpath(tdvp, to_name, &to_len);
5079 // if the path is not just "/", then append a "/"
5080 if ((to_len + 1 + tond.ni_cnd.cn_namelen + 1) < MAXPATHLEN) {
5081 if (to_len > 2) {
5082 to_name[to_len-1] = '/';
5083 } else {
5084 to_len--;
5085 }
5086 strlcpy(&to_name[to_len], tond.ni_cnd.cn_nameptr, MAXPATHLEN-to_len);
5087 to_len += tond.ni_cnd.cn_namelen + 1;
5088 to_name[to_len] = '\0';
5089 }
5090 }
5091
5092 error = VNOP_RENAME(fdvp, fvp, &fromnd.ni_cnd,
5093 tdvp, tvp, &tond.ni_cnd,
5094 ctx);
5095
5096 if (holding_mntlock) {
5097 /*
5098 * we can drop our serialization
5099 * lock now
5100 */
5101 mount_unlock_renames(locked_mp);
5102 mount_drop(locked_mp, 0);
5103 holding_mntlock = 0;
5104 }
5105 if (error) {
5106 /*
5107 * We may encounter a race in the VNOP where the destination didn't
5108 * exist when we did the namei, but it does by the time we go and
5109 * try to create the entry. In this case, we should re-drive this rename
5110 * call from the top again.
5111 */
5112 if (error == EEXIST) {
5113 do_retry = 1;
5114 }
5115
5116 goto out1;
5117 }
5118
5119 /* call out to allow 3rd party notification of rename.
5120 * Ignore result of kauth_authorize_fileop call.
5121 */
5122 kauth_authorize_fileop(vfs_context_ucred(ctx),
5123 KAUTH_FILEOP_RENAME,
5124 (uintptr_t)from_name, (uintptr_t)to_name);
5125
5126 #if CONFIG_FSE
5127 if (from_name != NULL && to_name != NULL) {
5128 if (tvp) {
5129 add_fsevent(FSE_RENAME, ctx,
5130 FSE_ARG_STRING, from_len, from_name,
5131 FSE_ARG_FINFO, &from_finfo,
5132 FSE_ARG_STRING, to_len, to_name,
5133 FSE_ARG_FINFO, &to_finfo,
5134 FSE_ARG_DONE);
5135 } else {
5136 add_fsevent(FSE_RENAME, ctx,
5137 FSE_ARG_STRING, from_len, from_name,
5138 FSE_ARG_FINFO, &from_finfo,
5139 FSE_ARG_STRING, to_len, to_name,
5140 FSE_ARG_DONE);
5141 }
5142 }
5143 #endif /* CONFIG_FSE */
5144
5145 /*
5146 * update filesystem's mount point data
5147 */
5148 if (mntrename) {
5149 char *cp, *pathend, *mpname;
5150 char * tobuf;
5151 struct mount *mp;
5152 int maxlen;
5153 size_t len = 0;
5154
5155 mp = fvp->v_mountedhere;
5156
5157 if (vfs_busy(mp, LK_NOWAIT)) {
5158 error = EBUSY;
5159 goto out1;
5160 }
5161 MALLOC_ZONE(tobuf, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
5162
5163 error = copyinstr(uap->to, tobuf, MAXPATHLEN, &len);
5164 if (!error) {
5165 /* find current mount point prefix */
5166 pathend = &mp->mnt_vfsstat.f_mntonname[0];
5167 for (cp = pathend; *cp != '\0'; ++cp) {
5168 if (*cp == '/')
5169 pathend = cp + 1;
5170 }
5171 /* find last component of target name */
5172 for (mpname = cp = tobuf; *cp != '\0'; ++cp) {
5173 if (*cp == '/')
5174 mpname = cp + 1;
5175 }
5176 /* append name to prefix */
5177 maxlen = MAXPATHLEN - (pathend - mp->mnt_vfsstat.f_mntonname);
5178 bzero(pathend, maxlen);
5179 strlcpy(pathend, mpname, maxlen);
5180 }
5181 FREE_ZONE(tobuf, MAXPATHLEN, M_NAMEI);
5182
5183 vfs_unbusy(mp);
5184 }
5185 /*
5186 * fix up name & parent pointers. note that we first
5187 * check that fvp has the same name/parent pointers it
5188 * had before the rename call... this is a 'weak' check
5189 * at best...
5190 */
5191 if (oname == fvp->v_name && oparent == fvp->v_parent) {
5192 int update_flags;
5193
5194 update_flags = VNODE_UPDATE_NAME;
5195
5196 if (fdvp != tdvp)
5197 update_flags |= VNODE_UPDATE_PARENT;
5198
5199 vnode_update_identity(fvp, tdvp, tond.ni_cnd.cn_nameptr, tond.ni_cnd.cn_namelen, tond.ni_cnd.cn_hash, update_flags);
5200 }
5201 out1:
5202 if (to_name != NULL) {
5203 RELEASE_PATH(to_name);
5204 to_name = NULL;
5205 }
5206 if (from_name != NULL) {
5207 RELEASE_PATH(from_name);
5208 from_name = NULL;
5209 }
5210 if (holding_mntlock) {
5211 mount_unlock_renames(locked_mp);
5212 mount_drop(locked_mp, 0);
5213 holding_mntlock = 0;
5214 }
5215 if (tdvp) {
5216 /*
5217 * nameidone has to happen before we vnode_put(tdvp)
5218 * since it may need to release the fs_nodelock on the tdvp
5219 */
5220 nameidone(&tond);
5221
5222 if (tvp)
5223 vnode_put(tvp);
5224 vnode_put(tdvp);
5225 }
5226 if (fdvp) {
5227 /*
5228 * nameidone has to happen before we vnode_put(fdvp)
5229 * since it may need to release the fs_nodelock on the fdvp
5230 */
5231 nameidone(&fromnd);
5232
5233 if (fvp)
5234 vnode_put(fvp);
5235 vnode_put(fdvp);
5236 }
5237
5238 /*
5239 * If things changed after we did the namei, then we will re-drive
5240 * this rename call from the top.
5241 */
5242 if(do_retry) {
5243 do_retry = 0;
5244 goto retry;
5245 }
5246
5247 return (error);
5248 }
5249
5250 /*
5251 * Make a directory file.
5252 *
5253 * Returns: 0 Success
5254 * EEXIST
5255 * namei:???
5256 * vnode_authorize:???
5257 * vn_create:???
5258 */
5259 /* ARGSUSED */
5260 static int
5261 mkdir1(vfs_context_t ctx, user_addr_t path, struct vnode_attr *vap)
5262 {
5263 vnode_t vp, dvp;
5264 int error;
5265 int update_flags = 0;
5266 struct nameidata nd;
5267
5268 AUDIT_ARG(mode, vap->va_mode);
5269 NDINIT(&nd, CREATE, LOCKPARENT | AUDITVNPATH1,
5270 UIO_USERSPACE, path, ctx);
5271 nd.ni_cnd.cn_flags |= WILLBEDIR;
5272 error = namei(&nd);
5273 if (error)
5274 return (error);
5275 dvp = nd.ni_dvp;
5276 vp = nd.ni_vp;
5277
5278 if (vp != NULL) {
5279 error = EEXIST;
5280 goto out;
5281 }
5282
5283 VATTR_SET(vap, va_type, VDIR);
5284
5285 #if CONFIG_MACF
5286 error = mac_vnode_check_create(ctx,
5287 nd.ni_dvp, &nd.ni_cnd, vap);
5288 if (error)
5289 goto out;
5290 #endif
5291
5292 /* authorize addition of a directory to the parent */
5293 if ((error = vnode_authorize(dvp, NULL, KAUTH_VNODE_ADD_SUBDIRECTORY, ctx)) != 0)
5294 goto out;
5295
5296
5297 /* make the directory */
5298 if ((error = vn_create(dvp, &vp, &nd.ni_cnd, vap, 0, ctx)) != 0)
5299 goto out;
5300
5301 // Make sure the name & parent pointers are hooked up
5302 if (vp->v_name == NULL)
5303 update_flags |= VNODE_UPDATE_NAME;
5304 if (vp->v_parent == NULLVP)
5305 update_flags |= VNODE_UPDATE_PARENT;
5306
5307 if (update_flags)
5308 vnode_update_identity(vp, dvp, nd.ni_cnd.cn_nameptr, nd.ni_cnd.cn_namelen, nd.ni_cnd.cn_hash, update_flags);
5309
5310 #if CONFIG_FSE
5311 add_fsevent(FSE_CREATE_DIR, ctx, FSE_ARG_VNODE, vp, FSE_ARG_DONE);
5312 #endif
5313
5314 out:
5315 /*
5316 * nameidone has to happen before we vnode_put(dvp)
5317 * since it may need to release the fs_nodelock on the dvp
5318 */
5319 nameidone(&nd);
5320
5321 if (vp)
5322 vnode_put(vp);
5323 vnode_put(dvp);
5324
5325 return (error);
5326 }
5327
5328
5329 int
5330 mkdir_extended(proc_t p, struct mkdir_extended_args *uap, __unused register_t *retval)
5331 {
5332 int ciferror;
5333 kauth_filesec_t xsecdst;
5334 struct vnode_attr va;
5335
5336 xsecdst = NULL;
5337 if ((uap->xsecurity != USER_ADDR_NULL) &&
5338 ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0))
5339 return ciferror;
5340
5341 VATTR_INIT(&va);
5342 VATTR_SET(&va, va_mode, (uap->mode & ACCESSPERMS) & ~p->p_fd->fd_cmask);
5343 if (xsecdst != NULL)
5344 VATTR_SET(&va, va_acl, &xsecdst->fsec_acl);
5345
5346 ciferror = mkdir1(vfs_context_current(), uap->path, &va);
5347 if (xsecdst != NULL)
5348 kauth_filesec_free(xsecdst);
5349 return ciferror;
5350 }
5351
5352 int
5353 mkdir(proc_t p, struct mkdir_args *uap, __unused register_t *retval)
5354 {
5355 struct vnode_attr va;
5356
5357 VATTR_INIT(&va);
5358 VATTR_SET(&va, va_mode, (uap->mode & ACCESSPERMS) & ~p->p_fd->fd_cmask);
5359
5360 return(mkdir1(vfs_context_current(), uap->path, &va));
5361 }
5362
5363 /*
5364 * Remove a directory file.
5365 */
5366 /* ARGSUSED */
5367 int
5368 rmdir(__unused proc_t p, struct rmdir_args *uap, __unused register_t *retval)
5369 {
5370 vnode_t vp, dvp;
5371 int error;
5372 struct nameidata nd;
5373 vfs_context_t ctx = vfs_context_current();
5374
5375 int restart_flag, oldvp_id = -1;
5376
5377 /*
5378 * This loop exists to restart rmdir in the unlikely case that two
5379 * processes are simultaneously trying to remove the same directory
5380 * containing orphaned appleDouble files.
5381 */
5382 do {
5383 restart_flag = 0;
5384
5385 NDINIT(&nd, DELETE, LOCKPARENT | AUDITVNPATH1,
5386 UIO_USERSPACE, uap->path, ctx);
5387 error = namei(&nd);
5388 if (error)
5389 return (error);
5390
5391 dvp = nd.ni_dvp;
5392 vp = nd.ni_vp;
5393
5394
5395 /*
5396 * If being restarted check if the new vp
5397 * still has the same v_id.
5398 */
5399 if (oldvp_id != -1 && oldvp_id != vp->v_id) {
5400 error = ENOENT;
5401 goto out;
5402 }
5403
5404 if (vp->v_type != VDIR) {
5405 /*
5406 * rmdir only deals with directories
5407 */
5408 error = ENOTDIR;
5409 } else if (dvp == vp) {
5410 /*
5411 * No rmdir "." please.
5412 */
5413 error = EINVAL;
5414 } else if (vp->v_flag & VROOT) {
5415 /*
5416 * The root of a mounted filesystem cannot be deleted.
5417 */
5418 error = EBUSY;
5419 } else {
5420 #if CONFIG_MACF
5421 error = mac_vnode_check_unlink(ctx, dvp,
5422 vp, &nd.ni_cnd);
5423 if (!error)
5424 #endif
5425 error = vnode_authorize(vp, nd.ni_dvp, KAUTH_VNODE_DELETE, ctx);
5426 }
5427 if (!error) {
5428 char *path = NULL;
5429 int len;
5430 fse_info finfo;
5431 int has_listeners = 0;
5432 int need_event = 0;
5433
5434 #if CONFIG_FSE
5435 need_event = need_fsevent(FSE_DELETE, dvp);
5436 if (need_event) {
5437 get_fse_info(vp, &finfo, ctx);
5438 }
5439 #endif
5440 has_listeners = kauth_authorize_fileop_has_listeners();
5441 if (need_event || has_listeners) {
5442 GET_PATH(path);
5443 if (path == NULL) {
5444 error = ENOMEM;
5445 goto out;
5446 }
5447 len = MAXPATHLEN;
5448 vn_getpath(vp, path, &len);
5449 }
5450
5451 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, ctx);
5452
5453 /*
5454 * Special case to remove orphaned AppleDouble
5455 * files. I don't like putting this in the kernel,
5456 * but carbon does not like putting this in carbon either,
5457 * so here we are.
5458 */
5459 if (error == ENOTEMPTY) {
5460 error = rmdir_remove_orphaned_appleDouble(vp, ctx, &restart_flag);
5461 if (error == EBUSY) {
5462 oldvp_id = vp->v_id;
5463 goto out;
5464 }
5465
5466
5467 /*
5468 * Assuming everything went well, we will try the RMDIR again
5469 */
5470 if (!error)
5471 error = VNOP_RMDIR(dvp, vp, &nd.ni_cnd, ctx);
5472 }
5473
5474 /*
5475 * Call out to allow 3rd party notification of delete.
5476 * Ignore result of kauth_authorize_fileop call.
5477 */
5478 if (!error) {
5479 if (has_listeners) {
5480 kauth_authorize_fileop(vfs_context_ucred(ctx),
5481 KAUTH_FILEOP_DELETE,
5482 (uintptr_t)vp,
5483 (uintptr_t)path);
5484 }
5485
5486 if (vp->v_flag & VISHARDLINK) {
5487 // see the comment in unlink1() about why we update
5488 // the parent of a hard link when it is removed
5489 vnode_update_identity(vp, NULL, NULL, 0, 0, VNODE_UPDATE_PARENT);
5490 }
5491
5492 #if CONFIG_FSE
5493 if (need_event) {
5494 add_fsevent(FSE_DELETE, ctx,
5495 FSE_ARG_STRING, len, path,
5496 FSE_ARG_FINFO, &finfo,
5497 FSE_ARG_DONE);
5498 }
5499 #endif
5500 }
5501 if (path != NULL)
5502 RELEASE_PATH(path);
5503 }
5504
5505 out:
5506 /*
5507 * nameidone has to happen before we vnode_put(dvp)
5508 * since it may need to release the fs_nodelock on the dvp
5509 */
5510 nameidone(&nd);
5511
5512 vnode_put(dvp);
5513 vnode_put(vp);
5514
5515 if (restart_flag == 0) {
5516 wakeup_one((caddr_t)vp);
5517 return (error);
5518 }
5519 tsleep(vp, PVFS, "rm AD", 1);
5520
5521 } while (restart_flag != 0);
5522
5523 return (error);
5524
5525 }
5526
5527 /* Get direntry length padded to 8 byte alignment */
5528 #define DIRENT64_LEN(namlen) \
5529 ((sizeof(struct direntry) + (namlen) - (MAXPATHLEN-1) + 7) & ~7)
5530
5531 static errno_t
5532 vnode_readdir64(struct vnode *vp, struct uio *uio, int flags, int *eofflag,
5533 int *numdirent, vfs_context_t ctxp)
5534 {
5535 /* Check if fs natively supports VNODE_READDIR_EXTENDED */
5536 if (vp->v_mount->mnt_vtable->vfc_vfsflags & VFC_VFSREADDIR_EXTENDED) {
5537 return VNOP_READDIR(vp, uio, flags, eofflag, numdirent, ctxp);
5538 } else {
5539 size_t bufsize;
5540 void * bufptr;
5541 uio_t auio;
5542 struct direntry entry64;
5543 struct dirent *dep;
5544 int bytesread;
5545 int error;
5546
5547 /*
5548 * Our kernel buffer needs to be smaller since re-packing
5549 * will expand each dirent. The worse case (when the name
5550 * length is 3) corresponds to a struct direntry size of 32
5551 * bytes (8-byte aligned) and a struct dirent size of 12 bytes
5552 * (4-byte aligned). So having a buffer that is 3/8 the size
5553 * will prevent us from reading more than we can pack.
5554 *
5555 * Since this buffer is wired memory, we will limit the
5556 * buffer size to a maximum of 32K. We would really like to
5557 * use 32K in the MIN(), but we use magic number 87371 to
5558 * prevent uio_resid() * 3 / 8 from overflowing.
5559 */
5560 bufsize = 3 * MIN(uio_resid(uio), 87371) / 8;
5561 MALLOC(bufptr, void *, bufsize, M_TEMP, M_WAITOK);
5562
5563 auio = uio_create(1, 0, UIO_SYSSPACE32, UIO_READ);
5564 uio_addiov(auio, (uintptr_t)bufptr, bufsize);
5565 auio->uio_offset = uio->uio_offset;
5566
5567 error = VNOP_READDIR(vp, auio, 0, eofflag, numdirent, ctxp);
5568
5569 dep = (struct dirent *)bufptr;
5570 bytesread = bufsize - uio_resid(auio);
5571
5572 /*
5573 * Convert all the entries and copy them out to user's buffer.
5574 */
5575 while (error == 0 && (char *)dep < ((char *)bufptr + bytesread)) {
5576 /* Convert a dirent to a dirent64. */
5577 entry64.d_ino = dep->d_ino;
5578 entry64.d_seekoff = 0;
5579 entry64.d_reclen = DIRENT64_LEN(dep->d_namlen);
5580 entry64.d_namlen = dep->d_namlen;
5581 entry64.d_type = dep->d_type;
5582 bcopy(dep->d_name, entry64.d_name, dep->d_namlen + 1);
5583
5584 /* Move to next entry. */
5585 dep = (struct dirent *)((char *)dep + dep->d_reclen);
5586
5587 /* Copy entry64 to user's buffer. */
5588 error = uiomove((caddr_t)&entry64, entry64.d_reclen, uio);
5589 }
5590
5591 /* Update the real offset using the offset we got from VNOP_READDIR. */
5592 if (error == 0) {
5593 uio->uio_offset = auio->uio_offset;
5594 }
5595 uio_free(auio);
5596 FREE(bufptr, M_TEMP);
5597 return (error);
5598 }
5599 }
5600
5601 /*
5602 * Read a block of directory entries in a file system independent format.
5603 */
5604 static int
5605 getdirentries_common(int fd, user_addr_t bufp, user_size_t bufsize, ssize_t *bytesread,
5606 off_t *offset, int flags)
5607 {
5608 vnode_t vp;
5609 struct vfs_context context = *vfs_context_current(); /* local copy */
5610 struct fileproc *fp;
5611 uio_t auio;
5612 int spacetype = proc_is64bit(vfs_context_proc(&context)) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5613 off_t loff;
5614 int error, eofflag, numdirent;
5615 char uio_buf[ UIO_SIZEOF(1) ];
5616
5617 error = fp_getfvp(vfs_context_proc(&context), fd, &fp, &vp);
5618 if (error) {
5619 return (error);
5620 }
5621 if ((fp->f_fglob->fg_flag & FREAD) == 0) {
5622 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
5623 error = EBADF;
5624 goto out;
5625 }
5626
5627 #if CONFIG_MACF
5628 error = mac_file_check_change_offset(vfs_context_ucred(&context), fp->f_fglob);
5629 if (error)
5630 goto out;
5631 #endif
5632 if ( (error = vnode_getwithref(vp)) ) {
5633 goto out;
5634 }
5635 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
5636
5637 unionread:
5638 if (vp->v_type != VDIR) {
5639 (void)vnode_put(vp);
5640 error = EINVAL;
5641 goto out;
5642 }
5643
5644 #if CONFIG_MACF
5645 error = mac_vnode_check_readdir(&context, vp);
5646 if (error != 0) {
5647 (void)vnode_put(vp);
5648 goto out;
5649 }
5650 #endif /* MAC */
5651
5652 loff = fp->f_fglob->fg_offset;
5653 auio = uio_createwithbuffer(1, loff, spacetype, UIO_READ, &uio_buf[0], sizeof(uio_buf));
5654 uio_addiov(auio, bufp, bufsize);
5655
5656 if (flags & VNODE_READDIR_EXTENDED) {
5657 error = vnode_readdir64(vp, auio, flags, &eofflag, &numdirent, &context);
5658 fp->f_fglob->fg_offset = uio_offset(auio);
5659 } else {
5660 error = VNOP_READDIR(vp, auio, 0, &eofflag, &numdirent, &context);
5661 fp->f_fglob->fg_offset = uio_offset(auio);
5662 }
5663 if (error) {
5664 (void)vnode_put(vp);
5665 goto out;
5666 }
5667
5668 if ((user_ssize_t)bufsize == uio_resid(auio)){
5669 if (union_dircheckp) {
5670 error = union_dircheckp(&vp, fp, &context);
5671 if (error == -1)
5672 goto unionread;
5673 if (error)
5674 goto out;
5675 }
5676
5677 if ((vp->v_flag & VROOT) && (vp->v_mount->mnt_flag & MNT_UNION)) {
5678 struct vnode *tvp = vp;
5679 vp = vp->v_mount->mnt_vnodecovered;
5680 vnode_getwithref(vp);
5681 vnode_ref(vp);
5682 fp->f_fglob->fg_data = (caddr_t) vp;
5683 fp->f_fglob->fg_offset = 0;
5684 vnode_rele(tvp);
5685 vnode_put(tvp);
5686 goto unionread;
5687 }
5688 }
5689
5690 vnode_put(vp);
5691 if (offset) {
5692 *offset = loff;
5693 }
5694 // LP64todo - fix this
5695 *bytesread = bufsize - uio_resid(auio);
5696 out:
5697 file_drop(fd);
5698 return (error);
5699 }
5700
5701
5702 int
5703 getdirentries(__unused struct proc *p, struct getdirentries_args *uap, register_t *retval)
5704 {
5705 off_t offset;
5706 long loff;
5707 ssize_t bytesread;
5708 int error;
5709
5710 AUDIT_ARG(fd, uap->fd);
5711 error = getdirentries_common(uap->fd, uap->buf, uap->count, &bytesread, &offset, 0);
5712
5713 if (error == 0) {
5714 loff = (long)offset;
5715 error = copyout((caddr_t)&loff, uap->basep, sizeof(long));
5716 *retval = bytesread;
5717 }
5718 return (error);
5719 }
5720
5721 int
5722 getdirentries64(__unused struct proc *p, struct getdirentries64_args *uap, user_ssize_t *retval)
5723 {
5724 off_t offset;
5725 ssize_t bytesread;
5726 int error;
5727
5728 AUDIT_ARG(fd, uap->fd);
5729 error = getdirentries_common(uap->fd, uap->buf, uap->bufsize, &bytesread, &offset, VNODE_READDIR_EXTENDED);
5730
5731 if (error == 0) {
5732 *retval = bytesread;
5733 error = copyout((caddr_t)&offset, uap->position, sizeof(off_t));
5734 }
5735 return (error);
5736 }
5737
5738
5739 /*
5740 * Set the mode mask for creation of filesystem nodes.
5741 */
5742 #warning XXX implement xsecurity
5743
5744 #define UMASK_NOXSECURITY (void *)1 /* leave existing xsecurity alone */
5745 static int
5746 umask1(proc_t p, int newmask, __unused kauth_filesec_t fsec, register_t *retval)
5747 {
5748 struct filedesc *fdp;
5749
5750 AUDIT_ARG(mask, newmask);
5751 proc_fdlock(p);
5752 fdp = p->p_fd;
5753 *retval = fdp->fd_cmask;
5754 fdp->fd_cmask = newmask & ALLPERMS;
5755 proc_fdunlock(p);
5756 return (0);
5757 }
5758
5759
5760 int
5761 umask_extended(proc_t p, struct umask_extended_args *uap, register_t *retval)
5762 {
5763 int ciferror;
5764 kauth_filesec_t xsecdst;
5765
5766 xsecdst = KAUTH_FILESEC_NONE;
5767 if (uap->xsecurity != USER_ADDR_NULL) {
5768 if ((ciferror = kauth_copyinfilesec(uap->xsecurity, &xsecdst)) != 0)
5769 return ciferror;
5770 } else {
5771 xsecdst = KAUTH_FILESEC_NONE;
5772 }
5773
5774 ciferror = umask1(p, uap->newmask, xsecdst, retval);
5775
5776 if (xsecdst != KAUTH_FILESEC_NONE)
5777 kauth_filesec_free(xsecdst);
5778 return ciferror;
5779 }
5780
5781 int
5782 umask(proc_t p, struct umask_args *uap, register_t *retval)
5783 {
5784 return(umask1(p, uap->newmask, UMASK_NOXSECURITY, retval));
5785 }
5786
5787 /*
5788 * Void all references to file by ripping underlying filesystem
5789 * away from vnode.
5790 */
5791 /* ARGSUSED */
5792 int
5793 revoke(proc_t p, struct revoke_args *uap, __unused register_t *retval)
5794 {
5795 vnode_t vp;
5796 struct vnode_attr va;
5797 vfs_context_t ctx = vfs_context_current();
5798 int error;
5799 struct nameidata nd;
5800
5801 NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNPATH1,
5802 UIO_USERSPACE, uap->path, ctx);
5803 error = namei(&nd);
5804 if (error)
5805 return (error);
5806 vp = nd.ni_vp;
5807
5808 nameidone(&nd);
5809
5810 #if CONFIG_MACF
5811 error = mac_vnode_check_revoke(ctx, vp);
5812 if (error)
5813 goto out;
5814 #endif
5815
5816 VATTR_INIT(&va);
5817 VATTR_WANTED(&va, va_uid);
5818 if ((error = vnode_getattr(vp, &va, ctx)))
5819 goto out;
5820 if (kauth_cred_getuid(vfs_context_ucred(ctx)) != va.va_uid &&
5821 (error = suser(vfs_context_ucred(ctx), &p->p_acflag)))
5822 goto out;
5823 if (vp->v_usecount > 1 || (vp->v_flag & VALIASED))
5824 VNOP_REVOKE(vp, REVOKEALL, ctx);
5825 out:
5826 vnode_put(vp);
5827 return (error);
5828 }
5829
5830
5831 /*
5832 * HFS/HFS PlUS SPECIFIC SYSTEM CALLS
5833 * The following system calls are designed to support features
5834 * which are specific to the HFS & HFS Plus volume formats
5835 */
5836
5837 #ifdef __APPLE_API_OBSOLETE
5838
5839 /************************************************/
5840 /* *** Following calls will be deleted soon *** */
5841 /************************************************/
5842
5843 /*
5844 * Make a complex file. A complex file is one with multiple forks (data streams)
5845 */
5846 /* ARGSUSED */
5847 int
5848 mkcomplex(__unused proc_t p, __unused struct mkcomplex_args *uap, __unused register_t *retval)
5849 {
5850 return (ENOTSUP);
5851 }
5852
5853 /*
5854 * Extended stat call which returns volumeid and vnodeid as well as other info
5855 */
5856 /* ARGSUSED */
5857 int
5858 statv(__unused proc_t p,
5859 __unused struct statv_args *uap,
5860 __unused register_t *retval)
5861 {
5862 return (ENOTSUP); /* We'll just return an error for now */
5863
5864 } /* end of statv system call */
5865
5866 /*
5867 * Extended lstat call which returns volumeid and vnodeid as well as other info
5868 */
5869 /* ARGSUSED */
5870 int
5871 lstatv(__unused proc_t p,
5872 __unused struct lstatv_args *uap,
5873 __unused register_t *retval)
5874 {
5875 return (ENOTSUP); /* We'll just return an error for now */
5876 } /* end of lstatv system call */
5877
5878 /*
5879 * Extended fstat call which returns volumeid and vnodeid as well as other info
5880 */
5881 /* ARGSUSED */
5882 int
5883 fstatv(__unused proc_t p,
5884 __unused struct fstatv_args *uap,
5885 __unused register_t *retval)
5886 {
5887 return (ENOTSUP); /* We'll just return an error for now */
5888 } /* end of fstatv system call */
5889
5890
5891 /************************************************/
5892 /* *** Preceding calls will be deleted soon *** */
5893 /************************************************/
5894
5895 #endif /* __APPLE_API_OBSOLETE */
5896
5897 /*
5898 * Obtain attribute information on objects in a directory while enumerating
5899 * the directory. This call does not yet support union mounted directories.
5900 * TO DO
5901 * 1.union mounted directories.
5902 */
5903
5904 /* ARGSUSED */
5905 int
5906 getdirentriesattr (proc_t p, struct getdirentriesattr_args *uap, register_t *retval)
5907 {
5908 vnode_t vp;
5909 struct fileproc *fp;
5910 uio_t auio = NULL;
5911 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
5912 uint32_t count;
5913 uint32_t newstate;
5914 int error, eofflag;
5915 uint32_t loff;
5916 struct attrlist attributelist;
5917 vfs_context_t ctx = vfs_context_current();
5918 int fd = uap->fd;
5919 char uio_buf[ UIO_SIZEOF(1) ];
5920 kauth_action_t action;
5921
5922 AUDIT_ARG(fd, fd);
5923
5924 /* Get the attributes into kernel space */
5925 if ((error = copyin(uap->alist, (caddr_t)&attributelist, sizeof(attributelist)))) {
5926 return(error);
5927 }
5928 if ((error = copyin(uap->count, (caddr_t)&count, sizeof(count)))) {
5929 return(error);
5930 }
5931 if ( (error = fp_getfvp(p, fd, &fp, &vp)) ) {
5932 return (error);
5933 }
5934 if ((fp->f_fglob->fg_flag & FREAD) == 0) {
5935 AUDIT_ARG(vnpath_withref, vp, ARG_VNODE1);
5936 error = EBADF;
5937 goto out;
5938 }
5939
5940
5941 #if CONFIG_MACF
5942 error = mac_file_check_change_offset(vfs_context_ucred(ctx),
5943 fp->f_fglob);
5944 if (error)
5945 goto out;
5946 #endif
5947
5948
5949 if ( (error = vnode_getwithref(vp)) )
5950 goto out;
5951
5952 AUDIT_ARG(vnpath, vp, ARG_VNODE1);
5953
5954 if (vp->v_type != VDIR) {
5955 (void)vnode_put(vp);
5956 error = EINVAL;
5957 goto out;
5958 }
5959
5960 #if CONFIG_MACF
5961 error = mac_vnode_check_readdir(ctx, vp);
5962 if (error != 0) {
5963 (void)vnode_put(vp);
5964 goto out;
5965 }
5966 #endif /* MAC */
5967
5968 /* set up the uio structure which will contain the users return buffer */
5969 loff = fp->f_fglob->fg_offset;
5970 auio = uio_createwithbuffer(1, loff, spacetype, UIO_READ,
5971 &uio_buf[0], sizeof(uio_buf));
5972 uio_addiov(auio, uap->buffer, uap->buffersize);
5973
5974 /*
5975 * If the only item requested is file names, we can let that past with
5976 * just LIST_DIRECTORY. If they want any other attributes, that means
5977 * they need SEARCH as well.
5978 */
5979 action = KAUTH_VNODE_LIST_DIRECTORY;
5980 if ((attributelist.commonattr & ~ATTR_CMN_NAME) ||
5981 attributelist.fileattr || attributelist.dirattr)
5982 action |= KAUTH_VNODE_SEARCH;
5983
5984 if ((error = vnode_authorize(vp, NULL, action, ctx)) == 0) {
5985 u_long ulcount = count;
5986
5987 error = VNOP_READDIRATTR(vp, &attributelist, auio,
5988 count,
5989 uap->options, (unsigned long *)&newstate, &eofflag,
5990 &ulcount, ctx);
5991 if (!error)
5992 count = ulcount;
5993 }
5994 (void)vnode_put(vp);
5995
5996 if (error)
5997 goto out;
5998 fp->f_fglob->fg_offset = uio_offset(auio); /* should be multiple of dirent, not variable */
5999
6000 if ((error = copyout((caddr_t) &count, uap->count, sizeof(count))))
6001 goto out;
6002 if ((error = copyout((caddr_t) &newstate, uap->newstate, sizeof(newstate))))
6003 goto out;
6004 if ((error = copyout((caddr_t) &loff, uap->basep, sizeof(loff))))
6005 goto out;
6006
6007 *retval = eofflag; /* similar to getdirentries */
6008 error = 0;
6009 out:
6010 file_drop(fd);
6011 return (error); /* return error earlier, an retval of 0 or 1 now */
6012
6013 } /* end of getdirentryattr system call */
6014
6015 /*
6016 * Exchange data between two files
6017 */
6018
6019 /* ARGSUSED */
6020 int
6021 exchangedata (__unused proc_t p, struct exchangedata_args *uap, __unused register_t *retval)
6022 {
6023
6024 struct nameidata fnd, snd;
6025 vfs_context_t ctx = vfs_context_current();
6026 vnode_t fvp;
6027 vnode_t svp;
6028 int error;
6029 u_long nameiflags;
6030 char *fpath = NULL;
6031 char *spath = NULL;
6032 int flen, slen;
6033 fse_info f_finfo, s_finfo;
6034
6035 nameiflags = 0;
6036 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
6037
6038 NDINIT(&fnd, LOOKUP, nameiflags | AUDITVNPATH1,
6039 UIO_USERSPACE, uap->path1, ctx);
6040
6041 error = namei(&fnd);
6042 if (error)
6043 goto out2;
6044
6045 nameidone(&fnd);
6046 fvp = fnd.ni_vp;
6047
6048 NDINIT(&snd, LOOKUP | CN_NBMOUNTLOOK, nameiflags | AUDITVNPATH2,
6049 UIO_USERSPACE, uap->path2, ctx);
6050
6051 error = namei(&snd);
6052 if (error) {
6053 vnode_put(fvp);
6054 goto out2;
6055 }
6056 nameidone(&snd);
6057 svp = snd.ni_vp;
6058
6059 /*
6060 * if the files are the same, return an inval error
6061 */
6062 if (svp == fvp) {
6063 error = EINVAL;
6064 goto out;
6065 }
6066
6067 /*
6068 * if the files are on different volumes, return an error
6069 */
6070 if (svp->v_mount != fvp->v_mount) {
6071 error = EXDEV;
6072 goto out;
6073 }
6074
6075 #if CONFIG_MACF
6076 error = mac_vnode_check_exchangedata(ctx,
6077 fvp, svp);
6078 if (error)
6079 goto out;
6080 #endif
6081 if (((error = vnode_authorize(fvp, NULL, KAUTH_VNODE_READ_DATA | KAUTH_VNODE_WRITE_DATA, ctx)) != 0) ||
6082 ((error = vnode_authorize(svp, NULL, KAUTH_VNODE_READ_DATA | KAUTH_VNODE_WRITE_DATA, ctx)) != 0))
6083 goto out;
6084
6085 if (
6086 #if CONFIG_FSE
6087 need_fsevent(FSE_EXCHANGE, fvp) ||
6088 #endif
6089 kauth_authorize_fileop_has_listeners()) {
6090 GET_PATH(fpath);
6091 GET_PATH(spath);
6092 if (fpath == NULL || spath == NULL) {
6093 error = ENOMEM;
6094 goto out;
6095 }
6096 flen = MAXPATHLEN;
6097 slen = MAXPATHLEN;
6098 if (vn_getpath(fvp, fpath, &flen) != 0 || fpath[0] == '\0') {
6099 printf("exchange: vn_getpath(fvp=%p) failed <<%s>>\n",
6100 fvp, fpath);
6101 }
6102 if (vn_getpath(svp, spath, &slen) != 0 || spath[0] == '\0') {
6103 printf("exchange: vn_getpath(svp=%p) failed <<%s>>\n",
6104 svp, spath);
6105 }
6106 #if CONFIG_FSE
6107 get_fse_info(fvp, &f_finfo, ctx);
6108 get_fse_info(svp, &s_finfo, ctx);
6109 #endif
6110 }
6111 /* Ok, make the call */
6112 error = VNOP_EXCHANGE(fvp, svp, 0, ctx);
6113
6114 if (error == 0) {
6115 const char *tmpname;
6116
6117 if (fpath != NULL && spath != NULL) {
6118 /* call out to allow 3rd party notification of exchangedata.
6119 * Ignore result of kauth_authorize_fileop call.
6120 */
6121 kauth_authorize_fileop(vfs_context_ucred(ctx), KAUTH_FILEOP_EXCHANGE,
6122 (uintptr_t)fpath, (uintptr_t)spath);
6123 }
6124 name_cache_lock();
6125
6126 tmpname = fvp->v_name;
6127 fvp->v_name = svp->v_name;
6128 svp->v_name = tmpname;
6129
6130 if (fvp->v_parent != svp->v_parent) {
6131 vnode_t tmp;
6132
6133 tmp = fvp->v_parent;
6134 fvp->v_parent = svp->v_parent;
6135 svp->v_parent = tmp;
6136 }
6137 name_cache_unlock();
6138
6139 #if CONFIG_FSE
6140 if (fpath != NULL && spath != NULL) {
6141 add_fsevent(FSE_EXCHANGE, ctx,
6142 FSE_ARG_STRING, flen, fpath,
6143 FSE_ARG_FINFO, &f_finfo,
6144 FSE_ARG_STRING, slen, spath,
6145 FSE_ARG_FINFO, &s_finfo,
6146 FSE_ARG_DONE);
6147 }
6148 #endif
6149 }
6150
6151 out:
6152 if (fpath != NULL)
6153 RELEASE_PATH(fpath);
6154 if (spath != NULL)
6155 RELEASE_PATH(spath);
6156 vnode_put(svp);
6157 vnode_put(fvp);
6158 out2:
6159 return (error);
6160 }
6161
6162
6163 /* ARGSUSED */
6164
6165 int
6166 searchfs(proc_t p, struct searchfs_args *uap, __unused register_t *retval)
6167 {
6168 vnode_t vp;
6169 int error=0;
6170 int fserror = 0;
6171 struct nameidata nd;
6172 struct user_fssearchblock searchblock;
6173 struct searchstate *state;
6174 struct attrlist *returnattrs;
6175 void *searchparams1,*searchparams2;
6176 uio_t auio = NULL;
6177 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6178 u_long nummatches;
6179 int mallocsize;
6180 u_long nameiflags;
6181 vfs_context_t ctx = vfs_context_current();
6182 char uio_buf[ UIO_SIZEOF(1) ];
6183
6184 /* Start by copying in fsearchblock paramater list */
6185 if (IS_64BIT_PROCESS(p)) {
6186 error = copyin(uap->searchblock, (caddr_t) &searchblock, sizeof(searchblock));
6187 }
6188 else {
6189 struct fssearchblock tmp_searchblock;
6190 error = copyin(uap->searchblock, (caddr_t) &tmp_searchblock, sizeof(tmp_searchblock));
6191 // munge into 64-bit version
6192 searchblock.returnattrs = CAST_USER_ADDR_T(tmp_searchblock.returnattrs);
6193 searchblock.returnbuffer = CAST_USER_ADDR_T(tmp_searchblock.returnbuffer);
6194 searchblock.returnbuffersize = tmp_searchblock.returnbuffersize;
6195 searchblock.maxmatches = tmp_searchblock.maxmatches;
6196 searchblock.timelimit.tv_sec = tmp_searchblock.timelimit.tv_sec;
6197 searchblock.timelimit.tv_usec = tmp_searchblock.timelimit.tv_usec;
6198 searchblock.searchparams1 = CAST_USER_ADDR_T(tmp_searchblock.searchparams1);
6199 searchblock.sizeofsearchparams1 = tmp_searchblock.sizeofsearchparams1;
6200 searchblock.searchparams2 = CAST_USER_ADDR_T(tmp_searchblock.searchparams2);
6201 searchblock.sizeofsearchparams2 = tmp_searchblock.sizeofsearchparams2;
6202 searchblock.searchattrs = tmp_searchblock.searchattrs;
6203 }
6204 if (error)
6205 return(error);
6206
6207 /* Do a sanity check on sizeofsearchparams1 and sizeofsearchparams2.
6208 */
6209 if (searchblock.sizeofsearchparams1 > SEARCHFS_MAX_SEARCHPARMS ||
6210 searchblock.sizeofsearchparams2 > SEARCHFS_MAX_SEARCHPARMS)
6211 return(EINVAL);
6212
6213 /* Now malloc a big bunch of space to hold the search parameters, the attrlists and the search state. */
6214 /* It all has to do into local memory and it's not that big so we might as well put it all together. */
6215 /* Searchparams1 shall be first so we might as well use that to hold the base address of the allocated*/
6216 /* block. */
6217
6218 mallocsize = searchblock.sizeofsearchparams1 + searchblock.sizeofsearchparams2 +
6219 sizeof(struct attrlist) + sizeof(struct searchstate);
6220
6221 MALLOC(searchparams1, void *, mallocsize, M_TEMP, M_WAITOK);
6222
6223 /* Now set up the various pointers to the correct place in our newly allocated memory */
6224
6225 searchparams2 = (void *) (((caddr_t) searchparams1) + searchblock.sizeofsearchparams1);
6226 returnattrs = (struct attrlist *) (((caddr_t) searchparams2) + searchblock.sizeofsearchparams2);
6227 state = (struct searchstate *) (((caddr_t) returnattrs) + sizeof (struct attrlist));
6228
6229 /* Now copy in the stuff given our local variables. */
6230
6231 if ((error = copyin(searchblock.searchparams1, searchparams1, searchblock.sizeofsearchparams1)))
6232 goto freeandexit;
6233
6234 if ((error = copyin(searchblock.searchparams2, searchparams2, searchblock.sizeofsearchparams2)))
6235 goto freeandexit;
6236
6237 if ((error = copyin(searchblock.returnattrs, (caddr_t) returnattrs, sizeof(struct attrlist))))
6238 goto freeandexit;
6239
6240 if ((error = copyin(uap->state, (caddr_t) state, sizeof(struct searchstate))))
6241 goto freeandexit;
6242
6243 /* set up the uio structure which will contain the users return buffer */
6244
6245 auio = uio_createwithbuffer(1, 0, spacetype, UIO_READ,
6246 &uio_buf[0], sizeof(uio_buf));
6247 uio_addiov(auio, searchblock.returnbuffer, searchblock.returnbuffersize);
6248
6249 nameiflags = 0;
6250 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
6251 NDINIT(&nd, LOOKUP, nameiflags | AUDITVNPATH1,
6252 UIO_USERSPACE, uap->path, ctx);
6253
6254 error = namei(&nd);
6255 if (error)
6256 goto freeandexit;
6257
6258 nameidone(&nd);
6259 vp = nd.ni_vp;
6260
6261
6262 /*
6263 * If searchblock.maxmatches == 0, then skip the search. This has happened
6264 * before and sometimes the underlyning code doesnt deal with it well.
6265 */
6266 if (searchblock.maxmatches == 0) {
6267 nummatches = 0;
6268 goto saveandexit;
6269 }
6270
6271 /*
6272 Allright, we have everything we need, so lets make that call.
6273
6274 We keep special track of the return value from the file system:
6275 EAGAIN is an acceptable error condition that shouldn't keep us
6276 from copying out any results...
6277 */
6278
6279 fserror = VNOP_SEARCHFS(vp,
6280 searchparams1,
6281 searchparams2,
6282 &searchblock.searchattrs,
6283 searchblock.maxmatches,
6284 &searchblock.timelimit,
6285 returnattrs,
6286 &nummatches,
6287 uap->scriptcode,
6288 uap->options,
6289 auio,
6290 state,
6291 ctx);
6292
6293 saveandexit:
6294
6295 vnode_put(vp);
6296
6297 /* Now copy out the stuff that needs copying out. That means the number of matches, the
6298 search state. Everything was already put into he return buffer by the vop call. */
6299
6300 if ((error = copyout((caddr_t) state, uap->state, sizeof(struct searchstate))) != 0)
6301 goto freeandexit;
6302
6303 if ((error = suulong(uap->nummatches, (uint64_t)nummatches)) != 0)
6304 goto freeandexit;
6305
6306 error = fserror;
6307
6308 freeandexit:
6309
6310 FREE(searchparams1,M_TEMP);
6311
6312 return(error);
6313
6314
6315 } /* end of searchfs system call */
6316
6317
6318 /*
6319 * Make a filesystem-specific control call:
6320 */
6321 /* ARGSUSED */
6322 int
6323 fsctl (proc_t p, struct fsctl_args *uap, __unused register_t *retval)
6324 {
6325 int error;
6326 boolean_t is64bit;
6327 struct nameidata nd;
6328 u_long nameiflags;
6329 u_long cmd = uap->cmd;
6330 u_int size;
6331 #define STK_PARAMS 128
6332 char stkbuf[STK_PARAMS];
6333 caddr_t data, memp;
6334 vfs_context_t ctx = vfs_context_current();
6335
6336 size = IOCPARM_LEN(cmd);
6337 if (size > IOCPARM_MAX) return (EINVAL);
6338
6339 is64bit = proc_is64bit(p);
6340
6341 memp = NULL;
6342 if (size > sizeof (stkbuf)) {
6343 if ((memp = (caddr_t)kalloc(size)) == 0) return ENOMEM;
6344 data = memp;
6345 } else {
6346 data = &stkbuf[0];
6347 };
6348
6349 if (cmd & IOC_IN) {
6350 if (size) {
6351 error = copyin(uap->data, data, size);
6352 if (error) goto FSCtl_Exit;
6353 } else {
6354 if (is64bit) {
6355 *(user_addr_t *)data = uap->data;
6356 }
6357 else {
6358 *(uint32_t *)data = (uint32_t)uap->data;
6359 }
6360 };
6361 } else if ((cmd & IOC_OUT) && size) {
6362 /*
6363 * Zero the buffer so the user always
6364 * gets back something deterministic.
6365 */
6366 bzero(data, size);
6367 } else if (cmd & IOC_VOID) {
6368 if (is64bit) {
6369 *(user_addr_t *)data = uap->data;
6370 }
6371 else {
6372 *(uint32_t *)data = (uint32_t)uap->data;
6373 }
6374 }
6375
6376 /* Get the vnode for the file we are getting info on: */
6377 nameiflags = 0;
6378 if ((uap->options & FSOPT_NOFOLLOW) == 0) nameiflags |= FOLLOW;
6379 NDINIT(&nd, LOOKUP, nameiflags, UIO_USERSPACE, uap->path, ctx);
6380 if ((error = namei(&nd))) goto FSCtl_Exit;
6381
6382 #if CONFIG_MACF
6383 error = mac_mount_check_fsctl(ctx, vnode_mount(nd.ni_vp), cmd);
6384 if (error) {
6385 vnode_put(nd.ni_vp);
6386 nameidone(&nd);
6387 goto FSCtl_Exit;
6388 }
6389 #endif
6390
6391 /* Invoke the filesystem-specific code */
6392 error = VNOP_IOCTL(nd.ni_vp, IOCBASECMD(cmd), data, uap->options, ctx);
6393
6394 vnode_put(nd.ni_vp);
6395 nameidone(&nd);
6396
6397 /*
6398 * Copy any data to user, size was
6399 * already set and checked above.
6400 */
6401 if (error == 0 && (cmd & IOC_OUT) && size)
6402 error = copyout(data, uap->data, size);
6403
6404 FSCtl_Exit:
6405 if (memp) kfree(memp, size);
6406
6407 return error;
6408 }
6409 /* end of fsctl system call */
6410
6411 /*
6412 * An in-kernel sync for power management to call.
6413 */
6414 __private_extern__ int
6415 sync_internal(void)
6416 {
6417 int error;
6418
6419 struct sync_args data;
6420
6421 int retval[2];
6422
6423
6424 error = sync(current_proc(), &data, &retval[0]);
6425
6426
6427 return (error);
6428 } /* end of sync_internal call */
6429
6430
6431 /*
6432 * Retrieve the data of an extended attribute.
6433 */
6434 int
6435 getxattr(proc_t p, struct getxattr_args *uap, user_ssize_t *retval)
6436 {
6437 vnode_t vp;
6438 struct nameidata nd;
6439 char attrname[XATTR_MAXNAMELEN+1];
6440 vfs_context_t ctx = vfs_context_current();
6441 uio_t auio = NULL;
6442 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6443 size_t attrsize = 0;
6444 size_t namelen;
6445 u_long nameiflags;
6446 int error;
6447 char uio_buf[ UIO_SIZEOF(1) ];
6448
6449 if (uap->options & (XATTR_NOSECURITY | XATTR_NODEFAULT))
6450 return (EINVAL);
6451
6452 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
6453 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, ctx);
6454 if ((error = namei(&nd))) {
6455 return (error);
6456 }
6457 vp = nd.ni_vp;
6458 nameidone(&nd);
6459
6460 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
6461 goto out;
6462 }
6463 if (xattr_protected(attrname)) {
6464 error = EPERM;
6465 goto out;
6466 }
6467 if (uap->value && uap->size > 0) {
6468 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_READ,
6469 &uio_buf[0], sizeof(uio_buf));
6470 uio_addiov(auio, uap->value, uap->size);
6471 }
6472
6473 error = vn_getxattr(vp, attrname, auio, &attrsize, uap->options, ctx);
6474 out:
6475 vnode_put(vp);
6476
6477 if (auio) {
6478 *retval = uap->size - uio_resid(auio);
6479 } else {
6480 *retval = (user_ssize_t)attrsize;
6481 }
6482
6483 return (error);
6484 }
6485
6486 /*
6487 * Retrieve the data of an extended attribute.
6488 */
6489 int
6490 fgetxattr(proc_t p, struct fgetxattr_args *uap, user_ssize_t *retval)
6491 {
6492 vnode_t vp;
6493 char attrname[XATTR_MAXNAMELEN+1];
6494 uio_t auio = NULL;
6495 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6496 size_t attrsize = 0;
6497 size_t namelen;
6498 int error;
6499 char uio_buf[ UIO_SIZEOF(1) ];
6500
6501 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY | XATTR_NODEFAULT))
6502 return (EINVAL);
6503
6504 if ( (error = file_vnode(uap->fd, &vp)) ) {
6505 return (error);
6506 }
6507 if ( (error = vnode_getwithref(vp)) ) {
6508 file_drop(uap->fd);
6509 return(error);
6510 }
6511 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
6512 goto out;
6513 }
6514 if (xattr_protected(attrname)) {
6515 error = EPERM;
6516 goto out;
6517 }
6518 if (uap->value && uap->size > 0) {
6519 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_READ,
6520 &uio_buf[0], sizeof(uio_buf));
6521 uio_addiov(auio, uap->value, uap->size);
6522 }
6523
6524 error = vn_getxattr(vp, attrname, auio, &attrsize, uap->options, vfs_context_current());
6525 out:
6526 (void)vnode_put(vp);
6527 file_drop(uap->fd);
6528
6529 if (auio) {
6530 *retval = uap->size - uio_resid(auio);
6531 } else {
6532 *retval = (user_ssize_t)attrsize;
6533 }
6534 return (error);
6535 }
6536
6537 /*
6538 * Set the data of an extended attribute.
6539 */
6540 int
6541 setxattr(proc_t p, struct setxattr_args *uap, int *retval)
6542 {
6543 vnode_t vp;
6544 struct nameidata nd;
6545 char attrname[XATTR_MAXNAMELEN+1];
6546 vfs_context_t ctx = vfs_context_current();
6547 uio_t auio = NULL;
6548 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6549 size_t namelen;
6550 u_long nameiflags;
6551 int error;
6552 char uio_buf[ UIO_SIZEOF(1) ];
6553
6554 if (uap->options & (XATTR_NOSECURITY | XATTR_NODEFAULT))
6555 return (EINVAL);
6556
6557 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
6558 return (error);
6559 }
6560 if (xattr_protected(attrname))
6561 return(EPERM);
6562 if (uap->size != 0 && uap->value == 0) {
6563 return (EINVAL);
6564 }
6565
6566 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
6567 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, ctx);
6568 if ((error = namei(&nd))) {
6569 return (error);
6570 }
6571 vp = nd.ni_vp;
6572 nameidone(&nd);
6573
6574 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_WRITE,
6575 &uio_buf[0], sizeof(uio_buf));
6576 uio_addiov(auio, uap->value, uap->size);
6577
6578 error = vn_setxattr(vp, attrname, auio, uap->options, ctx);
6579 #if CONFIG_FSE
6580 if (error == 0) {
6581 add_fsevent(FSE_XATTR_MODIFIED, ctx,
6582 FSE_ARG_VNODE, vp,
6583 FSE_ARG_DONE);
6584 }
6585 #endif
6586 vnode_put(vp);
6587 *retval = 0;
6588 return (error);
6589 }
6590
6591 /*
6592 * Set the data of an extended attribute.
6593 */
6594 int
6595 fsetxattr(proc_t p, struct fsetxattr_args *uap, int *retval)
6596 {
6597 vnode_t vp;
6598 char attrname[XATTR_MAXNAMELEN+1];
6599 uio_t auio = NULL;
6600 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6601 size_t namelen;
6602 int error;
6603 char uio_buf[ UIO_SIZEOF(1) ];
6604 vfs_context_t ctx = vfs_context_current();
6605
6606 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY | XATTR_NODEFAULT))
6607 return (EINVAL);
6608
6609 if ((error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen) != 0)) {
6610 return (error);
6611 }
6612 if (xattr_protected(attrname))
6613 return(EPERM);
6614 if (uap->size != 0 && uap->value == 0) {
6615 return (EINVAL);
6616 }
6617 if ( (error = file_vnode(uap->fd, &vp)) ) {
6618 return (error);
6619 }
6620 if ( (error = vnode_getwithref(vp)) ) {
6621 file_drop(uap->fd);
6622 return(error);
6623 }
6624 auio = uio_createwithbuffer(1, uap->position, spacetype, UIO_WRITE,
6625 &uio_buf[0], sizeof(uio_buf));
6626 uio_addiov(auio, uap->value, uap->size);
6627
6628 error = vn_setxattr(vp, attrname, auio, uap->options, vfs_context_current());
6629 #if CONFIG_FSE
6630 if (error == 0) {
6631 add_fsevent(FSE_XATTR_MODIFIED, ctx,
6632 FSE_ARG_VNODE, vp,
6633 FSE_ARG_DONE);
6634 }
6635 #endif
6636 vnode_put(vp);
6637 file_drop(uap->fd);
6638 *retval = 0;
6639 return (error);
6640 }
6641
6642 /*
6643 * Remove an extended attribute.
6644 */
6645 #warning "code duplication"
6646 int
6647 removexattr(proc_t p, struct removexattr_args *uap, int *retval)
6648 {
6649 vnode_t vp;
6650 struct nameidata nd;
6651 char attrname[XATTR_MAXNAMELEN+1];
6652 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6653 vfs_context_t ctx = vfs_context_current();
6654 size_t namelen;
6655 u_long nameiflags;
6656 int error;
6657
6658 if (uap->options & (XATTR_NOSECURITY | XATTR_NODEFAULT))
6659 return (EINVAL);
6660
6661 error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen);
6662 if (error != 0) {
6663 return (error);
6664 }
6665 if (xattr_protected(attrname))
6666 return(EPERM);
6667 nameiflags = (uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW;
6668 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, ctx);
6669 if ((error = namei(&nd))) {
6670 return (error);
6671 }
6672 vp = nd.ni_vp;
6673 nameidone(&nd);
6674
6675 error = vn_removexattr(vp, attrname, uap->options, ctx);
6676 #if CONFIG_FSE
6677 if (error == 0) {
6678 add_fsevent(FSE_XATTR_REMOVED, ctx,
6679 FSE_ARG_VNODE, vp,
6680 FSE_ARG_DONE);
6681 }
6682 #endif
6683 vnode_put(vp);
6684 *retval = 0;
6685 return (error);
6686 }
6687
6688 /*
6689 * Remove an extended attribute.
6690 */
6691 #warning "code duplication"
6692 int
6693 fremovexattr(__unused proc_t p, struct fremovexattr_args *uap, int *retval)
6694 {
6695 vnode_t vp;
6696 char attrname[XATTR_MAXNAMELEN+1];
6697 size_t namelen;
6698 int error;
6699 vfs_context_t ctx = vfs_context_current();
6700
6701 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY | XATTR_NODEFAULT))
6702 return (EINVAL);
6703
6704 error = copyinstr(uap->attrname, attrname, sizeof(attrname), &namelen);
6705 if (error != 0) {
6706 return (error);
6707 }
6708 if (xattr_protected(attrname))
6709 return(EPERM);
6710 if ( (error = file_vnode(uap->fd, &vp)) ) {
6711 return (error);
6712 }
6713 if ( (error = vnode_getwithref(vp)) ) {
6714 file_drop(uap->fd);
6715 return(error);
6716 }
6717
6718 error = vn_removexattr(vp, attrname, uap->options, vfs_context_current());
6719 #if CONFIG_FSE
6720 if (error == 0) {
6721 add_fsevent(FSE_XATTR_REMOVED, ctx,
6722 FSE_ARG_VNODE, vp,
6723 FSE_ARG_DONE);
6724 }
6725 #endif
6726 vnode_put(vp);
6727 file_drop(uap->fd);
6728 *retval = 0;
6729 return (error);
6730 }
6731
6732 /*
6733 * Retrieve the list of extended attribute names.
6734 */
6735 #warning "code duplication"
6736 int
6737 listxattr(proc_t p, struct listxattr_args *uap, user_ssize_t *retval)
6738 {
6739 vnode_t vp;
6740 struct nameidata nd;
6741 vfs_context_t ctx = vfs_context_current();
6742 uio_t auio = NULL;
6743 int spacetype = IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6744 size_t attrsize = 0;
6745 u_long nameiflags;
6746 int error;
6747 char uio_buf[ UIO_SIZEOF(1) ];
6748
6749 if (uap->options & (XATTR_NOSECURITY | XATTR_NODEFAULT))
6750 return (EINVAL);
6751
6752 nameiflags = ((uap->options & XATTR_NOFOLLOW) ? 0 : FOLLOW) | NOTRIGGER;
6753 NDINIT(&nd, LOOKUP, nameiflags, spacetype, uap->path, ctx);
6754 if ((error = namei(&nd))) {
6755 return (error);
6756 }
6757 vp = nd.ni_vp;
6758 nameidone(&nd);
6759 if (uap->namebuf != 0 && uap->bufsize > 0) {
6760 // LP64todo - fix this!
6761 auio = uio_createwithbuffer(1, 0, spacetype,
6762 UIO_READ, &uio_buf[0], sizeof(uio_buf));
6763 uio_addiov(auio, uap->namebuf, uap->bufsize);
6764 }
6765
6766 error = vn_listxattr(vp, auio, &attrsize, uap->options, ctx);
6767
6768 vnode_put(vp);
6769 if (auio) {
6770 *retval = (user_ssize_t)uap->bufsize - uio_resid(auio);
6771 } else {
6772 *retval = (user_ssize_t)attrsize;
6773 }
6774 return (error);
6775 }
6776
6777 /*
6778 * Retrieve the list of extended attribute names.
6779 */
6780 #warning "code duplication"
6781 int
6782 flistxattr(proc_t p, struct flistxattr_args *uap, user_ssize_t *retval)
6783 {
6784 vnode_t vp;
6785 uio_t auio = NULL;
6786 int spacetype = proc_is64bit(p) ? UIO_USERSPACE64 : UIO_USERSPACE32;
6787 size_t attrsize = 0;
6788 int error;
6789 char uio_buf[ UIO_SIZEOF(1) ];
6790
6791 if (uap->options & (XATTR_NOFOLLOW | XATTR_NOSECURITY | XATTR_NODEFAULT))
6792 return (EINVAL);
6793
6794 if ( (error = file_vnode(uap->fd, &vp)) ) {
6795 return (error);
6796 }
6797 if ( (error = vnode_getwithref(vp)) ) {
6798 file_drop(uap->fd);
6799 return(error);
6800 }
6801 if (uap->namebuf != 0 && uap->bufsize > 0) {
6802 // LP64todo - fix this!
6803 auio = uio_createwithbuffer(1, 0, spacetype,
6804 UIO_READ, &uio_buf[0], sizeof(uio_buf));
6805 uio_addiov(auio, uap->namebuf, uap->bufsize);
6806 }
6807
6808 error = vn_listxattr(vp, auio, &attrsize, uap->options, vfs_context_current());
6809
6810 vnode_put(vp);
6811 file_drop(uap->fd);
6812 if (auio) {
6813 *retval = (user_ssize_t)uap->bufsize - uio_resid(auio);
6814 } else {
6815 *retval = (user_ssize_t)attrsize;
6816 }
6817 return (error);
6818 }
6819
6820 /*
6821 * Common routine to handle various flavors of statfs data heading out
6822 * to user space.
6823 *
6824 * Returns: 0 Success
6825 * EFAULT
6826 */
6827 static int
6828 munge_statfs(struct mount *mp, struct vfsstatfs *sfsp,
6829 user_addr_t bufp, int *sizep, boolean_t is_64_bit,
6830 boolean_t partial_copy)
6831 {
6832 int error;
6833 int my_size, copy_size;
6834
6835 if (is_64_bit) {
6836 struct user_statfs sfs;
6837 my_size = copy_size = sizeof(sfs);
6838 bzero(&sfs, my_size);
6839 sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
6840 sfs.f_type = mp->mnt_vtable->vfc_typenum;
6841 sfs.f_reserved1 = (short)sfsp->f_fssubtype;
6842 sfs.f_bsize = (user_long_t)sfsp->f_bsize;
6843 sfs.f_iosize = (user_long_t)sfsp->f_iosize;
6844 sfs.f_blocks = (user_long_t)sfsp->f_blocks;
6845 sfs.f_bfree = (user_long_t)sfsp->f_bfree;
6846 sfs.f_bavail = (user_long_t)sfsp->f_bavail;
6847 sfs.f_files = (user_long_t)sfsp->f_files;
6848 sfs.f_ffree = (user_long_t)sfsp->f_ffree;
6849 sfs.f_fsid = sfsp->f_fsid;
6850 sfs.f_owner = sfsp->f_owner;
6851 strlcpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSNAMELEN);
6852 strlcpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MNAMELEN);
6853 strlcpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MNAMELEN);
6854
6855 if (partial_copy) {
6856 copy_size -= (sizeof(sfs.f_reserved3) + sizeof(sfs.f_reserved4));
6857 }
6858 error = copyout((caddr_t)&sfs, bufp, copy_size);
6859 }
6860 else {
6861 struct statfs sfs;
6862 my_size = copy_size = sizeof(sfs);
6863 bzero(&sfs, my_size);
6864
6865 sfs.f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
6866 sfs.f_type = mp->mnt_vtable->vfc_typenum;
6867 sfs.f_reserved1 = (short)sfsp->f_fssubtype;
6868
6869 /*
6870 * It's possible for there to be more than 2^^31 blocks in the filesystem, so we
6871 * have to fudge the numbers here in that case. We inflate the blocksize in order
6872 * to reflect the filesystem size as best we can.
6873 */
6874 if ((sfsp->f_blocks > LONG_MAX)
6875 /* Hack for 4061702 . I think the real fix is for Carbon to
6876 * look for some volume capability and not depend on hidden
6877 * semantics agreed between a FS and carbon.
6878 * f_blocks, f_bfree, and f_bavail set to -1 is the trigger
6879 * for Carbon to set bNoVolumeSizes volume attribute.
6880 * Without this the webdavfs files cannot be copied onto
6881 * disk as they look huge. This change should not affect
6882 * XSAN as they should not setting these to -1..
6883 */
6884 && (sfsp->f_blocks != 0xffffffffffffffffULL)
6885 && (sfsp->f_bfree != 0xffffffffffffffffULL)
6886 && (sfsp->f_bavail != 0xffffffffffffffffULL)) {
6887 int shift;
6888
6889 /*
6890 * Work out how far we have to shift the block count down to make it fit.
6891 * Note that it's possible to have to shift so far that the resulting
6892 * blocksize would be unreportably large. At that point, we will clip
6893 * any values that don't fit.
6894 *
6895 * For safety's sake, we also ensure that f_iosize is never reported as
6896 * being smaller than f_bsize.
6897 */
6898 for (shift = 0; shift < 32; shift++) {
6899 if ((sfsp->f_blocks >> shift) <= LONG_MAX)
6900 break;
6901 if ((sfsp->f_bsize << (shift + 1)) > LONG_MAX)
6902 break;
6903 }
6904 #define __SHIFT_OR_CLIP(x, s) ((((x) >> (s)) > LONG_MAX) ? LONG_MAX : ((x) >> (s)))
6905 sfs.f_blocks = (long)__SHIFT_OR_CLIP(sfsp->f_blocks, shift);
6906 sfs.f_bfree = (long)__SHIFT_OR_CLIP(sfsp->f_bfree, shift);
6907 sfs.f_bavail = (long)__SHIFT_OR_CLIP(sfsp->f_bavail, shift);
6908 #undef __SHIFT_OR_CLIP
6909 sfs.f_bsize = (long)(sfsp->f_bsize << shift);
6910 sfs.f_iosize = lmax(sfsp->f_iosize, sfsp->f_bsize);
6911 } else {
6912 /* filesystem is small enough to be reported honestly */
6913 sfs.f_bsize = (long)sfsp->f_bsize;
6914 sfs.f_iosize = (long)sfsp->f_iosize;
6915 sfs.f_blocks = (long)sfsp->f_blocks;
6916 sfs.f_bfree = (long)sfsp->f_bfree;
6917 sfs.f_bavail = (long)sfsp->f_bavail;
6918 }
6919 sfs.f_files = (long)sfsp->f_files;
6920 sfs.f_ffree = (long)sfsp->f_ffree;
6921 sfs.f_fsid = sfsp->f_fsid;
6922 sfs.f_owner = sfsp->f_owner;
6923 strlcpy(&sfs.f_fstypename[0], &sfsp->f_fstypename[0], MFSNAMELEN);
6924 strlcpy(&sfs.f_mntonname[0], &sfsp->f_mntonname[0], MNAMELEN);
6925 strlcpy(&sfs.f_mntfromname[0], &sfsp->f_mntfromname[0], MNAMELEN);
6926
6927 if (partial_copy) {
6928 copy_size -= (sizeof(sfs.f_reserved3) + sizeof(sfs.f_reserved4));
6929 }
6930 error = copyout((caddr_t)&sfs, bufp, copy_size);
6931 }
6932
6933 if (sizep != NULL) {
6934 *sizep = my_size;
6935 }
6936 return(error);
6937 }
6938
6939 /*
6940 * copy stat structure into user_stat structure.
6941 */
6942 void munge_stat(struct stat *sbp, struct user_stat *usbp)
6943 {
6944 bzero(usbp, sizeof(struct user_stat));
6945
6946 usbp->st_dev = sbp->st_dev;
6947 usbp->st_ino = sbp->st_ino;
6948 usbp->st_mode = sbp->st_mode;
6949 usbp->st_nlink = sbp->st_nlink;
6950 usbp->st_uid = sbp->st_uid;
6951 usbp->st_gid = sbp->st_gid;
6952 usbp->st_rdev = sbp->st_rdev;
6953 #ifndef _POSIX_C_SOURCE
6954 usbp->st_atimespec.tv_sec = sbp->st_atimespec.tv_sec;
6955 usbp->st_atimespec.tv_nsec = sbp->st_atimespec.tv_nsec;
6956 usbp->st_mtimespec.tv_sec = sbp->st_mtimespec.tv_sec;
6957 usbp->st_mtimespec.tv_nsec = sbp->st_mtimespec.tv_nsec;
6958 usbp->st_ctimespec.tv_sec = sbp->st_ctimespec.tv_sec;
6959 usbp->st_ctimespec.tv_nsec = sbp->st_ctimespec.tv_nsec;
6960 #else
6961 usbp->st_atime = sbp->st_atime;
6962 usbp->st_atimensec = sbp->st_atimensec;
6963 usbp->st_mtime = sbp->st_mtime;
6964 usbp->st_mtimensec = sbp->st_mtimensec;
6965 usbp->st_ctime = sbp->st_ctime;
6966 usbp->st_ctimensec = sbp->st_ctimensec;
6967 #endif
6968 usbp->st_size = sbp->st_size;
6969 usbp->st_blocks = sbp->st_blocks;
6970 usbp->st_blksize = sbp->st_blksize;
6971 usbp->st_flags = sbp->st_flags;
6972 usbp->st_gen = sbp->st_gen;
6973 usbp->st_lspare = sbp->st_lspare;
6974 usbp->st_qspare[0] = sbp->st_qspare[0];
6975 usbp->st_qspare[1] = sbp->st_qspare[1];
6976 }
6977
6978 /*
6979 * copy stat64 structure into user_stat64 structure.
6980 */
6981 void munge_stat64(struct stat64 *sbp, struct user_stat64 *usbp)
6982 {
6983 bzero(usbp, sizeof(struct user_stat));
6984
6985 usbp->st_dev = sbp->st_dev;
6986 usbp->st_ino = sbp->st_ino;
6987 usbp->st_mode = sbp->st_mode;
6988 usbp->st_nlink = sbp->st_nlink;
6989 usbp->st_uid = sbp->st_uid;
6990 usbp->st_gid = sbp->st_gid;
6991 usbp->st_rdev = sbp->st_rdev;
6992 #ifndef _POSIX_C_SOURCE
6993 usbp->st_atimespec.tv_sec = sbp->st_atimespec.tv_sec;
6994 usbp->st_atimespec.tv_nsec = sbp->st_atimespec.tv_nsec;
6995 usbp->st_mtimespec.tv_sec = sbp->st_mtimespec.tv_sec;
6996 usbp->st_mtimespec.tv_nsec = sbp->st_mtimespec.tv_nsec;
6997 usbp->st_ctimespec.tv_sec = sbp->st_ctimespec.tv_sec;
6998 usbp->st_ctimespec.tv_nsec = sbp->st_ctimespec.tv_nsec;
6999 usbp->st_birthtimespec.tv_sec = sbp->st_birthtimespec.tv_sec;
7000 usbp->st_birthtimespec.tv_nsec = sbp->st_birthtimespec.tv_nsec;
7001 #else
7002 usbp->st_atime = sbp->st_atime;
7003 usbp->st_atimensec = sbp->st_atimensec;
7004 usbp->st_mtime = sbp->st_mtime;
7005 usbp->st_mtimensec = sbp->st_mtimensec;
7006 usbp->st_ctime = sbp->st_ctime;
7007 usbp->st_ctimensec = sbp->st_ctimensec;
7008 usbp->st_birthtime = sbp->st_birthtime;
7009 usbp->st_birthtimensec = sbp->st_birthtimensec;
7010 #endif
7011 usbp->st_size = sbp->st_size;
7012 usbp->st_blocks = sbp->st_blocks;
7013 usbp->st_blksize = sbp->st_blksize;
7014 usbp->st_flags = sbp->st_flags;
7015 usbp->st_gen = sbp->st_gen;
7016 usbp->st_lspare = sbp->st_lspare;
7017 usbp->st_qspare[0] = sbp->st_qspare[0];
7018 usbp->st_qspare[1] = sbp->st_qspare[1];
7019 }