Print this page
uts: add a concept of a 'default' set of privileges, separate from 'basic'
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libc/port/gen/priv_str_xlate.c
+++ new/usr/src/lib/libc/port/gen/priv_str_xlate.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * priv_str_xlate.c - Privilege translation routines.
29 29 */
30 30
31 31 #pragma weak _priv_str_to_set = priv_str_to_set
32 32 #pragma weak _priv_set_to_str = priv_set_to_str
33 33 #pragma weak _priv_gettext = priv_gettext
34 34
35 35 #include "lint.h"
36 36 #include <stdio.h>
37 37 #include <stdlib.h>
38 38 #include <ctype.h>
39 39 #include <strings.h>
40 40 #include <errno.h>
41 41 #include <string.h>
42 42 #include <locale.h>
43 43 #include <sys/param.h>
44 44 #include <priv.h>
45 45 #include <alloca.h>
46 46 #include <locale.h>
47 47 #include "libc.h"
48 48 #include "../i18n/_loc_path.h"
49 49 #include "priv_private.h"
50 50
↓ open down ↓ |
50 lines elided |
↑ open up ↑ |
51 51 priv_set_t *
52 52 priv_basic(void)
53 53 {
54 54 priv_data_t *d;
55 55
56 56 LOADPRIVDATA(d);
57 57
58 58 return (d->pd_basicset);
59 59 }
60 60
61 +priv_set_t *
62 +priv_default(void)
63 +{
64 + priv_data_t *d;
65 +
66 + LOADPRIVDATA(d);
67 +
68 + return (d->pd_defaultset);
69 +}
70 +
61 71 /*
62 72 * Name: priv_str_to_set()
63 73 *
64 74 * Description: Given a buffer with privilege strings, the
65 75 * equivalent privilege set is returned.
66 76 *
67 77 * Special tokens recognized: all, none, basic and "".
68 78 *
69 79 * On failure, this function returns NULL.
70 80 * *endptr == NULL and errno set: resource error.
71 81 * *endptr != NULL: parse error.
72 82 */
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
73 83 priv_set_t *
74 84 priv_str_to_set(const char *priv_names,
75 85 const char *separators,
76 86 const char **endptr)
77 87 {
78 88
79 89 char *base;
80 90 char *offset;
81 91 char *last;
82 92 priv_set_t *pset = NULL;
83 - priv_set_t *zone;
84 - priv_set_t *basic;
93 + priv_set_t *zone = NULL;
94 + priv_set_t *basic = NULL;
95 + priv_set_t *deflt = NULL;
85 96
86 97 if (endptr != NULL)
87 98 *endptr = NULL;
88 99
89 100 if ((base = libc_strdup(priv_names)) == NULL ||
90 101 (pset = priv_allocset()) == NULL) {
91 102 /* Whether base is NULL or allocated, this works */
92 103 libc_free(base);
93 104 return (NULL);
94 105 }
95 106
96 107 priv_emptyset(pset);
97 108 basic = priv_basic();
109 + deflt = priv_default();
98 110 zone = privdata->pd_zoneset;
99 111
100 112 /* This is how to use strtok_r nicely in a while loop ... */
101 113 last = base;
102 114
103 115 while ((offset = strtok_r(NULL, separators, &last)) != NULL) {
104 116 /*
105 117 * Search for these special case strings.
106 118 */
107 119 if (basic != NULL && strcasecmp(offset, "basic") == 0) {
108 120 priv_union(basic, pset);
121 + } else if (deflt != NULL && strcasecmp(offset,
122 + "default") == 0) {
123 + priv_union(deflt, pset);
109 124 } else if (strcasecmp(offset, "none") == 0) {
110 125 priv_emptyset(pset);
111 126 } else if (strcasecmp(offset, "all") == 0) {
112 127 priv_fillset(pset);
113 128 } else if (strcasecmp(offset, "zone") == 0) {
114 129 priv_union(zone, pset);
115 130 } else {
116 131 boolean_t neg = (*offset == '-' || *offset == '!');
117 132 int privid;
118 133 int slen;
119 134
120 135 privid = priv_getbyname(offset +
121 136 ((neg || *offset == '+') ? 1 : 0));
122 137 if (privid < 0) {
123 138 slen = offset - base;
124 139 libc_free(base);
125 140 priv_freeset(pset);
126 141 if (endptr != NULL)
127 142 *endptr = priv_names + slen;
128 143 errno = EINVAL;
129 144 return (NULL);
130 145 } else {
131 146 if (neg)
132 147 PRIV_DELSET(pset, privid);
133 148 else
134 149 PRIV_ADDSET(pset, privid);
135 150 }
136 151 }
137 152 }
138 153
139 154 libc_free(base);
140 155 return (pset);
141 156 }
142 157
143 158 /*
144 159 * Name: priv_set_to_str()
145 160 *
146 161 * Description: Given a set of privileges, list of privileges are
147 162 * returned in privilege numeric order (which can be an ASCII sorted
148 163 * list as our implementation allows renumbering.
149 164 *
150 165 * String "none" identifies an empty privilege set, and string "all"
151 166 * identifies a full set.
152 167 *
153 168 * A pointer to a buffer is returned which needs to be freed by
154 169 * the caller.
155 170 *
156 171 * Several types of output are supported:
157 172 * PRIV_STR_PORT - portable output: basic,!basic
158 173 * PRIV_STR_LIT - literal output
159 174 * PRIV_STR_SHORT - shortest output
160 175 *
161 176 * NOTE: this function is called both from inside the library for the
162 177 * current environment and from outside the library using an externally
163 178 * generated priv_data_t * in order to analyze core files. It should
164 179 * return strings which can be free()ed by applications and it should
165 180 * not use any data from the current environment except in the special
166 181 * case that it is called from within libc, with a NULL priv_data_t *
167 182 * argument.
168 183 */
169 184
170 185 char *
171 186 __priv_set_to_str(
172 187 priv_data_t *d,
173 188 const priv_set_t *pset,
174 189 char separator,
175 190 int flag)
176 191 {
177 192 const char *pstr;
178 193 char *res, *resp;
179 194 int i;
180 195 char neg = separator == '!' ? '-' : '!';
181 196 priv_set_t *zone;
182 197 boolean_t all;
183 198 boolean_t use_libc_data = (d == NULL);
184 199
185 200 if (use_libc_data)
186 201 LOADPRIVDATA(d);
187 202
188 203 if (flag != PRIV_STR_PORT && __priv_isemptyset(d, pset))
189 204 return (strdup("none"));
190 205 if (flag != PRIV_STR_LIT && __priv_isfullset(d, pset))
191 206 return (strdup("all"));
192 207
193 208 /* Safe upper bound: global info contains all NULL separated privs */
194 209 res = resp = alloca(d->pd_pinfo->priv_globalinfosize);
195 210
196 211 /*
197 212 * Compute the shortest form; i.e., the form with the fewest privilege
198 213 * tokens.
199 214 * The following forms are possible:
200 215 * literal: priv1,priv2,priv3
201 216 * tokcount = present
202 217 * port: basic,!missing_basic,other
203 218 * tokcount = 1 + present - presentbasic + missingbasic
204 219 * zone: zone,!missing_zone
205 220 * tokcount = 1 + missingzone
206 221 * all: all,!missing1,!missing2
207 222 * tokcount = 1 + d->pd_nprivs - present;
208 223 *
209 224 * Note that zone and all forms are identical in the global zone;
210 225 * in that case (or any other where the token count is the same),
211 226 * all is preferred. Also, the zone form is only used when the
212 227 * indicated privileges are a subset of the zone set.
213 228 */
214 229
215 230 if (use_libc_data)
216 231 LOCKPRIVDATA();
217 232
218 233 if (flag == PRIV_STR_SHORT) {
219 234 int presentbasic, missingbasic, present, missing;
220 235 int presentzone, missingzone;
221 236 int count;
222 237
223 238 presentbasic = missingbasic = present = 0;
224 239 presentzone = missingzone = 0;
225 240 zone = d->pd_zoneset;
226 241
227 242 for (i = 0; i < d->pd_nprivs; i++) {
228 243 int mem = PRIV_ISMEMBER(pset, i);
229 244 if (d->pd_basicset != NULL &&
230 245 PRIV_ISMEMBER(d->pd_basicset, i)) {
231 246 if (mem)
232 247 presentbasic++;
233 248 else
234 249 missingbasic++;
235 250 }
236 251 if (zone != NULL && PRIV_ISMEMBER(zone, i)) {
237 252 if (mem)
238 253 presentzone++;
239 254 else
240 255 missingzone++;
241 256 }
242 257 if (mem)
243 258 present++;
244 259 }
245 260 missing = d->pd_nprivs - present;
246 261
247 262 if (1 - presentbasic + missingbasic < 0) {
248 263 flag = PRIV_STR_PORT;
249 264 count = present + 1 - presentbasic + missingbasic;
250 265 } else {
251 266 flag = PRIV_STR_LIT;
252 267 count = present;
253 268 }
254 269 if (count >= 1 + missing) {
255 270 flag = PRIV_STR_SHORT;
256 271 count = 1 + missing;
257 272 all = B_TRUE;
258 273 }
259 274 if (present == presentzone && 1 + missingzone < count) {
260 275 flag = PRIV_STR_SHORT;
261 276 all = B_FALSE;
262 277 }
263 278 }
264 279
265 280 switch (flag) {
266 281 case PRIV_STR_LIT:
267 282 *res = '\0';
268 283 break;
269 284 case PRIV_STR_PORT:
270 285 (void) strcpy(res, "basic");
271 286 if (d->pd_basicset == NULL)
272 287 flag = PRIV_STR_LIT;
273 288 break;
274 289 case PRIV_STR_SHORT:
275 290 if (all)
276 291 (void) strcpy(res, "all");
277 292 else
278 293 (void) strcpy(res, "zone");
279 294 break;
280 295 default:
281 296 if (use_libc_data)
282 297 UNLOCKPRIVDATA();
283 298 return (NULL);
284 299 }
285 300 res += strlen(res);
286 301
287 302 for (i = 0; i < d->pd_nprivs; i++) {
288 303 /* Map the privilege to the next one sorted by name */
289 304 int priv = d->pd_setsort[i];
290 305
291 306 if (PRIV_ISMEMBER(pset, priv)) {
292 307 switch (flag) {
293 308 case PRIV_STR_SHORT:
294 309 if (all || PRIV_ISMEMBER(zone, priv))
295 310 continue;
296 311 break;
297 312 case PRIV_STR_PORT:
298 313 if (PRIV_ISMEMBER(d->pd_basicset, priv))
299 314 continue;
300 315 break;
301 316 case PRIV_STR_LIT:
302 317 break;
303 318 }
304 319 if (res != resp)
305 320 *res++ = separator;
306 321 } else {
307 322 switch (flag) {
308 323 case PRIV_STR_LIT:
309 324 continue;
310 325 case PRIV_STR_PORT:
311 326 if (!PRIV_ISMEMBER(d->pd_basicset, priv))
312 327 continue;
313 328 break;
314 329 case PRIV_STR_SHORT:
315 330 if (!all && !PRIV_ISMEMBER(zone, priv))
316 331 continue;
317 332 break;
318 333 }
319 334 if (res != resp)
320 335 *res++ = separator;
321 336 *res++ = neg;
322 337 }
323 338 pstr = __priv_getbynum(d, priv);
324 339 (void) strcpy(res, pstr);
325 340 res += strlen(pstr);
326 341 }
327 342 if (use_libc_data)
328 343 UNLOCKPRIVDATA();
329 344 /* Special case the set with some high bits set */
330 345 return (strdup(*resp == '\0' ? "none" : resp));
331 346 }
332 347
333 348 /*
334 349 * priv_set_to_str() is defined to return a string that
335 350 * the caller must deallocate with free(3C). Grr...
336 351 */
337 352 char *
338 353 priv_set_to_str(const priv_set_t *pset, char separator, int flag)
339 354 {
340 355 return (__priv_set_to_str(NULL, pset, separator, flag));
341 356 }
342 357
343 358 static char *
344 359 do_priv_gettext(const char *priv, const char *file)
345 360 {
346 361 char buf[8*1024];
347 362 boolean_t inentry = B_FALSE;
348 363 FILE *namefp;
349 364
350 365 namefp = fopen(file, "rF");
351 366 if (namefp == NULL)
352 367 return (NULL);
353 368
354 369 /*
355 370 * parse the file; it must have the following format
356 371 * Lines starting with comments "#"
357 372 * Lines starting with non white space with one single token:
358 373 * the privileges; white space indented lines which are the
359 374 * description; no empty lines are allowed in the description.
360 375 */
361 376 while (fgets(buf, sizeof (buf), namefp) != NULL) {
362 377 char *lp; /* pointer to the current line */
363 378
364 379 if (buf[0] == '#')
365 380 continue;
366 381
367 382 if (buf[0] == '\n') {
368 383 inentry = B_FALSE;
369 384 continue;
370 385 }
371 386
372 387 if (inentry)
373 388 continue;
374 389
375 390 /* error; not skipping; yet line starts with white space */
376 391 if (isspace((unsigned char)buf[0]))
377 392 goto out;
378 393
379 394 /* Trim trailing newline */
380 395 buf[strlen(buf) - 1] = '\0';
381 396
382 397 if (strcasecmp(buf, priv) != 0) {
383 398 inentry = B_TRUE;
384 399 continue;
385 400 }
386 401
387 402 lp = buf;
388 403 while (fgets(lp, sizeof (buf) - (lp - buf), namefp) != NULL) {
389 404 char *tstart; /* start of text */
390 405 int len;
391 406
392 407 /* Empty line or start of next entry terminates */
393 408 if (*lp == '\n' || !isspace((unsigned char)*lp)) {
394 409 *lp = '\0';
395 410 (void) fclose(namefp);
396 411 return (strdup(buf));
397 412 }
398 413
399 414 /* Remove leading white space */
400 415 tstart = lp;
401 416 while (*tstart != '\0' &&
402 417 isspace((unsigned char)*tstart)) {
403 418 tstart++;
404 419 }
405 420
406 421 len = strlen(tstart);
407 422 (void) memmove(lp, tstart, len + 1);
408 423 lp += len;
409 424
410 425 /* Entry to big; prevent fgets() loop */
411 426 if (lp == &buf[sizeof (buf) - 1])
412 427 goto out;
413 428 }
414 429 if (lp != buf) {
415 430 *lp = '\0';
416 431 (void) fclose(namefp);
417 432 return (strdup(buf));
418 433 }
419 434 }
420 435 out:
421 436 (void) fclose(namefp);
422 437 return (NULL);
423 438 }
424 439
425 440 /*
426 441 * priv_gettext() is defined to return a string that
427 442 * the caller must deallocate with free(3C). Grr...
428 443 */
429 444 char *
430 445 priv_gettext(const char *priv)
431 446 {
432 447 char file[MAXPATHLEN];
433 448 locale_t curloc;
434 449 const char *loc;
435 450 char *ret;
436 451
437 452 /* Not a valid privilege */
438 453 if (priv_getbyname(priv) < 0)
439 454 return (NULL);
440 455
441 456 curloc = uselocale(NULL);
442 457 loc = current_locale(curloc, LC_MESSAGES);
443 458
444 459 if (snprintf(file, sizeof (file),
445 460 _DFLT_LOC_PATH "%s/LC_MESSAGES/priv_names", loc) < sizeof (file)) {
446 461 ret = do_priv_gettext(priv, (const char *)file);
447 462 if (ret != NULL)
448 463 return (ret);
449 464 }
450 465
451 466 /* If the path is too long or can't be opened, punt to default */
452 467 ret = do_priv_gettext(priv, "/etc/security/priv_names");
453 468 return (ret);
454 469 }
↓ open down ↓ |
336 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX