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