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#include "libbb.h"
94#include <sys/resource.h>
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
133enum {
134 OPT_a = (1 << 0) * ENABLE_SOFTLIMIT,
135 OPT_c = (1 << 1) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
136 OPT_d = (1 << 2) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
137 OPT_f = (1 << 3) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
138 OPT_l = (1 << 4) * ENABLE_SOFTLIMIT,
139 OPT_m = (1 << 5) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
140 OPT_o = (1 << 6) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
141 OPT_p = (1 << 7) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
142 OPT_r = (1 << 8) * ENABLE_SOFTLIMIT,
143 OPT_s = (1 << 9) * ENABLE_SOFTLIMIT,
144 OPT_t = (1 << 10) * ENABLE_SOFTLIMIT,
145 OPT_u = (1 << 11) * (ENABLE_CHPST || ENABLE_SETUIDGID),
146 OPT_U = (1 << 12) * (ENABLE_CHPST || ENABLE_ENVUIDGID),
147 OPT_e = (1 << 13) * (ENABLE_CHPST || ENABLE_ENVDIR),
148 OPT_root = (1 << 14) * ENABLE_CHPST,
149 OPT_n = (1 << 15) * ENABLE_CHPST,
150 OPT_v = (1 << 16) * ENABLE_CHPST,
151 OPT_P = (1 << 17) * ENABLE_CHPST,
152 OPT_0 = (1 << 18) * ENABLE_CHPST,
153 OPT_1 = (1 << 19) * ENABLE_CHPST,
154 OPT_2 = (1 << 20) * ENABLE_CHPST,
155};
156
157
158static NOINLINE void edir(const char *directory_name)
159{
160 int wdir;
161 DIR *dir;
162 struct dirent *d;
163 int fd;
164
165 wdir = xopen(".", O_RDONLY | O_NDELAY);
166 xchdir(directory_name);
167 dir = xopendir(".");
168 for (;;) {
169 char buf[256];
170 char *tail;
171 int size;
172
173 errno = 0;
174 d = readdir(dir);
175 if (!d) {
176 if (errno)
177 bb_perror_msg_and_die("readdir %s",
178 directory_name);
179 break;
180 }
181 if (d->d_name[0] == '.')
182 continue;
183 fd = open(d->d_name, O_RDONLY | O_NDELAY);
184 if (fd < 0) {
185 if ((errno == EISDIR) && directory_name) {
186 if (option_mask32 & OPT_v)
187 bb_perror_msg("warning: %s/%s is a directory",
188 directory_name, d->d_name);
189 continue;
190 }
191 bb_perror_msg_and_die("open %s/%s",
192 directory_name, d->d_name);
193 }
194 size = full_read(fd, buf, sizeof(buf)-1);
195 close(fd);
196 if (size < 0)
197 bb_perror_msg_and_die("read %s/%s",
198 directory_name, d->d_name);
199 if (size == 0) {
200 unsetenv(d->d_name);
201 continue;
202 }
203 buf[size] = '\n';
204 tail = strchr(buf, '\n');
205
206 while (1) {
207 *tail = '\0';
208 tail--;
209 if (tail < buf || !isspace(*tail))
210 break;
211 }
212 xsetenv(d->d_name, buf);
213 }
214 closedir(dir);
215 if (fchdir(wdir) == -1)
216 bb_perror_msg_and_die("fchdir");
217 close(wdir);
218}
219
220static void limit(int what, long l)
221{
222 struct rlimit r;
223
224
225 getrlimit(what, &r);
226 if ((l < 0) || (l > r.rlim_max))
227 r.rlim_cur = r.rlim_max;
228 else
229 r.rlim_cur = l;
230 if (setrlimit(what, &r) == -1)
231 bb_perror_msg_and_die("setrlimit");
232}
233
234int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
235int chpst_main(int argc UNUSED_PARAM, char **argv)
236{
237 struct bb_uidgid_t ugid;
238 char *set_user = set_user;
239 char *env_user = env_user;
240 char *env_dir = env_dir;
241 char *root;
242 char *nicestr;
243 unsigned limita;
244 unsigned limitc;
245 unsigned limitd;
246 unsigned limitf;
247 unsigned limitl;
248 unsigned limitm;
249 unsigned limito;
250 unsigned limitp;
251 unsigned limitr;
252 unsigned limits;
253 unsigned limitt;
254 unsigned opt;
255
256 if ((ENABLE_CHPST && applet_name[0] == 'c')
257 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
258 ) {
259
260
261
262 opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
263 opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
264 IF_CHPST("/:n:vP012"),
265 &limita, &limitc, &limitd, &limitf, &limitl,
266 &limitm, &limito, &limitp, &limitr, &limits, &limitt,
267 &set_user, &env_user, &env_dir
268 IF_CHPST(, &root, &nicestr));
269 argv += optind;
270 if (opt & OPT_m) {
271 limita = limits = limitl = limitd = limitm;
272 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
273 }
274 } else {
275 option_mask32 = opt = 0;
276 argv++;
277 if (!*argv)
278 bb_show_usage();
279 }
280
281
282 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
283 env_dir = *argv++;
284 opt |= OPT_e;
285 }
286
287
288 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
289 set_user = *argv++;
290 opt |= OPT_u;
291 }
292
293
294 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
295 env_user = *argv++;
296 opt |= OPT_U;
297 }
298
299
300 if (!*argv)
301 bb_show_usage();
302
303
304 if (opt & OPT_d) {
305#ifdef RLIMIT_DATA
306 limit(RLIMIT_DATA, limitd);
307#else
308 if (opt & OPT_v)
309 bb_error_msg("system does not support RLIMIT_%s",
310 "DATA");
311#endif
312 }
313 if (opt & OPT_s) {
314#ifdef RLIMIT_STACK
315 limit(RLIMIT_STACK, limits);
316#else
317 if (opt & OPT_v)
318 bb_error_msg("system does not support RLIMIT_%s",
319 "STACK");
320#endif
321 }
322 if (opt & OPT_l) {
323#ifdef RLIMIT_MEMLOCK
324 limit(RLIMIT_MEMLOCK, limitl);
325#else
326 if (opt & OPT_v)
327 bb_error_msg("system does not support RLIMIT_%s",
328 "MEMLOCK");
329#endif
330 }
331 if (opt & OPT_a) {
332#ifdef RLIMIT_VMEM
333 limit(RLIMIT_VMEM, limita);
334#else
335#ifdef RLIMIT_AS
336 limit(RLIMIT_AS, limita);
337#else
338 if (opt & OPT_v)
339 bb_error_msg("system does not support RLIMIT_%s",
340 "VMEM");
341#endif
342#endif
343 }
344 if (opt & OPT_o) {
345#ifdef RLIMIT_NOFILE
346 limit(RLIMIT_NOFILE, limito);
347#else
348#ifdef RLIMIT_OFILE
349 limit(RLIMIT_OFILE, limito);
350#else
351 if (opt & OPT_v)
352 bb_error_msg("system does not support RLIMIT_%s",
353 "NOFILE");
354#endif
355#endif
356 }
357 if (opt & OPT_p) {
358#ifdef RLIMIT_NPROC
359 limit(RLIMIT_NPROC, limitp);
360#else
361 if (opt & OPT_v)
362 bb_error_msg("system does not support RLIMIT_%s",
363 "NPROC");
364#endif
365 }
366 if (opt & OPT_f) {
367#ifdef RLIMIT_FSIZE
368 limit(RLIMIT_FSIZE, limitf);
369#else
370 if (opt & OPT_v)
371 bb_error_msg("system does not support RLIMIT_%s",
372 "FSIZE");
373#endif
374 }
375 if (opt & OPT_c) {
376#ifdef RLIMIT_CORE
377 limit(RLIMIT_CORE, limitc);
378#else
379 if (opt & OPT_v)
380 bb_error_msg("system does not support RLIMIT_%s",
381 "CORE");
382#endif
383 }
384 if (opt & OPT_r) {
385#ifdef RLIMIT_RSS
386 limit(RLIMIT_RSS, limitr);
387#else
388 if (opt & OPT_v)
389 bb_error_msg("system does not support RLIMIT_%s",
390 "RSS");
391#endif
392 }
393 if (opt & OPT_t) {
394#ifdef RLIMIT_CPU
395 limit(RLIMIT_CPU, limitt);
396#else
397 if (opt & OPT_v)
398 bb_error_msg("system does not support RLIMIT_%s",
399 "CPU");
400#endif
401 }
402
403 if (opt & OPT_P)
404 setsid();
405
406 if (opt & OPT_e)
407 edir(env_dir);
408
409 if (opt & (OPT_u|OPT_U))
410 xget_uidgid(&ugid, set_user);
411
412
413
414
415 if (opt & OPT_U) {
416 xsetenv("GID", utoa(ugid.gid));
417 xsetenv("UID", utoa(ugid.uid));
418 }
419
420 if (opt & OPT_root) {
421 xchroot(root);
422 }
423
424 if (opt & OPT_u) {
425 if (setgroups(1, &ugid.gid) == -1)
426 bb_perror_msg_and_die("setgroups");
427 xsetgid(ugid.gid);
428 xsetuid(ugid.uid);
429 }
430
431 if (opt & OPT_n) {
432 errno = 0;
433 if (nice(xatoi(nicestr)) == -1)
434 bb_perror_msg_and_die("nice");
435 }
436
437 if (opt & OPT_0)
438 close(STDIN_FILENO);
439 if (opt & OPT_1)
440 close(STDOUT_FILENO);
441 if (opt & OPT_2)
442 close(STDERR_FILENO);
443
444 BB_EXECVP_or_die(argv);
445}
446