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