ufs_acl.c (184629) | ufs_acl.c (192586) |
---|---|
1/*- 2 * Copyright (c) 1999-2003 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 17 unchanged lines hidden (view full) --- 26 * SUCH DAMAGE. 27 */ 28 29/* 30 * Support for POSIX.1e access control lists: UFS-specific support functions. 31 */ 32 33#include <sys/cdefs.h> | 1/*- 2 * Copyright (c) 1999-2003 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * This software was developed by Robert Watson for the TrustedBSD Project. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions --- 17 unchanged lines hidden (view full) --- 26 * SUCH DAMAGE. 27 */ 28 29/* 30 * Support for POSIX.1e access control lists: UFS-specific support functions. 31 */ 32 33#include <sys/cdefs.h> |
34__FBSDID("$FreeBSD: head/sys/ufs/ufs/ufs_acl.c 184629 2008-11-04 12:30:31Z trasz $"); | 34__FBSDID("$FreeBSD: head/sys/ufs/ufs/ufs_acl.c 192586 2009-05-22 15:56:43Z trasz $"); |
35 36#include "opt_ufs.h" 37#include "opt_quota.h" 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/stat.h> 42#include <sys/mount.h> --- 93 unchanged lines hidden (view full) --- 136{ 137 138 ip->i_mode &= ACL_PRESERVE_MASK; 139 ip->i_mode |= acl_posix1e_acl_to_mode(acl); 140 DIP_SET(ip, i_mode, ip->i_mode); 141} 142 143/* | 35 36#include "opt_ufs.h" 37#include "opt_quota.h" 38 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/stat.h> 42#include <sys/mount.h> --- 93 unchanged lines hidden (view full) --- 136{ 137 138 ip->i_mode &= ACL_PRESERVE_MASK; 139 ip->i_mode |= acl_posix1e_acl_to_mode(acl); 140 DIP_SET(ip, i_mode, ip->i_mode); 141} 142 143/* |
144 * Read POSIX.1e ACL from an EA. Return error if its not found 145 * or if any other error has occured. 146 */ 147static int 148ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp, 149 struct thread *td) 150{ 151 int error, len; 152 struct inode *ip = VTOI(vp); 153 154 len = sizeof(*old); 155 156 switch (type) { 157 case ACL_TYPE_ACCESS: 158 error = vn_extattr_get(vp, IO_NODELOCKED, 159 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 160 POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) old, 161 td); 162 break; 163 case ACL_TYPE_DEFAULT: 164 if (vp->v_type != VDIR) 165 return (EINVAL); 166 error = vn_extattr_get(vp, IO_NODELOCKED, 167 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 168 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, (char *) old, 169 td); 170 break; 171 default: 172 return (EINVAL); 173 } 174 175 if (error != 0) 176 return (error); 177 178 if (len != sizeof(*old)) { 179 /* 180 * A short (or long) read, meaning that for some reason 181 * the ACL is corrupted. Return EPERM since the object 182 * DAC protections are unsafe. 183 */ 184 printf("ufs_get_oldacl(): Loaded invalid ACL " 185 "(len = %d), inumber %d on %s\n", len, 186 ip->i_number, ip->i_fs->fs_fsmnt); 187 return (EPERM); 188 } 189 190 return (0); 191} 192 193/* |
|
144 * Retrieve the ACL on a file. 145 * 146 * As part of the ACL is stored in the inode, and the rest in an EA, 147 * assemble both into a final ACL product. Right now this is not done 148 * very efficiently. 149 */ | 194 * Retrieve the ACL on a file. 195 * 196 * As part of the ACL is stored in the inode, and the rest in an EA, 197 * assemble both into a final ACL product. Right now this is not done 198 * very efficiently. 199 */ |
150int 151ufs_getacl(ap) 152 struct vop_getacl_args /* { 153 struct vnode *vp; 154 struct acl_type_t type; 155 struct acl *aclp; 156 struct ucred *cred; 157 struct thread *td; 158 } */ *ap; | 200static int 201ufs_getacl_posix1e(struct vop_getacl_args *ap) |
159{ 160 struct inode *ip = VTOI(ap->a_vp); | 202{ 203 struct inode *ip = VTOI(ap->a_vp); |
161 int error, len; | 204 int error; 205 struct oldacl *old; |
162 163 /* 164 * XXX: If ufs_getacl() should work on file systems not supporting 165 * ACLs, remove this check. 166 */ 167 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 168 return (EOPNOTSUPP); 169 | 206 207 /* 208 * XXX: If ufs_getacl() should work on file systems not supporting 209 * ACLs, remove this check. 210 */ 211 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 212 return (EOPNOTSUPP); 213 |
214 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); 215 |
|
170 /* | 216 /* |
171 * Attempt to retrieve the ACL based on the ACL type. | 217 * Attempt to retrieve the ACL from the extended attributes. |
172 */ | 218 */ |
173 bzero(ap->a_aclp, sizeof(*ap->a_aclp)); 174 len = sizeof(*ap->a_aclp); 175 switch(ap->a_type) { 176 case ACL_TYPE_ACCESS: 177 /* 178 * ACL_TYPE_ACCESS ACLs may or may not be stored in the 179 * EA, as they are in fact a combination of the inode 180 * ownership/permissions and the EA contents. If the 181 * EA is present, merge the two in a temporary ACL 182 * storage, otherwise just return the inode contents. 183 */ 184 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED, 185 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 186 POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) ap->a_aclp, 187 ap->a_td); 188 switch (error) { 189 /* XXX: If ufs_getacl() should work on filesystems without 190 * the EA configured, add case EOPNOTSUPP here. */ 191 case ENOATTR: | 219 error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, ap->a_td); 220 switch (error) { 221 /* 222 * XXX: If ufs_getacl() should work on filesystems 223 * without the EA configured, add case EOPNOTSUPP here. 224 */ 225 case ENOATTR: 226 switch (ap->a_type) { 227 case ACL_TYPE_ACCESS: |
192 /* 193 * Legitimately no ACL set on object, purely 194 * emulate it through the inode. These fields will 195 * be updated when the ACL is synchronized with 196 * the inode later. 197 */ | 228 /* 229 * Legitimately no ACL set on object, purely 230 * emulate it through the inode. These fields will 231 * be updated when the ACL is synchronized with 232 * the inode later. 233 */ |
198 ap->a_aclp->acl_cnt = 3; 199 ap->a_aclp->acl_entry[0].ae_tag = ACL_USER_OBJ; 200 ap->a_aclp->acl_entry[0].ae_id = ACL_UNDEFINED_ID; 201 ap->a_aclp->acl_entry[0].ae_perm = ACL_PERM_NONE; 202 ap->a_aclp->acl_entry[1].ae_tag = ACL_GROUP_OBJ; 203 ap->a_aclp->acl_entry[1].ae_id = ACL_UNDEFINED_ID; 204 ap->a_aclp->acl_entry[1].ae_perm = ACL_PERM_NONE; 205 ap->a_aclp->acl_entry[2].ae_tag = ACL_OTHER; 206 ap->a_aclp->acl_entry[2].ae_id = ACL_UNDEFINED_ID; 207 ap->a_aclp->acl_entry[2].ae_perm = ACL_PERM_NONE; 208 ufs_sync_acl_from_inode(ip, ap->a_aclp); 209 error = 0; | 234 old->acl_cnt = 3; 235 old->acl_entry[0].ae_tag = ACL_USER_OBJ; 236 old->acl_entry[0].ae_id = ACL_UNDEFINED_ID; 237 old->acl_entry[0].ae_perm = ACL_PERM_NONE; 238 old->acl_entry[1].ae_tag = ACL_GROUP_OBJ; 239 old->acl_entry[1].ae_id = ACL_UNDEFINED_ID; 240 old->acl_entry[1].ae_perm = ACL_PERM_NONE; 241 old->acl_entry[2].ae_tag = ACL_OTHER; 242 old->acl_entry[2].ae_id = ACL_UNDEFINED_ID; 243 old->acl_entry[2].ae_perm = ACL_PERM_NONE; |
210 break; 211 | 244 break; 245 |
212 case 0: 213 if (len != sizeof(*ap->a_aclp)) { 214 /* 215 * A short (or long) read, meaning that for 216 * some reason the ACL is corrupted. Return 217 * EPERM since the object DAC protections 218 * are unsafe. 219 */ 220 printf("ufs_getacl(): Loaded invalid ACL (" 221 "%d bytes), inumber %d on %s\n", len, 222 ip->i_number, ip->i_fs->fs_fsmnt); 223 return (EPERM); 224 } 225 ufs_sync_acl_from_inode(ip, ap->a_aclp); | 246 case ACL_TYPE_DEFAULT: 247 /* 248 * Unlike ACL_TYPE_ACCESS, there is no relationship 249 * between the inode contents and the ACL, and it is 250 * therefore possible for the request for the ACL 251 * to fail since the ACL is undefined. In this 252 * situation, return success and an empty ACL, 253 * as required by POSIX.1e. 254 */ 255 old->acl_cnt = 0; |
226 break; | 256 break; |
227 228 default: 229 break; | |
230 } | 257 } |
231 break; | |
232 | 258 |
233 case ACL_TYPE_DEFAULT: 234 if (ap->a_vp->v_type != VDIR) { 235 error = EINVAL; 236 break; 237 } 238 error = vn_extattr_get(ap->a_vp, IO_NODELOCKED, 239 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 240 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, 241 (char *) ap->a_aclp, ap->a_td); 242 /* 243 * Unlike ACL_TYPE_ACCESS, there is no relationship between 244 * the inode contents and the ACL, and it is therefore 245 * possible for the request for the ACL to fail since the 246 * ACL is undefined. In this situation, return success 247 * and an empty ACL, as required by POSIX.1e. 248 */ 249 switch (error) { 250 /* XXX: If ufs_getacl() should work on filesystems without 251 * the EA configured, add case EOPNOTSUPP here. */ 252 case ENOATTR: 253 bzero(ap->a_aclp, sizeof(*ap->a_aclp)); 254 ap->a_aclp->acl_cnt = 0; 255 error = 0; 256 break; | 259 error = 0; |
257 | 260 |
258 case 0: 259 if (len != sizeof(*ap->a_aclp)) { 260 /* 261 * A short (or long) read, meaning that for 262 * some reason the ACL is corrupted. Return 263 * EPERM since the object default DAC 264 * protections are unsafe. 265 */ 266 printf("ufs_getacl(): Loaded invalid ACL (" 267 "%d bytes), inumber %d on %s\n", len, 268 ip->i_number, ip->i_fs->fs_fsmnt); 269 return (EPERM); 270 } | 261 /* FALLTHROUGH */ 262 case 0: 263 error = acl_copy_oldacl_into_acl(old, ap->a_aclp); 264 if (error != 0) |
271 break; 272 | 265 break; 266 |
273 default: 274 break; 275 } 276 break; 277 | 267 if (ap->a_type == ACL_TYPE_ACCESS) 268 ufs_sync_acl_from_inode(ip, ap->a_aclp); |
278 default: | 269 default: |
279 error = EINVAL; | 270 break; |
280 } 281 | 271 } 272 |
273 free(old, M_ACL); |
|
282 return (error); 283} 284 | 274 return (error); 275} 276 |
277int 278ufs_getacl(ap) 279 struct vop_getacl_args /* { 280 struct vnode *vp; 281 acl_type_t type; 282 struct acl *aclp; 283 struct ucred *cred; 284 struct thread *td; 285 } */ *ap; 286{ 287 288 return (ufs_getacl_posix1e(ap)); 289} 290 |
|
285/* 286 * Set the ACL on a file. 287 * 288 * As part of the ACL is stored in the inode, and the rest in an EA, 289 * this is necessarily non-atomic, and has complex authorization. 290 * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(), 291 * a fair number of different access checks may be required to go ahead 292 * with the operation at all. 293 */ | 291/* 292 * Set the ACL on a file. 293 * 294 * As part of the ACL is stored in the inode, and the rest in an EA, 295 * this is necessarily non-atomic, and has complex authorization. 296 * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(), 297 * a fair number of different access checks may be required to go ahead 298 * with the operation at all. 299 */ |
294int 295ufs_setacl(ap) 296 struct vop_setacl_args /* { 297 struct vnode *vp; 298 acl_type_t type; 299 struct acl *aclp; 300 struct ucred *cred; 301 struct proc *p; 302 } */ *ap; | 300static int 301ufs_setacl_posix1e(struct vop_setacl_args *ap) |
303{ 304 struct inode *ip = VTOI(ap->a_vp); 305 int error; | 302{ 303 struct inode *ip = VTOI(ap->a_vp); 304 int error; |
305 struct oldacl *old; |
|
306 307 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 308 return (EOPNOTSUPP); 309 310 /* 311 * If this is a set operation rather than a delete operation, 312 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is 313 * valid for the target. This will include a check on ap->a_type. --- 30 unchanged lines hidden (view full) --- 344 /* 345 * Must hold VADMIN (be file owner) or have appropriate privilege. 346 */ 347 if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td))) 348 return (error); 349 350 switch(ap->a_type) { 351 case ACL_TYPE_ACCESS: | 306 307 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 308 return (EOPNOTSUPP); 309 310 /* 311 * If this is a set operation rather than a delete operation, 312 * invoke VOP_ACLCHECK() on the passed ACL to determine if it is 313 * valid for the target. This will include a check on ap->a_type. --- 30 unchanged lines hidden (view full) --- 344 /* 345 * Must hold VADMIN (be file owner) or have appropriate privilege. 346 */ 347 if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td))) 348 return (error); 349 350 switch(ap->a_type) { 351 case ACL_TYPE_ACCESS: |
352 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 353 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 354 POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*ap->a_aclp), 355 (char *) ap->a_aclp, ap->a_td); | 352 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); 353 error = acl_copy_acl_into_oldacl(ap->a_aclp, old); 354 if (error == 0) { 355 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 356 POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE, 357 POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old), 358 (char *) old, ap->a_td); 359 } 360 free(old, M_ACL); |
356 break; 357 358 case ACL_TYPE_DEFAULT: 359 if (ap->a_aclp == NULL) { 360 error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED, 361 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 362 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td); 363 /* 364 * Attempting to delete a non-present default ACL 365 * will return success for portability purposes. 366 * (TRIX) 367 * 368 * XXX: Note that since we can't distinguish 369 * "that EA is not supported" from "that EA is not 370 * defined", the success case here overlaps the 371 * the ENOATTR->EOPNOTSUPP case below. 372 */ 373 if (error == ENOATTR) 374 error = 0; | 361 break; 362 363 case ACL_TYPE_DEFAULT: 364 if (ap->a_aclp == NULL) { 365 error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED, 366 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 367 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td); 368 /* 369 * Attempting to delete a non-present default ACL 370 * will return success for portability purposes. 371 * (TRIX) 372 * 373 * XXX: Note that since we can't distinguish 374 * "that EA is not supported" from "that EA is not 375 * defined", the success case here overlaps the 376 * the ENOATTR->EOPNOTSUPP case below. 377 */ 378 if (error == ENOATTR) 379 error = 0; |
375 } else 376 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 377 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 378 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, 379 sizeof(*ap->a_aclp), (char *) ap->a_aclp, ap->a_td); | 380 } else { 381 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO); 382 error = acl_copy_acl_into_oldacl(ap->a_aclp, old); 383 if (error == 0) { 384 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED, 385 POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE, 386 POSIX1E_ACL_DEFAULT_EXTATTR_NAME, 387 sizeof(*old), (char *) old, ap->a_td); 388 } 389 free(old, M_ACL); 390 } |
380 break; 381 382 default: 383 error = EINVAL; 384 } 385 /* 386 * Map lack of attribute definition in UFS_EXTATTR into lack of 387 * support for ACLs on the filesystem. --- 11 unchanged lines hidden (view full) --- 399 ufs_sync_inode_from_acl(ap->a_aclp, ip); 400 ip->i_flag |= IN_CHANGE; 401 } 402 403 VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); 404 return (0); 405} 406 | 391 break; 392 393 default: 394 error = EINVAL; 395 } 396 /* 397 * Map lack of attribute definition in UFS_EXTATTR into lack of 398 * support for ACLs on the filesystem. --- 11 unchanged lines hidden (view full) --- 410 ufs_sync_inode_from_acl(ap->a_aclp, ip); 411 ip->i_flag |= IN_CHANGE; 412 } 413 414 VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB); 415 return (0); 416} 417 |
407/* 408 * Check the validity of an ACL for a file. 409 */ | |
410int | 418int |
411ufs_aclcheck(ap) 412 struct vop_aclcheck_args /* { | 419ufs_setacl(ap) 420 struct vop_setacl_args /* { |
413 struct vnode *vp; 414 acl_type_t type; 415 struct acl *aclp; 416 struct ucred *cred; 417 struct thread *td; 418 } */ *ap; 419{ 420 | 421 struct vnode *vp; 422 acl_type_t type; 423 struct acl *aclp; 424 struct ucred *cred; 425 struct thread *td; 426 } */ *ap; 427{ 428 |
429 return (ufs_setacl_posix1e(ap)); 430} 431 432static int 433ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap) 434{ 435 |
|
421 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 422 return (EOPNOTSUPP); 423 424 /* 425 * Verify we understand this type of ACL, and that it applies 426 * to this kind of object. 427 * Rely on the acl_posix1e_check() routine to verify the contents. 428 */ --- 4 unchanged lines hidden (view full) --- 433 case ACL_TYPE_DEFAULT: 434 if (ap->a_vp->v_type != VDIR) 435 return (EINVAL); 436 break; 437 438 default: 439 return (EINVAL); 440 } | 436 if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0) 437 return (EOPNOTSUPP); 438 439 /* 440 * Verify we understand this type of ACL, and that it applies 441 * to this kind of object. 442 * Rely on the acl_posix1e_check() routine to verify the contents. 443 */ --- 4 unchanged lines hidden (view full) --- 448 case ACL_TYPE_DEFAULT: 449 if (ap->a_vp->v_type != VDIR) 450 return (EINVAL); 451 break; 452 453 default: 454 return (EINVAL); 455 } |
456 457 if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES) 458 return (EINVAL); 459 |
|
441 return (acl_posix1e_check(ap->a_aclp)); 442} 443 | 460 return (acl_posix1e_check(ap->a_aclp)); 461} 462 |
463/* 464 * Check the validity of an ACL for a file. 465 */ 466int 467ufs_aclcheck(ap) 468 struct vop_aclcheck_args /* { 469 struct vnode *vp; 470 acl_type_t type; 471 struct acl *aclp; 472 struct ucred *cred; 473 struct thread *td; 474 } */ *ap; 475{ 476 477 return (ufs_aclcheck_posix1e(ap)); 478} 479 |
|
444#endif /* !UFS_ACL */ | 480#endif /* !UFS_ACL */ |