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 /* Copyright 2015, Richard Lowe. */
  13 
  14 #include <err.h>
  15 #include <errno.h>
  16 #include <grp.h>
  17 #include <libintl.h>
  18 #include <procfs.h>
  19 #include <project.h>
  20 #include <pwd.h>
  21 #include <stdio.h>
  22 #include <stdlib.h>
  23 #include <string.h>
  24 #include <sys/secflags.h>
  25 #include <sys/types.h>
  26 
  27 #include <libproc.h>
  28 #include <libzonecfg.h>
  29 
  30 extern const char *__progname;
  31 
  32 static void
  33 print_flags(const char *set, secflagset_t flags)
  34 {
  35         char buf[1024];
  36 
  37         secflags_to_str(flags, buf, sizeof (buf));
  38         (void) printf("\t%s:\t%s\n", set, buf);
  39 }
  40 
  41 /*
  42  * Structure defining idtypes known to the priocntl command
  43  * along with the corresponding names.
  44  * The idtype values themselves are defined in <sys/procset.h>.
  45  */
  46 static struct idtypes {
  47         idtype_t        type;
  48         char            *name;
  49 } idtypes [] = {
  50         { P_ALL,        "all"           },
  51         { P_CTID,       "contract"      },
  52         { P_CTID,       "ctid"          },
  53         { P_GID,        "gid"           },
  54         { P_GID,        "group"         },
  55         { P_PGID,       "pgid"          },
  56         { P_PID,        "pid"           },
  57         { P_PPID,       "ppid"          },
  58         { P_PROJID,     "project"       },
  59         { P_PROJID,     "projid"        },
  60         { P_SID,        "session",      },
  61         { P_SID,        "sid"           },
  62         { P_SID,        "sid"           },
  63         { P_TASKID,     "taskid"        },
  64         { P_UID,        "uid"           },
  65         { P_UID,        "user"          },
  66         { P_ZONEID,     "zone"          },
  67         { P_ZONEID,     "zoneid"        },
  68         { 0,            NULL            }
  69 };
  70 
  71 static int
  72 str2idtype(char *idtypnm, idtype_t *idtypep)
  73 {
  74         struct idtypes  *curp;
  75 
  76         for (curp = idtypes; curp->name != NULL; curp++) {
  77                 if (strncasecmp(curp->name, idtypnm,
  78                     strlen(curp->name)) == 0) {
  79                         *idtypep = curp->type;
  80                         return (0);
  81                 }
  82         }
  83         return (-1);
  84 }
  85 
  86 static id_t
  87 getid(idtype_t type, char *value)
  88 {
  89         struct passwd *pwd;
  90         struct group *grp;
  91         id_t ret;
  92         char *endp;
  93 
  94         switch (type) {
  95         case P_UID:
  96                 if ((pwd = getpwnam(value)) != NULL)
  97                         return (pwd->pw_uid);
  98                 break;
  99         case P_GID:
 100                 if ((grp = getgrnam(value)) != NULL)
 101                         return (grp->gr_gid);
 102                 break;
 103         case P_PROJID:
 104                 if ((ret = getprojidbyname(value)) != (id_t)-1)
 105                         return (ret);
 106                 break;
 107         case P_ZONEID:
 108                 if (zone_get_id(value, &ret) == 0)
 109                         return (ret);
 110                 break;
 111         default:
 112                 break;
 113         }
 114 
 115         errno = 0;
 116 
 117         ret = (id_t)strtoul(value, &endp, 10);
 118 
 119         if ((errno != 0) || (*endp != '\0'))
 120                 return ((id_t)-1);
 121 
 122         return (ret);
 123 }
 124 
 125 int
 126 main(int argc, char **argv)
 127 {
 128         secflagdelta_t act;
 129         psecflagwhich_t which = PSF_INHERIT;
 130         int ret = 0;
 131         int pgrab_flags = PGRAB_RDONLY;
 132         int opt;
 133         char *idtypename = NULL;
 134         idtype_t idtype = P_PID;
 135         boolean_t usage = B_FALSE;
 136         boolean_t e_flag = B_FALSE;
 137         boolean_t l_flag = B_FALSE;
 138         boolean_t s_flag = B_FALSE;
 139         int errc = 0;
 140 
 141         while ((opt = getopt(argc, argv, "eFi:ls:")) != -1) {
 142                 switch (opt) {
 143                 case 'e':
 144                         e_flag = B_TRUE;
 145                         break;
 146                 case 'F':
 147                         pgrab_flags |= PGRAB_FORCE;
 148                         break;
 149                 case 'i':
 150                         idtypename = optarg;
 151                         break;
 152                 case 's':
 153                         s_flag = B_TRUE;
 154                         if ((strlen(optarg) >= 2) &&
 155                             ((optarg[1] == '='))) {
 156                                 switch (optarg[0]) {
 157                                 case 'L':
 158                                         which = PSF_LOWER;
 159                                         break;
 160                                 case 'U':
 161                                         which = PSF_UPPER;
 162                                         break;
 163                                 case 'I':
 164                                         which = PSF_INHERIT;
 165                                         break;
 166                                 case 'E':
 167                                         errx(1, "the effective flags cannot "
 168                                             "be changed", optarg[0]);
 169                                 default:
 170                                         errx(1, "unknown security flag "
 171                                             "set: '%c'", optarg[0]);
 172                                 }
 173 
 174                                 optarg += 2;
 175                         }
 176 
 177                         if (secflags_parse(NULL, optarg, &act) == -1)
 178                                 errx(1, "couldn't parse security flags: %s",
 179                                     optarg);
 180                         break;
 181                 case 'l':
 182                         l_flag = B_TRUE;
 183                         break;
 184                 default:
 185                         usage = B_TRUE;
 186                         break;
 187                 }
 188         }
 189 
 190         argc -= optind;
 191         argv += optind;
 192 
 193         if (l_flag && ((idtypename != NULL) || s_flag || (argc != 0)))
 194                 usage = B_TRUE;
 195         if ((idtypename != NULL) && !s_flag)
 196                 usage = B_TRUE;
 197         if (e_flag && !s_flag)
 198                 usage = B_TRUE;
 199         if (!l_flag && argc <= 0)
 200                 usage = B_TRUE;
 201 
 202         if (usage) {
 203                 (void) fprintf(stderr,
 204                     gettext("usage:\t%s [-F] { pid | core } ...\n"),
 205                     __progname);
 206                 (void) fprintf(stderr,
 207                     gettext("\t%s -s spec [-i idtype] id ...\n"),
 208                     __progname);
 209                 (void) fprintf(stderr,
 210                     gettext("\t%s -s spec -e command [arg]...\n"),
 211                     __progname);
 212                 (void) fprintf(stderr, gettext("\t%s -l\n"), __progname);
 213                 return (2);
 214         }
 215 
 216         if (l_flag) {
 217                 secflag_t i;
 218                 const char *name;
 219 
 220                 for (i = 0; (name = secflag_to_str(i)) != NULL; i++)
 221                         (void) printf("%s\n", name);
 222                 return (0);
 223         } else if (s_flag && e_flag) {
 224                 /*
 225                  * Don't use the strerror() message for EPERM, "Not Owner"
 226                  * which is misleading.
 227                  */
 228                 errc = psecflags(P_PID, P_MYID, which, &act);
 229                 switch (errc) {
 230                 case 0:
 231                         break;
 232                 case EPERM:
 233                         errx(1, gettext("failed setting "
 234                             "security-flags: Permission denied"));
 235                         break;
 236                 default:
 237                         err(1, gettext("failed setting security-flags"));
 238                 }
 239 
 240                 (void) execvp(argv[0], &argv[0]);
 241                 err(1, "%s", argv[0]);
 242         } else if (s_flag) {
 243                 int i;
 244                 id_t id;
 245 
 246                 if (idtypename != NULL)
 247                         if (str2idtype(idtypename, &idtype) == -1)
 248                                 errx(1, gettext("No such id type: '%s'"),
 249                                     idtypename);
 250 
 251                 for (i = 0; i < argc; i++) {
 252                         if ((id = getid(idtype, argv[i])) == (id_t)-1) {
 253                                 errx(1, gettext("invalid or non-existent "
 254                                     "identifier: '%s'"), argv[i]);
 255                         }
 256 
 257                         /*
 258                          * Don't use the strerror() message for EPERM, "Not
 259                          * Owner" which is misleading.
 260                          */
 261                         if (psecflags(idtype, id, which, &act) != 0) {
 262                                 switch (errno) {
 263                                 case EPERM:
 264                                         errx(1, gettext("failed setting "
 265                                             "security-flags: "
 266                                             "Permission denied"));
 267                                         break;
 268                                 default:
 269                                         err(1, gettext("failed setting "
 270                                             "security-flags"));
 271                                 }
 272                         }
 273                 }
 274 
 275                 return (0);
 276         }
 277 
 278         /* Display the flags for the given pids */
 279         while (argc-- > 0) {
 280                 struct ps_prochandle *Pr;
 281                 const char *arg;
 282                 psinfo_t psinfo;
 283                 prsecflags_t *psf;
 284                 int gcode;
 285 
 286                 if ((Pr = proc_arg_grab(arg = *argv++, PR_ARG_ANY,
 287                     pgrab_flags, &gcode)) == NULL) {
 288                         warnx(gettext("cannot examine %s: %s"),
 289                             arg, Pgrab_error(gcode));
 290                         ret = 1;
 291                         continue;
 292                 }
 293 
 294                 (void) memcpy(&psinfo, Ppsinfo(Pr), sizeof (psinfo_t));
 295                 proc_unctrl_psinfo(&psinfo);
 296 
 297                 if (Pstate(Pr) == PS_DEAD) {
 298                         (void) printf(gettext("core '%s' of %d:\t%.70s\n"),
 299                             arg, (int)psinfo.pr_pid, psinfo.pr_psargs);
 300                 } else {
 301                         (void) printf("%d:\t%.70s\n",
 302                             (int)psinfo.pr_pid, psinfo.pr_psargs);
 303                 }
 304 
 305                 if (Psecflags(Pr, &psf) != 0)
 306                         err(1, gettext("cannot read secflags of %s"), arg);
 307 
 308                 print_flags("E", psf->pr_effective);
 309                 print_flags("I", psf->pr_inherit);
 310                 print_flags("L", psf->pr_lower);
 311                 print_flags("U", psf->pr_upper);
 312 
 313                 Psecflags_free(psf);
 314                 Prelease(Pr, 0);
 315         }
 316 
 317         return (ret);
 318 }