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
print_flags(const char * set,secflagset_t flags)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
str2idtype(char * idtypnm,idtype_t * idtypep)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
getid(idtype_t type,char * value)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
main(int argc,char ** argv)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");
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 }
319