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