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