Home | History | Annotate | Line # | Download | only in kern
      1 /*-
      2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
      3  *
      4  * Copyright (c) 1999-2006 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  * Developed by the TrustedBSD Project.
     32  *
     33  * ACL support routines specific to POSIX.1e access control lists.  These are
     34  * utility routines for code common across file systems implementing POSIX.1e
     35  * ACLs.
     36  */
     37 
     38 #include <sys/cdefs.h>
     39 #if 0
     40 __FBSDID("$FreeBSD: head/sys/kern/subr_acl_posix1e.c 341827 2018-12-11 19:32:16Z mjg $");
     41 #endif
     42 __KERNEL_RCSID(0, "$NetBSD: subr_acl_posix1e.c,v 1.1 2020/05/16 18:31:50 christos Exp $");
     43 
     44 #include <sys/param.h>
     45 #include <sys/kernel.h>
     46 #include <sys/module.h>
     47 #include <sys/systm.h>
     48 #include <sys/mount.h>
     49 #include <sys/vnode.h>
     50 #include <sys/kauth.h>
     51 #include <sys/errno.h>
     52 #include <sys/stat.h>
     53 #include <sys/acl.h>
     54 
     55 /*
     56  * For the purposes of filesystems maintaining the _OBJ entries in an inode
     57  * with a mode_t field, this routine converts a mode_t entry to an
     58  * acl_perm_t.
     59  */
     60 acl_perm_t
     61 acl_posix1e_mode_to_perm(acl_tag_t tag, mode_t mode)
     62 {
     63 	acl_perm_t	perm = 0;
     64 
     65 	switch(tag) {
     66 	case ACL_USER_OBJ:
     67 		if (mode & S_IXUSR)
     68 			perm |= ACL_EXECUTE;
     69 		if (mode & S_IRUSR)
     70 			perm |= ACL_READ;
     71 		if (mode & S_IWUSR)
     72 			perm |= ACL_WRITE;
     73 		return (perm);
     74 
     75 	case ACL_GROUP_OBJ:
     76 		if (mode & S_IXGRP)
     77 			perm |= ACL_EXECUTE;
     78 		if (mode & S_IRGRP)
     79 			perm |= ACL_READ;
     80 		if (mode & S_IWGRP)
     81 			perm |= ACL_WRITE;
     82 		return (perm);
     83 
     84 	case ACL_OTHER:
     85 		if (mode & S_IXOTH)
     86 			perm |= ACL_EXECUTE;
     87 		if (mode & S_IROTH)
     88 			perm |= ACL_READ;
     89 		if (mode & S_IWOTH)
     90 			perm |= ACL_WRITE;
     91 		return (perm);
     92 
     93 	default:
     94 		printf("%s: invalid tag (%u)\n", __func__, tag);
     95 		return (0);
     96 	}
     97 }
     98 
     99 /*
    100  * Given inode information (uid, gid, mode), return an acl entry of the
    101  * appropriate type.
    102  */
    103 struct acl_entry
    104 acl_posix1e_mode_to_entry(acl_tag_t tag, uid_t uid, gid_t gid, mode_t mode)
    105 {
    106 	struct acl_entry	acl_entry;
    107 
    108 	acl_entry.ae_tag = tag;
    109 	acl_entry.ae_perm = acl_posix1e_mode_to_perm(tag, mode);
    110 	acl_entry.ae_entry_type = 0;
    111 	acl_entry.ae_flags = 0;
    112 	switch(tag) {
    113 	case ACL_USER_OBJ:
    114 		acl_entry.ae_id = uid;
    115 		break;
    116 
    117 	case ACL_GROUP_OBJ:
    118 		acl_entry.ae_id = gid;
    119 		break;
    120 
    121 	case ACL_OTHER:
    122 		acl_entry.ae_id = ACL_UNDEFINED_ID;
    123 		break;
    124 
    125 	default:
    126 		acl_entry.ae_id = ACL_UNDEFINED_ID;
    127 		printf("acl_posix1e_mode_to_entry: invalid tag (%d)\n", tag);
    128 	}
    129 
    130 	return (acl_entry);
    131 }
    132 
    133 /*
    134  * Utility function to generate a file mode given appropriate ACL entries.
    135  */
    136 mode_t
    137 acl_posix1e_perms_to_mode(struct acl_entry *acl_user_obj_entry,
    138     struct acl_entry *acl_group_obj_entry, struct acl_entry *acl_other_entry)
    139 {
    140 	mode_t	mode;
    141 
    142 	mode = 0;
    143 	if (acl_user_obj_entry->ae_perm & ACL_EXECUTE)
    144 		mode |= S_IXUSR;
    145 	if (acl_user_obj_entry->ae_perm & ACL_READ)
    146 		mode |= S_IRUSR;
    147 	if (acl_user_obj_entry->ae_perm & ACL_WRITE)
    148 		mode |= S_IWUSR;
    149 	if (acl_group_obj_entry->ae_perm & ACL_EXECUTE)
    150 		mode |= S_IXGRP;
    151 	if (acl_group_obj_entry->ae_perm & ACL_READ)
    152 		mode |= S_IRGRP;
    153 	if (acl_group_obj_entry->ae_perm & ACL_WRITE)
    154 		mode |= S_IWGRP;
    155 	if (acl_other_entry->ae_perm & ACL_EXECUTE)
    156 		mode |= S_IXOTH;
    157 	if (acl_other_entry->ae_perm & ACL_READ)
    158 		mode |= S_IROTH;
    159 	if (acl_other_entry->ae_perm & ACL_WRITE)
    160 		mode |= S_IWOTH;
    161 
    162 	return (mode);
    163 }
    164 
    165 /*
    166  * Utility function to generate a file mode given a complete POSIX.1e access
    167  * ACL.  Note that if the ACL is improperly formed, this may result in a
    168  * panic.
    169  */
    170 mode_t
    171 acl_posix1e_acl_to_mode(struct acl *acl)
    172 {
    173 	struct acl_entry *acl_mask, *acl_user_obj, *acl_group_obj, *acl_other;
    174 	int i;
    175 
    176 	/*
    177 	 * Find the ACL entries relevant to a POSIX permission mode.
    178 	 */
    179 	acl_user_obj = acl_group_obj = acl_other = acl_mask = NULL;
    180 	for (i = 0; i < acl->acl_cnt; i++) {
    181 		switch (acl->acl_entry[i].ae_tag) {
    182 		case ACL_USER_OBJ:
    183 			acl_user_obj = &acl->acl_entry[i];
    184 			break;
    185 
    186 		case ACL_GROUP_OBJ:
    187 			acl_group_obj = &acl->acl_entry[i];
    188 			break;
    189 
    190 		case ACL_OTHER:
    191 			acl_other = &acl->acl_entry[i];
    192 			break;
    193 
    194 		case ACL_MASK:
    195 			acl_mask = &acl->acl_entry[i];
    196 			break;
    197 
    198 		case ACL_USER:
    199 		case ACL_GROUP:
    200 			break;
    201 
    202 		default:
    203 			panic("acl_posix1e_acl_to_mode: bad ae_tag");
    204 		}
    205 	}
    206 
    207 	if (acl_user_obj == NULL || acl_group_obj == NULL || acl_other == NULL)
    208 		panic("acl_posix1e_acl_to_mode: missing base ae_tags");
    209 
    210 	/*
    211 	 * POSIX.1e specifies that if there is an ACL_MASK entry, we replace
    212 	 * the mode "group" bits with its permissions.  If there isn't, we
    213 	 * use the ACL_GROUP_OBJ permissions.
    214 	 */
    215 	if (acl_mask != NULL)
    216 		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_mask,
    217 		    acl_other));
    218 	else
    219 		return (acl_posix1e_perms_to_mode(acl_user_obj, acl_group_obj,
    220 		    acl_other));
    221 }
    222 
    223 /*
    224  * Perform a syntactic check of the ACL, sufficient to allow an implementing
    225  * filesystem to determine if it should accept this and rely on the POSIX.1e
    226  * ACL properties.
    227  */
    228 int
    229 acl_posix1e_check(struct acl *acl)
    230 {
    231 	int num_acl_user_obj, num_acl_user, num_acl_group_obj, num_acl_group;
    232 	int num_acl_mask, num_acl_other, i;
    233 
    234 	/*
    235 	 * Verify that the number of entries does not exceed the maximum
    236 	 * defined for acl_t.
    237 	 *
    238 	 * Verify that the correct number of various sorts of ae_tags are
    239 	 * present:
    240 	 *   Exactly one ACL_USER_OBJ
    241 	 *   Exactly one ACL_GROUP_OBJ
    242 	 *   Exactly one ACL_OTHER
    243 	 *   If any ACL_USER or ACL_GROUP entries appear, then exactly one
    244 	 *   ACL_MASK entry must also appear.
    245 	 *
    246 	 * Verify that all ae_perm entries are in ACL_PERM_BITS.
    247 	 *
    248 	 * Verify all ae_tag entries are understood by this implementation.
    249 	 *
    250 	 * Note: Does not check for uniqueness of qualifier (ae_id) field.
    251 	 */
    252 	num_acl_user_obj = num_acl_user = num_acl_group_obj = num_acl_group =
    253 	    num_acl_mask = num_acl_other = 0;
    254 	if (acl->acl_cnt > ACL_MAX_ENTRIES)
    255 		return (EINVAL);
    256 	for (i = 0; i < acl->acl_cnt; i++) {
    257 		struct acl_entry *ae = &acl->acl_entry[i];
    258 		/*
    259 		 * Check for a valid tag.
    260 		 */
    261 		switch(ae->ae_tag) {
    262 		case ACL_USER_OBJ:
    263 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
    264 			if (ae->ae_id != ACL_UNDEFINED_ID)
    265 				return (EINVAL);
    266 			num_acl_user_obj++;
    267 			break;
    268 		case ACL_GROUP_OBJ:
    269 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
    270 			if (ae->ae_id != ACL_UNDEFINED_ID)
    271 				return (EINVAL);
    272 			num_acl_group_obj++;
    273 			break;
    274 		case ACL_USER:
    275 			if (ae->ae_id == ACL_UNDEFINED_ID)
    276 				return (EINVAL);
    277 			num_acl_user++;
    278 			break;
    279 		case ACL_GROUP:
    280 			if (ae->ae_id == ACL_UNDEFINED_ID)
    281 				return (EINVAL);
    282 			num_acl_group++;
    283 			break;
    284 		case ACL_OTHER:
    285 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
    286 			if (ae->ae_id != ACL_UNDEFINED_ID)
    287 				return (EINVAL);
    288 			num_acl_other++;
    289 			break;
    290 		case ACL_MASK:
    291 			ae->ae_id = ACL_UNDEFINED_ID; /* XXX */
    292 			if (ae->ae_id != ACL_UNDEFINED_ID)
    293 				return (EINVAL);
    294 			num_acl_mask++;
    295 			break;
    296 		default:
    297 			return (EINVAL);
    298 		}
    299 		/*
    300 		 * Check for valid perm entries.
    301 		 */
    302 		if ((acl->acl_entry[i].ae_perm | ACL_PERM_BITS) !=
    303 		    ACL_PERM_BITS)
    304 			return (EINVAL);
    305 	}
    306 	if ((num_acl_user_obj != 1) || (num_acl_group_obj != 1) ||
    307 	    (num_acl_other != 1) || (num_acl_mask != 0 && num_acl_mask != 1))
    308 		return (EINVAL);
    309 	if (((num_acl_group != 0) || (num_acl_user != 0)) &&
    310 	    (num_acl_mask != 1))
    311 		return (EINVAL);
    312 	return (0);
    313 }
    314 
    315 /*
    316  * Given a requested mode for a new object, and a default ACL, combine the
    317  * two to produce a new mode.  Be careful not to clear any bits that aren't
    318  * intended to be affected by the POSIX.1e ACL.  Eventually, this might also
    319  * take the cmask as an argument, if we push that down into
    320  * per-filesystem-code.
    321  */
    322 mode_t
    323 acl_posix1e_newfilemode(mode_t cmode, struct acl *dacl)
    324 {
    325 	mode_t mode;
    326 
    327 	mode = cmode;
    328 	/*
    329 	 * The current composition policy is that a permission bit must be
    330 	 * set in *both* the ACL and the requested creation mode for it to
    331 	 * appear in the resulting mode/ACL.  First clear any possibly
    332 	 * effected bits, then reconstruct.
    333 	 */
    334 	mode &= ACL_PRESERVE_MASK;
    335 	mode |= (ACL_OVERRIDE_MASK & cmode & acl_posix1e_acl_to_mode(dacl));
    336 
    337 	return (mode);
    338 }
    339