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 #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 size_t entry_size; 137 138 ASSERT(vp); 139 140 bzero(&vsecattr, sizeof (vsecattr_t)); 141 142 switch (cmd) { 143 144 case ACE_GETACLCNT: 145 case GETACLCNT: 146 if (cmd == GETACLCNT) { 147 entry_size = sizeof (aclent_t); 148 vsecattr.vsa_mask = VSA_ACLCNT | VSA_DFACLCNT; 149 } else { 150 entry_size = sizeof (ace_t); 151 vsecattr.vsa_mask = VSA_ACECNT; 152 } 153 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) 154 return (error); 155 *rv = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt; 156 if (vsecattr.vsa_aclcnt && vsecattr.vsa_aclentp) { 157 kmem_free(vsecattr.vsa_aclentp, 158 vsecattr.vsa_aclcnt * entry_size); 159 } 160 if (vsecattr.vsa_dfaclcnt && vsecattr.vsa_dfaclentp) { 161 kmem_free(vsecattr.vsa_dfaclentp, 162 vsecattr.vsa_dfaclcnt * entry_size); 163 } 164 break; 165 case GETACL: 166 /* 167 * Minimum ACL size is three entries so might as well 168 * bail out here. 169 */ 170 if (nentries < 3) 171 return (EINVAL); 172 /* 173 * NULL output buffer is also a pretty easy bail out. 174 */ 175 if (aclbufp == NULL) 176 return (EFAULT); 177 vsecattr.vsa_mask = VSA_ACL | VSA_ACLCNT | VSA_DFACL | 178 VSA_DFACLCNT; 179 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) 180 return (error); 181 /* Check user's buffer is big enough */ 182 numacls = vsecattr.vsa_aclcnt + vsecattr.vsa_dfaclcnt; 183 aclbsize = vsecattr.vsa_aclcnt * sizeof (aclent_t); 184 dfaclbsize = vsecattr.vsa_dfaclcnt * sizeof (aclent_t); 185 if (numacls > nentries) { 186 error = ENOSPC; 187 goto errout; 188 } 189 /* Sort the acl & default acl lists */ 190 if (vsecattr.vsa_aclcnt > 1) 191 ksort((caddr_t)vsecattr.vsa_aclentp, 192 vsecattr.vsa_aclcnt, sizeof (aclent_t), cmp2acls); 193 if (vsecattr.vsa_dfaclcnt > 1) 194 ksort((caddr_t)vsecattr.vsa_dfaclentp, 195 vsecattr.vsa_dfaclcnt, sizeof (aclent_t), cmp2acls); 196 /* Copy out acl's */ 197 uaddrp = (caddr_t)aclbufp; 198 if (aclbsize > 0) { /* bug #1262490 */ 199 if (copyout(vsecattr.vsa_aclentp, uaddrp, aclbsize)) { 200 error = EFAULT; 201 goto errout; 202 } 203 } 204 /* Copy out default acl's */ 205 if (dfaclbsize > 0) { 206 uaddrp += aclbsize; 207 if (copyout(vsecattr.vsa_dfaclentp, 208 uaddrp, dfaclbsize)) { 209 error = EFAULT; 210 goto errout; 211 } 212 } 213 *rv = numacls; 214 if (vsecattr.vsa_aclcnt) { 215 kmem_free(vsecattr.vsa_aclentp, 216 vsecattr.vsa_aclcnt * sizeof (aclent_t)); 217 } 218 if (vsecattr.vsa_dfaclcnt) { 219 kmem_free(vsecattr.vsa_dfaclentp, 220 vsecattr.vsa_dfaclcnt * sizeof (aclent_t)); 221 } 222 break; 223 224 case ACE_GETACL: 225 if (aclbufp == NULL) 226 return (EFAULT); 227 228 vsecattr.vsa_mask = VSA_ACE | VSA_ACECNT; 229 if (error = VOP_GETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) 230 return (error); 231 232 aclbsize = vsecattr.vsa_aclcnt * sizeof (ace_t); 233 if (vsecattr.vsa_aclcnt > nentries) { 234 error = ENOSPC; 235 goto errout; 236 } 237 238 if (aclbsize > 0) { 239 if ((error = copyout(vsecattr.vsa_aclentp, 240 aclbufp, aclbsize)) != 0) { 241 goto errout; 242 } 243 } 244 245 *rv = vsecattr.vsa_aclcnt; 246 if (vsecattr.vsa_aclcnt) { 247 kmem_free(vsecattr.vsa_aclentp, vsecattr.vsa_aclentsz); 248 } 249 break; 250 251 case SETACL: 252 /* 253 * Minimum ACL size is three entries so might as well 254 * bail out here. Also limit request size to prevent user 255 * from allocating too much kernel memory. Maximum size 256 * is MAX_ACL_ENTRIES for the ACL part and MAX_ACL_ENTRIES 257 * for the default ACL part. (bug 4058667) 258 */ 259 if (nentries < 3 || nentries > (MAX_ACL_ENTRIES * 2)) 260 return (EINVAL); 261 /* 262 * NULL output buffer is also an easy bail out. 263 */ 264 if (aclbufp == NULL) 265 return (EFAULT); 266 vsecattr.vsa_mask = VSA_ACL; 267 aclbsize = nentries * sizeof (aclent_t); 268 vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP); 269 aaclp = vsecattr.vsa_aclentp; 270 vsecattr.vsa_aclcnt = nentries; 271 uaddrp = (caddr_t)aclbufp; 272 if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) { 273 kmem_free(aaclp, aclbsize); 274 return (EFAULT); 275 } 276 /* Sort the acl list */ 277 ksort((caddr_t)vsecattr.vsa_aclentp, 278 vsecattr.vsa_aclcnt, sizeof (aclent_t), cmp2acls); 279 280 /* Break into acl and default acl lists */ 281 for (numacls = 0, aclp = vsecattr.vsa_aclentp; 282 numacls < vsecattr.vsa_aclcnt; 283 aclp++, numacls++) { 284 if (aclp->a_type & ACL_DEFAULT) 285 break; 286 } 287 288 /* Find where defaults start (if any) */ 289 if (numacls < vsecattr.vsa_aclcnt) { 290 vsecattr.vsa_mask |= VSA_DFACL; 291 vsecattr.vsa_dfaclcnt = nentries - numacls; 292 vsecattr.vsa_dfaclentp = aclp; 293 vsecattr.vsa_aclcnt = numacls; 294 } 295 /* Adjust if they're all defaults */ 296 if (vsecattr.vsa_aclcnt == 0) { 297 vsecattr.vsa_mask &= ~VSA_ACL; 298 vsecattr.vsa_aclentp = NULL; 299 } 300 /* Only directories can have defaults */ 301 if (vsecattr.vsa_dfaclcnt && vp->v_type != VDIR) { 302 kmem_free(aaclp, aclbsize); 303 return (ENOTDIR); 304 } 305 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 306 if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) { 307 kmem_free(aaclp, aclbsize); 308 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 309 return (error); 310 } 311 312 /* 313 * Should return 0 upon success according to the man page 314 * and SVR4 semantics. (Bug #1214399: SETACL returns wrong rc) 315 */ 316 *rv = 0; 317 kmem_free(aaclp, aclbsize); 318 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 319 break; 320 321 case ACE_SETACL: 322 if (nentries < 1 || nentries > MAX_ACL_ENTRIES) 323 return (EINVAL); 324 325 if (aclbufp == NULL) 326 return (EFAULT); 327 328 vsecattr.vsa_mask = VSA_ACE; 329 aclbsize = nentries * sizeof (ace_t); 330 vsecattr.vsa_aclentp = kmem_alloc(aclbsize, KM_SLEEP); 331 aaclp = vsecattr.vsa_aclentp; 332 vsecattr.vsa_aclcnt = nentries; 333 vsecattr.vsa_aclentsz = aclbsize; 334 uaddrp = (caddr_t)aclbufp; 335 if (copyin(uaddrp, vsecattr.vsa_aclentp, aclbsize)) { 336 kmem_free(aaclp, aclbsize); 337 return (EFAULT); 338 } 339 (void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL); 340 if (error = VOP_SETSECATTR(vp, &vsecattr, 0, CRED(), NULL)) { 341 kmem_free(aaclp, aclbsize); 342 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 343 return (error); 344 } 345 *rv = 0; 346 kmem_free(aaclp, aclbsize); 347 VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL); 348 break; 349 350 default: 351 return (EINVAL); 352 } 353 354 return (0); 355 356 errout: 357 if (aclbsize && vsecattr.vsa_aclentp) 358 kmem_free(vsecattr.vsa_aclentp, aclbsize); 359 if (dfaclbsize && vsecattr.vsa_dfaclentp) 360 kmem_free(vsecattr.vsa_dfaclentp, dfaclbsize); 361 return (error); 362 } 363