1 /*
   2  * This file and its contents are supplied under the terms of the
   3  * Common Development and Distribution License ("CDDL"), version 1.0.
   4  * You may only use this file in accordance with the terms of version
   5  * 1.0 of the CDDL.
   6  *
   7  * A full copy of the text of the CDDL should have accompanied this
   8  * source.  A copy of the CDDL is also available via the Internet at
   9  * http://www.illumos.org/license/CDDL.
  10  */
  11 
  12 #include <err.h>
  13 #include <errno.h>
  14 #include <grp.h>
  15 #include <libintl.h>
  16 #include <procfs.h>
  17 #include <project.h>
  18 #include <pwd.h>
  19 #include <stdio.h>
  20 #include <stdlib.h>
  21 #include <string.h>
  22 
  23 #include <libproc.h>
  24 #include <libzonecfg.h>
  25 
  26 extern const char *__progname;
  27 extern int psecflags(idtype_t, id_t, psecflags_cmd_t, uint_t);
  28 
  29 struct flagdesc {
  30         uint_t value;
  31         char *name;
  32 } flagdescs[] = {
  33         { PROC_SEC_ASLR, "aslr" },
  34         { 0x0, NULL }
  35 };
  36 
  37 void
  38 print_flags(char *set, uint_t flags)
  39 {
  40         char *buf;
  41         size_t buflen = 13;     /* 0x + 8 digits + comma + space + NUL */
  42         struct flagdesc *fd;
  43 
  44         if (flags == 0) {
  45                 (void) printf(gettext("\t%s:\tnone\n"), set);
  46                 return;
  47         }
  48 
  49         for (fd = flagdescs; fd->value != 0x0; fd++)
  50                 buflen += strlen(fd->name) + 2; /* + comma, space */
  51 
  52         if ((buf = calloc(buflen, sizeof (char))) == NULL)
  53                 err(1, gettext("allocation failed"));
  54 
  55         for (fd = flagdescs; fd->value != 0; fd++) {
  56                 if (flags & fd->value)
  57                         (void) snprintf(buf, buflen, "%s, %s", buf, fd->name);
  58                 flags &= ~fd->value;
  59         }
  60 
  61         if (flags != 0) /* Contained unknown flags */
  62                 (void) snprintf(buf, buflen, "%s, 0x%08x", buf, flags);
  63 
  64         buf += 2;               /* Skip the comma on the first entry */
  65 
  66         (void) printf("\t%s:\t%s\n", set, buf);
  67         free(buf);
  68 }
  69 
  70 typedef struct {
  71         psecflags_cmd_t cmd;
  72         uint_t value;
  73 } act_arg_t;
  74 
  75 act_arg_t *
  76 parse_secflags(const char *spec)
  77 {
  78         char *flag = NULL;
  79         char *s;
  80         struct flagdesc *fd;
  81         boolean_t fail = B_FALSE;
  82         act_arg_t *ret;
  83 
  84         if ((ret = malloc(sizeof (act_arg_t))) == NULL)
  85                 err(1, gettext("allocation failed"));
  86 
  87         if ((s = strdup(spec)) == NULL)
  88                 err(1, gettext("allocation failed"));
  89 
  90         if (s[0] == '+') {
  91                 ret->cmd = PSECFLAGS_ENABLE;
  92                 s++;
  93         } else if (s[0] == '-') {
  94                 ret->cmd = PSECFLAGS_DISABLE;
  95                 s++;
  96         } else {
  97                 ret->cmd = PSECFLAGS_SET;
  98         }
  99 
 100         if (strncasecmp("none", s, strlen(s)) == 0) {
 101                 if (ret->cmd != PSECFLAGS_SET)
 102                         errx(1, gettext("'none' is only valid with set, not "
 103                             "enable or disable"));
 104                 ret->value = 0x0;
 105                 free(s);
 106                 return (ret);
 107         }
 108 
 109 next:
 110         while ((flag = strsep(&s, ",")) != NULL) {
 111                 for (fd = flagdescs; fd->value != 0x0; fd++) {
 112                         if (strncasecmp(flag, fd->name,
 113                             strlen(fd->name)) == 0) {
 114                                 ret->value |= fd->value;
 115                                 goto next;
 116                         }
 117                 }
 118 
 119                 if (strncasecmp("none", flag, strlen(flag)) == 0) {
 120                         (void) fprintf(stderr, gettext("%s: 'none' is not "
 121                             "valid with other flags\n"), __progname);
 122                 } else {
 123                         (void) fprintf(stderr, gettext("%s: invalid "
 124                             "security-flag: '%s'\n"),
 125                             __progname, flag);
 126                 }
 127                 fail = B_TRUE;
 128         }
 129 
 130         free(s);
 131 
 132         if (fail)
 133                 exit(1);
 134 
 135         return (ret);
 136 }
 137 
 138 /*
 139  * Structure defining idtypes known to the priocntl command
 140  * along with the corresponding names and a liberal guess
 141  * of the max number of procs sharing any given ID of that type.
 142  * The idtype values themselves are defined in <sys/procset.h>.
 143  */
 144 static struct idtypes {
 145         idtype_t        type;
 146         char            *name;
 147 } idtypes [] = {
 148         { P_ALL,        "all"           },
 149         { P_CTID,       "contract"      },
 150         { P_CTID,       "ctid"          },
 151         { P_GID,        "gid"           },
 152         { P_GID,        "group"         },
 153         { P_PGID,       "pgid"          },
 154         { P_PID,        "pid"           },
 155         { P_PPID,       "ppid"          },
 156         { P_PROJID,     "project"       },
 157         { P_PROJID,     "projid"        },
 158         { P_SID,        "session",      },
 159         { P_SID,        "sid"           },
 160         { P_SID,        "sid"           },
 161         { P_TASKID,     "taskid"        },
 162         { P_UID,        "uid"           },
 163         { P_UID,        "user"          },
 164         { P_ZONEID,     "zone"          },
 165         { P_ZONEID,     "zoneid"        },
 166         { 0,            NULL            }
 167 };
 168 
 169 int
 170 str2idtype(char *idtypnm, idtype_t *idtypep)
 171 {
 172         struct idtypes  *curp;
 173 
 174         for (curp = idtypes; curp->name != NULL; curp++) {
 175                 if (strncasecmp(curp->name, idtypnm,
 176                     strlen(curp->name)) == 0) {
 177                         *idtypep = curp->type;
 178                         return (0);
 179                 }
 180         }
 181         return (-1);
 182 }
 183 
 184 id_t
 185 getid(idtype_t type, char *value)
 186 {
 187         struct passwd *pwd;
 188         struct group *grp;
 189         id_t ret;
 190         char *endp;
 191 
 192         switch (type) {
 193         case P_UID:
 194                 if ((pwd = getpwnam(value)) != NULL)
 195                         return (pwd->pw_uid);
 196                 break;
 197         case P_GID:
 198                 if ((grp = getgrnam(value)) != NULL)
 199                         return (grp->gr_gid);
 200                 break;
 201         case P_PROJID:
 202                 if ((ret = getprojidbyname(value)) != (id_t)-1)
 203                         return (ret);
 204                 break;
 205         case P_ZONEID:
 206                 if (zone_get_id(value, &ret) == 0)
 207                         return (ret);
 208                 break;
 209         default:
 210                 break;
 211         }
 212 
 213         ret = (id_t)strtoul(value, &endp, 10);
 214         if (errno || *endp != '\0')
 215                 return ((id_t)-1);
 216 
 217         return (ret);
 218 }
 219 
 220 int
 221 main(int argc, char **argv)
 222 {
 223         act_arg_t *act = NULL;
 224         int ret = 0;
 225         int pgrab_flags = PGRAB_RDONLY;
 226         int opt;
 227         char *idtypename = NULL;
 228         idtype_t idtype = P_PID;
 229         boolean_t usage = B_FALSE;
 230         boolean_t e_flag = B_FALSE;
 231         boolean_t l_flag = B_FALSE;
 232 
 233         while ((opt = getopt(argc, argv, "eFi:ls:")) != -1) {
 234                 switch (opt) {
 235                 case 'e':
 236                         e_flag = B_TRUE;
 237                         break;
 238                 case 'F':
 239                         pgrab_flags |= PGRAB_FORCE;
 240                         break;
 241                 case 'i':
 242                         idtypename = optarg;
 243                         break;
 244                 case 's':
 245                         act = parse_secflags(optarg);
 246                         break;
 247                 case 'l':
 248                         l_flag = B_TRUE;
 249                         break;
 250                 default:
 251                         usage = B_TRUE;
 252                         break;
 253                 }
 254         }
 255 
 256         argc -= optind;
 257         argv += optind;
 258 
 259         if (l_flag && ((idtypename != NULL) || (act != NULL) || (argc != 0)))
 260                 usage = B_TRUE;
 261         if ((idtypename != NULL) && (act == NULL))
 262                 usage = B_TRUE;
 263         if (e_flag && (act == NULL))
 264                 usage = B_TRUE;
 265         if (!l_flag && argc <= 0)
 266                 usage = B_TRUE;
 267 
 268         if (usage) {
 269                 (void) fprintf(stderr,
 270                     gettext("usage:\t%s [-F] { pid | core } ...\n"),
 271                     __progname);
 272                 (void) fprintf(stderr,
 273                     gettext("\t%s -s [-+]flags [-i idtype] id ...\n"),
 274                     __progname);
 275                 (void) fprintf(stderr,
 276                     gettext("\t%s -s [-+]flags -e command [arg]...\n"),
 277                     __progname);
 278                 (void) fprintf(stderr, gettext("\t%s -l\n"), __progname);
 279                 return (2);
 280         }
 281 
 282         if (l_flag) {
 283                 struct flagdesc *fd;
 284 
 285                 for (fd = flagdescs; fd->value != 0x0; fd++) {
 286                         (void) printf("%s\n", fd->name);
 287                 }
 288                 return (0);
 289         } else if ((act != NULL) && e_flag) {
 290                 if (psecflags(P_PID, P_MYID, act->cmd, act->value) != 0)
 291                         err(1, gettext("failed setting security-flags"));
 292 
 293                 (void) execvp(argv[0], &argv[0]);
 294                 err(1, "%s", argv[0]);
 295         } else if (act != NULL) {
 296                 int i;
 297                 id_t id;
 298 
 299                 if (idtypename != NULL)
 300                         if (str2idtype(idtypename, &idtype) == -1)
 301                                 errx(1, gettext("No such id type: '%s'"),
 302                                     idtypename);
 303 
 304                 for (i = 0; i < argc; i++) {
 305                         if ((id = getid(idtype, argv[i])) == (id_t)-1) {
 306                                 errx(1, gettext("invalid or non-existent "
 307                                     "identifier: '%s'"), argv[i]);
 308                         }
 309 
 310                         if (psecflags(idtype, id, act->cmd, act->value) != 0)
 311                                 err(1, gettext("failed setting "
 312                                     "security-flags"));
 313                 }
 314 
 315                 return (0);
 316         }
 317 
 318         /* Display the flags for the given pids */
 319         while (argc-- > 0) {
 320                 struct ps_prochandle *Pr;
 321                 const char *arg;
 322                 psinfo_t psinfo;
 323                 int gcode;
 324 
 325                 if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY,
 326                     pgrab_flags, &gcode)) == NULL) {
 327                         warnx(gettext("cannot examine %s: %s"),
 328                             arg, Pgrab_error(gcode));
 329                         ret = 1;
 330                         continue;
 331                 }
 332 
 333                 (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
 334                 proc_unctrl_psinfo(&psinfo);
 335 
 336                 if (Pstate(Pr) == PS_DEAD) {
 337                         (void) printf(gettext("core '%s' of %d:\t%.70s\n"),
 338                             arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
 339                 } else {
 340                         (void) printf("%d:\t%.70s\n",
 341                             (int)psinfo.pr_pid, psinfo.pr_psargs);
 342                 }
 343 
 344                 print_flags("E", Pstatus(Pr)->pr_secflags.psf_effective);
 345                 print_flags("I", Pstatus(Pr)->pr_secflags.psf_inherit);
 346 
 347                 Prelease(Pr, 0);
 348         }
 349 
 350         return (ret);
 351 }