Deleted Added
full compact
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 */