Home | History | Annotate | Download | only in syscall
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  2051  prabahar  * Common Development and Distribution License (the "License").
      6  2051  prabahar  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21     0    stevel /*
     22  5331       amw  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23     0    stevel  * Use is subject to license terms.
     24     0    stevel  */
     25     0    stevel 
     26     0    stevel /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
     27     0    stevel /*	  All Rights Reserved  	*/
     28     0    stevel 
     29     0    stevel /*
     30     0    stevel  * Portions of this source code were derived from Berkeley 4.3 BSD
     31     0    stevel  * under license from the Regents of the University of California.
     32     0    stevel  */
     33     0    stevel 
     34     0    stevel #pragma ident	"%Z%%M%	%I%	%E% SMI"
     35     0    stevel 
     36     0    stevel #include <sys/param.h>
     37     0    stevel #include <sys/isa_defs.h>
     38     0    stevel #include <sys/types.h>
     39     0    stevel #include <sys/sysmacros.h>
     40     0    stevel #include <sys/cred.h>
     41     0    stevel #include <sys/user.h>
     42     0    stevel #include <sys/systm.h>
     43     0    stevel #include <sys/errno.h>
     44     0    stevel #include <sys/fcntl.h>
     45     0    stevel #include <sys/pathname.h>
     46     0    stevel #include <sys/var.h>
     47     0    stevel #include <sys/vfs.h>
     48     0    stevel #include <sys/vnode.h>
     49     0    stevel #include <sys/file.h>
     50     0    stevel #include <sys/mode.h>
     51     0    stevel #include <sys/proc.h>
     52     0    stevel #include <sys/uio.h>
     53     0    stevel #include <sys/poll.h>
     54     0    stevel #include <sys/kmem.h>
     55     0    stevel #include <sys/filio.h>
     56     0    stevel #include <sys/cmn_err.h>
     57     0    stevel #include <sys/policy.h>
     58     0    stevel #include <sys/zone.h>
     59     0    stevel 
     60     0    stevel #include <sys/debug.h>
     61     0    stevel #include <c2/audit.h>
     62  2051  prabahar #include <fs/fs_subr.h>
     63     0    stevel 
     64     0    stevel /*
     65     0    stevel  * Change current working directory (".").
     66     0    stevel  */
     67     0    stevel static int	chdirec(vnode_t *, int ischroot, int do_traverse);
     68     0    stevel 
     69     0    stevel int
     70     0    stevel chdir(char *fname)
     71     0    stevel {
     72     0    stevel 	vnode_t *vp;
     73     0    stevel 	int error;
     74  2051  prabahar 	int estale_retry = 0;
     75     0    stevel 
     76     0    stevel lookup:
     77     0    stevel 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
     78  2051  prabahar 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
     79     0    stevel 			goto lookup;
     80     0    stevel 		return (set_errno(error));
     81     0    stevel 	}
     82     0    stevel 
     83     0    stevel 	error = chdirec(vp, 0, 1);
     84     0    stevel 	if (error) {
     85  2051  prabahar 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
     86     0    stevel 			goto lookup;
     87     0    stevel 		return (set_errno(error));
     88     0    stevel 	}
     89     0    stevel 	return (0);
     90     0    stevel }
     91     0    stevel 
     92     0    stevel /*
     93     0    stevel  * File-descriptor based version of 'chdir'.
     94     0    stevel  */
     95     0    stevel int
     96     0    stevel fchdir(int fd)
     97     0    stevel {
     98     0    stevel 	vnode_t *vp;
     99     0    stevel 	file_t *fp;
    100     0    stevel 	int error;
    101     0    stevel 
    102     0    stevel 	if ((fp = getf(fd)) == NULL)
    103     0    stevel 		return (set_errno(EBADF));
    104     0    stevel 	vp = fp->f_vnode;
    105     0    stevel 	VN_HOLD(vp);
    106     0    stevel 	releasef(fd);
    107     0    stevel 	error = chdirec(vp, 0, 0);
    108     0    stevel 	if (error)
    109     0    stevel 		return (set_errno(error));
    110     0    stevel 	return (0);
    111     0    stevel }
    112     0    stevel 
    113     0    stevel /*
    114     0    stevel  * Change notion of root ("/") directory.
    115     0    stevel  */
    116     0    stevel int
    117     0    stevel chroot(char *fname)
    118     0    stevel {
    119     0    stevel 	vnode_t *vp;
    120     0    stevel 	int error;
    121  2051  prabahar 	int estale_retry = 0;
    122     0    stevel 
    123     0    stevel lookup:
    124     0    stevel 	if (error = lookupname(fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp)) {
    125  2051  prabahar 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
    126     0    stevel 			goto lookup;
    127     0    stevel 		return (set_errno(error));
    128     0    stevel 	}
    129     0    stevel 
    130     0    stevel 	error = chdirec(vp, 1, 1);
    131     0    stevel 	if (error) {
    132  2051  prabahar 		if ((error == ESTALE) && fs_need_estale_retry(estale_retry++))
    133     0    stevel 			goto lookup;
    134     0    stevel 		return (set_errno(error));
    135     0    stevel 	}
    136     0    stevel 	return (0);
    137     0    stevel }
    138     0    stevel 
    139     0    stevel /*
    140     0    stevel  *	++++++++++++++++++++++++
    141     0    stevel  *	++  SunOS4.1 Buyback  ++
    142     0    stevel  *	++++++++++++++++++++++++
    143     0    stevel  * Change root directory with a user given fd
    144     0    stevel  */
    145     0    stevel int
    146     0    stevel fchroot(int fd)
    147     0    stevel {
    148     0    stevel 	vnode_t *vp;
    149     0    stevel 	file_t *fp;
    150     0    stevel 	int error;
    151     0    stevel 
    152     0    stevel 	if ((fp = getf(fd)) == NULL)
    153     0    stevel 		return (set_errno(EBADF));
    154     0    stevel 	vp = fp->f_vnode;
    155     0    stevel 	VN_HOLD(vp);
    156     0    stevel 	releasef(fd);
    157     0    stevel 	error = chdirec(vp, 1, 0);
    158     0    stevel 	if (error)
    159     0    stevel 		return (set_errno(error));
    160     0    stevel 	return (0);
    161     0    stevel }
    162     0    stevel 
    163     0    stevel static int
    164     0    stevel chdirec(vnode_t *vp, int ischroot, int do_traverse)
    165     0    stevel {
    166     0    stevel 	int error;
    167     0    stevel 	vnode_t *oldvp;
    168     0    stevel 	proc_t *pp = curproc;
    169     0    stevel 	vnode_t **vpp;
    170     0    stevel 	refstr_t *cwd;
    171     0    stevel 	int newcwd = 1;
    172     0    stevel 
    173     0    stevel 	if (vp->v_type != VDIR) {
    174     0    stevel 		error = ENOTDIR;
    175     0    stevel 		goto bad;
    176     0    stevel 	}
    177  5331       amw 	if (error = VOP_ACCESS(vp, VEXEC, 0, CRED(), NULL))
    178     0    stevel 		goto bad;
    179     0    stevel 
    180     0    stevel 	/*
    181     0    stevel 	 * The VOP_ACCESS() may have covered 'vp' with a new filesystem,
    182     0    stevel 	 * if 'vp' is an autoFS vnode. Traverse the mountpoint so
    183     0    stevel 	 * that we don't end up with a covered current directory.
    184     0    stevel 	 */
    185     0    stevel 	if (vn_mountedvfs(vp) != NULL && do_traverse) {
    186     0    stevel 		if (error = traverse(&vp))
    187     0    stevel 			goto bad;
    188     0    stevel 	}
    189     0    stevel 
    190     0    stevel 	/*
    191     0    stevel 	 * Special chroot semantics: chroot is allowed if privileged
    192     0    stevel 	 * or if the target is really a loopback mount of the root (or
    193     0    stevel 	 * root of the zone) as determined by comparing dev and inode
    194     0    stevel 	 * numbers
    195     0    stevel 	 */
    196     0    stevel 	if (ischroot) {
    197     0    stevel 		struct vattr tattr;
    198     0    stevel 		struct vattr rattr;
    199     0    stevel 		vnode_t *zonevp = curproc->p_zone->zone_rootvp;
    200     0    stevel 
    201     0    stevel 		tattr.va_mask = AT_FSID|AT_NODEID;
    202  5331       amw 		if (error = VOP_GETATTR(vp, &tattr, 0, CRED(), NULL))
    203     0    stevel 			goto bad;
    204     0    stevel 
    205     0    stevel 		rattr.va_mask = AT_FSID|AT_NODEID;
    206  5331       amw 		if (error = VOP_GETATTR(zonevp, &rattr, 0, CRED(), NULL))
    207     0    stevel 			goto bad;
    208     0    stevel 
    209     0    stevel 		if ((tattr.va_fsid != rattr.va_fsid ||
    210     0    stevel 		    tattr.va_nodeid != rattr.va_nodeid) &&
    211     0    stevel 		    (error = secpolicy_chroot(CRED())) != 0)
    212     0    stevel 			goto bad;
    213     0    stevel 
    214     0    stevel 		vpp = &PTOU(pp)->u_rdir;
    215     0    stevel 	} else {
    216     0    stevel 		vpp = &PTOU(pp)->u_cdir;
    217     0    stevel 	}
    218     0    stevel 
    219     0    stevel 	if (audit_active)	/* update abs cwd/root path see c2audit.c */
    220     0    stevel 		audit_chdirec(vp, vpp);
    221     0    stevel 
    222     0    stevel 	mutex_enter(&pp->p_lock);
    223     0    stevel 	/*
    224     0    stevel 	 * This bit of logic prevents us from overwriting u_cwd if we are
    225     0    stevel 	 * changing to the same directory.  We set the cwd to NULL so that we
    226     0    stevel 	 * don't try to do the lookup on the next call to getcwd().
    227     0    stevel 	 */
    228     0    stevel 	if (!ischroot && *vpp != NULL && vp != NULL && VN_CMP(*vpp, vp))
    229     0    stevel 		newcwd = 0;
    230     0    stevel 
    231     0    stevel 	oldvp = *vpp;
    232     0    stevel 	*vpp = vp;
    233     0    stevel 	if ((cwd = PTOU(pp)->u_cwd) != NULL && newcwd)
    234     0    stevel 		PTOU(pp)->u_cwd = NULL;
    235     0    stevel 	mutex_exit(&pp->p_lock);
    236     0    stevel 
    237     0    stevel 	if (cwd && newcwd)
    238     0    stevel 		refstr_rele(cwd);
    239     0    stevel 	if (oldvp)
    240     0    stevel 		VN_RELE(oldvp);
    241     0    stevel 	return (0);
    242     0    stevel 
    243     0    stevel bad:
    244     0    stevel 	VN_RELE(vp);
    245     0    stevel 	return (error);
    246     0    stevel }
    247