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.
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.
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]
23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * priv_str_xlate.c - Privilege translation routines.
31 #pragma weak _priv_str_to_set = priv_str_to_set
32 #pragma weak _priv_set_to_str = priv_set_to_str
33 #pragma weak _priv_gettext = priv_gettext
43 #include <sys/param.h>
48 #include "../i18n/_loc_path.h"
49 #include "priv_private.h"
58 return (d
->pd_basicset
);
62 * Name: priv_str_to_set()
64 * Description: Given a buffer with privilege strings, the
65 * equivalent privilege set is returned.
67 * Special tokens recognized: all, none, basic and "".
69 * On failure, this function returns NULL.
70 * *endptr == NULL and errno set: resource error.
71 * *endptr != NULL: parse error.
74 priv_str_to_set(const char *priv_names
,
75 const char *separators
,
82 priv_set_t
*pset
= NULL
;
89 if ((base
= libc_strdup(priv_names
)) == NULL
||
90 (pset
= priv_allocset()) == NULL
) {
91 /* Whether base is NULL or allocated, this works */
98 zone
= privdata
->pd_zoneset
;
100 /* This is how to use strtok_r nicely in a while loop ... */
103 while ((offset
= strtok_r(NULL
, separators
, &last
)) != NULL
) {
105 * Search for these special case strings.
107 if (basic
!= NULL
&& strcasecmp(offset
, "basic") == 0) {
108 priv_union(basic
, pset
);
109 } else if (strcasecmp(offset
, "none") == 0) {
111 } else if (strcasecmp(offset
, "all") == 0) {
113 } else if (strcasecmp(offset
, "zone") == 0) {
114 priv_union(zone
, pset
);
116 boolean_t neg
= (*offset
== '-' || *offset
== '!');
120 privid
= priv_getbyname(offset
+
121 ((neg
|| *offset
== '+') ? 1 : 0));
123 slen
= offset
- base
;
127 *endptr
= priv_names
+ slen
;
132 PRIV_DELSET(pset
, privid
);
134 PRIV_ADDSET(pset
, privid
);
144 * Name: priv_set_to_str()
146 * Description: Given a set of privileges, list of privileges are
147 * returned in privilege numeric order (which can be an ASCII sorted
148 * list as our implementation allows renumbering.
150 * String "none" identifies an empty privilege set, and string "all"
151 * identifies a full set.
153 * A pointer to a buffer is returned which needs to be freed by
156 * Several types of output are supported:
157 * PRIV_STR_PORT - portable output: basic,!basic
158 * PRIV_STR_LIT - literal output
159 * PRIV_STR_SHORT - shortest output
161 * NOTE: this function is called both from inside the library for the
162 * current environment and from outside the library using an externally
163 * generated priv_data_t * in order to analyze core files. It should
164 * return strings which can be free()ed by applications and it should
165 * not use any data from the current environment except in the special
166 * case that it is called from within libc, with a NULL priv_data_t *
173 const priv_set_t
*pset
,
180 char neg
= separator
== '!' ? '-' : '!';
183 boolean_t use_libc_data
= (d
== NULL
);
188 if (flag
!= PRIV_STR_PORT
&& __priv_isemptyset(d
, pset
))
189 return (strdup("none"));
190 if (flag
!= PRIV_STR_LIT
&& __priv_isfullset(d
, pset
))
191 return (strdup("all"));
193 /* Safe upper bound: global info contains all NULL separated privs */
194 res
= resp
= alloca(d
->pd_pinfo
->priv_globalinfosize
);
197 * Compute the shortest form; i.e., the form with the fewest privilege
199 * The following forms are possible:
200 * literal: priv1,priv2,priv3
202 * port: basic,!missing_basic,other
203 * tokcount = 1 + present - presentbasic + missingbasic
204 * zone: zone,!missing_zone
205 * tokcount = 1 + missingzone
206 * all: all,!missing1,!missing2
207 * tokcount = 1 + d->pd_nprivs - present;
209 * Note that zone and all forms are identical in the global zone;
210 * in that case (or any other where the token count is the same),
211 * all is preferred. Also, the zone form is only used when the
212 * indicated privileges are a subset of the zone set.
218 if (flag
== PRIV_STR_SHORT
) {
219 int presentbasic
, missingbasic
, present
, missing
;
220 int presentzone
, missingzone
;
223 presentbasic
= missingbasic
= present
= 0;
224 presentzone
= missingzone
= 0;
225 zone
= d
->pd_zoneset
;
227 for (i
= 0; i
< d
->pd_nprivs
; i
++) {
228 int mem
= PRIV_ISMEMBER(pset
, i
);
229 if (d
->pd_basicset
!= NULL
&&
230 PRIV_ISMEMBER(d
->pd_basicset
, i
)) {
236 if (zone
!= NULL
&& PRIV_ISMEMBER(zone
, i
)) {
245 missing
= d
->pd_nprivs
- present
;
247 if (1 - presentbasic
+ missingbasic
< 0) {
248 flag
= PRIV_STR_PORT
;
249 count
= present
+ 1 - presentbasic
+ missingbasic
;
254 if (count
>= 1 + missing
) {
255 flag
= PRIV_STR_SHORT
;
259 if (present
== presentzone
&& 1 + missingzone
< count
) {
260 flag
= PRIV_STR_SHORT
;
270 (void) strcpy(res
, "basic");
271 if (d
->pd_basicset
== NULL
)
276 (void) strcpy(res
, "all");
278 (void) strcpy(res
, "zone");
287 for (i
= 0; i
< d
->pd_nprivs
; i
++) {
288 /* Map the privilege to the next one sorted by name */
289 int priv
= d
->pd_setsort
[i
];
291 if (PRIV_ISMEMBER(pset
, priv
)) {
294 if (all
|| PRIV_ISMEMBER(zone
, priv
))
298 if (PRIV_ISMEMBER(d
->pd_basicset
, priv
))
311 if (!PRIV_ISMEMBER(d
->pd_basicset
, priv
))
315 if (!all
&& !PRIV_ISMEMBER(zone
, priv
))
323 pstr
= __priv_getbynum(d
, priv
);
324 (void) strcpy(res
, pstr
);
329 /* Special case the set with some high bits set */
330 return (strdup(*resp
== '\0' ? "none" : resp
));
334 * priv_set_to_str() is defined to return a string that
335 * the caller must deallocate with free(3C). Grr...
338 priv_set_to_str(const priv_set_t
*pset
, char separator
, int flag
)
340 return (__priv_set_to_str(NULL
, pset
, separator
, flag
));
344 do_priv_gettext(const char *priv
, const char *file
)
347 boolean_t inentry
= B_FALSE
;
350 namefp
= fopen(file
, "rF");
355 * parse the file; it must have the following format
356 * Lines starting with comments "#"
357 * Lines starting with non white space with one single token:
358 * the privileges; white space indented lines which are the
359 * description; no empty lines are allowed in the description.
361 while (fgets(buf
, sizeof (buf
), namefp
) != NULL
) {
362 char *lp
; /* pointer to the current line */
367 if (buf
[0] == '\n') {
375 /* error; not skipping; yet line starts with white space */
376 if (isspace((unsigned char)buf
[0]))
379 /* Trim trailing newline */
380 buf
[strlen(buf
) - 1] = '\0';
382 if (strcasecmp(buf
, priv
) != 0) {
388 while (fgets(lp
, sizeof (buf
) - (lp
- buf
), namefp
) != NULL
) {
389 char *tstart
; /* start of text */
392 /* Empty line or start of next entry terminates */
393 if (*lp
== '\n' || !isspace((unsigned char)*lp
)) {
395 (void) fclose(namefp
);
396 return (strdup(buf
));
399 /* Remove leading white space */
401 while (*tstart
!= '\0' &&
402 isspace((unsigned char)*tstart
)) {
406 len
= strlen(tstart
);
407 (void) memmove(lp
, tstart
, len
+ 1);
410 /* Entry to big; prevent fgets() loop */
411 if (lp
== &buf
[sizeof (buf
) - 1])
416 (void) fclose(namefp
);
417 return (strdup(buf
));
421 (void) fclose(namefp
);
426 * priv_gettext() is defined to return a string that
427 * the caller must deallocate with free(3C). Grr...
430 priv_gettext(const char *priv
)
432 char file
[MAXPATHLEN
];
437 /* Not a valid privilege */
438 if (priv_getbyname(priv
) < 0)
441 curloc
= uselocale(NULL
);
442 loc
= current_locale(curloc
, LC_MESSAGES
);
444 if (snprintf(file
, sizeof (file
),
445 _DFLT_LOC_PATH
"%s/LC_MESSAGES/priv_names", loc
) < sizeof (file
)) {
446 ret
= do_priv_gettext(priv
, (const char *)file
);
451 /* If the path is too long or can't be opened, punt to default */
452 ret
= do_priv_gettext(priv
, "/etc/security/priv_names");