1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 /* 30 * Portions of this source code were derived from Berkeley 4.3 BSD 31 * under license from the Regents of the University of California. 32 */ 33 34 #include <sys/param.h> 35 #include <sys/isa_defs.h> 36 #include <sys/types.h> 37 #include <sys/sysmacros.h> 38 #include <sys/cred.h> 39 #include <sys/systm.h> 40 #include <sys/errno.h> 41 #include <sys/fcntl.h> 42 #include <sys/pathname.h> 43 #include <sys/vfs.h> 44 #include <sys/vnode.h> 45 #include <sys/file.h> 46 #include <sys/mode.h> 47 #include <sys/uio.h> 48 #include <sys/kmem.h> 49 #include <sys/filio.h> 50 #include <sys/acl.h> 51 #include <sys/cmn_err.h> 52 #include <acl/acl_common.h> 53 54 #include <sys/unistd.h> 55 #include <sys/debug.h> 56 #include <fs/fs_subr.h> 57 58 static int cacl(int cmd, int nentries, void *aclbufp, 59 vnode_t *vp, int *rv); 60 61 /* 62 * Get/Set ACL of a file. 63 */ 64 int 65 acl(const char *fname, int cmd, int nentries, void *aclbufp) 66 { 67 struct vnode *vp; 68 int error; 69 int rv = 0; 70 int estale_retry = 0; 71 72 /* Sanity check arguments */ 73 if (fname == NULL) 74 return (set_errno(EINVAL)); 75 lookup: 76 error = lookupname((char *)fname, UIO_USERSPACE, FOLLOW, NULLVPP, &vp); 77 if (error) { 78 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 79 goto lookup; 80 return (set_errno(error)); 81 } 82 83 error = cacl(cmd, nentries, aclbufp, vp, &rv); 84 VN_RELE(vp); 85 if (error) { 86 if ((error == ESTALE) && fs_need_estale_retry(estale_retry++)) 87 goto lookup; 88 return (set_errno(error)); 89 } 90 return (rv); 91 } 92 93 /* 94 * Get/Set ACL of a file with facl system call. 95 */ 96 int 97 facl(int fdes, int cmd, int nentries, void *aclbufp) 98 { 99 file_t *fp; 100 int error; 101 int rv = 0; 102 103 if ((fp = getf(fdes)) == NULL) 104 return (set_errno(EBADF)); 105 if (fp->f_flag & FREVOKED) { 106 releasef(fdes); 107 return (set_errno(EBADF)); 108 } 109 110 error = cacl(cmd, nentries, aclbufp, fp->f_vnode, &rv); 111 releasef(fdes); 112 113 if (error) 114 return (set_errno(error)); 115 return (rv); 116 } 117 118 119 /* 120 * Common code for acl() and facl(). 121 */ 122 static int 123 cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv) 124 { 125 int error; 126 int aclbsize; /* size of acl list in bytes */ 127 int dfaclbsize; /* size of default acl list in bytes */ 128 int numacls; 129 caddr_t uaddrp; 130 aclent_t *aclp, *aaclp; 131 vsecattr_t vsecattr; 132 size_t entry_size; 133 134 ASSERT(vp); 135 136 bzero(&vsecattr, sizeof (vsecattr_t)); 137 dfaclbsize = 0; 138 139 switch (cmd) { 140 141 case ACE_GETACLCNT: 142 case GETACLCNT: 143 if (cmd == GETACLCNT) { 144 entry_size = sizeof (aclent_t); 145 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 146 } else { 147 entry_size = sizeof (ace_t); 148 vsecattr.vsa_mask = VSA_ACECNT; 149 } 150 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) 151 return (error); 152 *rv = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt; 153 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp) { 154 kmem_free(vsecattr.vsa_aclentp, 155 vsecattr.vsa_aclcnt * entry_size); 156 } 157 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp) { 158 kmem_free(vsecattr.vsa_dfaclentp, 159 vsecattr.vsa_dfaclcnt * entry_size); 160 } 161 break; 162 case GETACL: 163 /* 164 * Minimum ACL size is three entries so might as well 165 * bail out here. 166 */ 167 if (nentries < 3) 168 return (EINVAL); 169 /* 170 * NULL output buffer is also a pretty easy bail out. 171 */ 172 if (aclbufp == NULL) 173 return (EFAULT); 174 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 175 VSA_DFACLCNT; 176 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) 177 return (error); 178 /* Check user's buffer is big enough */ 179 numacls = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt; 180 aclbsize = vsecattr.vsa_aclcnt * sizeof (aclent_t); 181 dfaclbsize = vsecattr.vsa_dfaclcnt * sizeof (aclent_t); 182 if (numacls > nentries) { 183 error = ENOSPC; 184 goto errout; 185 } 186 /* Sort the acl & default acl lists */ 187 if (vsecattr.vsa_aclcnt > 1) 188 ksort((caddr_t)vsecattr.vsa_aclentp, 189 vsecattr.vsa_aclcnt, sizeof (aclent_t), cmp2acls); 190 if (vsecattr.vsa_dfaclcnt > 1) 191 ksort((caddr_t)vsecattr.vsa_dfaclentp, 192 vsecattr.vsa_dfaclcnt, sizeof (aclent_t), cmp2acls); 193 /* Copy out acl's */ 194 uaddrp = (caddr_t)aclbufp; 195 if (aclbsize > 0) { /* bug #1262490 */ 196 if (copyout(vsecattr.vsa_aclentp, uaddrp, aclbsize)) { 197 error = EFAULT; 198 goto errout; 199 } 200 } 201 /* Copy out default acl's */ 202 if (dfaclbsize > 0) { 203 uaddrp += aclbsize; 204 if (copyout(vsecattr.vsa_dfaclentp, 205 uaddrp, dfaclbsize)) { 206 error = EFAULT; 207 goto errout; 208 } 209 } 210 *rv = numacls; 211 if (vsecattr.vsa_aclcnt) { 212 kmem_free(vsecattr.vsa_aclentp, 213 vsecattr.vsa_aclcnt * sizeof (aclent_t)); 214 } 215 if (vsecattr.vsa_dfaclcnt) { 216 kmem_free(vsecattr.vsa_dfaclentp, 217 vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 218 } 219 break; 220 221 case ACE_GETACL: 222 if (aclbufp == NULL) 223 return (EFAULT); 224 225 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT; 226 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) 227 return (error); 228 229 aclbsize = vsecattr.vsa_aclcnt * sizeof (ace_t); 230 if (vsecattr.vsa_aclcnt > nentries) { 231 error = ENOSPC; 232 goto errout; 233 } 234 235 if (aclbsize > 0) { 236 if ((error = copyout(vsecattr.vsa_aclentp, 237 aclbufp, aclbsize)) != 0) { 238 goto errout; 239 } 240 } 241 242 *rv = vsecattr.vsa_aclcnt; 243 if (vsecattr.vsa_aclcnt) { 244 kmem_free(vsecattr.vsa_aclentp, vsecattr.vsa_aclentsz); 245 } 246 break; 247 248 case SETACL: 249 /* 250 * Minimum ACL size is three entries so might as well 251 * bail out here. Also limit request size to prevent user 252 * from allocating too much kernel memory. Maximum size 253 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES 254 * for the default ACL part. (bug 4058667) 255 */ 256 if (nentries < 3 || nentries > (MAX_ACL_ENTRIES * 2)) 257 return (EINVAL); 258 /* 259 * NULL output buffer is also an easy bail out. 260 */ 261 if (aclbufp == NULL) 262 return (EFAULT); 263 vsecattr.vsa_mask = VSA_ACL; 264 aclbsize = nentries * sizeof (aclent_t); 265 vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP); 266 aaclp = vsecattr.vsa_aclentp; 267 vsecattr.vsa_aclcnt = nentries; 268 uaddrp = (caddr_t)aclbufp; 269 if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) { 270 kmem_free(aaclp, aclbsize); 271 return (EFAULT); 272 } 273 /* Sort the acl list */ 274 ksort((caddr_t)vsecattr.vsa_aclentp, 275 vsecattr.vsa_aclcnt, sizeof (aclent_t), cmp2acls); 276 277 /* Break into acl and default acl lists */ 278 for (numacls = 0, aclp = vsecattr.vsa_aclentp; 279 numacls < vsecattr.vsa_aclcnt; 280 aclp++, numacls++) { 281 if (aclp->a_type & ACL_DEFAULT) 282 break; 283 } 284 285 /* Find where defaults start (if any) */ 286 if (numacls < vsecattr.vsa_aclcnt) { 287 vsecattr.vsa_mask |= VSA_DFACL; 288 vsecattr.vsa_dfaclcnt = nentries - numacls; 289 vsecattr.vsa_dfaclentp = aclp; 290 vsecattr.vsa_aclcnt = numacls; 291 } 292 /* Adjust if they're all defaults */ 293 if (vsecattr.vsa_aclcnt == 0) { 294 vsecattr.vsa_mask &= ~VSA_ACL; 295 vsecattr.vsa_aclentp = NULL; 296 } 297 /* Only directories can have defaults */ 298 if (vsecattr.vsa_dfaclcnt && vp->v_type != VDIR) { 299 kmem_free(aaclp, aclbsize); 300 return (ENOTDIR); 301 } 302 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 303 if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) { 304 kmem_free(aaclp, aclbsize); 305 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 306 return (error); 307 } 308 309 /* 310 * Should return 0 upon success according to the man page 311 * and SVR4 semantics. (Bug #1214399: SETACL returns wrong rc) 312 */ 313 *rv = 0; 314 kmem_free(aaclp, aclbsize); 315 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 316 break; 317 318 case ACE_SETACL: 319 if (nentries < 1 || nentries > MAX_ACL_ENTRIES) 320 return (EINVAL); 321 322 if (aclbufp == NULL) 323 return (EFAULT); 324 325 vsecattr.vsa_mask = VSA_ACE; 326 aclbsize = nentries * sizeof (ace_t); 327 vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP); 328 aaclp = vsecattr.vsa_aclentp; 329 vsecattr.vsa_aclcnt = nentries; 330 vsecattr.vsa_aclentsz = aclbsize; 331 uaddrp = (caddr_t)aclbufp; 332 if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) { 333 kmem_free(aaclp, aclbsize); 334 return (EFAULT); 335 } 336 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 337 if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) { 338 kmem_free(aaclp, aclbsize); 339 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 340 return (error); 341 } 342 *rv = 0; 343 kmem_free(aaclp, aclbsize); 344 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 345 break; 346 347 default: 348 return (EINVAL); 349 } 350 351 return (0); 352 353 errout: 354 if (aclbsize && vsecattr.vsa_aclentp) 355 kmem_free(vsecattr.vsa_aclentp, aclbsize); 356 if (dfaclbsize && vsecattr.vsa_dfaclentp) 357 kmem_free(vsecattr.vsa_dfaclentp, dfaclbsize); 358 return (error); 359 } 360