xref: /illumos-gate/usr/src/lib/libc/port/gen/priv_str_xlate.c (revision c8d284976ee7a60fd288bb6667ddb74331be96e9)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5004388ebScasper  * Common Development and Distribution License (the "License").
6004388ebScasper  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22004388ebScasper  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  *	priv_str_xlate.c - Privilege translation routines.
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate #pragma weak priv_str_to_set = _priv_str_to_set
337c478bd9Sstevel@tonic-gate #pragma weak priv_set_to_str = _priv_set_to_str
347c478bd9Sstevel@tonic-gate #pragma weak priv_gettext = _priv_gettext
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate #include "synonyms.h"
377c478bd9Sstevel@tonic-gate #include <stdio.h>
387c478bd9Sstevel@tonic-gate #include <stdlib.h>
397c478bd9Sstevel@tonic-gate #include <ctype.h>
407c478bd9Sstevel@tonic-gate #include <strings.h>
417c478bd9Sstevel@tonic-gate #include <errno.h>
427c478bd9Sstevel@tonic-gate #include <string.h>
437c478bd9Sstevel@tonic-gate #include <locale.h>
447c478bd9Sstevel@tonic-gate #include <sys/param.h>
457c478bd9Sstevel@tonic-gate #include <priv.h>
467c478bd9Sstevel@tonic-gate #include <alloca.h>
477c478bd9Sstevel@tonic-gate #include <locale.h>
487c478bd9Sstevel@tonic-gate #include "libc.h"
497c478bd9Sstevel@tonic-gate #include "../i18n/_loc_path.h"
507c478bd9Sstevel@tonic-gate #include "priv_private.h"
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate priv_set_t *
537c478bd9Sstevel@tonic-gate priv_basic(void)
547c478bd9Sstevel@tonic-gate {
557c478bd9Sstevel@tonic-gate 	priv_data_t *d;
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate 	LOADPRIVDATA(d);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate 	return (d->pd_basicset);
607c478bd9Sstevel@tonic-gate }
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate /*
637c478bd9Sstevel@tonic-gate  *	Name:	priv_str_to_set()
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  *	Description:	Given a buffer with privilege strings, the
667c478bd9Sstevel@tonic-gate  *	equivalent privilege set is returned.
677c478bd9Sstevel@tonic-gate  *
687c478bd9Sstevel@tonic-gate  *	Special tokens recognized: all, none, basic and "".
697c478bd9Sstevel@tonic-gate  *
707c478bd9Sstevel@tonic-gate  *	On failure, this function returns NULL.
717c478bd9Sstevel@tonic-gate  *	*endptr == NULL and errno set: resource error.
727c478bd9Sstevel@tonic-gate  *	*endptr != NULL: parse error.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate priv_set_t *
757c478bd9Sstevel@tonic-gate priv_str_to_set(const char *priv_names,
767c478bd9Sstevel@tonic-gate 		const char *separators,
777c478bd9Sstevel@tonic-gate 		const char **endptr)
787c478bd9Sstevel@tonic-gate {
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	char *base;
817c478bd9Sstevel@tonic-gate 	char *offset;
827c478bd9Sstevel@tonic-gate 	char *last;
837c478bd9Sstevel@tonic-gate 	priv_set_t *pset = NULL;
847c478bd9Sstevel@tonic-gate 	priv_set_t *zone;
857c478bd9Sstevel@tonic-gate 	priv_set_t *basic;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	if (endptr != NULL)
887c478bd9Sstevel@tonic-gate 		*endptr = NULL;
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate 	if ((base = libc_strdup(priv_names)) == NULL ||
917c478bd9Sstevel@tonic-gate 	    (pset = priv_allocset()) == NULL) {
927c478bd9Sstevel@tonic-gate 		/* Whether base is NULL or allocated, this works */
937c478bd9Sstevel@tonic-gate 		libc_free(base);
947c478bd9Sstevel@tonic-gate 		return (NULL);
957c478bd9Sstevel@tonic-gate 	}
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	priv_emptyset(pset);
987c478bd9Sstevel@tonic-gate 	basic = priv_basic();
997c478bd9Sstevel@tonic-gate 	zone = privdata->pd_zoneset;
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	/* This is how to use strtok_r nicely in a while loop ... */
1027c478bd9Sstevel@tonic-gate 	last = base;
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate 	while ((offset = strtok_r(NULL, separators, &last)) != NULL) {
1057c478bd9Sstevel@tonic-gate 		/*
1067c478bd9Sstevel@tonic-gate 		 * Search for these special case strings.
1077c478bd9Sstevel@tonic-gate 		 */
1087c478bd9Sstevel@tonic-gate 		if (basic != NULL && strcasecmp(offset, "basic") == 0) {
1097c478bd9Sstevel@tonic-gate 			priv_union(basic, pset);
1107c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(offset, "none") == 0) {
1117c478bd9Sstevel@tonic-gate 			priv_emptyset(pset);
1127c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(offset, "all") == 0) {
1137c478bd9Sstevel@tonic-gate 			priv_fillset(pset);
1147c478bd9Sstevel@tonic-gate 		} else if (strcasecmp(offset, "zone") == 0) {
1157c478bd9Sstevel@tonic-gate 			priv_union(zone, pset);
1167c478bd9Sstevel@tonic-gate 		} else {
1177c478bd9Sstevel@tonic-gate 			boolean_t neg = (*offset == '-' || *offset == '!');
1187c478bd9Sstevel@tonic-gate 			int privid;
1197c478bd9Sstevel@tonic-gate 			int slen;
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate 			privid = priv_getbyname(offset +
1227c478bd9Sstevel@tonic-gate 			    ((neg || *offset == '+') ? 1 : 0));
1237c478bd9Sstevel@tonic-gate 			if (privid < 0) {
1247c478bd9Sstevel@tonic-gate 				slen = offset - base;
1257c478bd9Sstevel@tonic-gate 				libc_free(base);
1267c478bd9Sstevel@tonic-gate 				priv_freeset(pset);
1277c478bd9Sstevel@tonic-gate 				if (endptr != NULL)
1287c478bd9Sstevel@tonic-gate 					*endptr = priv_names + slen;
1297c478bd9Sstevel@tonic-gate 				errno = EINVAL;
1307c478bd9Sstevel@tonic-gate 				return (NULL);
1317c478bd9Sstevel@tonic-gate 			} else {
1327c478bd9Sstevel@tonic-gate 				if (neg)
1337c478bd9Sstevel@tonic-gate 					PRIV_DELSET(pset, privid);
1347c478bd9Sstevel@tonic-gate 				else
1357c478bd9Sstevel@tonic-gate 					PRIV_ADDSET(pset, privid);
1367c478bd9Sstevel@tonic-gate 			}
1377c478bd9Sstevel@tonic-gate 		}
1387c478bd9Sstevel@tonic-gate 	}
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	libc_free(base);
1417c478bd9Sstevel@tonic-gate 	return (pset);
1427c478bd9Sstevel@tonic-gate }
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  *	Name:	priv_set_to_str()
1467c478bd9Sstevel@tonic-gate  *
1477c478bd9Sstevel@tonic-gate  *	Description:	Given a set of privileges, list of privileges are
1487c478bd9Sstevel@tonic-gate  *	returned in privilege numeric order (which can be an ASCII sorted
1497c478bd9Sstevel@tonic-gate  *	list as our implementation allows renumbering.
1507c478bd9Sstevel@tonic-gate  *
1517c478bd9Sstevel@tonic-gate  *	String "none" identifies an empty privilege set, and string "all"
1527c478bd9Sstevel@tonic-gate  *	identifies a full set.
1537c478bd9Sstevel@tonic-gate  *
1547c478bd9Sstevel@tonic-gate  *	A pointer to a buffer is returned which needs to be freed by
1557c478bd9Sstevel@tonic-gate  *	the caller.
1567c478bd9Sstevel@tonic-gate  *
1577c478bd9Sstevel@tonic-gate  *	Several types of output are supported:
1587c478bd9Sstevel@tonic-gate  *		PRIV_STR_PORT		- portable output: basic,!basic
1597c478bd9Sstevel@tonic-gate  *		PRIV_STR_LIT		- literal output
1607c478bd9Sstevel@tonic-gate  *		PRIV_STR_SHORT		- shortest output
1617c478bd9Sstevel@tonic-gate  *
1627c478bd9Sstevel@tonic-gate  * NOTE: this function is called both from inside the library for the
1637c478bd9Sstevel@tonic-gate  * current environment and from outside the library using an externally
1647c478bd9Sstevel@tonic-gate  * generated priv_data_t * in order to analyze core files.  It should
1657c478bd9Sstevel@tonic-gate  * return strings which can be free()ed by applications and it should
1667c478bd9Sstevel@tonic-gate  * not use any data from the current environment except in the special
1677c478bd9Sstevel@tonic-gate  * case that it is called from within libc, with a NULL priv_data_t *
1687c478bd9Sstevel@tonic-gate  * argument.
1697c478bd9Sstevel@tonic-gate  */
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate char *
1727c478bd9Sstevel@tonic-gate __priv_set_to_str(
1737c478bd9Sstevel@tonic-gate 	priv_data_t *d,
1747c478bd9Sstevel@tonic-gate 	const priv_set_t *pset,
1757c478bd9Sstevel@tonic-gate 	char separator,
1767c478bd9Sstevel@tonic-gate 	int flag)
1777c478bd9Sstevel@tonic-gate {
1787c478bd9Sstevel@tonic-gate 	const char *pstr;
1797c478bd9Sstevel@tonic-gate 	char *res, *resp;
1807c478bd9Sstevel@tonic-gate 	int i;
1817c478bd9Sstevel@tonic-gate 	char neg = separator == '!' ? '-' : '!';
1827c478bd9Sstevel@tonic-gate 	priv_set_t *zone;
1837c478bd9Sstevel@tonic-gate 	boolean_t all;
1847c478bd9Sstevel@tonic-gate 	boolean_t use_libc_data = (d == NULL);
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	if (use_libc_data)
1877c478bd9Sstevel@tonic-gate 		LOADPRIVDATA(d);
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	if (flag != PRIV_STR_PORT && __priv_isemptyset(d, pset))
1907c478bd9Sstevel@tonic-gate 		return (strdup("none"));
1917c478bd9Sstevel@tonic-gate 	if (flag != PRIV_STR_LIT && __priv_isfullset(d, pset))
1927c478bd9Sstevel@tonic-gate 		return (strdup("all"));
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/* Safe upper bound: global info contains all NULL separated privs */
1957c478bd9Sstevel@tonic-gate 	res = resp = alloca(d->pd_pinfo->priv_globalinfosize);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	/*
1987c478bd9Sstevel@tonic-gate 	 * Compute the shortest form; i.e., the form with the fewest privilege
1997c478bd9Sstevel@tonic-gate 	 * tokens.
2007c478bd9Sstevel@tonic-gate 	 * The following forms are possible:
2017c478bd9Sstevel@tonic-gate 	 *	literal: priv1,priv2,priv3
2027c478bd9Sstevel@tonic-gate 	 *		tokcount = present
2037c478bd9Sstevel@tonic-gate 	 *	port: basic,!missing_basic,other
2047c478bd9Sstevel@tonic-gate 	 *		tokcount = 1 + present - presentbasic + missingbasic
2057c478bd9Sstevel@tonic-gate 	 *	zone: zone,!missing_zone
2067c478bd9Sstevel@tonic-gate 	 *		tokcount = 1 + missingzone
2077c478bd9Sstevel@tonic-gate 	 *	all: all,!missing1,!missing2
2087c478bd9Sstevel@tonic-gate 	 *		tokcount = 1 + d->pd_nprivs - present;
2097c478bd9Sstevel@tonic-gate 	 *
2107c478bd9Sstevel@tonic-gate 	 * Note that zone and all forms are identical in the global zone;
2117c478bd9Sstevel@tonic-gate 	 * in that case (or any other where the token count is the same),
2127c478bd9Sstevel@tonic-gate 	 * all is preferred.  Also, the zone form is only used when the
2137c478bd9Sstevel@tonic-gate 	 * indicated privileges are a subset of the zone set.
2147c478bd9Sstevel@tonic-gate 	 */
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	if (use_libc_data)
2177c478bd9Sstevel@tonic-gate 		LOCKPRIVDATA();
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	if (flag == PRIV_STR_SHORT) {
2207c478bd9Sstevel@tonic-gate 		int presentbasic, missingbasic, present, missing;
2217c478bd9Sstevel@tonic-gate 		int presentzone, missingzone;
2227c478bd9Sstevel@tonic-gate 		int count;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 		presentbasic = missingbasic = present = 0;
2257c478bd9Sstevel@tonic-gate 		presentzone = missingzone = 0;
2267c478bd9Sstevel@tonic-gate 		zone = d->pd_zoneset;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 		for (i = 0; i < d->pd_nprivs; i++) {
2297c478bd9Sstevel@tonic-gate 			int mem = PRIV_ISMEMBER(pset, i);
2307c478bd9Sstevel@tonic-gate 			if (d->pd_basicset != NULL &&
2317c478bd9Sstevel@tonic-gate 			    PRIV_ISMEMBER(d->pd_basicset, i)) {
2327c478bd9Sstevel@tonic-gate 				if (mem)
2337c478bd9Sstevel@tonic-gate 					presentbasic++;
2347c478bd9Sstevel@tonic-gate 				else
2357c478bd9Sstevel@tonic-gate 					missingbasic++;
2367c478bd9Sstevel@tonic-gate 			}
2377c478bd9Sstevel@tonic-gate 			if (zone != NULL && PRIV_ISMEMBER(zone, i)) {
2387c478bd9Sstevel@tonic-gate 				if (mem)
2397c478bd9Sstevel@tonic-gate 					presentzone++;
2407c478bd9Sstevel@tonic-gate 				else
2417c478bd9Sstevel@tonic-gate 					missingzone++;
2427c478bd9Sstevel@tonic-gate 			}
2437c478bd9Sstevel@tonic-gate 			if (mem)
2447c478bd9Sstevel@tonic-gate 				present++;
2457c478bd9Sstevel@tonic-gate 		}
2467c478bd9Sstevel@tonic-gate 		missing = d->pd_nprivs - present;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 		if (1 - presentbasic + missingbasic < 0) {
2497c478bd9Sstevel@tonic-gate 			flag = PRIV_STR_PORT;
2507c478bd9Sstevel@tonic-gate 			count = present + 1 - presentbasic + missingbasic;
2517c478bd9Sstevel@tonic-gate 		} else {
2527c478bd9Sstevel@tonic-gate 			flag = PRIV_STR_LIT;
2537c478bd9Sstevel@tonic-gate 			count = present;
2547c478bd9Sstevel@tonic-gate 		}
2557c478bd9Sstevel@tonic-gate 		if (count >= 1 + missing) {
2567c478bd9Sstevel@tonic-gate 			flag = PRIV_STR_SHORT;
2577c478bd9Sstevel@tonic-gate 			count = 1 + missing;
2587c478bd9Sstevel@tonic-gate 			all = B_TRUE;
2597c478bd9Sstevel@tonic-gate 		}
2607c478bd9Sstevel@tonic-gate 		if (present == presentzone && 1 + missingzone < count) {
2617c478bd9Sstevel@tonic-gate 			flag = PRIV_STR_SHORT;
2627c478bd9Sstevel@tonic-gate 			all = B_FALSE;
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 	}
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	switch (flag) {
2677c478bd9Sstevel@tonic-gate 	case PRIV_STR_LIT:
2687c478bd9Sstevel@tonic-gate 		*res = '\0';
2697c478bd9Sstevel@tonic-gate 		break;
2707c478bd9Sstevel@tonic-gate 	case PRIV_STR_PORT:
2717c478bd9Sstevel@tonic-gate 		(void) strcpy(res, "basic");
2727c478bd9Sstevel@tonic-gate 		if (d->pd_basicset == NULL)
2737c478bd9Sstevel@tonic-gate 			flag = PRIV_STR_LIT;
2747c478bd9Sstevel@tonic-gate 		break;
2757c478bd9Sstevel@tonic-gate 	case PRIV_STR_SHORT:
2767c478bd9Sstevel@tonic-gate 		if (all)
2777c478bd9Sstevel@tonic-gate 			(void) strcpy(res, "all");
2787c478bd9Sstevel@tonic-gate 		else
2797c478bd9Sstevel@tonic-gate 			(void) strcpy(res, "zone");
2807c478bd9Sstevel@tonic-gate 		break;
2817c478bd9Sstevel@tonic-gate 	default:
2827c478bd9Sstevel@tonic-gate 		if (use_libc_data)
2837c478bd9Sstevel@tonic-gate 			UNLOCKPRIVDATA();
2847c478bd9Sstevel@tonic-gate 		return (NULL);
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 	res += strlen(res);
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	for (i = 0; i < d->pd_nprivs; i++) {
2897c478bd9Sstevel@tonic-gate 		/* Map the privilege to the next one sorted by name */
2907c478bd9Sstevel@tonic-gate 		int priv = d->pd_setsort[i];
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 		if (PRIV_ISMEMBER(pset, priv)) {
2937c478bd9Sstevel@tonic-gate 			switch (flag) {
2947c478bd9Sstevel@tonic-gate 			case PRIV_STR_SHORT:
2957c478bd9Sstevel@tonic-gate 				if (all || PRIV_ISMEMBER(zone, priv))
2967c478bd9Sstevel@tonic-gate 					continue;
2977c478bd9Sstevel@tonic-gate 				break;
2987c478bd9Sstevel@tonic-gate 			case PRIV_STR_PORT:
2997c478bd9Sstevel@tonic-gate 				if (PRIV_ISMEMBER(d->pd_basicset, priv))
3007c478bd9Sstevel@tonic-gate 					continue;
3017c478bd9Sstevel@tonic-gate 				break;
3027c478bd9Sstevel@tonic-gate 			case PRIV_STR_LIT:
3037c478bd9Sstevel@tonic-gate 				break;
3047c478bd9Sstevel@tonic-gate 			}
3057c478bd9Sstevel@tonic-gate 			if (res != resp)
3067c478bd9Sstevel@tonic-gate 				*res++ = separator;
3077c478bd9Sstevel@tonic-gate 		} else {
3087c478bd9Sstevel@tonic-gate 			switch (flag) {
3097c478bd9Sstevel@tonic-gate 			case PRIV_STR_LIT:
3107c478bd9Sstevel@tonic-gate 				continue;
3117c478bd9Sstevel@tonic-gate 			case PRIV_STR_PORT:
3127c478bd9Sstevel@tonic-gate 				if (!PRIV_ISMEMBER(d->pd_basicset, priv))
3137c478bd9Sstevel@tonic-gate 					continue;
3147c478bd9Sstevel@tonic-gate 				break;
3157c478bd9Sstevel@tonic-gate 			case PRIV_STR_SHORT:
3167c478bd9Sstevel@tonic-gate 				if (!all && !PRIV_ISMEMBER(zone, priv))
3177c478bd9Sstevel@tonic-gate 					continue;
3187c478bd9Sstevel@tonic-gate 				break;
3197c478bd9Sstevel@tonic-gate 			}
3207c478bd9Sstevel@tonic-gate 			if (res != resp)
3217c478bd9Sstevel@tonic-gate 				*res++ = separator;
3227c478bd9Sstevel@tonic-gate 			*res++ = neg;
3237c478bd9Sstevel@tonic-gate 		}
3247c478bd9Sstevel@tonic-gate 		pstr = __priv_getbynum(d, priv);
3257c478bd9Sstevel@tonic-gate 		(void) strcpy(res, pstr);
3267c478bd9Sstevel@tonic-gate 		res += strlen(pstr);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 	if (use_libc_data)
3297c478bd9Sstevel@tonic-gate 		UNLOCKPRIVDATA();
3307c478bd9Sstevel@tonic-gate 	/* Special case the set with some high bits set */
3317c478bd9Sstevel@tonic-gate 	return (strdup(*resp == '\0' ? "none" : resp));
3327c478bd9Sstevel@tonic-gate }
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate /*
3357c478bd9Sstevel@tonic-gate  * priv_set_to_str() is defined to return a string that
3367c478bd9Sstevel@tonic-gate  * the caller must deallocate with free(3C).  Grr...
3377c478bd9Sstevel@tonic-gate  */
3387c478bd9Sstevel@tonic-gate char *
3397c478bd9Sstevel@tonic-gate priv_set_to_str(const priv_set_t *pset, char separator, int flag)
3407c478bd9Sstevel@tonic-gate {
3417c478bd9Sstevel@tonic-gate 	return (__priv_set_to_str(NULL, pset, separator, flag));
3427c478bd9Sstevel@tonic-gate }
3437c478bd9Sstevel@tonic-gate 
344*c8d28497Ssayama static char *
345*c8d28497Ssayama do_priv_gettext(const char *priv, const char *file)
3467c478bd9Sstevel@tonic-gate {
3477c478bd9Sstevel@tonic-gate 	char buf[8*1024];
3487c478bd9Sstevel@tonic-gate 	boolean_t inentry = B_FALSE;
349*c8d28497Ssayama 	FILE	*namefp;
3507c478bd9Sstevel@tonic-gate 
351*c8d28497Ssayama 	namefp = fopen(file, "rF");
3527c478bd9Sstevel@tonic-gate 	if (namefp == NULL)
3537c478bd9Sstevel@tonic-gate 		return (NULL);
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	/*
3567c478bd9Sstevel@tonic-gate 	 * parse the file; it must have the following format
3577c478bd9Sstevel@tonic-gate 	 * Lines starting with comments "#"
3587c478bd9Sstevel@tonic-gate 	 * Lines starting with non white space with one single token:
3597c478bd9Sstevel@tonic-gate 	 * the privileges; white space indented lines which are the
3607c478bd9Sstevel@tonic-gate 	 * description; no empty lines are allowed in the description.
3617c478bd9Sstevel@tonic-gate 	 */
3627c478bd9Sstevel@tonic-gate 	while (fgets(buf, sizeof (buf), namefp) != NULL) {
3637c478bd9Sstevel@tonic-gate 		char *lp;		/* pointer to the current line */
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 		if (buf[0] == '#')
3667c478bd9Sstevel@tonic-gate 			continue;
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 		if (buf[0] == '\n') {
3697c478bd9Sstevel@tonic-gate 			inentry = B_FALSE;
3707c478bd9Sstevel@tonic-gate 			continue;
3717c478bd9Sstevel@tonic-gate 		}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 		if (inentry)
3747c478bd9Sstevel@tonic-gate 			continue;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 		/* error; not skipping; yet line starts with white space */
3777c478bd9Sstevel@tonic-gate 		if (isspace((unsigned char)buf[0]))
3787c478bd9Sstevel@tonic-gate 			goto out;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 		/* Trim trailing newline */
3817c478bd9Sstevel@tonic-gate 		buf[strlen(buf) - 1] = '\0';
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate 		if (strcasecmp(buf, priv) != 0) {
3847c478bd9Sstevel@tonic-gate 			inentry = B_TRUE;
3857c478bd9Sstevel@tonic-gate 			continue;
3867c478bd9Sstevel@tonic-gate 		}
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate 		lp = buf;
3897c478bd9Sstevel@tonic-gate 		while (fgets(lp, sizeof (buf) - (lp - buf), namefp) != NULL) {
3907c478bd9Sstevel@tonic-gate 			char *tstart;	/* start of text */
3917c478bd9Sstevel@tonic-gate 			int len;
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 			/* Empty line or start of next entry terminates */
3947c478bd9Sstevel@tonic-gate 			if (*lp == '\n' || !isspace((unsigned char)*lp)) {
3957c478bd9Sstevel@tonic-gate 				*lp = '\0';
3967c478bd9Sstevel@tonic-gate 				(void) fclose(namefp);
3977c478bd9Sstevel@tonic-gate 				return (strdup(buf));
3987c478bd9Sstevel@tonic-gate 			}
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 			/* Remove leading white space */
4017c478bd9Sstevel@tonic-gate 			tstart = lp;
4027c478bd9Sstevel@tonic-gate 			while (*tstart != '\0' &&
4037c478bd9Sstevel@tonic-gate 				isspace((unsigned char)*tstart)) {
4047c478bd9Sstevel@tonic-gate 				tstart++;
4057c478bd9Sstevel@tonic-gate 			}
4067c478bd9Sstevel@tonic-gate 
4077c478bd9Sstevel@tonic-gate 			len = strlen(tstart);
4087c478bd9Sstevel@tonic-gate 			(void) memmove(lp, tstart, len + 1);
4097c478bd9Sstevel@tonic-gate 			lp += len;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 			/* Entry to big; prevent fgets() loop */
4127c478bd9Sstevel@tonic-gate 			if (lp == &buf[sizeof (buf) - 1])
4137c478bd9Sstevel@tonic-gate 				goto out;
4147c478bd9Sstevel@tonic-gate 		}
4157c478bd9Sstevel@tonic-gate 		if (lp != buf) {
4167c478bd9Sstevel@tonic-gate 			*lp = '\0';
4177c478bd9Sstevel@tonic-gate 			(void) fclose(namefp);
4187c478bd9Sstevel@tonic-gate 			return (strdup(buf));
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate out:
4227c478bd9Sstevel@tonic-gate 	(void) fclose(namefp);
4237c478bd9Sstevel@tonic-gate 	return (NULL);
4247c478bd9Sstevel@tonic-gate }
425*c8d28497Ssayama 
426*c8d28497Ssayama /*
427*c8d28497Ssayama  * priv_gettext() is defined to return a string that
428*c8d28497Ssayama  * the caller must deallocate with free(3C).  Grr...
429*c8d28497Ssayama  */
430*c8d28497Ssayama char *
431*c8d28497Ssayama priv_gettext(const char *priv)
432*c8d28497Ssayama {
433*c8d28497Ssayama 	char file[MAXPATHLEN];
434*c8d28497Ssayama 	const char *loc;
435*c8d28497Ssayama 	char	*ret;
436*c8d28497Ssayama 
437*c8d28497Ssayama 	/* Not a valid privilege */
438*c8d28497Ssayama 	if (priv_getbyname(priv) < 0)
439*c8d28497Ssayama 		return (NULL);
440*c8d28497Ssayama 
441*c8d28497Ssayama 	if ((loc = setlocale(LC_MESSAGES, NULL)) == NULL)
442*c8d28497Ssayama 		loc = "C";
443*c8d28497Ssayama 
444*c8d28497Ssayama 	if (snprintf(file, sizeof (file),
445*c8d28497Ssayama 	    _DFLT_LOC_PATH "%s/LC_MESSAGES/priv_names", loc) < sizeof (file)) {
446*c8d28497Ssayama 		ret = do_priv_gettext(priv, (const char *)file);
447*c8d28497Ssayama 		if (ret != NULL)
448*c8d28497Ssayama 			return (ret);
449*c8d28497Ssayama 	}
450*c8d28497Ssayama 
451*c8d28497Ssayama 	/* If the path is too long or can't be opened, punt to default */
452*c8d28497Ssayama 	ret = do_priv_gettext(priv, "/etc/security/priv_names");
453*c8d28497Ssayama 	return (ret);
454*c8d28497Ssayama }
455