sys: general adoption of SPDX licensing ID tags.
[freebsd.git] / sys / ufs / ufs / ufs_acl.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 1999-2003 Robert N. M. Watson
5  * All rights reserved.
6  *
7  * This software was developed by Robert Watson for the TrustedBSD Project.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30
31 /*
32  * Support for POSIX.1e access control lists: UFS-specific support functions.
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 #include "opt_ufs.h"
39 #include "opt_quota.h"
40
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/stat.h>
44 #include <sys/mount.h>
45 #include <sys/vnode.h>
46 #include <sys/types.h>
47 #include <sys/acl.h>
48 #include <sys/event.h>
49 #include <sys/extattr.h>
50 #include <sys/proc.h>
51
52 #include <ufs/ufs/quota.h>
53 #include <ufs/ufs/inode.h>
54 #include <ufs/ufs/acl.h>
55 #include <ufs/ufs/extattr.h>
56 #include <ufs/ufs/dir.h>
57 #include <ufs/ufs/ufsmount.h>
58 #include <ufs/ufs/ufs_extern.h>
59 #include <ufs/ffs/fs.h>
60
61 #ifdef UFS_ACL
62
63 FEATURE(ufs_acl, "ACL support for UFS");
64
65 /*
66  * Synchronize an ACL and an inode by copying over appropriate inode fields
67  * to the passed ACL.  Assumes an ACL that would satisfy acl_posix1e_check(),
68  * and may panic if not.
69  */
70 void
71 ufs_sync_acl_from_inode(struct inode *ip, struct acl *acl)
72 {
73         struct acl_entry        *acl_mask, *acl_group_obj;
74         int     i;
75
76         /*
77          * Update ACL_USER_OBJ, ACL_OTHER, but simply identify ACL_MASK
78          * and ACL_GROUP_OBJ for use after we know whether ACL_MASK is
79          * present.
80          */
81         acl_mask = NULL;
82         acl_group_obj = NULL;
83         for (i = 0; i < acl->acl_cnt; i++) {
84                 switch (acl->acl_entry[i].ae_tag) {
85                 case ACL_USER_OBJ:
86                         acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
87                             ACL_USER_OBJ, ip->i_mode);
88                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
89                         break;
90         
91                 case ACL_GROUP_OBJ:
92                         acl_group_obj = &acl->acl_entry[i];
93                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
94                         break;
95
96                 case ACL_OTHER:
97                         acl->acl_entry[i].ae_perm = acl_posix1e_mode_to_perm(
98                             ACL_OTHER, ip->i_mode);
99                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
100                         break;
101
102                 case ACL_MASK:
103                         acl_mask = &acl->acl_entry[i];
104                         acl->acl_entry[i].ae_id = ACL_UNDEFINED_ID;
105                         break;
106
107                 case ACL_USER:
108                 case ACL_GROUP:
109                         break;
110         
111                 default:
112                         panic("ufs_sync_acl_from_inode(): bad ae_tag");
113                 }
114         }
115
116         if (acl_group_obj == NULL)
117                 panic("ufs_sync_acl_from_inode(): no ACL_GROUP_OBJ");
118
119         if (acl_mask == NULL) {
120                 /*
121                  * There is no ACL_MASK, so update ACL_GROUP_OBJ.
122                  */
123                 acl_group_obj->ae_perm = acl_posix1e_mode_to_perm(
124                     ACL_GROUP_OBJ, ip->i_mode);
125         } else {
126                 /*
127                  * Update the ACL_MASK entry instead of ACL_GROUP_OBJ.
128                  */
129                 acl_mask->ae_perm = acl_posix1e_mode_to_perm(ACL_GROUP_OBJ,
130                     ip->i_mode);
131         }
132 }
133
134 /*
135  * Calculate what the inode mode should look like based on an authoritative
136  * ACL for the inode.  Replace only the fields in the inode that the ACL
137  * can represent.
138  */
139 void
140 ufs_sync_inode_from_acl(struct acl *acl, struct inode *ip)
141 {
142
143         ip->i_mode &= ACL_PRESERVE_MASK;
144         ip->i_mode |= acl_posix1e_acl_to_mode(acl);
145         DIP_SET(ip, i_mode, ip->i_mode);
146 }
147
148 /*
149  * Retrieve NFSv4 ACL, skipping access checks.  Must be used in UFS code
150  * instead of VOP_GETACL() when we don't want to be restricted by the user
151  * not having ACL_READ_ACL permission, e.g. when calculating inherited ACL
152  * or in ufs_vnops.c:ufs_accessx().
153  */
154 int
155 ufs_getacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td)
156 {
157         int error, len;
158         struct inode *ip = VTOI(vp);
159
160         len = sizeof(*aclp);
161         bzero(aclp, len);
162
163         error = vn_extattr_get(vp, IO_NODELOCKED,
164             NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME,
165             &len, (char *) aclp, td);
166         aclp->acl_maxcnt = ACL_MAX_ENTRIES;
167         if (error == ENOATTR) {
168                 /*
169                  * Legitimately no ACL set on object, purely
170                  * emulate it through the inode.
171                  */
172                 acl_nfs4_sync_acl_from_mode(aclp, ip->i_mode, ip->i_uid);
173
174                 return (0);
175         }
176
177         if (error)
178                 return (error);
179
180         if (len != sizeof(*aclp)) {
181                 /*
182                  * A short (or long) read, meaning that for
183                  * some reason the ACL is corrupted.  Return
184                  * EPERM since the object DAC protections
185                  * are unsafe.
186                  */
187                 printf("ufs_getacl_nfs4(): Loaded invalid ACL ("
188                     "%d bytes), inumber %ju on %s\n", len,
189                     (uintmax_t)ip->i_number, ITOFS(ip)->fs_fsmnt);
190
191                 return (EPERM);
192         }
193
194         error = acl_nfs4_check(aclp, vp->v_type == VDIR);
195         if (error) {
196                 printf("ufs_getacl_nfs4(): Loaded invalid ACL "
197                     "(failed acl_nfs4_check), inumber %ju on %s\n",
198                     (uintmax_t)ip->i_number, ITOFS(ip)->fs_fsmnt);
199
200                 return (EPERM);
201         }
202
203         return (0);
204 }
205
206 static int
207 ufs_getacl_nfs4(struct vop_getacl_args *ap)
208 {
209         int error;
210
211         if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0)
212                 return (EINVAL);
213
214         error = VOP_ACCESSX(ap->a_vp, VREAD_ACL, ap->a_td->td_ucred, ap->a_td);
215         if (error)
216                 return (error);
217
218         error = ufs_getacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td);
219
220         return (error);
221 }
222
223 /*
224  * Read POSIX.1e ACL from an EA.  Return error if its not found
225  * or if any other error has occurred.
226  */
227 static int
228 ufs_get_oldacl(acl_type_t type, struct oldacl *old, struct vnode *vp,
229     struct thread *td)
230 {
231         int error, len;
232         struct inode *ip = VTOI(vp);
233
234         len = sizeof(*old);
235
236         switch (type) {
237         case ACL_TYPE_ACCESS:
238                 error = vn_extattr_get(vp, IO_NODELOCKED,
239                     POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
240                     POSIX1E_ACL_ACCESS_EXTATTR_NAME, &len, (char *) old,
241                     td);
242                 break;
243         case ACL_TYPE_DEFAULT:
244                 if (vp->v_type != VDIR)
245                         return (EINVAL);
246                 error = vn_extattr_get(vp, IO_NODELOCKED,
247                     POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
248                     POSIX1E_ACL_DEFAULT_EXTATTR_NAME, &len, (char *) old,
249                     td);
250                 break;
251         default:
252                 return (EINVAL);
253         }
254
255         if (error != 0)
256                 return (error);
257
258         if (len != sizeof(*old)) {
259                 /*
260                  * A short (or long) read, meaning that for some reason
261                  * the ACL is corrupted.  Return EPERM since the object
262                  * DAC protections are unsafe.
263                  */
264                 printf("ufs_get_oldacl(): Loaded invalid ACL "
265                     "(len = %d), inumber %ju on %s\n", len,
266                     (uintmax_t)ip->i_number, ITOFS(ip)->fs_fsmnt);
267                 return (EPERM);
268         }
269
270         return (0);
271 }
272
273 /*
274  * Retrieve the ACL on a file.
275  *
276  * As part of the ACL is stored in the inode, and the rest in an EA,
277  * assemble both into a final ACL product.  Right now this is not done
278  * very efficiently.
279  */
280 static int
281 ufs_getacl_posix1e(struct vop_getacl_args *ap)
282 {
283         struct inode *ip = VTOI(ap->a_vp);
284         int error;
285         struct oldacl *old;
286
287         /*
288          * XXX: If ufs_getacl() should work on file systems not supporting
289          * ACLs, remove this check.
290          */
291         if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
292                 return (EINVAL);
293
294         old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
295
296         /*
297          * Attempt to retrieve the ACL from the extended attributes.
298          */
299         error = ufs_get_oldacl(ap->a_type, old, ap->a_vp, ap->a_td);
300         switch (error) {
301         /*
302          * XXX: If ufs_getacl() should work on filesystems
303          * without the EA configured, add case EOPNOTSUPP here.
304          */
305         case ENOATTR:
306                 switch (ap->a_type) {
307                 case ACL_TYPE_ACCESS:
308                         /*
309                          * Legitimately no ACL set on object, purely
310                          * emulate it through the inode.  These fields will
311                          * be updated when the ACL is synchronized with
312                          * the inode later.
313                          */
314                         old->acl_cnt = 3;
315                         old->acl_entry[0].ae_tag = ACL_USER_OBJ;
316                         old->acl_entry[0].ae_id = ACL_UNDEFINED_ID;
317                         old->acl_entry[0].ae_perm = ACL_PERM_NONE;
318                         old->acl_entry[1].ae_tag = ACL_GROUP_OBJ;
319                         old->acl_entry[1].ae_id = ACL_UNDEFINED_ID;
320                         old->acl_entry[1].ae_perm = ACL_PERM_NONE;
321                         old->acl_entry[2].ae_tag = ACL_OTHER;
322                         old->acl_entry[2].ae_id = ACL_UNDEFINED_ID;
323                         old->acl_entry[2].ae_perm = ACL_PERM_NONE;
324                         break;
325
326                 case ACL_TYPE_DEFAULT:
327                         /*
328                          * Unlike ACL_TYPE_ACCESS, there is no relationship
329                          * between the inode contents and the ACL, and it is
330                          * therefore possible for the request for the ACL
331                          * to fail since the ACL is undefined.  In this
332                          * situation, return success and an empty ACL,
333                          * as required by POSIX.1e.
334                          */
335                         old->acl_cnt = 0;
336                         break;
337                 }
338                 /* FALLTHROUGH */
339         case 0:
340                 error = acl_copy_oldacl_into_acl(old, ap->a_aclp);
341                 if (error != 0)
342                         break;
343
344                 if (ap->a_type == ACL_TYPE_ACCESS)
345                         ufs_sync_acl_from_inode(ip, ap->a_aclp);
346         default:
347                 break;
348         }
349
350         free(old, M_ACL);
351         return (error);
352 }
353
354 int
355 ufs_getacl(ap)
356         struct vop_getacl_args /* {
357                 struct vnode *vp;
358                 acl_type_t type;
359                 struct acl *aclp;
360                 struct ucred *cred;
361                 struct thread *td;
362         } */ *ap;
363 {
364
365         if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0)
366                 return (EOPNOTSUPP);
367
368         if (ap->a_type == ACL_TYPE_NFS4)
369                 return (ufs_getacl_nfs4(ap));
370
371         return (ufs_getacl_posix1e(ap));
372 }
373
374 /*
375  * Set NFSv4 ACL without doing any access checking.  This is required
376  * e.g. by the UFS code that implements ACL inheritance, or from
377  * ufs_vnops.c:ufs_chmod(), as some of the checks have to be skipped
378  * in that case, and others are redundant.
379  */
380 int
381 ufs_setacl_nfs4_internal(struct vnode *vp, struct acl *aclp, struct thread *td)
382 {
383         int error;
384         mode_t mode;
385         struct inode *ip = VTOI(vp);
386
387         KASSERT(acl_nfs4_check(aclp, vp->v_type == VDIR) == 0,
388             ("invalid ACL passed to ufs_setacl_nfs4_internal"));
389
390         if (acl_nfs4_is_trivial(aclp, ip->i_uid)) {
391                 error = vn_extattr_rm(vp, IO_NODELOCKED,
392                     NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME, td);
393
394                 /*
395                  * An attempt to remove ACL from a file that didn't have
396                  * any extended entries is not an error.
397                  */
398                 if (error == ENOATTR)
399                         error = 0;
400
401         } else {
402                 error = vn_extattr_set(vp, IO_NODELOCKED,
403                     NFS4_ACL_EXTATTR_NAMESPACE, NFS4_ACL_EXTATTR_NAME,
404                     sizeof(*aclp), (char *) aclp, td);
405         }
406
407         /*
408          * Map lack of attribute definition in UFS_EXTATTR into lack of
409          * support for ACLs on the filesystem.
410          */
411         if (error == ENOATTR)
412                 return (EOPNOTSUPP);
413
414         if (error)
415                 return (error);
416
417         mode = ip->i_mode;
418
419         acl_nfs4_sync_mode_from_acl(&mode, aclp);
420
421         ip->i_mode &= ACL_PRESERVE_MASK;
422         ip->i_mode |= mode;
423         DIP_SET(ip, i_mode, ip->i_mode);
424         ip->i_flag |= IN_CHANGE;
425
426         VN_KNOTE_UNLOCKED(vp, NOTE_ATTRIB);
427
428         error = UFS_UPDATE(vp, 0);
429         return (error);
430 }
431
432 static int
433 ufs_setacl_nfs4(struct vop_setacl_args *ap)
434 {
435         int error;
436         struct inode *ip = VTOI(ap->a_vp);
437
438         if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0)
439                 return (EINVAL);
440
441         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
442                 return (EROFS);
443
444         if (ap->a_aclp == NULL)
445                 return (EINVAL);
446
447         error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp, ap->a_cred,
448             ap->a_td);
449         if (error)
450                 return (error);
451
452         /*
453          * Authorize the ACL operation.
454          */
455         if (ip->i_flags & (IMMUTABLE | APPEND))
456                 return (EPERM);
457
458         /*
459          * Must hold VWRITE_ACL or have appropriate privilege.
460          */
461         if ((error = VOP_ACCESSX(ap->a_vp, VWRITE_ACL, ap->a_cred, ap->a_td)))
462                 return (error);
463
464         /*
465          * With NFSv4 ACLs, chmod(2) may need to add additional entries.
466          * Make sure it has enough room for that - splitting every entry
467          * into two and appending "canonical six" entries at the end.
468          */
469         if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
470                 return (ENOSPC);
471
472         error = ufs_setacl_nfs4_internal(ap->a_vp, ap->a_aclp, ap->a_td);
473
474         return (error);
475 }
476
477 /*
478  * Set the ACL on a file.
479  *
480  * As part of the ACL is stored in the inode, and the rest in an EA,
481  * this is necessarily non-atomic, and has complex authorization.
482  * As ufs_setacl() includes elements of ufs_chown() and ufs_chmod(),
483  * a fair number of different access checks may be required to go ahead
484  * with the operation at all.
485  */
486 static int
487 ufs_setacl_posix1e(struct vop_setacl_args *ap)
488 {
489         struct inode *ip = VTOI(ap->a_vp);
490         int error;
491         struct oldacl *old;
492
493         if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
494                 return (EINVAL);
495
496         /*
497          * If this is a set operation rather than a delete operation,
498          * invoke VOP_ACLCHECK() on the passed ACL to determine if it is
499          * valid for the target.  This will include a check on ap->a_type.
500          */
501         if (ap->a_aclp != NULL) {
502                 /*
503                  * Set operation.
504                  */
505                 error = VOP_ACLCHECK(ap->a_vp, ap->a_type, ap->a_aclp,
506                     ap->a_cred, ap->a_td);
507                 if (error != 0)
508                         return (error);
509         } else {
510                 /*
511                  * Delete operation.
512                  * POSIX.1e allows only deletion of the default ACL on a
513                  * directory (ACL_TYPE_DEFAULT).
514                  */
515                 if (ap->a_type != ACL_TYPE_DEFAULT)
516                         return (EINVAL);
517                 if (ap->a_vp->v_type != VDIR)
518                         return (ENOTDIR);
519         }
520
521         if (ap->a_vp->v_mount->mnt_flag & MNT_RDONLY)
522                 return (EROFS);
523
524         /*
525          * Authorize the ACL operation.
526          */
527         if (ip->i_flags & (IMMUTABLE | APPEND))
528                 return (EPERM);
529
530         /*
531          * Must hold VADMIN (be file owner) or have appropriate privilege.
532          */
533         if ((error = VOP_ACCESS(ap->a_vp, VADMIN, ap->a_cred, ap->a_td)))
534                 return (error);
535
536         switch(ap->a_type) {
537         case ACL_TYPE_ACCESS:
538                 old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
539                 error = acl_copy_acl_into_oldacl(ap->a_aclp, old);
540                 if (error == 0) {
541                         error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
542                             POSIX1E_ACL_ACCESS_EXTATTR_NAMESPACE,
543                             POSIX1E_ACL_ACCESS_EXTATTR_NAME, sizeof(*old),
544                             (char *) old, ap->a_td);
545                 }
546                 free(old, M_ACL);
547                 break;
548
549         case ACL_TYPE_DEFAULT:
550                 if (ap->a_aclp == NULL) {
551                         error = vn_extattr_rm(ap->a_vp, IO_NODELOCKED,
552                             POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
553                             POSIX1E_ACL_DEFAULT_EXTATTR_NAME, ap->a_td);
554                         /*
555                          * Attempting to delete a non-present default ACL
556                          * will return success for portability purposes.
557                          * (TRIX)
558                          *
559                          * XXX: Note that since we can't distinguish
560                          * "that EA is not supported" from "that EA is not
561                          * defined", the success case here overlaps the
562                          * the ENOATTR->EOPNOTSUPP case below.
563                          */
564                         if (error == ENOATTR)
565                                 error = 0;
566                 } else {
567                         old = malloc(sizeof(*old), M_ACL, M_WAITOK | M_ZERO);
568                         error = acl_copy_acl_into_oldacl(ap->a_aclp, old);
569                         if (error == 0) {
570                                 error = vn_extattr_set(ap->a_vp, IO_NODELOCKED,
571                                     POSIX1E_ACL_DEFAULT_EXTATTR_NAMESPACE,
572                                     POSIX1E_ACL_DEFAULT_EXTATTR_NAME,
573                                     sizeof(*old), (char *) old, ap->a_td);
574                         }
575                         free(old, M_ACL);
576                 }
577                 break;
578
579         default:
580                 error = EINVAL;
581         }
582         /*
583          * Map lack of attribute definition in UFS_EXTATTR into lack of
584          * support for ACLs on the filesystem.
585          */
586         if (error == ENOATTR)
587                 return (EOPNOTSUPP);
588         if (error != 0)
589                 return (error);
590
591         if (ap->a_type == ACL_TYPE_ACCESS) {
592                 /*
593                  * Now that the EA is successfully updated, update the
594                  * inode and mark it as changed.
595                  */
596                 ufs_sync_inode_from_acl(ap->a_aclp, ip);
597                 ip->i_flag |= IN_CHANGE;
598                 error = UFS_UPDATE(ap->a_vp, 0);
599         }
600
601         VN_KNOTE_UNLOCKED(ap->a_vp, NOTE_ATTRIB);
602         return (error);
603 }
604
605 int
606 ufs_setacl(ap)
607         struct vop_setacl_args /* {
608                 struct vnode *vp;
609                 acl_type_t type;
610                 struct acl *aclp;
611                 struct ucred *cred;
612                 struct thread *td;
613         } */ *ap;
614 {
615         if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0)
616                 return (EOPNOTSUPP);
617
618         if (ap->a_type == ACL_TYPE_NFS4)
619                 return (ufs_setacl_nfs4(ap));
620
621         return (ufs_setacl_posix1e(ap));
622 }
623
624 static int
625 ufs_aclcheck_nfs4(struct vop_aclcheck_args *ap)
626 {
627         int is_directory = 0;
628
629         if ((ap->a_vp->v_mount->mnt_flag & MNT_NFS4ACLS) == 0)
630                 return (EINVAL);
631
632         /*
633          * With NFSv4 ACLs, chmod(2) may need to add additional entries.
634          * Make sure it has enough room for that - splitting every entry
635          * into two and appending "canonical six" entries at the end.
636          */
637         if (ap->a_aclp->acl_cnt > (ACL_MAX_ENTRIES - 6) / 2)
638                 return (ENOSPC);
639
640         if (ap->a_vp->v_type == VDIR)
641                 is_directory = 1;
642
643         return (acl_nfs4_check(ap->a_aclp, is_directory));
644 }
645
646 static int
647 ufs_aclcheck_posix1e(struct vop_aclcheck_args *ap)
648 {
649
650         if ((ap->a_vp->v_mount->mnt_flag & MNT_ACLS) == 0)
651                 return (EINVAL);
652
653         /*
654          * Verify we understand this type of ACL, and that it applies
655          * to this kind of object.
656          * Rely on the acl_posix1e_check() routine to verify the contents.
657          */
658         switch(ap->a_type) {
659         case ACL_TYPE_ACCESS:
660                 break;
661
662         case ACL_TYPE_DEFAULT:
663                 if (ap->a_vp->v_type != VDIR)
664                         return (EINVAL);
665                 break;
666
667         default:
668                 return (EINVAL);
669         }
670
671         if (ap->a_aclp->acl_cnt > OLDACL_MAX_ENTRIES)
672                 return (EINVAL);
673
674         return (acl_posix1e_check(ap->a_aclp));
675 }
676
677 /*
678  * Check the validity of an ACL for a file.
679  */
680 int
681 ufs_aclcheck(ap)
682         struct vop_aclcheck_args /* {
683                 struct vnode *vp;
684                 acl_type_t type;
685                 struct acl *aclp;
686                 struct ucred *cred;
687                 struct thread *td;
688         } */ *ap;
689 {
690
691         if ((ap->a_vp->v_mount->mnt_flag & (MNT_ACLS | MNT_NFS4ACLS)) == 0)
692                 return (EOPNOTSUPP);
693
694         if (ap->a_type == ACL_TYPE_NFS4)
695                 return (ufs_aclcheck_nfs4(ap));
696
697         return (ufs_aclcheck_posix1e(ap));
698 }
699
700 #endif /* !UFS_ACL */