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