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 2006 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 #ifdef C2_AUDIT 108 if (fp->f_flag & FREVOKED) { 109 releasef(fdes); 110 return (set_errno(EBADF)); 111 } 112 #endif /* C2_AUDIT */ 113 114 error = cacl(cmd, nentries, aclbufp, fp->f_vnode, &rv); 115 releasef(fdes); 116 117 if (error) 118 return (set_errno(error)); 119 return (rv); 120 } 121 122 123 /* 124 * Common code for acl() and facl(). 125 */ 126 static int 127 cacl(int cmd, int nentries, void *aclbufp, vnode_t *vp, int *rv) 128 { 129 int error; 130 int aclbsize; /* size of acl list in bytes */ 131 int dfaclbsize; /* size of default acl list in bytes */ 132 int numacls; 133 caddr_t uaddrp; 134 aclent_t *aclp, *aaclp; 135 vsecattr_t vsecattr; 136 137 ASSERT(vp); 138 139 bzero(&vsecattr, sizeof (vsecattr_t)); 140 141 switch (cmd) { 142 143 case ACE_GETACLCNT: 144 case GETACLCNT: 145 if (cmd == GETACLCNT) 146 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 147 else 148 vsecattr.vsa_mask = VSA_ACECNT; 149 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED())) 150 return (error); 151 *rv = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt; 152 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp) { 153 kmem_free(vsecattr.vsa_aclentp, 154 vsecattr.vsa_aclcnt * sizeof (aclent_t)); 155 } 156 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp) { 157 kmem_free(vsecattr.vsa_dfaclentp, 158 vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 159 } 160 break; 161 case GETACL: 162 /* 163 * Minimum ACL size is three entries so might as well 164 * bail out here. 165 */ 166 if (nentries < 3) 167 return (EINVAL); 168 /* 169 * NULL output buffer is also a pretty easy bail out. 170 */ 171 if (aclbufp == NULL) 172 return (EFAULT); 173 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 174 VSA_DFACLCNT; 175 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED())) 176 return (error); 177 /* Check user's buffer is big enough */ 178 numacls = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt; 179 aclbsize = vsecattr.vsa_aclcnt * sizeof (aclent_t); 180 dfaclbsize = vsecattr.vsa_dfaclcnt * sizeof (aclent_t); 181 if (numacls > nentries) { 182 error = ENOSPC; 183 goto errout; 184 } 185 /* Sort the acl & default acl lists */ 186 if (vsecattr.vsa_aclcnt > 1) 187 ksort((caddr_t)vsecattr.vsa_aclentp, 188 vsecattr.vsa_aclcnt, sizeof (aclent_t), cmp2acls); 189 if (vsecattr.vsa_dfaclcnt > 1) 190 ksort((caddr_t)vsecattr.vsa_dfaclentp, 191 vsecattr.vsa_dfaclcnt, sizeof (aclent_t), cmp2acls); 192 /* Copy out acl's */ 193 uaddrp = (caddr_t)aclbufp; 194 if (aclbsize > 0) { /* bug #1262490 */ 195 if (copyout(vsecattr.vsa_aclentp, uaddrp, aclbsize)) { 196 error = EFAULT; 197 goto errout; 198 } 199 } 200 /* Copy out default acl's */ 201 if (dfaclbsize > 0) { 202 uaddrp += aclbsize; 203 if (copyout(vsecattr.vsa_dfaclentp, 204 uaddrp, dfaclbsize)) { 205 error = EFAULT; 206 goto errout; 207 } 208 } 209 *rv = numacls; 210 if (vsecattr.vsa_aclcnt) { 211 kmem_free(vsecattr.vsa_aclentp, 212 vsecattr.vsa_aclcnt * sizeof (aclent_t)); 213 } 214 if (vsecattr.vsa_dfaclcnt) { 215 kmem_free(vsecattr.vsa_dfaclentp, 216 vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 217 } 218 break; 219 220 case ACE_GETACL: 221 if (aclbufp == NULL) 222 return (EFAULT); 223 224 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT; 225 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED())) 226 return (error); 227 228 aclbsize = vsecattr.vsa_aclcnt * sizeof (ace_t); 229 if (vsecattr.vsa_aclcnt > nentries) { 230 error = ENOSPC; 231 goto errout; 232 } 233 234 if (aclbsize > 0) { 235 if ((error = copyout(vsecattr.vsa_aclentp, 236 aclbufp, aclbsize)) != 0) { 237 goto errout; 238 } 239 } 240 241 *rv = vsecattr.vsa_aclcnt; 242 if (vsecattr.vsa_aclcnt) { 243 kmem_free(vsecattr.vsa_aclentp, 244 vsecattr.vsa_aclcnt * sizeof (ace_t)); 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())) { 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 uaddrp = (caddr_t)aclbufp; 331 if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) { 332 kmem_free(aaclp, aclbsize); 333 return (EFAULT); 334 } 335 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 336 if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED())) { 337 kmem_free(aaclp, aclbsize); 338 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 339 return (error); 340 } 341 *rv = 0; 342 kmem_free(aaclp, aclbsize); 343 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 344 break; 345 346 default: 347 return (EINVAL); 348 } 349 350 return (0); 351 352 errout: 353 if (aclbsize && vsecattr.vsa_aclentp) 354 kmem_free(vsecattr.vsa_aclentp, aclbsize); 355 if (dfaclbsize && vsecattr.vsa_dfaclentp) 356 kmem_free(vsecattr.vsa_dfaclentp, dfaclbsize); 357 return (error); 358 } 359