unix/fiss

src/chpst/chpst.c in master
Repositories | Summary | Log | Files | LICENSE

chpst.c (7089B) download


  1
  2#include "parse.h"
  3
  4#include <arg.h>
  5#include <common.h>
  6#include <fcntl.h>
  7#include <fmt.h>
  8#include <grp.h>
  9#include <stdbool.h>
 10#include <stdlib.h>
 11#include <string.h>
 12#include <sys/file.h>
 13#include <sys/resource.h>
 14#include <unistd.h>
 15
 16void usage(void) {
 17	print("Usage:\n"
 18	      "  chpst [-vP012] [-u user[:group]] [-U user[:group]] [-b argv0] [-e dir]\n"
 19	      "      [-/ root] [-C pwd] [-n nice] [-l|-L lock] [-m n] [-d n] [-o n] [-p n] [-f n]\n"
 20	      "      [-c n] command ...\n"
 21	      "  softlimit [-m n] [-a n] [-d n] [-o n] [-p n] [-f n] [-c n] [-r n] [-t n]\n"
 22	      "      [-l n] [-s n]  command ...\n"
 23	      "  setuidgid user[:group] command ...\n"
 24	      "  envuidgid user[:group] command ...\n"
 25	      "  pgrphack command ...\n"
 26	      "  setlock [-nNxX] lock command ...\n");
 27}
 28
 29void limit(int what, long l) {
 30	struct rlimit r;
 31
 32	if (getrlimit(what, &r) == -1)
 33		fprint(1, "error: unable to getrlimit: %r\n");
 34
 35	if (l < 0) {
 36		r.rlim_cur = 0;
 37	} else if ((unsigned long) l > r.rlim_max)
 38		r.rlim_cur = r.rlim_max;
 39	else
 40		r.rlim_cur = l;
 41
 42	if (setrlimit(what, &r) == -1)
 43		fprint(1, "error: unable to setrlimit: %r\n");
 44}
 45
 46
 47int main(int argc, char** argv) {
 48	int   lockfd, lockflags = 0, gid_len = 0;
 49	char *arg0 = NULL, *root = NULL, *cd = NULL, *lock = NULL;
 50	uid_t uid = 0;
 51	gid_t gid[61];
 52
 53	argv0 = argv[0];
 54
 55	long limitd      = -2,
 56	     limits      = -2,
 57	     limitl      = -2,
 58	     limita      = -2,
 59	     limito      = -2,
 60	     limitp      = -2,
 61	     limitf      = -2,
 62	     limitc      = -2,
 63	     limitr      = -2,
 64	     limitt      = -2;
 65	long nicelevel   = 0;
 66	bool ssid        = false;
 67	bool closestd[3] = { false, false, false };
 68
 69	if (streq(argv0, "setuidgid") || streq(argv0, "envuidgid")) {
 70		if (argc < 2) {
 71			fprint(1, "%s <uid-gid> command...", argv0);
 72			return 1;
 73		}
 74		gid_len = parse_ugid(argv[1], &uid, gid);
 75		SHIFT(2);
 76	} else if (streq(argv0, "pgrphack")) {
 77		ssid = true;
 78		SHIFT(1);
 79	} else if (streq(argv0, "setlock")) {
 80		ARGBEGIN {
 81			case 'n':
 82				lockflags = LOCK_EX | LOCK_NB;
 83				break;
 84			case 'N':
 85				lockflags = LOCK_EX;
 86				break;
 87			case 'x':
 88			case 'X':
 89				fprint(1, "warning: '-%c' is ignored\n", ARGC());
 90				break;
 91			default:
 92				usage();
 93				return 1;
 94		}
 95		ARGEND;
 96
 97		if (argc < 1) {
 98			fprint(1, "%s [-xXnN] command...", argv0);
 99			return 1;
100		}
101		lock = argv[1];
102		SHIFT(1);
103	} else if (streq(argv0, "softlimit")) {
104		ARGBEGIN {
105			case 'm':
106				limits = limitl = limita = limitd = atol(EARGF(usage()));
107				break;
108			case 'a':
109				limita = atol(EARGF(usage()));
110				break;
111			case 'd':
112				limitd = atol(EARGF(usage()));
113				break;
114			case 'o':
115				limito = atol(EARGF(usage()));
116				break;
117			case 'p':
118				limitp = atol(EARGF(usage()));
119				break;
120			case 'f':
121				limitf = atol(EARGF(usage()));
122				break;
123			case 'c':
124				limitc = atol(EARGF(usage()));
125				break;
126			case 'r':
127				limitr = atol(EARGF(usage()));
128				break;
129			case 't':
130				limitt = atol(EARGF(usage()));
131				break;
132			case 'l':
133				limitl = atol(EARGF(usage()));
134				break;
135			case 's':
136				limits = atol(EARGF(usage()));
137				break;
138			default:
139				usage();
140				return 1;
141		}
142		ARGEND;
143	} else {
144		ARGBEGIN {
145			case 'u':
146			case 'U':
147				gid_len = parse_ugid(EARGF(usage()), &uid, gid);
148				break;
149			case 'b':
150				arg0 = EARGF(usage());
151				break;
152			case '/':
153				root = EARGF(usage());
154				break;
155			case 'C':
156				cd = EARGF(usage());
157				break;
158			case 'n':
159				nicelevel = atol(EARGF(usage()));
160				break;
161			case 'l':
162				lock      = EARGF(usage());
163				lockflags = LOCK_EX | LOCK_NB;
164				break;
165			case 'L':
166				lock      = EARGF(usage());
167				lockflags = LOCK_EX;
168				break;
169			case 'v':    // ignored
170				break;
171			case 'P':
172				ssid = true;
173				break;
174			case '0':
175			case '1':
176			case '2':
177				closestd[ARGC() - '0'] = true;
178				break;
179			case 'm':
180				limits = limitl = limita = limitd = atol(EARGF(usage()));
181				break;
182			case 'd':
183				limitd = atol(EARGF(usage()));
184				break;
185			case 'o':
186				limito = atol(EARGF(usage()));
187				break;
188			case 'p':
189				limitp = atol(EARGF(usage()));
190				break;
191			case 'f':
192				limitf = atol(EARGF(usage()));
193				break;
194			case 'c':
195				limitc = atol(EARGF(usage()));
196				break;
197			case 'r':
198				limitr = atol(EARGF(usage()));
199				break;
200			case 't':
201				limitt = atol(EARGF(usage()));
202				break;
203			case 'e':
204				fprint(1, "warning: '-%c' is ignored\n", ARGC());
205				break;
206			default:
207				usage();
208				return 1;
209		}
210		ARGEND;
211	}
212
213	if (argc == 0) {
214		fprint(1, "%s: command required\n", argv0);
215		return 1;
216	}
217
218	if (ssid) {
219		setsid();
220	}
221
222	if (uid) {
223		setgroups(gid_len, gid);
224		setgid(gid[0]);
225		setuid(uid);
226		// $EUID
227	}
228
229	if (root) {
230		if (chroot(root) == -1)
231			fprint(1, "unable to change root directory: %r\n");
232
233		// chdir to '/', otherwise the next command will complain 'directory not found'
234		chdir("/");
235	}
236
237	if (cd) {
238		chdir(cd);
239	}
240
241	if (nicelevel != 0) {
242		if (nice(nicelevel) == -1)
243			fprint(1, "unable to set nice level: %r\n");
244	}
245
246	if (limitd >= -1) {
247#ifdef RLIMIT_DATA
248		limit(RLIMIT_DATA, limitd);
249#else
250		if (verbose)
251			fprint(1, "system does not support RLIMIT_DATA\n");
252#endif
253	}
254	if (limits >= -1) {
255#ifdef RLIMIT_STACK
256		limit(RLIMIT_STACK, limits);
257#else
258		if (verbose)
259			fprint(1, "system does not support RLIMIT_STACK\n");
260#endif
261	}
262	if (limitl >= -1) {
263#ifdef RLIMIT_MEMLOCK
264		limit(RLIMIT_MEMLOCK, limitl);
265#else
266		if (verbose)
267			fprint(1, "system does not support RLIMIT_MEMLOCK\n");
268#endif
269	}
270	if (limita >= -1) {
271#ifdef RLIMIT_VMEM
272		limit(RLIMIT_VMEM, limita);
273#else
274#	ifdef RLIMIT_AS
275		limit(RLIMIT_AS, limita);
276#	else
277		if (verbose)
278			fprint(1, "system does neither support RLIMIT_VMEM nor RLIMIT_AS\n");
279#	endif
280#endif
281	}
282	if (limito >= -1) {
283#ifdef RLIMIT_NOFILE
284		limit(RLIMIT_NOFILE, limito);
285#else
286#	ifdef RLIMIT_OFILE
287		limit(RLIMIT_OFILE, limito);
288#	else
289		if (verbose)
290			fprint(1, "system does neither support RLIMIT_NOFILE nor RLIMIT_OFILE\n");
291#	endif
292#endif
293	}
294	if (limitp >= -1) {
295#ifdef RLIMIT_NPROC
296		limit(RLIMIT_NPROC, limitp);
297#else
298		if (verbose)
299			fprint(1, "system does not support RLIMIT_NPROC\n");
300#endif
301	}
302	if (limitf >= -1) {
303#ifdef RLIMIT_FSIZE
304		limit(RLIMIT_FSIZE, limitf);
305#else
306		if (verbose)
307			fprint(1, "system does not support RLIMIT_FSIZE\n");
308#endif
309	}
310	if (limitc >= -1) {
311#ifdef RLIMIT_CORE
312		limit(RLIMIT_CORE, limitc);
313#else
314		if (verbose)
315			fprint(1, "system does not support RLIMIT_CORE\n");
316#endif
317	}
318	if (limitr >= -1) {
319#ifdef RLIMIT_RSS
320		limit(RLIMIT_RSS, limitr);
321#else
322		if (verbose)
323			fprint(1, "system does not support RLIMIT_RSS\n");
324#endif
325	}
326	if (limitt >= -1) {
327#ifdef RLIMIT_CPU
328		limit(RLIMIT_CPU, limitt);
329#else
330		if (verbose)
331			fprint(1, "system does not support RLIMIT_CPU\n");
332#endif
333	}
334
335	if (lock) {
336		if ((lockfd = open(lock, O_WRONLY | O_APPEND)) == -1)
337			fprint(1, "unable to open lock: %r\n");
338
339		if (flock(lockfd, lockflags) == -1)
340			fprint(1, "unable to lock: %r\n");
341	}
342
343	for (int i = 0; i < 3; i++)
344		if (closestd[i] && close(i) == -1)
345			fprint(1, "unable to close std-%d: %r\n", i);
346
347	execvp(arg0 ? arg0 : *argv, argv);
348	fprint(1, "cannot execute: %r\n");
349}