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/privlib.c
+++ new/usr/src/lib/libc/port/gen/privlib.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 2015 Gary Mills
24 24 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 25 */
26 26
27 27 #pragma weak _getprivimplinfo = getprivimplinfo
28 28 #pragma weak _priv_addset = priv_addset
29 29 #pragma weak _priv_allocset = priv_allocset
30 30 #pragma weak _priv_copyset = priv_copyset
31 31 #pragma weak _priv_delset = priv_delset
32 32 #pragma weak _priv_emptyset = priv_emptyset
33 33 #pragma weak _priv_basicset = priv_basicset
34 34 #pragma weak _priv_fillset = priv_fillset
35 35 #pragma weak _priv_freeset = priv_freeset
36 36 #pragma weak _priv_getbyname = priv_getbyname
37 37 #pragma weak _priv_getbynum = priv_getbynum
38 38 #pragma weak _priv_getsetbyname = priv_getsetbyname
39 39 #pragma weak _priv_getsetbynum = priv_getsetbynum
40 40 #pragma weak _priv_ineffect = priv_ineffect
41 41 #pragma weak _priv_intersect = priv_intersect
42 42 #pragma weak _priv_inverse = priv_inverse
43 43 #pragma weak _priv_isemptyset = priv_isemptyset
44 44 #pragma weak _priv_isequalset = priv_isequalset
45 45 #pragma weak _priv_isfullset = priv_isfullset
46 46 #pragma weak _priv_ismember = priv_ismember
47 47 #pragma weak _priv_issubset = priv_issubset
48 48 #pragma weak _priv_set = priv_set
49 49 #pragma weak _priv_union = priv_union
50 50
51 51 #include "lint.h"
52 52
53 53 #define _STRUCTURED_PROC 1
54 54
55 55 #include "priv_private.h"
56 56 #include "mtlib.h"
57 57 #include "libc.h"
58 58 #include <errno.h>
59 59 #include <stdarg.h>
60 60 #include <stdlib.h>
61 61 #include <unistd.h>
62 62 #include <strings.h>
63 63 #include <synch.h>
64 64 #include <alloca.h>
65 65 #include <atomic.h>
66 66 #include <sys/ucred.h>
67 67 #include <sys/procfs.h>
68 68 #include <sys/param.h>
69 69 #include <sys/corectl.h>
70 70 #include <priv_utils.h>
71 71 #include <zone.h>
72 72
73 73 /* Include each string only once - until the compiler/linker are fixed */
74 74 static const char *permitted = PRIV_PERMITTED;
75 75 static const char *effective = PRIV_EFFECTIVE;
76 76 static const char *limit = PRIV_LIMIT;
77 77 static const char *inheritable = PRIV_INHERITABLE;
78 78 /*
79 79 * Data independent privilege set operations.
80 80 *
81 81 * Only a few functions are provided that do not default to
82 82 * the system implementation of privileges. A limited set of
83 83 * interfaces is provided that accepts a priv_data_t *
84 84 * argument; this set of interfaces is a private interface between libc
85 85 * and libproc. It is delivered in order to interpret privilege sets
86 86 * in debuggers in a implementation independent way. As such, we
87 87 * don't need to provide the bulk of the interfaces, only a few
88 88 * boolean tests (isfull, isempty) the name<->num mappings and
89 89 * set pretty print functions. The boolean tests are only needed for
90 90 * the latter, so those aren't provided externally.
91 91 *
92 92 * Additionally, we provide the function that maps the kernel implementation
93 93 * structure into a libc private data structure.
94 94 */
95 95
96 96 priv_data_t *privdata;
97 97
98 98 static mutex_t pd_lock = DEFAULTMUTEX;
99 99
100 100 static int
101 101 parseninfo(priv_info_names_t *na, char ***buf, int *cp)
102 102 {
103 103 char *q;
104 104 int i;
105 105
106 106 *buf = libc_malloc(sizeof (char *) * na->cnt);
107 107
108 108 if (*buf == NULL)
109 109 return (-1);
110 110
111 111 q = na->names;
112 112
113 113 for (i = 0; i < na->cnt; i++) {
114 114 int l = strlen(q);
115 115
116 116 (*buf)[i] = q;
117 117 q += l + 1;
118 118 }
119 119 *cp = na->cnt;
120 120 return (0);
121 121 }
122 122
123 123 struct strint {
124 124 char *name;
125 125 int rank;
126 126 };
127 127
128 128 static int
129 129 strintcmp(const void *a, const void *b)
130 130 {
131 131 const struct strint *ap = a;
132 132 const struct strint *bp = b;
133 133
134 134 return (strcasecmp(ap->name, bp->name));
135 135 }
136 136
137 137 priv_data_t *
138 138 __priv_parse_info(priv_impl_info_t *ip)
139 139 {
140 140 priv_data_t *tmp;
141 141 char *x;
142 142 size_t size = PRIV_IMPL_INFO_SIZE(ip);
143 143 int i;
144 144
145 145 tmp = libc_malloc(sizeof (*tmp));
146 146
147 147 if (tmp == NULL)
148 148 return (NULL);
149 149
150 150 (void) memset(tmp, 0, sizeof (*tmp));
151 151
152 152 tmp->pd_pinfo = ip;
153 153 tmp->pd_setsize = sizeof (priv_chunk_t) * ip->priv_setsize;
154 154 tmp->pd_ucredsize = UCRED_SIZE(ip);
155 155
156 156 x = (char *)ip;
157 157 x += ip->priv_headersize;
158 158
159 159 while (x < ((char *)ip) + size) {
160 160 /* LINTED: alignment */
161 161 priv_info_names_t *na = (priv_info_names_t *)x;
162 162 /* LINTED: alignment */
163 163 priv_info_set_t *st = (priv_info_set_t *)x;
164 164 struct strint *tmparr;
165 165
166 166 switch (na->info.priv_info_type) {
167 167 case PRIV_INFO_SETNAMES:
168 168 if (parseninfo(na, &tmp->pd_setnames, &tmp->pd_nsets))
169 169 goto out;
170 170 break;
171 171 case PRIV_INFO_PRIVNAMES:
172 172 if (parseninfo(na, &tmp->pd_privnames, &tmp->pd_nprivs))
173 173 goto out;
174 174 /*
175 175 * We compute a sorted index which allows us
176 176 * to present a sorted list of privileges
177 177 * without actually having to sort it each time.
178 178 */
179 179 tmp->pd_setsort = libc_malloc(tmp->pd_nprivs *
180 180 sizeof (int));
181 181 if (tmp->pd_setsort == NULL)
182 182 goto out;
183 183
184 184 tmparr = libc_malloc(tmp->pd_nprivs *
185 185 sizeof (struct strint));
186 186
187 187 if (tmparr == NULL)
188 188 goto out;
189 189
190 190 for (i = 0; i < tmp->pd_nprivs; i++) {
191 191 tmparr[i].rank = i;
192 192 tmparr[i].name = tmp->pd_privnames[i];
↓ open down ↓ |
192 lines elided |
↑ open up ↑ |
193 193 }
194 194 qsort(tmparr, tmp->pd_nprivs, sizeof (struct strint),
195 195 strintcmp);
196 196 for (i = 0; i < tmp->pd_nprivs; i++)
197 197 tmp->pd_setsort[i] = tmparr[i].rank;
198 198 libc_free(tmparr);
199 199 break;
200 200 case PRIV_INFO_BASICPRIVS:
201 201 tmp->pd_basicset = (priv_set_t *)&st->set[0];
202 202 break;
203 + case PRIV_INFO_DEFAULTPRIVS:
204 + tmp->pd_defaultset = (priv_set_t *)&st->set[0];
205 + break;
203 206 default:
204 207 /* unknown, ignore */
205 208 break;
206 209 }
207 210 x += na->info.priv_info_size;
208 211 }
209 212 return (tmp);
210 213 out:
211 214 libc_free(tmp->pd_setnames);
212 215 libc_free(tmp->pd_privnames);
213 216 libc_free(tmp->pd_setsort);
214 217 libc_free(tmp);
215 218 return (NULL);
216 219 }
217 220
218 221 /*
219 222 * Caller must have allocated d->pd_pinfo and should free it,
220 223 * if necessary.
221 224 */
222 225 void
223 226 __priv_free_info(priv_data_t *d)
224 227 {
225 228 libc_free(d->pd_setnames);
226 229 libc_free(d->pd_privnames);
227 230 libc_free(d->pd_setsort);
228 231 libc_free(d);
229 232 }
230 233
231 234 /*
232 235 * Return with the pd_lock held and data loaded or indicate failure.
233 236 */
234 237 int
235 238 lock_data(void)
236 239 {
237 240 if (__priv_getdata() == NULL)
238 241 return (-1);
239 242
240 243 lmutex_lock(&pd_lock);
241 244 return (0);
242 245 }
243 246
244 247 boolean_t
245 248 refresh_data(void)
246 249 {
247 250 priv_impl_info_t *ip, ii;
248 251 priv_data_t *tmp;
249 252 char *p0, *q0;
250 253 int oldn, newn;
251 254 int i;
252 255
253 256 if (getprivinfo(&ii, sizeof (ii)) != 0 ||
254 257 ii.priv_max == privdata->pd_nprivs)
255 258 return (B_FALSE);
256 259
257 260 ip = alloca(PRIV_IMPL_INFO_SIZE(&ii));
258 261
259 262 (void) getprivinfo(ip, PRIV_IMPL_INFO_SIZE(&ii));
260 263
261 264 /* Parse the info; then copy the additional bits */
262 265 tmp = __priv_parse_info(ip);
263 266 if (tmp == NULL)
264 267 return (B_FALSE);
265 268
266 269 oldn = privdata->pd_nprivs;
267 270 p0 = privdata->pd_privnames[0];
268 271
269 272 newn = tmp->pd_nprivs;
270 273 q0 = tmp->pd_privnames[0];
271 274
272 275 /* copy the extra information to the old datastructure */
273 276 (void) memcpy((char *)privdata->pd_pinfo + sizeof (priv_impl_info_t),
274 277 (char *)ip + sizeof (priv_impl_info_t),
275 278 PRIV_IMPL_INFO_SIZE(ip) - sizeof (priv_impl_info_t));
276 279
277 280 /* Copy the first oldn pointers */
278 281 (void) memcpy(tmp->pd_privnames, privdata->pd_privnames,
279 282 oldn * sizeof (char *));
280 283
281 284 /* Adjust the rest */
282 285 for (i = oldn; i < newn; i++)
283 286 tmp->pd_privnames[i] += p0 - q0;
284 287
285 288 /* Install the larger arrays */
286 289 libc_free(privdata->pd_privnames);
287 290 privdata->pd_privnames = tmp->pd_privnames;
288 291 tmp->pd_privnames = NULL;
289 292
290 293 libc_free(privdata->pd_setsort);
291 294 privdata->pd_setsort = tmp->pd_setsort;
292 295 tmp->pd_setsort = NULL;
293 296
294 297 /* Copy the rest of the data */
295 298 *privdata->pd_pinfo = *ip;
296 299
297 300 privdata->pd_nprivs = newn;
298 301
299 302 __priv_free_info(tmp);
300 303 return (B_TRUE);
301 304 }
302 305
303 306 void
304 307 unlock_data(void)
305 308 {
306 309 lmutex_unlock(&pd_lock);
307 310 }
308 311
309 312 static priv_set_t *__priv_allocset(priv_data_t *);
310 313
311 314 priv_data_t *
312 315 __priv_getdata(void)
313 316 {
314 317 if (privdata == NULL) {
315 318 lmutex_lock(&pd_lock);
316 319 if (privdata == NULL) {
317 320 priv_data_t *tmp;
318 321 priv_impl_info_t *ip;
319 322 size_t size = sizeof (priv_impl_info_t) + 2048;
320 323 size_t realsize;
321 324 priv_impl_info_t *aip = alloca(size);
322 325
323 326 if (getprivinfo(aip, size) != 0)
324 327 goto out;
325 328
326 329 realsize = PRIV_IMPL_INFO_SIZE(aip);
327 330
328 331 ip = libc_malloc(realsize);
329 332
330 333 if (ip == NULL)
331 334 goto out;
332 335
333 336 if (realsize <= size) {
334 337 (void) memcpy(ip, aip, realsize);
335 338 } else if (getprivinfo(ip, realsize) != 0) {
336 339 libc_free(ip);
337 340 goto out;
338 341 }
339 342
340 343 if ((tmp = __priv_parse_info(ip)) == NULL) {
341 344 libc_free(ip);
342 345 goto out;
343 346 }
344 347
345 348 /* Allocate the zoneset just once, here */
346 349 tmp->pd_zoneset = __priv_allocset(tmp);
347 350 if (tmp->pd_zoneset == NULL)
348 351 goto clean;
349 352
350 353 if (zone_getattr(getzoneid(), ZONE_ATTR_PRIVSET,
351 354 tmp->pd_zoneset, tmp->pd_setsize)
352 355 == tmp->pd_setsize) {
353 356 membar_producer();
354 357 privdata = tmp;
355 358 goto out;
356 359 }
357 360
358 361 priv_freeset(tmp->pd_zoneset);
359 362 clean:
360 363 __priv_free_info(tmp);
361 364 libc_free(ip);
362 365 }
363 366 out:
364 367 lmutex_unlock(&pd_lock);
365 368 }
366 369 membar_consumer();
367 370 return (privdata);
368 371 }
369 372
370 373 const priv_impl_info_t *
371 374 getprivimplinfo(void)
372 375 {
373 376 priv_data_t *d;
374 377
375 378 LOADPRIVDATA(d);
376 379
377 380 return (d->pd_pinfo);
378 381 }
379 382
380 383 static priv_set_t *
381 384 priv_vlist(va_list ap)
382 385 {
383 386 priv_set_t *pset = priv_allocset();
384 387 const char *priv;
385 388
386 389 if (pset == NULL)
387 390 return (NULL);
388 391
389 392 priv_emptyset(pset);
390 393
391 394 while ((priv = va_arg(ap, const char *)) != NULL) {
392 395 if (priv_addset(pset, priv) < 0) {
393 396 priv_freeset(pset);
394 397 return (NULL);
395 398 }
396 399 }
397 400 return (pset);
398 401 }
399 402
400 403 /*
401 404 * priv_set(op, set, priv_id1, priv_id2, ..., NULL)
402 405 *
403 406 * Library routine to enable a user process to set a specific
404 407 * privilege set appropriately using a single call. User is
405 408 * required to terminate the list of privileges with NULL.
406 409 */
407 410 int
408 411 priv_set(priv_op_t op, priv_ptype_t setname, ...)
409 412 {
410 413 va_list ap;
411 414 priv_set_t *pset;
412 415 int ret;
413 416
414 417 va_start(ap, setname);
415 418
416 419 pset = priv_vlist(ap);
417 420
418 421 va_end(ap);
419 422
420 423 if (pset == NULL)
421 424 return (-1);
422 425
423 426 /* All sets */
424 427 if (setname == NULL) {
425 428 priv_data_t *d;
426 429 int set;
427 430
428 431 LOADPRIVDATA(d);
429 432
430 433 for (set = 0; set < d->pd_nsets; set++)
431 434 if ((ret = syscall(SYS_privsys, PRIVSYS_SETPPRIV, op,
432 435 set, (void *)pset, d->pd_setsize)) != 0)
433 436 break;
434 437 } else {
435 438 ret = setppriv(op, setname, pset);
436 439 }
437 440
438 441 priv_freeset(pset);
439 442 return (ret);
440 443 }
441 444
442 445 /*
443 446 * priv_ineffect(privilege).
444 447 * tests the existence of a privilege against the effective set.
445 448 */
446 449 boolean_t
447 450 priv_ineffect(const char *priv)
448 451 {
449 452 priv_set_t *curset;
450 453 boolean_t res;
451 454
452 455 curset = priv_allocset();
453 456
454 457 if (curset == NULL)
455 458 return (B_FALSE);
456 459
457 460 if (getppriv(effective, curset) != 0 ||
458 461 !priv_ismember(curset, priv))
459 462 res = B_FALSE;
460 463 else
461 464 res = B_TRUE;
462 465
463 466 priv_freeset(curset);
464 467
465 468 return (res);
466 469 }
467 470
468 471 /*
469 472 * The routine __init_daemon_priv() is private to Solaris and is
470 473 * used by daemons to limit the privileges they can use and
471 474 * to set the uid they run under.
472 475 */
473 476
474 477 static const char root_cp[] = "/core.%f.%t";
475 478 static const char daemon_cp[] = "/var/tmp/core.%f.%t";
476 479
477 480 int
478 481 __init_daemon_priv(int flags, uid_t uid, gid_t gid, ...)
479 482 {
480 483 priv_set_t *nset;
481 484 priv_set_t *perm = NULL;
482 485 va_list pa;
483 486 priv_data_t *d;
484 487 int ret = -1;
485 488 char buf[1024];
486 489
487 490 LOADPRIVDATA(d);
488 491
↓ open down ↓ |
276 lines elided |
↑ open up ↑ |
489 492 va_start(pa, gid);
490 493
491 494 nset = priv_vlist(pa);
492 495
493 496 va_end(pa);
494 497
495 498 if (nset == NULL)
496 499 return (-1);
497 500
498 501 /* Always add the basic set */
502 + /* XXX: Always add the _default_ set? */
499 503 if (d->pd_basicset != NULL)
500 504 priv_union(d->pd_basicset, nset);
501 505
502 506 /*
503 507 * This is not a significant failure: it allows us to start programs
504 508 * with sufficient privileges and with the proper uid. We don't
505 509 * care enough about the extra groups in that case.
506 510 */
507 511 if (flags & PU_RESETGROUPS)
508 512 (void) setgroups(0, NULL);
509 513
510 514 if (gid != (gid_t)-1 && setgid(gid) != 0)
511 515 goto end;
512 516
513 517 perm = priv_allocset();
514 518 if (perm == NULL)
515 519 goto end;
516 520
517 521 /* E = P */
518 522 (void) getppriv(permitted, perm);
519 523 (void) setppriv(PRIV_SET, effective, perm);
520 524
521 525 /* Now reset suid and euid */
522 526 if (uid != (uid_t)-1 && setreuid(uid, uid) != 0)
523 527 goto end;
524 528
525 529 /* Check for the limit privs */
526 530 if ((flags & PU_LIMITPRIVS) &&
527 531 setppriv(PRIV_SET, limit, nset) != 0)
528 532 goto end;
529 533
530 534 if (flags & PU_CLEARLIMITSET) {
531 535 priv_emptyset(perm);
532 536 if (setppriv(PRIV_SET, limit, perm) != 0)
533 537 goto end;
534 538 }
535 539
536 540 /* Remove the privileges from all the other sets */
537 541 if (setppriv(PRIV_SET, permitted, nset) != 0)
538 542 goto end;
539 543
540 544 if (!(flags & PU_INHERITPRIVS))
541 545 priv_emptyset(nset);
542 546
543 547 ret = setppriv(PRIV_SET, inheritable, nset);
544 548 end:
545 549 priv_freeset(nset);
546 550 priv_freeset(perm);
547 551
548 552 if (core_get_process_path(buf, sizeof (buf), getpid()) == 0 &&
549 553 strcmp(buf, "core") == 0) {
550 554
551 555 if ((uid == (uid_t)-1 ? geteuid() : uid) == 0) {
552 556 (void) core_set_process_path(root_cp, sizeof (root_cp),
553 557 getpid());
554 558 } else {
555 559 (void) core_set_process_path(daemon_cp,
556 560 sizeof (daemon_cp), getpid());
557 561 }
558 562 }
559 563 (void) setpflags(__PROC_PROTECT, 0);
560 564
561 565 return (ret);
562 566 }
563 567
564 568 /*
565 569 * The routine __fini_daemon_priv() is private to Solaris and is
566 570 * used by daemons to clear remaining unwanted privileges and
567 571 * reenable core dumps.
568 572 */
569 573 void
570 574 __fini_daemon_priv(const char *priv, ...)
571 575 {
572 576 priv_set_t *nset;
573 577 va_list pa;
574 578
575 579 if (priv != NULL) {
576 580
577 581 va_start(pa, priv);
578 582 nset = priv_vlist(pa);
579 583 va_end(pa);
580 584
581 585 if (nset == NULL)
582 586 return;
583 587
584 588 (void) priv_addset(nset, priv);
585 589 (void) setppriv(PRIV_OFF, permitted, nset);
586 590 priv_freeset(nset);
587 591 }
588 592
589 593 (void) setpflags(__PROC_PROTECT, 0);
590 594 }
591 595
592 596 /*
593 597 * The routine __init_suid_priv() is private to Solaris and is
594 598 * used by set-uid root programs to limit the privileges acquired
595 599 * to those actually needed.
596 600 */
597 601
598 602 static priv_set_t *bracketpriv;
599 603
600 604 int
601 605 __init_suid_priv(int flags, ...)
602 606 {
603 607 priv_set_t *nset = NULL;
604 608 priv_set_t *tmpset = NULL;
605 609 va_list pa;
606 610 int r = -1;
607 611 uid_t ruid, euid;
608 612
609 613 euid = geteuid();
610 614
611 615 /* If we're not set-uid root, don't reset the uid */
612 616 if (euid == 0) {
613 617 ruid = getuid();
614 618 /* If we're running as root, keep everything */
615 619 if (ruid == 0)
616 620 return (0);
617 621 }
618 622
619 623 /* Can call this only once */
620 624 if (bracketpriv != NULL)
621 625 return (-1);
622 626
623 627 va_start(pa, flags);
624 628
625 629 nset = priv_vlist(pa);
626 630
627 631 va_end(pa);
628 632
629 633 if (nset == NULL)
630 634 goto end;
631 635
632 636 tmpset = priv_allocset();
633 637
634 638 if (tmpset == NULL)
635 639 goto end;
636 640
637 641 /* We cannot grow our privileges beyond P, so start there */
638 642 (void) getppriv(permitted, tmpset);
639 643
640 644 /* Is the privilege we need even in P? */
↓ open down ↓ |
132 lines elided |
↑ open up ↑ |
641 645 if (!priv_issubset(nset, tmpset))
642 646 goto end;
643 647
644 648 bracketpriv = priv_allocset();
645 649 if (bracketpriv == NULL)
646 650 goto end;
647 651
648 652 priv_copyset(nset, bracketpriv);
649 653
650 654 /* Always add the basic set */
655 + /* XXX: Always add the default set? */
651 656 priv_union(priv_basic(), nset);
652 657
653 658 /* But don't add what we don't have */
654 659 priv_intersect(tmpset, nset);
655 660
656 661 (void) getppriv(inheritable, tmpset);
657 662
658 663 /* And stir in the inheritable privileges */
659 664 priv_union(tmpset, nset);
660 665
661 666 if ((r = setppriv(PRIV_SET, effective, tmpset)) != 0)
662 667 goto end;
663 668
664 669 if ((r = setppriv(PRIV_SET, permitted, nset)) != 0)
665 670 goto end;
666 671
667 672 if (flags & PU_CLEARLIMITSET)
668 673 priv_emptyset(nset);
669 674
670 675 if ((flags & (PU_LIMITPRIVS|PU_CLEARLIMITSET)) != 0 &&
671 676 (r = setppriv(PRIV_SET, limit, nset)) != 0)
672 677 goto end;
673 678
674 679 if (euid == 0)
675 680 r = setreuid(ruid, ruid);
676 681
677 682 end:
678 683 priv_freeset(tmpset);
679 684 priv_freeset(nset);
680 685 if (r != 0) {
681 686 /* Fail without leaving uid 0 around */
682 687 if (euid == 0)
683 688 (void) setreuid(ruid, ruid);
684 689 priv_freeset(bracketpriv);
685 690 bracketpriv = NULL;
686 691 }
687 692
688 693 return (r);
689 694 }
690 695
691 696 /*
692 697 * Toggle privileges on/off in the effective set.
693 698 */
694 699 int
695 700 __priv_bracket(priv_op_t op)
696 701 {
697 702 /* We're running fully privileged or didn't check errors first time */
698 703 if (bracketpriv == NULL)
699 704 return (0);
700 705
701 706 /* Only PRIV_ON and PRIV_OFF are valid */
702 707 if (op == PRIV_SET)
703 708 return (-1);
704 709
705 710 return (setppriv(op, effective, bracketpriv));
706 711 }
707 712
708 713 /*
709 714 * Remove privileges from E & P.
710 715 */
711 716 void
712 717 __priv_relinquish(void)
713 718 {
714 719 if (bracketpriv != NULL) {
715 720 (void) setppriv(PRIV_OFF, permitted, bracketpriv);
716 721 priv_freeset(bracketpriv);
717 722 bracketpriv = NULL;
718 723 }
719 724 }
720 725
721 726 /*
722 727 * Use binary search on the ordered list.
723 728 */
724 729 int
725 730 __priv_getbyname(const priv_data_t *d, const char *name)
726 731 {
727 732 char *const *list;
728 733 const int *order;
729 734 int lo = 0;
730 735 int hi;
731 736
732 737 if (d == NULL)
733 738 return (-1);
734 739
735 740 list = d->pd_privnames;
736 741 order = d->pd_setsort;
737 742 hi = d->pd_nprivs - 1;
738 743
739 744 if (strncasecmp(name, "priv_", 5) == 0)
740 745 name += 5;
741 746
742 747 do {
743 748 int mid = (lo + hi) / 2;
744 749 int res = strcasecmp(name, list[order[mid]]);
745 750
746 751 if (res == 0)
747 752 return (order[mid]);
748 753 else if (res < 0)
749 754 hi = mid - 1;
750 755 else
751 756 lo = mid + 1;
752 757 } while (lo <= hi);
753 758
754 759 errno = EINVAL;
755 760 return (-1);
756 761 }
757 762
758 763 int
759 764 priv_getbyname(const char *name)
760 765 {
761 766 WITHPRIVLOCKED(int, -1, __priv_getbyname(GETPRIVDATA(), name))
762 767 }
763 768
764 769 int
765 770 __priv_getsetbyname(const priv_data_t *d, const char *name)
766 771 {
767 772 int i;
768 773 int n = d->pd_nsets;
769 774 char *const *list = d->pd_setnames;
770 775
771 776 if (strncasecmp(name, "priv_", 5) == 0)
772 777 name += 5;
773 778
774 779 for (i = 0; i < n; i++) {
775 780 if (strcasecmp(list[i], name) == 0)
776 781 return (i);
777 782 }
778 783
779 784 errno = EINVAL;
780 785 return (-1);
781 786 }
782 787
783 788 int
784 789 priv_getsetbyname(const char *name)
785 790 {
786 791 /* Not locked: sets don't change */
787 792 return (__priv_getsetbyname(GETPRIVDATA(), name));
788 793 }
789 794
790 795 static const char *
791 796 priv_bynum(int i, int n, char **list)
792 797 {
793 798 if (i < 0 || i >= n)
794 799 return (NULL);
795 800
796 801 return (list[i]);
797 802 }
798 803
799 804 const char *
800 805 __priv_getbynum(const priv_data_t *d, int num)
801 806 {
802 807 if (d == NULL)
803 808 return (NULL);
804 809 return (priv_bynum(num, d->pd_nprivs, d->pd_privnames));
805 810 }
806 811
807 812 const char *
808 813 priv_getbynum(int num)
809 814 {
810 815 WITHPRIVLOCKED(const char *, NULL, __priv_getbynum(GETPRIVDATA(), num))
811 816 }
812 817
813 818 const char *
814 819 __priv_getsetbynum(const priv_data_t *d, int num)
815 820 {
816 821 if (d == NULL)
817 822 return (NULL);
818 823 return (priv_bynum(num, d->pd_nsets, d->pd_setnames));
819 824 }
820 825
821 826 const char *
822 827 priv_getsetbynum(int num)
823 828 {
824 829 return (__priv_getsetbynum(GETPRIVDATA(), num));
825 830 }
826 831
827 832
828 833 /*
829 834 * Privilege manipulation functions
830 835 *
831 836 * Without knowing the details of the privilege set implementation,
832 837 * opaque pointers can be used to manipulate sets at will.
833 838 */
834 839
835 840 static priv_set_t *
836 841 __priv_allocset(priv_data_t *d)
837 842 {
838 843 if (d == NULL)
839 844 return (NULL);
840 845
841 846 return (libc_malloc(d->pd_setsize));
842 847 }
843 848
844 849 priv_set_t *
845 850 priv_allocset(void)
846 851 {
847 852 return (__priv_allocset(GETPRIVDATA()));
848 853 }
849 854
850 855 void
851 856 priv_freeset(priv_set_t *p)
852 857 {
853 858 int er = errno;
854 859
855 860 libc_free(p);
856 861 errno = er;
857 862 }
858 863
859 864 void
860 865 __priv_emptyset(priv_data_t *d, priv_set_t *set)
861 866 {
862 867 (void) memset(set, 0, d->pd_setsize);
863 868 }
864 869
865 870 void
866 871 priv_emptyset(priv_set_t *set)
867 872 {
↓ open down ↓ |
207 lines elided |
↑ open up ↑ |
868 873 __priv_emptyset(GETPRIVDATA(), set);
869 874 }
870 875
871 876 void
872 877 priv_basicset(priv_set_t *set)
873 878 {
874 879 priv_copyset(priv_basic(), set);
875 880 }
876 881
877 882 void
883 +priv_defaultset(priv_set_t *set)
884 +{
885 + priv_copyset(priv_default(), set);
886 +}
887 +
888 +void
878 889 __priv_fillset(priv_data_t *d, priv_set_t *set)
879 890 {
880 891 (void) memset(set, ~0, d->pd_setsize);
881 892 }
882 893
883 894 void
884 895 priv_fillset(priv_set_t *set)
885 896 {
886 897 __priv_fillset(GETPRIVDATA(), set);
887 898 }
888 899
889 900
890 901 #define PRIV_TEST_BODY_D(d, test) \
891 902 int i; \
892 903 \
893 904 for (i = d->pd_pinfo->priv_setsize; i-- > 0; ) \
894 905 if (!(test)) \
895 906 return (B_FALSE); \
896 907 \
897 908 return (B_TRUE)
898 909
899 910 boolean_t
900 911 priv_isequalset(const priv_set_t *a, const priv_set_t *b)
901 912 {
902 913 priv_data_t *d;
903 914
904 915 LOADPRIVDATA(d);
905 916
906 917 return ((boolean_t)(memcmp(a, b, d->pd_setsize) == 0));
907 918 }
908 919
909 920 boolean_t
910 921 __priv_isemptyset(priv_data_t *d, const priv_set_t *set)
911 922 {
912 923 PRIV_TEST_BODY_D(d, ((priv_chunk_t *)set)[i] == 0);
913 924 }
914 925
915 926 boolean_t
916 927 priv_isemptyset(const priv_set_t *set)
917 928 {
918 929 return (__priv_isemptyset(GETPRIVDATA(), set));
919 930 }
920 931
921 932 boolean_t
922 933 __priv_isfullset(priv_data_t *d, const priv_set_t *set)
923 934 {
924 935 PRIV_TEST_BODY_D(d, ((priv_chunk_t *)set)[i] == ~(priv_chunk_t)0);
925 936 }
926 937
927 938 boolean_t
928 939 priv_isfullset(const priv_set_t *set)
929 940 {
930 941 return (__priv_isfullset(GETPRIVDATA(), set));
931 942 }
932 943
933 944 /*
934 945 * Return true if a is a subset of b
935 946 */
936 947 boolean_t
937 948 __priv_issubset(priv_data_t *d, const priv_set_t *a, const priv_set_t *b)
938 949 {
939 950 PRIV_TEST_BODY_D(d, (((priv_chunk_t *)a)[i] | ((priv_chunk_t *)b)[i]) ==
940 951 ((priv_chunk_t *)b)[i]);
941 952 }
942 953
943 954 boolean_t
944 955 priv_issubset(const priv_set_t *a, const priv_set_t *b)
945 956 {
946 957 return (__priv_issubset(GETPRIVDATA(), a, b));
947 958 }
948 959
949 960 #define PRIV_CHANGE_BODY(a, op, b) \
950 961 int i; \
951 962 priv_data_t *d; \
952 963 \
953 964 LOADPRIVDATA(d); \
954 965 \
955 966 for (i = 0; i < d->pd_pinfo->priv_setsize; i++) \
956 967 ((priv_chunk_t *)a)[i] op \
957 968 ((priv_chunk_t *)b)[i]
958 969
959 970 /* B = A ^ B */
960 971 void
961 972 priv_intersect(const priv_set_t *a, priv_set_t *b)
962 973 {
963 974 /* CSTYLED */
964 975 PRIV_CHANGE_BODY(b, &=, a);
965 976 }
966 977
967 978 /* B = A */
968 979 void
969 980 priv_copyset(const priv_set_t *a, priv_set_t *b)
970 981 {
971 982 /* CSTYLED */
972 983 PRIV_CHANGE_BODY(b, =, a);
973 984 }
974 985
975 986 /* B = A v B */
976 987 void
977 988 priv_union(const priv_set_t *a, priv_set_t *b)
978 989 {
979 990 /* CSTYLED */
980 991 PRIV_CHANGE_BODY(b, |=, a);
981 992 }
982 993
983 994 /* A = ! A */
984 995 void
985 996 priv_inverse(priv_set_t *a)
986 997 {
987 998 PRIV_CHANGE_BODY(a, = ~, a);
988 999 }
989 1000
990 1001 /*
991 1002 * Manipulating single privileges.
992 1003 */
993 1004
994 1005 int
995 1006 priv_addset(priv_set_t *a, const char *p)
996 1007 {
997 1008 int priv = priv_getbyname(p);
998 1009
999 1010 if (priv < 0)
1000 1011 return (-1);
1001 1012
1002 1013 PRIV_ADDSET(a, priv);
1003 1014
1004 1015 return (0);
1005 1016 }
1006 1017
1007 1018 int
1008 1019 priv_delset(priv_set_t *a, const char *p)
1009 1020 {
1010 1021 int priv = priv_getbyname(p);
1011 1022
1012 1023 if (priv < 0)
1013 1024 return (-1);
1014 1025
1015 1026 PRIV_DELSET(a, priv);
1016 1027 return (0);
1017 1028 }
1018 1029
1019 1030 boolean_t
1020 1031 priv_ismember(const priv_set_t *a, const char *p)
1021 1032 {
1022 1033 int priv = priv_getbyname(p);
1023 1034
1024 1035 if (priv < 0)
1025 1036 return (B_FALSE);
1026 1037
1027 1038 return ((boolean_t)PRIV_ISMEMBER(a, priv));
1028 1039 }
↓ open down ↓ |
141 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX