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#include "libbb.h"
32#include <dirent.h>
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
71enum {
72 OPT_a = (1 << 0) * ENABLE_SOFTLIMIT,
73 OPT_c = (1 << 1) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
74 OPT_d = (1 << 2) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
75 OPT_f = (1 << 3) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
76 OPT_l = (1 << 4) * ENABLE_SOFTLIMIT,
77 OPT_m = (1 << 5) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
78 OPT_o = (1 << 6) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
79 OPT_p = (1 << 7) * (ENABLE_SOFTLIMIT || ENABLE_CHPST),
80 OPT_r = (1 << 8) * ENABLE_SOFTLIMIT,
81 OPT_s = (1 << 9) * ENABLE_SOFTLIMIT,
82 OPT_t = (1 << 10) * ENABLE_SOFTLIMIT,
83 OPT_u = (1 << 11) * (ENABLE_CHPST || ENABLE_SETUIDGID),
84 OPT_U = (1 << 12) * (ENABLE_CHPST || ENABLE_ENVUIDGID),
85 OPT_e = (1 << 13) * (ENABLE_CHPST || ENABLE_ENVDIR),
86 OPT_root = (1 << 14) * ENABLE_CHPST,
87 OPT_n = (1 << 15) * ENABLE_CHPST,
88 OPT_v = (1 << 16) * ENABLE_CHPST,
89 OPT_P = (1 << 17) * ENABLE_CHPST,
90 OPT_0 = (1 << 18) * ENABLE_CHPST,
91 OPT_1 = (1 << 19) * ENABLE_CHPST,
92 OPT_2 = (1 << 20) * ENABLE_CHPST,
93};
94
95
96static NOINLINE void edir(const char *directory_name)
97{
98 int wdir;
99 DIR *dir;
100 struct dirent *d;
101 int fd;
102
103 wdir = xopen(".", O_RDONLY | O_NDELAY);
104 xchdir(directory_name);
105 dir = xopendir(".");
106 for (;;) {
107 char buf[256];
108 char *tail;
109 int size;
110
111 errno = 0;
112 d = readdir(dir);
113 if (!d) {
114 if (errno)
115 bb_perror_msg_and_die("readdir %s",
116 directory_name);
117 break;
118 }
119 if (d->d_name[0] == '.')
120 continue;
121 fd = open(d->d_name, O_RDONLY | O_NDELAY);
122 if (fd < 0) {
123 if ((errno == EISDIR) && directory_name) {
124 if (option_mask32 & OPT_v)
125 bb_perror_msg("warning: %s/%s is a directory",
126 directory_name, d->d_name);
127 continue;
128 } else
129 bb_perror_msg_and_die("open %s/%s",
130 directory_name, d->d_name);
131 }
132 size = full_read(fd, buf, sizeof(buf)-1);
133 close(fd);
134 if (size < 0)
135 bb_perror_msg_and_die("read %s/%s",
136 directory_name, d->d_name);
137 if (size == 0) {
138 unsetenv(d->d_name);
139 continue;
140 }
141 buf[size] = '\n';
142 tail = strchr(buf, '\n');
143
144 while (1) {
145 *tail = '\0';
146 tail--;
147 if (tail < buf || !isspace(*tail))
148 break;
149 }
150 xsetenv(d->d_name, buf);
151 }
152 closedir(dir);
153 if (fchdir(wdir) == -1)
154 bb_perror_msg_and_die("fchdir");
155 close(wdir);
156}
157
158static void limit(int what, long l)
159{
160 struct rlimit r;
161
162
163 getrlimit(what, &r);
164 if ((l < 0) || (l > r.rlim_max))
165 r.rlim_cur = r.rlim_max;
166 else
167 r.rlim_cur = l;
168 if (setrlimit(what, &r) == -1)
169 bb_perror_msg_and_die("setrlimit");
170}
171
172int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
173int chpst_main(int argc UNUSED_PARAM, char **argv)
174{
175 struct bb_uidgid_t ugid;
176 char *set_user = set_user;
177 char *env_user = env_user;
178 char *env_dir = env_dir;
179 char *root;
180 char *nicestr;
181 unsigned limita;
182 unsigned limitc;
183 unsigned limitd;
184 unsigned limitf;
185 unsigned limitl;
186 unsigned limitm;
187 unsigned limito;
188 unsigned limitp;
189 unsigned limitr;
190 unsigned limits;
191 unsigned limitt;
192 unsigned opt;
193
194 if ((ENABLE_CHPST && applet_name[0] == 'c')
195 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
196 ) {
197
198
199
200 opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
201 opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
202 IF_CHPST("/:n:vP012"),
203 &limita, &limitc, &limitd, &limitf, &limitl,
204 &limitm, &limito, &limitp, &limitr, &limits, &limitt,
205 &set_user, &env_user, &env_dir
206 IF_CHPST(, &root, &nicestr));
207 argv += optind;
208 if (opt & OPT_m) {
209 limita = limits = limitl = limitd = limitm;
210 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
211 }
212 } else {
213 option_mask32 = opt = 0;
214 argv++;
215 if (!*argv)
216 bb_show_usage();
217 }
218
219
220 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
221 env_dir = *argv++;
222 opt |= OPT_e;
223 }
224
225
226 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
227 set_user = *argv++;
228 opt |= OPT_u;
229 }
230
231
232 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
233 env_user = *argv++;
234 opt |= OPT_U;
235 }
236
237
238 if (!*argv)
239 bb_show_usage();
240
241
242 if (opt & OPT_d) {
243#ifdef RLIMIT_DATA
244 limit(RLIMIT_DATA, limitd);
245#else
246 if (opt & OPT_v)
247 bb_error_msg("system does not support RLIMIT_%s",
248 "DATA");
249#endif
250 }
251 if (opt & OPT_s) {
252#ifdef RLIMIT_STACK
253 limit(RLIMIT_STACK, limits);
254#else
255 if (opt & OPT_v)
256 bb_error_msg("system does not support RLIMIT_%s",
257 "STACK");
258#endif
259 }
260 if (opt & OPT_l) {
261#ifdef RLIMIT_MEMLOCK
262 limit(RLIMIT_MEMLOCK, limitl);
263#else
264 if (opt & OPT_v)
265 bb_error_msg("system does not support RLIMIT_%s",
266 "MEMLOCK");
267#endif
268 }
269 if (opt & OPT_a) {
270#ifdef RLIMIT_VMEM
271 limit(RLIMIT_VMEM, limita);
272#else
273#ifdef RLIMIT_AS
274 limit(RLIMIT_AS, limita);
275#else
276 if (opt & OPT_v)
277 bb_error_msg("system does not support RLIMIT_%s",
278 "VMEM");
279#endif
280#endif
281 }
282 if (opt & OPT_o) {
283#ifdef RLIMIT_NOFILE
284 limit(RLIMIT_NOFILE, limito);
285#else
286#ifdef RLIMIT_OFILE
287 limit(RLIMIT_OFILE, limito);
288#else
289 if (opt & OPT_v)
290 bb_error_msg("system does not support RLIMIT_%s",
291 "NOFILE");
292#endif
293#endif
294 }
295 if (opt & OPT_p) {
296#ifdef RLIMIT_NPROC
297 limit(RLIMIT_NPROC, limitp);
298#else
299 if (opt & OPT_v)
300 bb_error_msg("system does not support RLIMIT_%s",
301 "NPROC");
302#endif
303 }
304 if (opt & OPT_f) {
305#ifdef RLIMIT_FSIZE
306 limit(RLIMIT_FSIZE, limitf);
307#else
308 if (opt & OPT_v)
309 bb_error_msg("system does not support RLIMIT_%s",
310 "FSIZE");
311#endif
312 }
313 if (opt & OPT_c) {
314#ifdef RLIMIT_CORE
315 limit(RLIMIT_CORE, limitc);
316#else
317 if (opt & OPT_v)
318 bb_error_msg("system does not support RLIMIT_%s",
319 "CORE");
320#endif
321 }
322 if (opt & OPT_r) {
323#ifdef RLIMIT_RSS
324 limit(RLIMIT_RSS, limitr);
325#else
326 if (opt & OPT_v)
327 bb_error_msg("system does not support RLIMIT_%s",
328 "RSS");
329#endif
330 }
331 if (opt & OPT_t) {
332#ifdef RLIMIT_CPU
333 limit(RLIMIT_CPU, limitt);
334#else
335 if (opt & OPT_v)
336 bb_error_msg("system does not support RLIMIT_%s",
337 "CPU");
338#endif
339 }
340
341 if (opt & OPT_P)
342 setsid();
343
344 if (opt & OPT_e)
345 edir(env_dir);
346
347
348
349
350 if (opt & OPT_U) {
351 xget_uidgid(&ugid, env_user);
352 xsetenv("GID", utoa(ugid.gid));
353 xsetenv("UID", utoa(ugid.uid));
354 }
355
356 if (opt & OPT_u) {
357 xget_uidgid(&ugid, set_user);
358 }
359
360 if (opt & OPT_root) {
361 xchdir(root);
362 xchroot(".");
363 }
364
365 if (opt & OPT_u) {
366 if (setgroups(1, &ugid.gid) == -1)
367 bb_perror_msg_and_die("setgroups");
368 xsetgid(ugid.gid);
369 xsetuid(ugid.uid);
370 }
371
372 if (opt & OPT_n) {
373 errno = 0;
374 if (nice(xatoi(nicestr)) == -1)
375 bb_perror_msg_and_die("nice");
376 }
377
378 if (opt & OPT_0)
379 close(STDIN_FILENO);
380 if (opt & OPT_1)
381 close(STDOUT_FILENO);
382 if (opt & OPT_2)
383 close(STDERR_FILENO);
384
385 BB_EXECVP_or_die(argv);
386}
387