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 * 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 * 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 * 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 * 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 * 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 * 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