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 pfexec
= B_FALSE
;
67 static boolean_t xpol
= B_FALSE
;
68 static int mode
= PRIV_STR_PORT
;
71 main(int argc
, char **argv
)
77 (void) setlocale(LC_ALL
, "");
78 (void) textdomain(TEXT_DOMAIN
);
80 if ((command
= strrchr(argv
[0], '/')) != NULL
)
85 while ((opt
= getopt(argc
, argv
, "lDNPevs:xS")) != EOF
) {
106 mode
= PRIV_STR_SHORT
;
114 if ((rc
= parsespec(optarg
)) != 0)
130 if ((argc
< 1 && !list
) || Doff
&& Don
|| list
&& (set
|| exec
))
134 * Make sure we'll have enough file descriptors to handle a target
135 * that has many many mappings.
137 if (getrlimit(RLIMIT_NOFILE
, &rlim
) == 0) {
138 rlim
.rlim_cur
= rlim
.rlim_max
;
139 (void) setrlimit(RLIMIT_NOFILE
, &rlim
);
140 (void) enable_extended_FILE_stdio(-1, -1);
145 rc
= execvp(argv
[0], &argv
[0]);
146 (void) fprintf(stderr
, "%s: %s: %s\n", command
, argv
[0],
161 struct ps_prochandle
*Pr
;
170 procname
= arg
; /* for perr() */
172 if ((Pr
= proc_arg_grab(arg
, set
? PR_ARG_PIDS
: PR_ARG_ANY
,
173 PGRAB_RETAIN
| PGRAB_FORCE
| (set
? 0 : PGRAB_RDONLY
) |
174 PGRAB_NOSTOP
, &gcode
)) == NULL
) {
175 (void) fprintf(stderr
, "%s: cannot examine %s: %s\n",
176 command
, arg
, Pgrab_error(gcode
));
180 if (Ppriv(Pr
, &ppriv
) == -1) {
185 sz
= PRIV_PRPRIV_SIZE(ppriv
);
188 * The ppriv fields are unsigned and may overflow, so check them
189 * separately. Size must be word aligned, so check that too.
190 * Make sure size is "smallish" too.
192 if ((sz
& 3) || ppriv
->pr_nsets
== 0 ||
193 sz
/ ppriv
->pr_nsets
< ppriv
->pr_setsize
||
194 ppriv
->pr_infosize
> sz
|| sz
> 1024 * 1024) {
195 (void) fprintf(stderr
,
196 "%s: %s: bad PRNOTES section, size = %lx\n",
197 command
, arg
, (long)sz
);
199 Ppriv_free(Pr
, ppriv
);
204 privupdate(ppriv
, arg
);
205 if (Psetpriv(Pr
, ppriv
) != 0) {
208 Ppriv_free(Pr
, ppriv
);
212 Ppriv_free(Pr
, ppriv
);
216 if (Pstate(Pr
) == PS_DEAD
) {
217 (void) printf("core '%s' of %d:\t%.70s\n",
218 arg
, (int)Ppsinfo(Pr
)->pr_pid
, Ppsinfo(Pr
)->pr_psargs
);
219 pdata
= Pprivinfo(Pr
);
220 nodata
= Pstate(Pr
) == PS_DEAD
&& pdata
== NULL
;
222 (void) printf("%d:\t%.70s\n",
223 (int)Ppsinfo(Pr
)->pr_pid
, Ppsinfo(Pr
)->pr_psargs
);
228 x
= (char *)ppriv
+ sz
- ppriv
->pr_infosize
;
229 while (x
< (char *)ppriv
+ sz
) {
230 /* LINTED: alignment */
231 priv_info_t
*pi
= (priv_info_t
*)x
;
232 priv_info_uint_t
*pii
;
234 switch (pi
->priv_info_type
) {
235 case PRIV_INFO_FLAGS
:
236 /* LINTED: alignment */
237 pii
= (priv_info_uint_t
*)x
;
238 (void) printf("flags =");
240 (void) putchar('\n');
243 (void) fprintf(stderr
, "%s: unknown priv_info: %d\n",
244 arg
, pi
->priv_info_type
);
247 if (pi
->priv_info_size
> ppriv
->pr_infosize
||
248 pi
->priv_info_size
<= sizeof (priv_info_t
) ||
249 (pi
->priv_info_size
& 3) != 0) {
250 (void) fprintf(stderr
, "%s: bad priv_info_size: %u\n",
251 arg
, pi
->priv_info_size
);
254 x
+= pi
->priv_info_size
;
257 for (i
= 0; i
< ppriv
->pr_nsets
; i
++) {
258 extern const char *__priv_getsetbynum(const void *, int);
259 const char *setnm
= pdata
? __priv_getsetbynum(pdata
, i
) :
262 (priv_chunk_t
*)&ppriv
->pr_sets
[ppriv
->pr_setsize
* i
];
265 (void) printf("\t%c: ", setnm
&& !nodata
? *setnm
: '?');
267 extern char *__priv_set_to_str(void *,
268 const priv_set_t
*, char, int);
269 priv_set_t
*pset
= (priv_set_t
*)pc
;
274 s
= __priv_set_to_str(pdata
, pset
, ',', mode
);
276 s
= priv_set_to_str(pset
, ',', mode
);
281 for (j
= 0; j
< ppriv
->pr_setsize
; j
++)
282 (void) printf("%08x", pc
[j
]);
283 (void) putchar('\n');
287 Ppriv_free(Pr
, ppriv
);
294 (void) fprintf(stderr
, "%s: %s: %s\n", command
, s
, strerror(errno
));
304 (void) fprintf(stderr
, "%s: ", procname
);
315 (void) fprintf(stderr
,
316 "usage:\t%s [-v] [-S] [-D|-N] [-s spec] { pid | core } ...\n"
317 "\t%s -e [-D|-N] [-M] [-s spec] cmd [args ...]\n"
318 "\t%s -l [-v] [privilege ...]\n"
319 " (report, set or list process privileges)\n", command
,
326 * Parse the privilege bits to add and/or remove from
329 * [EPIL][+-=]priv,priv,priv
333 strindex(char c
, const char *str
)
349 badspec(const char *spec
)
351 (void) fprintf(stderr
, "%s: bad privilege specification: \"%s\"\n",
358 * For each set, you can set either add and/or
359 * remove or you can set assign.
361 static priv_set_t
**rem
, **add
, **assign
;
362 static const priv_impl_info_t
*pri
= NULL
;
373 pri
= getprivimplinfo();
376 fatal("getprivimplinfo");
378 sets
= malloc(pri
->priv_nsets
+ 1);
382 for (i
= 0; i
< pri
->priv_nsets
; i
++) {
383 sets
[i
] = *priv_getsetbynum(i
);
384 if (islower(sets
[i
]))
385 sets
[i
] = toupper(sets
[i
]);
388 sets
[pri
->priv_nsets
] = '\0';
390 rem
= calloc(pri
->priv_nsets
, sizeof (priv_set_t
*));
391 add
= calloc(pri
->priv_nsets
, sizeof (priv_set_t
*));
392 assign
= calloc(pri
->priv_nsets
, sizeof (priv_set_t
*));
393 if (rem
== NULL
|| add
== NULL
|| assign
== NULL
)
398 parsespec(const char *spec
)
406 boolean_t freeupd
= B_TRUE
;
411 p
= strpbrk(spec
, "+-=");
413 if (p
== NULL
|| p
- spec
> pri
->priv_nsets
)
416 if (p
[1] == '\0' || (upd
= priv_str_to_set(p
+ 1, ",", NULL
)) == NULL
)
433 /* Update all sets? */
434 if (count
== 0 || *spec
== 'a' || *spec
== 'A') {
435 count
= pri
->priv_nsets
;
440 for (i
= 0; i
< count
; i
++) {
441 int ind
= strindex(q
[i
], sets
);
446 /* Assign is mutually exclusive with add/remove and itself */
447 if (((toupd
== &rem
|| toupd
== &add
) && assign
[ind
] != NULL
) ||
448 (toupd
== &assign
&& (assign
[ind
] != NULL
||
449 rem
[ind
] != NULL
|| add
[ind
] != NULL
))) {
450 (void) fprintf(stderr
, "%s: conflicting spec: %s\n",
454 if ((*toupd
)[ind
] != NULL
) {
456 priv_intersect(upd
, (*toupd
)[ind
]);
458 priv_union(upd
, (*toupd
)[ind
]);
470 privupdate(prpriv_t
*pr
, const char *arg
)
475 for (i
= 0; i
< pri
->priv_nsets
; i
++) {
477 (priv_set_t
*)&pr
->pr_sets
[pr
->pr_setsize
* i
];
479 priv_intersect(rem
[i
], target
);
481 priv_union(add
[i
], target
);
482 if (assign
[i
] != NULL
)
483 priv_copyset(assign
[i
], target
);
487 if (Doff
|| Don
|| pfexec
|| xpol
) {
488 priv_info_uint_t
*pii
;
489 int sz
= PRIV_PRPRIV_SIZE(pr
);
490 char *x
= (char *)pr
+ PRIV_PRPRIV_INFO_OFFSET(pr
);
493 while (x
< (char *)pr
+ sz
) {
494 /* LINTED: alignment */
495 priv_info_t
*pi
= (priv_info_t
*)x
;
497 if (pi
->priv_info_type
== PRIV_INFO_FLAGS
) {
498 /* LINTED: alignment */
499 pii
= (priv_info_uint_t
*)x
;
503 if (pi
->priv_info_size
> pr
->pr_infosize
||
504 pi
->priv_info_size
<= sizeof (priv_info_t
) ||
505 (pi
->priv_info_size
& 3) != 0)
507 x
+= pi
->priv_info_size
;
509 (void) fprintf(stderr
,
510 "%s: cannot find privilege flags to set\n", arg
);
515 pr
->pr_infosize
= sizeof (priv_info_uint_t
);
516 /* LINTED: alignment */
517 pii
= (priv_info_uint_t
*)
518 ((char *)pr
+ PRIV_PRPRIV_INFO_OFFSET(pr
));
529 pii
->info
.priv_info_size
= sizeof (*pii
);
530 pii
->info
.priv_info_type
= PRIV_INFO_FLAGS
;
538 privupdate_self(void)
543 if (setpflags(PRIV_PFEXEC
, 1) != 0)
544 fatal("setpflags(PRIV_PFEXEC)");
548 priv_set_t
*target
= priv_allocset();
551 fatal("priv_allocet");
553 set
= priv_getsetbyname(PRIV_INHERITABLE
);
554 if (rem
[set
] != NULL
|| add
[set
] != NULL
||
555 assign
[set
] != NULL
) {
556 (void) getppriv(PRIV_INHERITABLE
, target
);
557 if (rem
[set
] != NULL
)
558 priv_intersect(rem
[set
], target
);
559 if (add
[set
] != NULL
)
560 priv_union(add
[set
], target
);
561 if (assign
[set
] != NULL
)
562 priv_copyset(assign
[set
], target
);
563 if (setppriv(PRIV_SET
, PRIV_INHERITABLE
, target
) != 0)
564 fatal("setppriv(Inheritable)");
566 set
= priv_getsetbyname(PRIV_LIMIT
);
567 if (rem
[set
] != NULL
|| add
[set
] != NULL
||
568 assign
[set
] != NULL
) {
569 (void) getppriv(PRIV_LIMIT
, target
);
570 if (rem
[set
] != NULL
)
571 priv_intersect(rem
[set
], target
);
572 if (add
[set
] != NULL
)
573 priv_union(add
[set
], target
);
574 if (assign
[set
] != NULL
)
575 priv_copyset(assign
[set
], target
);
576 if (setppriv(PRIV_SET
, PRIV_LIMIT
, target
) != 0)
577 fatal("setppriv(Limit)");
579 priv_freeset(target
);
583 (void) setpflags(PRIV_DEBUG
, Don
? 1 : 0);
585 (void) setpflags(PRIV_XPOLICY
, 1);
587 (void) setpflags(PRIV_PFEXEC
, 1);
591 dopriv(const char *p
)
595 char *text
= priv_gettext(p
);
599 for (p
= text
; q
= strchr(p
, '\n'); p
= q
+ 1) {
601 (void) printf("\t%s\n", p
);
609 dumppriv(char **argv
)
615 if (argv
[0] == NULL
) {
616 for (i
= 0; ((pname
= priv_getbynum(i
++)) != NULL
); )
619 for (; *argv
; argv
++) {
620 priv_set_t
*pset
= priv_str_to_set(*argv
, ",", NULL
);
623 (void) fprintf(stderr
, "%s: %s: bad privilege"
624 " list\n", command
, *argv
);
628 for (i
= 0; ((pname
= priv_getbynum(i
++)) != NULL
); )
629 if (priv_ismember(pset
, pname
))
640 { PRIV_DEBUG
, "PRIV_DEBUG" },
641 { PRIV_AWARE
, "PRIV_AWARE" },
642 { PRIV_AWARE_INHERIT
, "PRIV_AWARE_INHERIT" },
643 { PRIV_AWARE_RESET
, "PRIV_AWARE_RESET" },
644 { PRIV_XPOLICY
, "PRIV_XPOLICY" },
645 { PRIV_PFEXEC
, "PRIV_PFEXEC" },
649 * Print flags preceeded by a space.
652 flags2str(uint_t pflags
)
658 (void) fputs(" <none>", stdout
);
661 for (i
= 0; i
< sizeof (flags
)/sizeof (flags
[0]) && pflags
!= 0; i
++) {
662 if ((pflags
& flags
[i
].flag
) != 0) {
663 (void) printf("%c%s", c
, flags
[i
].name
);
664 pflags
&= ~flags
[i
].flag
;
669 (void) printf("%c<0x%x>", c
, pflags
);