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 }