Home | History | Annotate | Line # | Download | only in posix1e
acl_from_text_nfs4.c revision 1.1
      1 /*-
      2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
      3  *
      4  * Copyright (c) 2008, 2009 Edward Tomasz Napieraa <trasz (at) FreeBSD.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 #if 0
     31 __FBSDID("$FreeBSD: head/lib/libc/posix1e/acl_from_text_nfs4.c 326193 2017-11-25 17:12:48Z pfg $");
     32 #else
     33 __RCSID("$NetBSD: acl_from_text_nfs4.c,v 1.1 2020/05/16 18:31:47 christos Exp $");
     34 #endif
     35 
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <unistd.h>
     39 #include <errno.h>
     40 #include <assert.h>
     41 #include <string.h>
     42 #include <pwd.h>
     43 #include <grp.h>
     44 #include <ctype.h>
     45 #include <err.h>
     46 #include <sys/syscall.h>
     47 #include <sys/types.h>
     48 #include <sys/acl.h>
     49 
     50 #include "acl_support.h"
     51 
     52 #define MAX_ENTRY_LENGTH 512
     53 
     54 /*
     55  * Parse the tag field of ACL entry passed as "str".  If qualifier
     56  * needs to follow, then the variable referenced by "need_qualifier"
     57  * is set to 1, otherwise it's set to 0.
     58  */
     59 static int
     60 parse_tag(const char *str, acl_entry_t entry, int *need_qualifier)
     61 {
     62 
     63 	assert(need_qualifier != NULL);
     64 	*need_qualifier = 0;
     65 
     66 	if (strcmp(str, "owner@") == 0)
     67 		return (acl_set_tag_type(entry, ACL_USER_OBJ));
     68 	if (strcmp(str, "group@") == 0)
     69 		return (acl_set_tag_type(entry, ACL_GROUP_OBJ));
     70 	if (strcmp(str, "everyone@") == 0)
     71 		return (acl_set_tag_type(entry, ACL_EVERYONE));
     72 
     73 	*need_qualifier = 1;
     74 
     75 	if (strcmp(str, "user") == 0 || strcmp(str, "u") == 0)
     76 		return (acl_set_tag_type(entry, ACL_USER));
     77 	if (strcmp(str, "group") == 0 || strcmp(str, "g") == 0)
     78 		return (acl_set_tag_type(entry, ACL_GROUP));
     79 
     80 	warnx("malformed ACL: invalid \"tag\" field");
     81 
     82 	return (-1);
     83 }
     84 
     85 /*
     86  * Parse the qualifier field of ACL entry passed as "str".
     87  * If user or group name cannot be resolved, then the variable
     88  * referenced by "need_qualifier" is set to 1; it will be checked
     89  * later to figure out whether the appended_id is required.
     90  */
     91 static int
     92 parse_qualifier(char *str, acl_entry_t entry, int *need_qualifier)
     93 {
     94 	int qualifier_length, error;
     95 	uid_t id;
     96 	acl_tag_t tag;
     97 
     98 	assert(need_qualifier != NULL);
     99 	*need_qualifier = 0;
    100 
    101 	qualifier_length = strlen(str);
    102 
    103 	if (qualifier_length == 0) {
    104 		warnx("malformed ACL: empty \"qualifier\" field");
    105 		return (-1);
    106 	}
    107 
    108 	error = acl_get_tag_type(entry, &tag);
    109 	if (error)
    110 		return (error);
    111 
    112 	error = _acl_name_to_id(tag, str, &id);
    113 	if (error) {
    114 		*need_qualifier = 1;
    115 		return (0);
    116 	}
    117 
    118 	return (acl_set_qualifier(entry, &id));
    119 }
    120 
    121 static int
    122 parse_access_mask(char *str, acl_entry_t entry)
    123 {
    124 	int error;
    125 	acl_perm_t perm;
    126 
    127 	error = _nfs4_parse_access_mask(str, &perm);
    128 	if (error)
    129 		return (error);
    130 
    131 	error = acl_set_permset(entry, &perm);
    132 
    133 	return (error);
    134 }
    135 
    136 static int
    137 parse_flags(char *str, acl_entry_t entry)
    138 {
    139 	int error;
    140 	acl_flag_t flags;
    141 
    142 	error = _nfs4_parse_flags(str, &flags);
    143 	if (error)
    144 		return (error);
    145 
    146 	error = acl_set_flagset_np(entry, &flags);
    147 
    148 	return (error);
    149 }
    150 
    151 static int
    152 parse_entry_type(const char *str, acl_entry_t entry)
    153 {
    154 
    155 	if (strcmp(str, "allow") == 0)
    156 		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALLOW));
    157 	if (strcmp(str, "deny") == 0)
    158 		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_DENY));
    159 	if (strcmp(str, "audit") == 0)
    160 		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_AUDIT));
    161 	if (strcmp(str, "alarm") == 0)
    162 		return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALARM));
    163 
    164 	warnx("malformed ACL: invalid \"type\" field");
    165 
    166 	return (-1);
    167 }
    168 
    169 static int
    170 parse_appended_id(char *str, acl_entry_t entry)
    171 {
    172 	int qualifier_length;
    173 	char *end;
    174 	id_t id;
    175 
    176 	qualifier_length = strlen(str);
    177 	if (qualifier_length == 0) {
    178 		warnx("malformed ACL: \"appended id\" field present, "
    179 	           "but empty");
    180 		return (-1);
    181 	}
    182 
    183 	id = strtod(str, &end);
    184 	if (end - str != qualifier_length) {
    185 		warnx("malformed ACL: appended id is not a number");
    186 		return (-1);
    187 	}
    188 
    189 	return (acl_set_qualifier(entry, &id));
    190 }
    191 
    192 static int
    193 number_of_colons(const char *str)
    194 {
    195 	int count = 0;
    196 
    197 	while (*str != '\0') {
    198 		if (*str == ':')
    199 			count++;
    200 
    201 		str++;
    202 	}
    203 
    204 	return (count);
    205 }
    206 
    207 int
    208 _nfs4_acl_entry_from_text(acl_t aclp, char *str)
    209 {
    210 	int error, need_qualifier;
    211 	acl_entry_t entry;
    212 	char *field, *qualifier_field = NULL;
    213 
    214 	error = acl_create_entry(&aclp, &entry);
    215 	if (error)
    216 		return (error);
    217 
    218 	assert(_entry_brand(entry) == ACL_BRAND_NFS4);
    219 
    220 	if (str == NULL)
    221 		goto truncated_entry;
    222 	field = strsep(&str, ":");
    223 
    224 	field = string_skip_whitespace(field);
    225 	if ((*field == '\0') && (!str)) {
    226 		/*
    227 		 * Is an entirely comment line, skip to next
    228 		 * comma.
    229 		 */
    230 		return (0);
    231 	}
    232 
    233 	error = parse_tag(field, entry, &need_qualifier);
    234 	if (error)
    235 		goto malformed_field;
    236 
    237 	if (need_qualifier) {
    238 		if (str == NULL)
    239 			goto truncated_entry;
    240 		qualifier_field = field = strsep(&str, ":");
    241 		error = parse_qualifier(field, entry, &need_qualifier);
    242 		if (error)
    243 			goto malformed_field;
    244 	}
    245 
    246 	if (str == NULL)
    247 		goto truncated_entry;
    248 	field = strsep(&str, ":");
    249 	error = parse_access_mask(field, entry);
    250 	if (error)
    251 		goto malformed_field;
    252 
    253 	if (str == NULL)
    254 		goto truncated_entry;
    255 	/* Do we have "flags" field? */
    256 	if (number_of_colons(str) > 0) {
    257 		field = strsep(&str, ":");
    258 		error = parse_flags(field, entry);
    259 		if (error)
    260 			goto malformed_field;
    261 	}
    262 
    263 	if (str == NULL)
    264 		goto truncated_entry;
    265 	field = strsep(&str, ":");
    266 	error = parse_entry_type(field, entry);
    267 	if (error)
    268 		goto malformed_field;
    269 
    270 	if (need_qualifier) {
    271 		if (str == NULL) {
    272 			warnx("malformed ACL: unknown user or group name "
    273 			    "\"%s\"", qualifier_field);
    274 			goto truncated_entry;
    275 		}
    276 
    277 		error = parse_appended_id(str, entry);
    278 		if (error)
    279 			goto malformed_field;
    280 	}
    281 
    282 	return (0);
    283 
    284 truncated_entry:
    285 malformed_field:
    286 	acl_delete_entry(aclp, entry);
    287 	errno = EINVAL;
    288 	return (-1);
    289 }
    290