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