psecflags.c revision d2a70789f056fc6c9ce3ab047b52126d80b0e3da
/*
* This file and its contents are supplied under the terms of the
* Common Development and Distribution License ("CDDL"), version 1.0.
* You may only use this file in accordance with the terms of version
* 1.0 of the CDDL.
*
* A full copy of the text of the CDDL should have accompanied this
* source. A copy of the CDDL is also available via the Internet at
* http://www.illumos.org/license/CDDL.
*/
/* Copyright 2015, Richard Lowe. */
#include <err.h>
#include <errno.h>
#include <grp.h>
#include <libintl.h>
#include <procfs.h>
#include <project.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/secflags.h>
#include <sys/types.h>
#include <libproc.h>
#include <libzonecfg.h>
extern const char *__progname;
static void
print_flags(const char *set, secflagset_t flags)
{
char buf[1024];
secflags_to_str(flags, buf, sizeof (buf));
(void) printf("\t%s:\t%s\n", set, buf);
}
/*
* Structure defining idtypes known to the priocntl command
* along with the corresponding names.
* The idtype values themselves are defined in <sys/procset.h>.
*/
static struct idtypes {
idtype_t type;
char *name;
} idtypes [] = {
{ P_ALL, "all" },
{ P_CTID, "contract" },
{ P_CTID, "ctid" },
{ P_GID, "gid" },
{ P_GID, "group" },
{ P_PGID, "pgid" },
{ P_PID, "pid" },
{ P_PPID, "ppid" },
{ P_PROJID, "project" },
{ P_PROJID, "projid" },
{ P_SID, "session", },
{ P_SID, "sid" },
{ P_SID, "sid" },
{ P_TASKID, "taskid" },
{ P_UID, "uid" },
{ P_UID, "user" },
{ P_ZONEID, "zone" },
{ P_ZONEID, "zoneid" },
{ 0, NULL }
};
static int
str2idtype(char *idtypnm, idtype_t *idtypep)
{
struct idtypes *curp;
for (curp = idtypes; curp->name != NULL; curp++) {
if (strncasecmp(curp->name, idtypnm,
strlen(curp->name)) == 0) {
*idtypep = curp->type;
return (0);
}
}
return (-1);
}
static id_t
getid(idtype_t type, char *value)
{
struct passwd *pwd;
struct group *grp;
id_t ret;
char *endp;
switch (type) {
case P_UID:
if ((pwd = getpwnam(value)) != NULL)
return (pwd->pw_uid);
break;
case P_GID:
if ((grp = getgrnam(value)) != NULL)
return (grp->gr_gid);
break;
case P_PROJID:
if ((ret = getprojidbyname(value)) != (id_t)-1)
return (ret);
break;
case P_ZONEID:
if (zone_get_id(value, &ret) == 0)
return (ret);
break;
default:
break;
}
errno = 0;
ret = (id_t)strtoul(value, &endp, 10);
if ((errno != 0) || (*endp != '\0'))
return ((id_t)-1);
return (ret);
}
int
main(int argc, char **argv)
{
secflagdelta_t act;
psecflagwhich_t which = PSF_INHERIT;
int ret = 0;
int pgrab_flags = PGRAB_RDONLY;
int opt;
char *idtypename = NULL;
idtype_t idtype = P_PID;
boolean_t usage = B_FALSE;
boolean_t e_flag = B_FALSE;
boolean_t l_flag = B_FALSE;
boolean_t s_flag = B_FALSE;
int errc = 0;
while ((opt = getopt(argc, argv, "eFi:ls:")) != -1) {
switch (opt) {
case 'e':
e_flag = B_TRUE;
break;
case 'F':
pgrab_flags |= PGRAB_FORCE;
break;
case 'i':
idtypename = optarg;
break;
case 's':
s_flag = B_TRUE;
if ((strlen(optarg) >= 2) &&
((optarg[1] == '='))) {
switch (optarg[0]) {
case 'L':
which = PSF_LOWER;
break;
case 'U':
which = PSF_UPPER;
break;
case 'I':
which = PSF_INHERIT;
break;
case 'E':
errx(1, "the effective flags cannot "
"be changed", optarg[0]);
default:
errx(1, "unknown security flag "
"set: '%c'", optarg[0]);
}
optarg += 2;
}
if (secflags_parse(NULL, optarg, &act) == -1)
errx(1, "couldn't parse security flags: %s",
optarg);
break;
case 'l':
l_flag = B_TRUE;
break;
default:
usage = B_TRUE;
break;
}
}
argc -= optind;
argv += optind;
if (l_flag && ((idtypename != NULL) || s_flag || (argc != 0)))
usage = B_TRUE;
if ((idtypename != NULL) && !s_flag)
usage = B_TRUE;
if (e_flag && !s_flag)
usage = B_TRUE;
if (!l_flag && argc <= 0)
usage = B_TRUE;
if (usage) {
(void) fprintf(stderr,
gettext("usage:\t%s [-F] { pid | core } ...\n"),
__progname);
(void) fprintf(stderr,
gettext("\t%s -s spec [-i idtype] id ...\n"),
__progname);
(void) fprintf(stderr,
gettext("\t%s -s spec -e command [arg]...\n"),
__progname);
(void) fprintf(stderr, gettext("\t%s -l\n"), __progname);
return (2);
}
if (l_flag) {
secflag_t i;
const char *name;
for (i = 0; (name = secflag_to_str(i)) != NULL; i++)
(void) printf("%s\n", name);
return (0);
} else if (s_flag && e_flag) {
/*
* Don't use the strerror() message for EPERM, "Not Owner"
* which is misleading.
*/
errc = psecflags(P_PID, P_MYID, which, &act);
switch (errc) {
case 0:
break;
case EPERM:
errx(1, gettext("failed setting "
"security-flags: Permission denied"));
break;
default:
err(1, gettext("failed setting security-flags"));
}
(void) execvp(argv[0], &argv[0]);
err(1, "%s", argv[0]);
} else if (s_flag) {
int i;
id_t id;
if (idtypename != NULL)
if (str2idtype(idtypename, &idtype) == -1)
errx(1, gettext("No such id type: '%s'"),
idtypename);
for (i = 0; i < argc; i++) {
if ((id = getid(idtype, argv[i])) == (id_t)-1) {
errx(1, gettext("invalid or non-existent "
"identifier: '%s'"), argv[i]);
}
/*
* Don't use the strerror() message for EPERM, "Not
* Owner" which is misleading.
*/
if (psecflags(idtype, id, which, &act) != 0) {
switch (errno) {
case EPERM:
errx(1, gettext("failed setting "
"security-flags: "
"Permission denied"));
break;
default:
err(1, gettext("failed setting "
"security-flags"));
}
}
}
return (0);
}
/* Display the flags for the given pids */
while (argc-- > 0) {
struct ps_prochandle *Pr;
const char *arg;
psinfo_t psinfo;
prsecflags_t *psf;
int gcode;
if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY,
pgrab_flags, &gcode)) == NULL) {
warnx(gettext("cannot examine %s: %s"),
arg, Pgrab_error(gcode));
ret = 1;
continue;
}
(void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
proc_unctrl_psinfo(&psinfo);
if (Pstate(Pr) == PS_DEAD) {
(void) printf(gettext("core '%s' of %d:\t%.70s\n"),
arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
} else {
(void) printf("%d:\t%.70s\n",
(int)psinfo.pr_pid, psinfo.pr_psargs);
}
if (Psecflags(Pr, &psf) != 0)
err(1, gettext("cannot read secflags of %s"), arg);
print_flags("E", psf->pr_effective);
print_flags("I", psf->pr_inherit);
print_flags("L", psf->pr_lower);
print_flags("U", psf->pr_upper);
Psecflags_free(psf);
Prelease(Pr, 0);
}
return (ret);
}