Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 
     27 #include <stdlib.h>
     28 #include <string.h>
     29 #include <unistd.h>
     30 #include <limits.h>
     31 #include <grp.h>
     32 #include <pwd.h>
     33 #include <strings.h>
     34 #include <sys/types.h>
     35 #include <errno.h>
     36 #include <sys/stat.h>
     37 #include <sys/varargs.h>
     38 #include <locale.h>
     39 #include <aclutils.h>
     40 #include <sys/avl.h>
     41 #include <acl_common.h>
     42 #include <idmap.h>
     43 
     44 #define	ACL_PATH	0
     45 #define	ACL_FD		1
     46 
     47 
     48 typedef union {
     49 	const char *file;
     50 	int  fd;
     51 } acl_inp;
     52 
     53 
     54 /*
     55  * Determine whether a file has a trivial ACL
     56  * returns: 	0 = trivial
     57  *		1 = nontrivial
     58  *		<0 some other system failure, such as ENOENT or EPERM
     59  */
     60 int
     61 acl_trivial(const char *filename)
     62 {
     63 	int acl_flavor;
     64 	int aclcnt;
     65 	int cntcmd;
     66 	int val = 0;
     67 	ace_t *acep;
     68 
     69 	acl_flavor = pathconf(filename, _PC_ACL_ENABLED);
     70 
     71 	if (acl_flavor == _ACL_ACE_ENABLED)
     72 		cntcmd = ACE_GETACLCNT;
     73 	else
     74 		cntcmd = GETACLCNT;
     75 
     76 	aclcnt = acl(filename, cntcmd, 0, NULL);
     77 	if (aclcnt > 0) {
     78 		if (acl_flavor == _ACL_ACE_ENABLED) {
     79 			acep = malloc(sizeof (ace_t) * aclcnt);
     80 			if (acep == NULL)
     81 				return (-1);
     82 			if (acl(filename, ACE_GETACL,
     83 			    aclcnt, acep) < 0) {
     84 				free(acep);
     85 				return (-1);
     86 			}
     87 
     88 			val = ace_trivial(acep, aclcnt);
     89 			free(acep);
     90 
     91 		} else if (aclcnt > MIN_ACL_ENTRIES)
     92 			val = 1;
     93 	}
     94 	return (val);
     95 }
     96 
     97 
     98 static int
     99 cacl_get(acl_inp inp, int get_flag, int type, acl_t **aclp)
    100 {
    101 	const char *fname;
    102 	int fd;
    103 	int ace_acl = 0;
    104 	int error;
    105 	int getcmd, cntcmd;
    106 	acl_t *acl_info;
    107 	int	save_errno;
    108 	int	stat_error;
    109 	struct stat64 statbuf;
    110 
    111 	*aclp = NULL;
    112 	if (type == ACL_PATH) {
    113 		fname = inp.file;
    114 		ace_acl = pathconf(fname, _PC_ACL_ENABLED);
    115 	} else {
    116 		fd = inp.fd;
    117 		ace_acl = fpathconf(fd, _PC_ACL_ENABLED);
    118 	}
    119 
    120 	/*
    121 	 * if acl's aren't supported then
    122 	 * send it through the old GETACL interface
    123 	 */
    124 	if (ace_acl == 0 || ace_acl == -1) {
    125 		ace_acl = _ACL_ACLENT_ENABLED;
    126 	}
    127 
    128 	if (ace_acl & _ACL_ACE_ENABLED) {
    129 		cntcmd = ACE_GETACLCNT;
    130 		getcmd = ACE_GETACL;
    131 		acl_info = acl_alloc(ACE_T);
    132 	} else {
    133 		cntcmd = GETACLCNT;
    134 		getcmd = GETACL;
    135 		acl_info = acl_alloc(ACLENT_T);
    136 	}
    137 
    138 	if (acl_info == NULL)
    139 		return (-1);
    140 
    141 	if (type == ACL_PATH) {
    142 		acl_info->acl_cnt = acl(fname, cntcmd, 0, NULL);
    143 	} else {
    144 		acl_info->acl_cnt = facl(fd, cntcmd, 0, NULL);
    145 	}
    146 
    147 	save_errno = errno;
    148 	if (acl_info->acl_cnt < 0) {
    149 		acl_free(acl_info);
    150 		errno = save_errno;
    151 		return (-1);
    152 	}
    153 
    154 	if (acl_info->acl_cnt == 0) {
    155 		acl_free(acl_info);
    156 		errno = save_errno;
    157 		return (0);
    158 	}
    159 
    160 	acl_info->acl_aclp =
    161 	    malloc(acl_info->acl_cnt * acl_info->acl_entry_size);
    162 	save_errno = errno;
    163 
    164 	if (acl_info->acl_aclp == NULL) {
    165 		acl_free(acl_info);
    166 		errno = save_errno;
    167 		return (-1);
    168 	}
    169 
    170 	if (type == ACL_PATH) {
    171 		stat_error = stat64(fname, &statbuf);
    172 		error = acl(fname, getcmd, acl_info->acl_cnt,
    173 		    acl_info->acl_aclp);
    174 	} else {
    175 		stat_error = fstat64(fd, &statbuf);
    176 		error = facl(fd, getcmd, acl_info->acl_cnt,
    177 		    acl_info->acl_aclp);
    178 	}
    179 
    180 	save_errno = errno;
    181 	if (error == -1) {
    182 		acl_free(acl_info);
    183 		errno = save_errno;
    184 		return (-1);
    185 	}
    186 
    187 
    188 	if (stat_error == 0) {
    189 		acl_info->acl_flags =
    190 		    (S_ISDIR(statbuf.st_mode) ? ACL_IS_DIR : 0);
    191 	} else
    192 		acl_info->acl_flags = 0;
    193 
    194 	switch (acl_info->acl_type) {
    195 	case ACLENT_T:
    196 		if (acl_info->acl_cnt <= MIN_ACL_ENTRIES)
    197 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
    198 		break;
    199 	case ACE_T:
    200 		if (ace_trivial(acl_info->acl_aclp, acl_info->acl_cnt) == 0)
    201 			acl_info->acl_flags |= ACL_IS_TRIVIAL;
    202 		break;
    203 	default:
    204 		errno = EINVAL;
    205 		acl_free(acl_info);
    206 		return (-1);
    207 	}
    208 
    209 	if ((acl_info->acl_flags & ACL_IS_TRIVIAL) &&
    210 	    (get_flag & ACL_NO_TRIVIAL)) {
    211 		acl_free(acl_info);
    212 		errno = 0;
    213 		return (0);
    214 	}
    215 
    216 	*aclp = acl_info;
    217 	return (0);
    218 }
    219 
    220 /*
    221  * return -1 on failure, otherwise the number of acl
    222  * entries is returned
    223  */
    224 int
    225 acl_get(const char *path, int get_flag, acl_t **aclp)
    226 {
    227 	acl_inp acl_inp;
    228 	acl_inp.file = path;
    229 
    230 	return (cacl_get(acl_inp, get_flag, ACL_PATH, aclp));
    231 }
    232 
    233 int
    234 facl_get(int fd, int get_flag, acl_t **aclp)
    235 {
    236 
    237 	acl_inp acl_inp;
    238 	acl_inp.fd = fd;
    239 
    240 	return (cacl_get(acl_inp, get_flag, ACL_FD, aclp));
    241 }
    242 
    243 /*
    244  * Set an ACL, translates acl to ace_t when appropriate.
    245  */
    246 static int
    247 cacl_set(acl_inp *acl_inp, acl_t *aclp, int type)
    248 {
    249 	int error = 0;
    250 	int acl_flavor_target;
    251 	struct stat64 statbuf;
    252 	int stat_error;
    253 	int isdir;
    254 
    255 
    256 	if (type == ACL_PATH) {
    257 		stat_error = stat64(acl_inp->file, &statbuf);
    258 		if (stat_error)
    259 			return (-1);
    260 		acl_flavor_target = pathconf(acl_inp->file, _PC_ACL_ENABLED);
    261 	} else {
    262 		stat_error = fstat64(acl_inp->fd, &statbuf);
    263 		if (stat_error)
    264 			return (-1);
    265 		acl_flavor_target = fpathconf(acl_inp->fd, _PC_ACL_ENABLED);
    266 	}
    267 
    268 	/*
    269 	 * If target returns an error or 0 from pathconf call then
    270 	 * fall back to UFS/POSIX Draft interface.
    271 	 * In the case of 0 we will then fail in either acl(2) or
    272 	 * acl_translate().  We could erroneously get 0 back from
    273 	 * a file system that is using fs_pathconf() and not answering
    274 	 * the _PC_ACL_ENABLED question itself.
    275 	 */
    276 	if (acl_flavor_target == 0 || acl_flavor_target == -1)
    277 		acl_flavor_target = _ACL_ACLENT_ENABLED;
    278 
    279 	isdir = S_ISDIR(statbuf.st_mode);
    280 
    281 	if ((error = acl_translate(aclp, acl_flavor_target, isdir,
    282 	    statbuf.st_uid, statbuf.st_gid)) != 0) {
    283 		return (error);
    284 	}
    285 
    286 	if (type == ACL_PATH) {
    287 		error = acl(acl_inp->file,
    288 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
    289 		    aclp->acl_cnt, aclp->acl_aclp);
    290 	} else {
    291 		error = facl(acl_inp->fd,
    292 		    (aclp->acl_type == ACE_T) ? ACE_SETACL : SETACL,
    293 		    aclp->acl_cnt, aclp->acl_aclp);
    294 	}
    295 
    296 	return (error);
    297 }
    298 
    299 int
    300 acl_set(const char *path, acl_t *aclp)
    301 {
    302 	acl_inp acl_inp;
    303 
    304 	acl_inp.file = path;
    305 
    306 	return (cacl_set(&acl_inp, aclp, ACL_PATH));
    307 }
    308 
    309 int
    310 facl_set(int fd, acl_t *aclp)
    311 {
    312 	acl_inp acl_inp;
    313 
    314 	acl_inp.fd = fd;
    315 
    316 	return (cacl_set(&acl_inp, aclp, ACL_FD));
    317 }
    318 
    319 int
    320 acl_cnt(acl_t *aclp)
    321 {
    322 	return (aclp->acl_cnt);
    323 }
    324 
    325 int
    326 acl_type(acl_t *aclp)
    327 {
    328 	return (aclp->acl_type);
    329 }
    330 
    331 acl_t *
    332 acl_dup(acl_t *aclp)
    333 {
    334 	acl_t *newaclp;
    335 
    336 	newaclp = acl_alloc(aclp->acl_type);
    337 	if (newaclp == NULL)
    338 		return (NULL);
    339 
    340 	newaclp->acl_aclp = malloc(aclp->acl_entry_size * aclp->acl_cnt);
    341 	if (newaclp->acl_aclp == NULL) {
    342 		acl_free(newaclp);
    343 		return (NULL);
    344 	}
    345 
    346 	(void) memcpy(newaclp->acl_aclp,
    347 	    aclp->acl_aclp, aclp->acl_entry_size * aclp->acl_cnt);
    348 	newaclp->acl_cnt = aclp->acl_cnt;
    349 
    350 	return (newaclp);
    351 }
    352 
    353 int
    354 acl_flags(acl_t *aclp)
    355 {
    356 	return (aclp->acl_flags);
    357 }
    358 
    359 void *
    360 acl_data(acl_t *aclp)
    361 {
    362 	return (aclp->acl_aclp);
    363 }
    364 
    365 /*
    366  * Take an acl array and build an acl_t.
    367  */
    368 acl_t *
    369 acl_to_aclp(enum acl_type type, void *acl, int count)
    370 {
    371 	acl_t *aclp;
    372 
    373 
    374 	aclp = acl_alloc(type);
    375 	if (aclp == NULL)
    376 		return (aclp);
    377 
    378 	aclp->acl_aclp = acl;
    379 	aclp->acl_cnt = count;
    380 
    381 	return (aclp);
    382 }
    383 
    384 /*
    385  * Remove an ACL from a file and create a trivial ACL based
    386  * off of the mode argument.  After acl has been set owner/group
    387  * are updated to match owner,group arguments
    388  */
    389 int
    390 acl_strip(const char *file, uid_t owner, gid_t group, mode_t mode)
    391 {
    392 	int	error = 0;
    393 	aclent_t min_acl[MIN_ACL_ENTRIES];
    394 	ace_t	min_ace_acl[6];	/* owner, group, everyone + complement denies */
    395 	int	acl_flavor;
    396 	int	aclcnt;
    397 
    398 	acl_flavor = pathconf(file, _PC_ACL_ENABLED);
    399 
    400 	/*
    401 	 * force it through aclent flavor when file system doesn't
    402 	 * understand question
    403 	 */
    404 	if (acl_flavor == 0 || acl_flavor == -1)
    405 		acl_flavor = _ACL_ACLENT_ENABLED;
    406 
    407 	if (acl_flavor & _ACL_ACLENT_ENABLED) {
    408 		min_acl[0].a_type = USER_OBJ;
    409 		min_acl[0].a_id   = owner;
    410 		min_acl[0].a_perm = ((mode & 0700) >> 6);
    411 		min_acl[1].a_type = GROUP_OBJ;
    412 		min_acl[1].a_id   = group;
    413 		min_acl[1].a_perm = ((mode & 0070) >> 3);
    414 		min_acl[2].a_type = CLASS_OBJ;
    415 		min_acl[2].a_id   = (uid_t)-1;
    416 		min_acl[2].a_perm = ((mode & 0070) >> 3);
    417 		min_acl[3].a_type = OTHER_OBJ;
    418 		min_acl[3].a_id   = (uid_t)-1;
    419 		min_acl[3].a_perm = (mode & 0007);
    420 		aclcnt = 4;
    421 		error = acl(file, SETACL, aclcnt, min_acl);
    422 	} else if (acl_flavor & _ACL_ACE_ENABLED) {
    423 		(void) memcpy(min_ace_acl, trivial_acl, sizeof (ace_t) * 6);
    424 
    425 		/*
    426 		 * Make aces match request mode
    427 		 */
    428 		adjust_ace_pair(&min_ace_acl[0], (mode & 0700) >> 6);
    429 		adjust_ace_pair(&min_ace_acl[2], (mode & 0070) >> 3);
    430 		adjust_ace_pair(&min_ace_acl[4], mode & 0007);
    431 
    432 		error = acl(file, ACE_SETACL, 6, min_ace_acl);
    433 	} else {
    434 		errno = EINVAL;
    435 		error = 1;
    436 	}
    437 
    438 	if (error == 0)
    439 		error = chown(file, owner, group);
    440 	return (error);
    441 }
    442 
    443 static int
    444 ace_match(void *entry1, void *entry2)
    445 {
    446 	ace_t *p1 = (ace_t *)entry1;
    447 	ace_t *p2 = (ace_t *)entry2;
    448 	ace_t ace1, ace2;
    449 
    450 	ace1 = *p1;
    451 	ace2 = *p2;
    452 
    453 	/*
    454 	 * Need to fixup who field for abstrations for
    455 	 * accurate comparison, since field is undefined.
    456 	 */
    457 	if (ace1.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
    458 		ace1.a_who = (uid_t)-1;
    459 	if (ace2.a_flags & (ACE_OWNER|ACE_GROUP|ACE_EVERYONE))
    460 		ace2.a_who = (uid_t)-1;
    461 	return (memcmp(&ace1, &ace2, sizeof (ace_t)));
    462 }
    463 
    464 static int
    465 aclent_match(void *entry1, void *entry2)
    466 {
    467 	aclent_t *aclent1 = (aclent_t *)entry1;
    468 	aclent_t *aclent2 = (aclent_t *)entry2;
    469 
    470 	return (memcmp(aclent1, aclent2, sizeof (aclent_t)));
    471 }
    472 
    473 /*
    474  * Find acl entries in acl that correspond to removeacl.  Search
    475  * is started from slot.  The flag argument indicates whether to
    476  * remove all matches or just the first match.
    477  */
    478 int
    479 acl_removeentries(acl_t *acl, acl_t *removeacl, int start_slot, int flag)
    480 {
    481 	int i, j;
    482 	int match;
    483 	int (*acl_match)(void *acl1, void *acl2);
    484 	void *acl_entry, *remove_entry;
    485 	void *start;
    486 	int found = 0;
    487 
    488 	if (flag != ACL_REMOVE_ALL && flag != ACL_REMOVE_FIRST)
    489 		flag = ACL_REMOVE_FIRST;
    490 
    491 	if (acl == NULL || removeacl == NULL)
    492 		return (EACL_NO_ACL_ENTRY);
    493 
    494 	if (acl->acl_type != removeacl->acl_type)
    495 		return (EACL_DIFF_TYPE);
    496 
    497 	if (acl->acl_type == ACLENT_T)
    498 		acl_match = aclent_match;
    499 	else
    500 		acl_match = ace_match;
    501 
    502 	for (i = 0, remove_entry = removeacl->acl_aclp;
    503 	    i != removeacl->acl_cnt; i++) {
    504 
    505 		j = 0;
    506 		acl_entry = (char *)acl->acl_aclp +
    507 		    (acl->acl_entry_size * start_slot);
    508 		for (;;) {
    509 			match = acl_match(acl_entry, remove_entry);
    510 			if (match == 0)  {
    511 				found++;
    512 
    513 				/* avoid memmove if last entry */
    514 				if (acl->acl_cnt == (j + 1)) {
    515 					acl->acl_cnt--;
    516 					break;
    517 				}
    518 
    519 				start = (char *)acl_entry +
    520 				    acl->acl_entry_size;
    521 				(void) memmove(acl_entry, start,
    522 				    acl->acl_entry_size *
    523 				    (acl->acl_cnt-- - (j + 1)));
    524 
    525 				if (flag == ACL_REMOVE_FIRST)
    526 					break;
    527 				/*
    528 				 * List has changed, just continue so this
    529 				 * slot gets checked with it's new contents.
    530 				 */
    531 				continue;
    532 			}
    533 			acl_entry = ((char *)acl_entry + acl->acl_entry_size);
    534 			if (++j >= acl->acl_cnt) {
    535 				break;
    536 			}
    537 		}
    538 		remove_entry = (char *)remove_entry + removeacl->acl_entry_size;
    539 	}
    540 
    541 	return ((found == 0) ? EACL_NO_ACL_ENTRY : 0);
    542 }
    543 
    544 /*
    545  * Replace entires entries in acl1 with the corresponding entries
    546  * in newentries.  The where argument specifies where to begin
    547  * the replacement.  If the where argument is 1 greater than the
    548  * number of acl entries in acl1 then they are appended.  If the
    549  * where argument is 2+ greater than the number of acl entries then
    550  * EACL_INVALID_SLOT is returned.
    551  */
    552 int
    553 acl_modifyentries(acl_t *acl1, acl_t *newentries, int where)
    554 {
    555 
    556 	int slot;
    557 	int slots_needed;
    558 	int slots_left;
    559 	int newsize;
    560 
    561 	if (acl1 == NULL || newentries == NULL)
    562 		return (EACL_NO_ACL_ENTRY);
    563 
    564 	if (where < 0 || where >= acl1->acl_cnt)
    565 		return (EACL_INVALID_SLOT);
    566 
    567 	if (acl1->acl_type != newentries->acl_type)
    568 		return (EACL_DIFF_TYPE);
    569 
    570 	slot = where;
    571 
    572 	slots_left = acl1->acl_cnt - slot + 1;
    573 	if (slots_left < newentries->acl_cnt) {
    574 		slots_needed = newentries->acl_cnt - slots_left;
    575 		newsize = (acl1->acl_entry_size * acl1->acl_cnt) +
    576 		    (acl1->acl_entry_size * slots_needed);
    577 		acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
    578 		if (acl1->acl_aclp == NULL)
    579 			return (-1);
    580 	}
    581 	(void) memcpy((char *)acl1->acl_aclp + (acl1->acl_entry_size * slot),
    582 	    newentries->acl_aclp,
    583 	    newentries->acl_entry_size * newentries->acl_cnt);
    584 
    585 	/*
    586 	 * Did ACL grow?
    587 	 */
    588 
    589 	if ((slot + newentries->acl_cnt) > acl1->acl_cnt) {
    590 		acl1->acl_cnt = slot + newentries->acl_cnt;
    591 	}
    592 
    593 	return (0);
    594 }
    595 
    596 /*
    597  * Add acl2 entries into acl1.  The where argument specifies where
    598  * to add the entries.
    599  */
    600 int
    601 acl_addentries(acl_t *acl1, acl_t *acl2, int where)
    602 {
    603 
    604 	int newsize;
    605 	int len;
    606 	void *start;
    607 	void *to;
    608 
    609 	if (acl1 == NULL || acl2 == NULL)
    610 		return (EACL_NO_ACL_ENTRY);
    611 
    612 	if (acl1->acl_type != acl2->acl_type)
    613 		return (EACL_DIFF_TYPE);
    614 
    615 	/*
    616 	 * allow where to specify 1 past last slot for an append operation
    617 	 * but anything greater is an error.
    618 	 */
    619 	if (where < 0 || where > acl1->acl_cnt)
    620 		return (EACL_INVALID_SLOT);
    621 
    622 	newsize = (acl2->acl_entry_size * acl2->acl_cnt) +
    623 	    (acl1->acl_entry_size * acl1->acl_cnt);
    624 	acl1->acl_aclp = realloc(acl1->acl_aclp, newsize);
    625 	if (acl1->acl_aclp == NULL)
    626 		return (-1);
    627 
    628 	/*
    629 	 * first push down entries where new ones will be inserted
    630 	 */
    631 
    632 	to = (void *)((char *)acl1->acl_aclp +
    633 	    ((where + acl2->acl_cnt) * acl1->acl_entry_size));
    634 
    635 	start = (void *)((char *)acl1->acl_aclp +
    636 	    where * acl1->acl_entry_size);
    637 
    638 	if (where < acl1->acl_cnt) {
    639 		len = (acl1->acl_cnt - where) * acl1->acl_entry_size;
    640 		(void) memmove(to, start, len);
    641 	}
    642 
    643 	/*
    644 	 * now stick in new entries.
    645 	 */
    646 
    647 	(void) memmove(start, acl2->acl_aclp,
    648 	    acl2->acl_cnt * acl2->acl_entry_size);
    649 
    650 	acl1->acl_cnt += acl2->acl_cnt;
    651 	return (0);
    652 }
    653 
    654 /*
    655  * return text for an ACL error.
    656  */
    657 char *
    658 acl_strerror(int errnum)
    659 {
    660 	switch (errnum) {
    661 	case EACL_GRP_ERROR:
    662 		return (dgettext(TEXT_DOMAIN,
    663 		    "There is more than one group or default group entry"));
    664 	case EACL_USER_ERROR:
    665 		return (dgettext(TEXT_DOMAIN,
    666 		    "There is more than one user or default user entry"));
    667 	case EACL_OTHER_ERROR:
    668 		return (dgettext(TEXT_DOMAIN,
    669 		    "There is more than one other entry"));
    670 	case EACL_CLASS_ERROR:
    671 		return (dgettext(TEXT_DOMAIN,
    672 		    "There is more than one mask entry"));
    673 	case EACL_DUPLICATE_ERROR:
    674 		return (dgettext(TEXT_DOMAIN,
    675 		    "Duplicate user or group entries"));
    676 	case EACL_MISS_ERROR:
    677 		return (dgettext(TEXT_DOMAIN,
    678 		    "Missing user/group owner, other, mask entry"));
    679 	case EACL_MEM_ERROR:
    680 		return (dgettext(TEXT_DOMAIN,
    681 		    "Memory error"));
    682 	case EACL_ENTRY_ERROR:
    683 		return (dgettext(TEXT_DOMAIN,
    684 		    "Unrecognized entry type"));
    685 	case EACL_INHERIT_ERROR:
    686 		return (dgettext(TEXT_DOMAIN,
    687 		    "Invalid inheritance flags"));
    688 	case EACL_FLAGS_ERROR:
    689 		return (dgettext(TEXT_DOMAIN,
    690 		    "Unrecognized entry flags"));
    691 	case EACL_PERM_MASK_ERROR:
    692 		return (dgettext(TEXT_DOMAIN,
    693 		    "Invalid ACL permissions"));
    694 	case EACL_COUNT_ERROR:
    695 		return (dgettext(TEXT_DOMAIN,
    696 		    "Invalid ACL count"));
    697 	case EACL_INVALID_SLOT:
    698 		return (dgettext(TEXT_DOMAIN,
    699 		    "Invalid ACL entry number specified"));
    700 	case EACL_NO_ACL_ENTRY:
    701 		return (dgettext(TEXT_DOMAIN,
    702 		    "ACL entry doesn't exist"));
    703 	case EACL_DIFF_TYPE:
    704 		return (dgettext(TEXT_DOMAIN,
    705 		    "Different file system ACL types cannot be merged"));
    706 	case EACL_INVALID_USER_GROUP:
    707 		return (dgettext(TEXT_DOMAIN, "Invalid user or group"));
    708 	case EACL_INVALID_STR:
    709 		return (dgettext(TEXT_DOMAIN, "ACL string is invalid"));
    710 	case EACL_FIELD_NOT_BLANK:
    711 		return (dgettext(TEXT_DOMAIN, "Field expected to be blank"));
    712 	case EACL_INVALID_ACCESS_TYPE:
    713 		return (dgettext(TEXT_DOMAIN, "Invalid access type"));
    714 	case EACL_UNKNOWN_DATA:
    715 		return (dgettext(TEXT_DOMAIN, "Unrecognized entry"));
    716 	case EACL_MISSING_FIELDS:
    717 		return (dgettext(TEXT_DOMAIN,
    718 		    "ACL specification missing required fields"));
    719 	case EACL_INHERIT_NOTDIR:
    720 		return (dgettext(TEXT_DOMAIN,
    721 		    "Inheritance flags are only allowed on directories"));
    722 	case -1:
    723 		return (strerror(errno));
    724 	default:
    725 		errno = EINVAL;
    726 		return (dgettext(TEXT_DOMAIN, "Unknown error"));
    727 	}
    728 }
    729 
    730 extern int yyinteractive;
    731 
    732 /* PRINTFLIKE1 */
    733 void
    734 acl_error(const char *fmt, ...)
    735 {
    736 	va_list va;
    737 
    738 	if (yyinteractive == 0)
    739 		return;
    740 
    741 	va_start(va, fmt);
    742 	(void) vfprintf(stderr, fmt, va);
    743 	va_end(va);
    744 }
    745 
    746 int
    747 sid_to_id(char *sid, boolean_t user, uid_t *id)
    748 {
    749 	idmap_handle_t *idmap_hdl = NULL;
    750 	idmap_get_handle_t *get_hdl = NULL;
    751 	char *rid_start = NULL;
    752 	idmap_stat status;
    753 	char *end;
    754 	int error = 1;
    755 	char *domain_start;
    756 
    757 	if ((domain_start = strchr(sid, '@')) == NULL) {
    758 		idmap_rid_t rid;
    759 
    760 		if ((rid_start = strrchr(sid, '-')) == NULL)
    761 			return (1);
    762 		*rid_start++ = '\0';
    763 		errno = 0;
    764 		rid = strtoul(rid_start--, &end, 10);
    765 		if (errno == 0 && *end == '\0') {
    766 			if (idmap_init(&idmap_hdl) == IDMAP_SUCCESS &&
    767 			    idmap_get_create(idmap_hdl, &get_hdl) ==
    768 			    IDMAP_SUCCESS) {
    769 				if (user)
    770 					error = idmap_get_uidbysid(get_hdl,
    771 					    sid, rid, IDMAP_REQ_FLG_USE_CACHE,
    772 					    id, &status);
    773 				else
    774 					error = idmap_get_gidbysid(get_hdl,
    775 					    sid, rid, IDMAP_REQ_FLG_USE_CACHE,
    776 					    id, &status);
    777 				if (error == IDMAP_SUCCESS) {
    778 					error = idmap_get_mappings(get_hdl);
    779 					if (error == IDMAP_SUCCESS &&
    780 					    status != IDMAP_SUCCESS)
    781 						error = 1;
    782 					else
    783 						error = 0;
    784 				}
    785 			} else {
    786 				error = 1;
    787 			}
    788 			if (get_hdl)
    789 				idmap_get_destroy(get_hdl);
    790 			if (idmap_hdl)
    791 				(void) idmap_fini(idmap_hdl);
    792 		} else {
    793 			error = 1;
    794 		}
    795 		*rid_start = '-'; /* putback character removed earlier */
    796 	} else {
    797 		char *name = sid;
    798 		*domain_start++ = '\0';
    799 
    800 		if (user)
    801 			error = idmap_getuidbywinname(name, domain_start,
    802 			    IDMAP_REQ_FLG_USE_CACHE, id);
    803 		else
    804 			error = idmap_getgidbywinname(name, domain_start,
    805 			    IDMAP_REQ_FLG_USE_CACHE, id);
    806 		*--domain_start = '@';
    807 		error = (error == IDMAP_SUCCESS) ? 0 : 1;
    808 	}
    809 
    810 	return (error);
    811 }
    812