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]
22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
25 * Copyright (c) 2013 by Delphix. All rights reserved.
26 * Copyright 2015, Joyent, Inc.
29 * Program to examine or set process privileges.
33 #include <stdio_ext.h>
39 #include <sys/types.h>
48 static int look(char *);
49 static void perr(char *);
50 static void usage(void);
51 static void loadprivinfo(void);
52 static int parsespec(const char *);
53 static void privupdate(prpriv_t
*, const char *);
54 static void privupdate_self(void);
55 static int dumppriv(char **);
56 static void flags2str(uint_t
);
59 static char *procname
;
60 static boolean_t verb
= B_FALSE
;
61 static boolean_t set
= B_FALSE
;
62 static boolean_t exec
= B_FALSE
;
63 static boolean_t Don
= B_FALSE
;
64 static boolean_t Doff
= B_FALSE
;
65 static boolean_t list
= B_FALSE
;
66 static boolean_t mac_aware
= B_FALSE
;
67 static boolean_t pfexec
= B_FALSE
;
68 static boolean_t xpol
= B_FALSE
;
69 static int mode
= PRIV_STR_PORT
;
72 main(int argc
, char **argv
)
78 (void) setlocale(LC_ALL
, "");
79 (void) textdomain(TEXT_DOMAIN
);
81 if ((command
= strrchr(argv
[0], '/')) != NULL
)
86 while ((opt
= getopt(argc
, argv
, "lDMNPevs:xS")) != EOF
) {
110 mode
= PRIV_STR_SHORT
;
118 if ((rc
= parsespec(optarg
)) != 0)
134 if ((argc
< 1 && !list
) || Doff
&& Don
|| list
&& (set
|| exec
) ||
135 (mac_aware
&& !exec
))
139 * Make sure we'll have enough file descriptors to handle a target
140 * that has many many mappings.
142 if (getrlimit(RLIMIT_NOFILE
, &rlim
) == 0) {
143 rlim
.rlim_cur
= rlim
.rlim_max
;
144 (void) setrlimit(RLIMIT_NOFILE
, &rlim
);
145 (void) enable_extended_FILE_stdio(-1, -1);
150 rc
= execvp(argv
[0], &argv
[0]);
151 (void) fprintf(stderr
, "%s: %s: %s\n", command
, argv
[0],
166 struct ps_prochandle
*Pr
;
175 procname
= arg
; /* for perr() */
177 if ((Pr
= proc_arg_grab(arg
, set
? PR_ARG_PIDS
: PR_ARG_ANY
,
178 PGRAB_RETAIN
| PGRAB_FORCE
| (set
? 0 : PGRAB_RDONLY
) |
179 PGRAB_NOSTOP
, &gcode
)) == NULL
) {
180 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
181 command
, arg
, Pgrab_error(gcode
));
185 if (Ppriv(Pr
, &ppriv
) == -1) {
190 sz
= PRIV_PRPRIV_SIZE(ppriv
);
193 * The ppriv fields are unsigned and may overflow, so check them
194 * separately. Size must be word aligned, so check that too.
195 * Make sure size is "smallish" too.
197 if ((sz
& 3) || ppriv
->pr_nsets
== 0 ||
198 sz
/ ppriv
->pr_nsets
< ppriv
->pr_setsize
||
199 ppriv
->pr_infosize
> sz
|| sz
> 1024 * 1024) {
200 (void) fprintf(stderr
,
201 "%s: %s: bad PRNOTES section, size = %lx\n",
202 command
, arg
, (long)sz
);
204 Ppriv_free(Pr
, ppriv
);
209 privupdate(ppriv
, arg
);
210 if (Psetpriv(Pr
, ppriv
) != 0) {
213 Ppriv_free(Pr
, ppriv
);
217 Ppriv_free(Pr
, ppriv
);
221 if (Pstate(Pr
) == PS_DEAD
) {
222 (void) printf("core '%s' of %d:\t%.70s\n",
223 arg
, (int)Ppsinfo(Pr
)->pr_pid
, Ppsinfo(Pr
)->pr_psargs
);
224 pdata
= Pprivinfo(Pr
);
225 nodata
= Pstate(Pr
) == PS_DEAD
&& pdata
== NULL
;
227 (void) printf("%d:\t%.70s\n",
228 (int)Ppsinfo(Pr
)->pr_pid
, Ppsinfo(Pr
)->pr_psargs
);
233 x
= (char *)ppriv
+ sz
- ppriv
->pr_infosize
;
234 while (x
< (char *)ppriv
+ sz
) {
235 /* LINTED: alignment */
236 priv_info_t
*pi
= (priv_info_t
*)x
;
237 priv_info_uint_t
*pii
;
239 switch (pi
->priv_info_type
) {
240 case PRIV_INFO_FLAGS
:
241 /* LINTED: alignment */
242 pii
= (priv_info_uint_t
*)x
;
243 (void) printf("flags =");
245 (void) putchar('\n');
248 (void) fprintf(stderr
, "%s: unknown priv_info: %d\n",
249 arg
, pi
->priv_info_type
);
252 if (pi
->priv_info_size
> ppriv
->pr_infosize
||
253 pi
->priv_info_size
<= sizeof (priv_info_t
) ||
254 (pi
->priv_info_size
& 3) != 0) {
255 (void) fprintf(stderr
, "%s: bad priv_info_size: %u\n",
256 arg
, pi
->priv_info_size
);
259 x
+= pi
->priv_info_size
;
262 for (i
= 0; i
< ppriv
->pr_nsets
; i
++) {
263 extern const char *__priv_getsetbynum(const void *, int);
264 const char *setnm
= pdata
? __priv_getsetbynum(pdata
, i
) :
267 (priv_chunk_t
*)&ppriv
->pr_sets
[ppriv
->pr_setsize
* i
];
270 (void) printf("\t%c: ", setnm
&& !nodata
? *setnm
: '?');
272 extern char *__priv_set_to_str(void *,
273 const priv_set_t
*, char, int);
274 priv_set_t
*pset
= (priv_set_t
*)pc
;
279 s
= __priv_set_to_str(pdata
, pset
, ',', mode
);
281 s
= priv_set_to_str(pset
, ',', mode
);
286 for (j
= 0; j
< ppriv
->pr_setsize
; j
++)
287 (void) printf("%08x", pc
[j
]);
288 (void) putchar('\n');
292 Ppriv_free(Pr
, ppriv
);
299 (void) fprintf(stderr
, "%s: %s: %s\n", command
, s
, strerror(errno
));
309 (void) fprintf(stderr
, "%s: ", procname
);
320 (void) fprintf(stderr
,
321 "usage:\t%s [-v] [-S] [-D|-N] [-s spec] { pid | core } ...\n"
322 "\t%s -e [-D|-N] [-M] [-s spec] cmd [args ...]\n"
323 "\t%s -l [-v] [privilege ...]\n"
324 " (report, set or list process privileges)\n", command
,
331 * Parse the privilege bits to add and/or remove from
334 * [EPIL][+-=]priv,priv,priv
338 strindex(char c
, const char *str
)
354 badspec(const char *spec
)
356 (void) fprintf(stderr
, "%s: bad privilege specification: \"%s\"\n",
363 * For each set, you can set either add and/or
364 * remove or you can set assign.
366 static priv_set_t
**rem
, **add
, **assign
;
367 static const priv_impl_info_t
*pri
= NULL
;
378 pri
= getprivimplinfo();
381 fatal("getprivimplinfo");
383 sets
= malloc(pri
->priv_nsets
+ 1);
387 for (i
= 0; i
< pri
->priv_nsets
; i
++) {
388 sets
[i
] = *priv_getsetbynum(i
);
389 if (islower(sets
[i
]))
390 sets
[i
] = toupper(sets
[i
]);
393 sets
[pri
->priv_nsets
] = '\0';
395 rem
= calloc(pri
->priv_nsets
, sizeof (priv_set_t
*));
396 add
= calloc(pri
->priv_nsets
, sizeof (priv_set_t
*));
397 assign
= calloc(pri
->priv_nsets
, sizeof (priv_set_t
*));
398 if (rem
== NULL
|| add
== NULL
|| assign
== NULL
)
403 parsespec(const char *spec
)
411 boolean_t freeupd
= B_TRUE
;
416 p
= strpbrk(spec
, "+-=");
418 if (p
== NULL
|| p
- spec
> pri
->priv_nsets
)
421 if (p
[1] == '\0' || (upd
= priv_str_to_set(p
+ 1, ",", NULL
)) == NULL
)
438 /* Update all sets? */
439 if (count
== 0 || *spec
== 'a' || *spec
== 'A') {
440 count
= pri
->priv_nsets
;
445 for (i
= 0; i
< count
; i
++) {
446 int ind
= strindex(q
[i
], sets
);
451 /* Assign is mutually exclusive with add/remove and itself */
452 if (((toupd
== &rem
|| toupd
== &add
) && assign
[ind
] != NULL
) ||
453 (toupd
== &assign
&& (assign
[ind
] != NULL
||
454 rem
[ind
] != NULL
|| add
[ind
] != NULL
))) {
455 (void) fprintf(stderr
, "%s: conflicting spec: %s\n",
459 if ((*toupd
)[ind
] != NULL
) {
461 priv_intersect(upd
, (*toupd
)[ind
]);
463 priv_union(upd
, (*toupd
)[ind
]);
475 privupdate(prpriv_t
*pr
, const char *arg
)
480 for (i
= 0; i
< pri
->priv_nsets
; i
++) {
482 (priv_set_t
*)&pr
->pr_sets
[pr
->pr_setsize
* i
];
484 priv_intersect(rem
[i
], target
);
486 priv_union(add
[i
], target
);
487 if (assign
[i
] != NULL
)
488 priv_copyset(assign
[i
], target
);
492 if (Doff
|| Don
|| pfexec
|| xpol
) {
493 priv_info_uint_t
*pii
;
494 int sz
= PRIV_PRPRIV_SIZE(pr
);
495 char *x
= (char *)pr
+ PRIV_PRPRIV_INFO_OFFSET(pr
);
498 while (x
< (char *)pr
+ sz
) {
499 /* LINTED: alignment */
500 priv_info_t
*pi
= (priv_info_t
*)x
;
502 if (pi
->priv_info_type
== PRIV_INFO_FLAGS
) {
503 /* LINTED: alignment */
504 pii
= (priv_info_uint_t
*)x
;
508 if (pi
->priv_info_size
> pr
->pr_infosize
||
509 pi
->priv_info_size
<= sizeof (priv_info_t
) ||
510 (pi
->priv_info_size
& 3) != 0)
512 x
+= pi
->priv_info_size
;
514 (void) fprintf(stderr
,
515 "%s: cannot find privilege flags to set\n", arg
);
520 pr
->pr_infosize
= sizeof (priv_info_uint_t
);
521 /* LINTED: alignment */
522 pii
= (priv_info_uint_t
*)
523 ((char *)pr
+ PRIV_PRPRIV_INFO_OFFSET(pr
));
534 pii
->info
.priv_info_size
= sizeof (*pii
);
535 pii
->info
.priv_info_type
= PRIV_INFO_FLAGS
;
543 privupdate_self(void)
548 if (setpflags(NET_MAC_AWARE
, 1) != 0)
549 fatal("setpflags(NET_MAC_AWARE)");
550 if (setpflags(NET_MAC_AWARE_INHERIT
, 1) != 0)
551 fatal("setpflags(NET_MAC_AWARE_INHERIT)");
554 if (setpflags(PRIV_PFEXEC
, 1) != 0)
555 fatal("setpflags(PRIV_PFEXEC)");
559 priv_set_t
*target
= priv_allocset();
562 fatal("priv_allocet");
564 set
= priv_getsetbyname(PRIV_INHERITABLE
);
565 if (rem
[set
] != NULL
|| add
[set
] != NULL
||
566 assign
[set
] != NULL
) {
567 (void) getppriv(PRIV_INHERITABLE
, target
);
568 if (rem
[set
] != NULL
)
569 priv_intersect(rem
[set
], target
);
570 if (add
[set
] != NULL
)
571 priv_union(add
[set
], target
);
572 if (assign
[set
] != NULL
)
573 priv_copyset(assign
[set
], target
);
574 if (setppriv(PRIV_SET
, PRIV_INHERITABLE
, target
) != 0)
575 fatal("setppriv(Inheritable)");
577 set
= priv_getsetbyname(PRIV_LIMIT
);
578 if (rem
[set
] != NULL
|| add
[set
] != NULL
||
579 assign
[set
] != NULL
) {
580 (void) getppriv(PRIV_LIMIT
, target
);
581 if (rem
[set
] != NULL
)
582 priv_intersect(rem
[set
], target
);
583 if (add
[set
] != NULL
)
584 priv_union(add
[set
], target
);
585 if (assign
[set
] != NULL
)
586 priv_copyset(assign
[set
], target
);
587 if (setppriv(PRIV_SET
, PRIV_LIMIT
, target
) != 0)
588 fatal("setppriv(Limit)");
590 priv_freeset(target
);
594 (void) setpflags(PRIV_DEBUG
, Don
? 1 : 0);
596 (void) setpflags(PRIV_XPOLICY
, 1);
598 (void) setpflags(PRIV_PFEXEC
, 1);
602 dopriv(const char *p
)
606 char *text
= priv_gettext(p
);
610 for (p
= text
; q
= strchr(p
, '\n'); p
= q
+ 1) {
612 (void) printf("\t%s\n", p
);
620 dumppriv(char **argv
)
626 if (argv
[0] == NULL
) {
627 for (i
= 0; ((pname
= priv_getbynum(i
++)) != NULL
); )
630 for (; *argv
; argv
++) {
631 priv_set_t
*pset
= priv_str_to_set(*argv
, ",", NULL
);
634 (void) fprintf(stderr
, "%s: %s: bad privilege"
635 " list\n", command
, *argv
);
639 for (i
= 0; ((pname
= priv_getbynum(i
++)) != NULL
); )
640 if (priv_ismember(pset
, pname
))
651 { PRIV_DEBUG
, "PRIV_DEBUG" },
652 { PRIV_AWARE
, "PRIV_AWARE" },
653 { PRIV_AWARE_INHERIT
, "PRIV_AWARE_INHERIT" },
654 { PRIV_AWARE_RESET
, "PRIV_AWARE_RESET" },
655 { PRIV_XPOLICY
, "PRIV_XPOLICY" },
656 { PRIV_PFEXEC
, "PRIV_PFEXEC" },
657 { NET_MAC_AWARE
, "NET_MAC_AWARE" },
658 { NET_MAC_AWARE_INHERIT
, "NET_MAC_AWARE_INHERIT" },
662 * Print flags preceeded by a space.
665 flags2str(uint_t pflags
)
671 (void) fputs(" <none>", stdout
);
674 for (i
= 0; i
< sizeof (flags
)/sizeof (flags
[0]) && pflags
!= 0; i
++) {
675 if ((pflags
& flags
[i
].flag
) != 0) {
676 (void) printf("%c%s", c
, flags
[i
].name
);
677 pflags
&= ~flags
[i
].flag
;
682 (void) printf("%c<0x%x>", c
, pflags
);