1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137#include "libbb.h"
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176enum {
177 OPT_a = (1 << 0) * ENABLE_SOFTLIMIT,
178 OPT_c = (1 << 1) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
179 OPT_d = (1 << 2) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
180 OPT_f = (1 << 3) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
181 OPT_l = (1 << 4) * ENABLE_SOFTLIMIT,
182 OPT_m = (1 << 5) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
183 OPT_o = (1 << 6) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
184 OPT_p = (1 << 7) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
185 OPT_r = (1 << 8) * ENABLE_SOFTLIMIT,
186 OPT_s = (1 << 9) * ENABLE_SOFTLIMIT,
187 OPT_t = (1 << 10) * ENABLE_SOFTLIMIT,
188 OPT_u = (1 << 11) * (ENABLE_CHPST || ENABLE_SETUIDGID),
189 OPT_U = (1 << 12) * (ENABLE_CHPST || ENABLE_ENVUIDGID),
190 OPT_e = (1 << 13) * (ENABLE_CHPST || ENABLE_ENVDIR),
191 OPT_root = (1 << 14) * ENABLE_CHPST,
192 OPT_n = (1 << 15) * ENABLE_CHPST,
193 OPT_v = (1 << 16) * ENABLE_CHPST,
194 OPT_P = (1 << 17) * ENABLE_CHPST,
195 OPT_0 = (1 << 18) * ENABLE_CHPST,
196 OPT_1 = (1 << 19) * ENABLE_CHPST,
197 OPT_2 = (1 << 20) * ENABLE_CHPST,
198};
199
200
201static NOINLINE void edir(const char *directory_name)
202{
203 int wdir;
204 DIR *dir;
205 struct dirent *d;
206 int fd;
207
208 wdir = xopen(".", O_RDONLY | O_NDELAY);
209 xchdir(directory_name);
210 dir = xopendir(".");
211 for (;;) {
212 char buf[256];
213 char *tail;
214 int size;
215
216 errno = 0;
217 d = readdir(dir);
218 if (!d) {
219 if (errno)
220 bb_perror_msg_and_die("readdir %s",
221 directory_name);
222 break;
223 }
224 if (d->d_name[0] == '.')
225 continue;
226 fd = open(d->d_name, O_RDONLY | O_NDELAY);
227 if (fd < 0) {
228 if ((errno == EISDIR) && directory_name) {
229 if (option_mask32 & OPT_v)
230 bb_perror_msg("warning: %s/%s is a directory",
231 directory_name, d->d_name);
232 continue;
233 }
234 bb_perror_msg_and_die("open %s/%s",
235 directory_name, d->d_name);
236 }
237 size = full_read(fd, buf, sizeof(buf)-1);
238 close(fd);
239 if (size < 0)
240 bb_perror_msg_and_die("read %s/%s",
241 directory_name, d->d_name);
242 if (size == 0) {
243 unsetenv(d->d_name);
244 continue;
245 }
246 buf[size] = '\n';
247 tail = strchr(buf, '\n');
248
249 while (1) {
250 *tail = '\0';
251 tail--;
252 if (tail < buf || !isspace(*tail))
253 break;
254 }
255 xsetenv(d->d_name, buf);
256 }
257 closedir(dir);
258 xfchdir(wdir);
259 close(wdir);
260}
261
262static void limit(int what, long l)
263{
264 struct rlimit r;
265
266
267 getrlimit(what, &r);
268 if ((l < 0) || (l > r.rlim_max))
269 r.rlim_cur = r.rlim_max;
270 else
271 r.rlim_cur = l;
272 if (setrlimit(what, &r) == -1)
273 bb_simple_perror_msg_and_die("setrlimit");
274}
275
276int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
277int chpst_main(int argc UNUSED_PARAM, char **argv)
278{
279 struct bb_uidgid_t ugid;
280 char *set_user = set_user;
281 char *env_dir = env_dir;
282 char *root;
283 char *nicestr;
284 unsigned limita;
285 unsigned limitc;
286 unsigned limitd;
287 unsigned limitf;
288 unsigned limitl;
289 unsigned limitm;
290 unsigned limito;
291 unsigned limitp;
292 unsigned limitr;
293 unsigned limits;
294 unsigned limitt;
295 unsigned opt;
296
297 if ((ENABLE_CHPST && applet_name[0] == 'c')
298 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
299 ) {
300
301
302
303 opt = getopt32(argv, "^+"
304 "a:+c:+d:+f:+l:+m:+o:+p:+r:+s:+t:+u:U:e:"
305 IF_CHPST("/:n:vP012")
306 "\0" "-1",
307 &limita, &limitc, &limitd, &limitf, &limitl,
308 &limitm, &limito, &limitp, &limitr, &limits, &limitt,
309 &set_user, &set_user, &env_dir
310 IF_CHPST(, &root, &nicestr));
311 argv += optind;
312 if (opt & OPT_m) {
313 limita = limits = limitl = limitd = limitm;
314 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
315 }
316 } else {
317 option_mask32 = opt = 0;
318 argv++;
319 if (!*argv)
320 bb_show_usage();
321 }
322
323
324 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
325 env_dir = *argv++;
326 opt |= OPT_e;
327 }
328
329
330 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
331 set_user = *argv++;
332 opt |= OPT_u;
333 }
334
335
336 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
337 set_user = *argv++;
338 opt |= OPT_U;
339 }
340
341
342 if (!*argv)
343 bb_show_usage();
344
345
346 if (opt & OPT_d) {
347#ifdef RLIMIT_DATA
348 limit(RLIMIT_DATA, limitd);
349#else
350 if (opt & OPT_v)
351 bb_error_msg("system does not support RLIMIT_%s",
352 "DATA");
353#endif
354 }
355 if (opt & OPT_s) {
356#ifdef RLIMIT_STACK
357 limit(RLIMIT_STACK, limits);
358#else
359 if (opt & OPT_v)
360 bb_error_msg("system does not support RLIMIT_%s",
361 "STACK");
362#endif
363 }
364 if (opt & OPT_l) {
365#ifdef RLIMIT_MEMLOCK
366 limit(RLIMIT_MEMLOCK, limitl);
367#else
368 if (opt & OPT_v)
369 bb_error_msg("system does not support RLIMIT_%s",
370 "MEMLOCK");
371#endif
372 }
373 if (opt & OPT_a) {
374#ifdef RLIMIT_VMEM
375 limit(RLIMIT_VMEM, limita);
376#else
377#ifdef RLIMIT_AS
378 limit(RLIMIT_AS, limita);
379#else
380 if (opt & OPT_v)
381 bb_error_msg("system does not support RLIMIT_%s",
382 "VMEM");
383#endif
384#endif
385 }
386 if (opt & OPT_o) {
387#ifdef RLIMIT_NOFILE
388 limit(RLIMIT_NOFILE, limito);
389#else
390#ifdef RLIMIT_OFILE
391 limit(RLIMIT_OFILE, limito);
392#else
393 if (opt & OPT_v)
394 bb_error_msg("system does not support RLIMIT_%s",
395 "NOFILE");
396#endif
397#endif
398 }
399 if (opt & OPT_p) {
400#ifdef RLIMIT_NPROC
401 limit(RLIMIT_NPROC, limitp);
402#else
403 if (opt & OPT_v)
404 bb_error_msg("system does not support RLIMIT_%s",
405 "NPROC");
406#endif
407 }
408 if (opt & OPT_f) {
409#ifdef RLIMIT_FSIZE
410 limit(RLIMIT_FSIZE, limitf);
411#else
412 if (opt & OPT_v)
413 bb_error_msg("system does not support RLIMIT_%s",
414 "FSIZE");
415#endif
416 }
417 if (opt & OPT_c) {
418#ifdef RLIMIT_CORE
419 limit(RLIMIT_CORE, limitc);
420#else
421 if (opt & OPT_v)
422 bb_error_msg("system does not support RLIMIT_%s",
423 "CORE");
424#endif
425 }
426 if (opt & OPT_r) {
427#ifdef RLIMIT_RSS
428 limit(RLIMIT_RSS, limitr);
429#else
430 if (opt & OPT_v)
431 bb_error_msg("system does not support RLIMIT_%s",
432 "RSS");
433#endif
434 }
435 if (opt & OPT_t) {
436#ifdef RLIMIT_CPU
437 limit(RLIMIT_CPU, limitt);
438#else
439 if (opt & OPT_v)
440 bb_error_msg("system does not support RLIMIT_%s",
441 "CPU");
442#endif
443 }
444
445 if (opt & OPT_P)
446 setsid();
447
448 if (opt & OPT_e)
449 edir(env_dir);
450
451 if (opt & (OPT_u|OPT_U))
452 xget_uidgid(&ugid, set_user);
453
454
455
456
457 if (opt & OPT_U) {
458 xsetenv("GID", utoa(ugid.gid));
459 xsetenv("UID", utoa(ugid.uid));
460 }
461
462 if (opt & OPT_root) {
463 xchroot(root);
464 }
465
466
467 if (opt & OPT_n) {
468 errno = 0;
469 if (nice(xatoi(nicestr)) == -1)
470 bb_simple_perror_msg_and_die("nice");
471 }
472
473 if (opt & OPT_u) {
474 if (setgroups(1, &ugid.gid) == -1)
475 bb_simple_perror_msg_and_die("setgroups");
476 xsetgid(ugid.gid);
477 xsetuid(ugid.uid);
478 }
479
480 if (opt & OPT_0)
481 close(STDIN_FILENO);
482 if (opt & OPT_1)
483 close(STDOUT_FILENO);
484 if (opt & OPT_2)
485 close(STDERR_FILENO);
486
487 BB_EXECVP_or_die(argv);
488}
489