2 Copyright (c) 2001-2006, Gerrit Pape
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
8 1. Redistributions of source code must retain the above copyright notice,
9 this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29 /* Dependencies on runit_lib.c removed */
35 Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
37 Only softlimit and chpst are taking options:
40 -o N Limit number of open files per process
41 -p N Limit number of processes per uid
42 -m BYTES Same as -d BYTES -s BYTES -l BYTES [-a BYTES]
43 -d BYTES Limit data segment
44 -f BYTES Limit output file sizes
45 -c BYTES Limit core file size
47 -a BYTES Limit total size of all segments
48 -s BYTES Limit stack segment
49 -l BYTES Limit locked memory size
50 -r BYTES Limit resident set size
53 -u USER[:GRP] Set uid and gid
54 -U USER[:GRP] Set $UID and $GID in environment
55 -e DIR Set environment variables as specified by files in DIR
57 -n NICE Add NICE to nice value
59 -P Create new process group
60 -0 -1 -2 Close fd 0,1,2
62 Even though we accept all these options for both softlimit and chpst,
63 they are not to be advertised on their help texts.
64 We have enough problems with feature creep in other people's
65 software, don't want to add our own.
67 envdir, envuidgid, setuidgid take no options, but they reuse code which
68 handles -e, -U and -u.
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,
95 /* TODO: use recursive_action? */
96 static NOINLINE void edir(const char *directory_name)
103 wdir = xopen(".", O_RDONLY | O_NDELAY);
104 xchdir(directory_name);
115 bb_perror_msg_and_die("readdir %s",
119 if (d->d_name[0] == '.')
121 fd = open(d->d_name, O_RDONLY | O_NDELAY);
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);
129 bb_perror_msg_and_die("open %s/%s",
130 directory_name, d->d_name);
132 size = full_read(fd, buf, sizeof(buf)-1);
135 bb_perror_msg_and_die("read %s/%s",
136 directory_name, d->d_name);
142 tail = strchr(buf, '\n');
143 /* skip trailing whitespace */
147 if (tail < buf || !isspace(*tail))
150 xsetenv(d->d_name, buf);
153 if (fchdir(wdir) == -1)
154 bb_perror_msg_and_die("fchdir");
158 static void limit(int what, long l)
162 /* Never fails under Linux (except if you pass it bad arguments) */
164 if ((l < 0) || (l > r.rlim_max))
165 r.rlim_cur = r.rlim_max;
168 if (setrlimit(what, &r) == -1)
169 bb_perror_msg_and_die("setrlimit");
172 int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
173 int chpst_main(int argc UNUSED_PARAM, char **argv)
175 struct bb_uidgid_t ugid;
176 char *set_user = set_user; /* for compiler */
177 char *env_user = env_user;
178 char *env_dir = env_dir;
194 if ((ENABLE_CHPST && applet_name[0] == 'c')
195 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
197 // FIXME: can we live with int-sized limits?
198 // can we live with 40000 days?
199 // if yes -> getopt converts strings to numbers for us
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));
208 if (opt & OPT_m) { // -m means -asld
209 limita = limits = limitl = limitd = limitm;
210 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
213 option_mask32 = opt = 0;
220 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
226 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
232 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
237 // we must have PROG [ARGS]
244 limit(RLIMIT_DATA, limitd);
247 bb_error_msg("system does not support RLIMIT_%s",
253 limit(RLIMIT_STACK, limits);
256 bb_error_msg("system does not support RLIMIT_%s",
261 #ifdef RLIMIT_MEMLOCK
262 limit(RLIMIT_MEMLOCK, limitl);
265 bb_error_msg("system does not support RLIMIT_%s",
271 limit(RLIMIT_VMEM, limita);
274 limit(RLIMIT_AS, limita);
277 bb_error_msg("system does not support RLIMIT_%s",
284 limit(RLIMIT_NOFILE, limito);
287 limit(RLIMIT_OFILE, limito);
290 bb_error_msg("system does not support RLIMIT_%s",
297 limit(RLIMIT_NPROC, limitp);
300 bb_error_msg("system does not support RLIMIT_%s",
306 limit(RLIMIT_FSIZE, limitf);
309 bb_error_msg("system does not support RLIMIT_%s",
315 limit(RLIMIT_CORE, limitc);
318 bb_error_msg("system does not support RLIMIT_%s",
324 limit(RLIMIT_RSS, limitr);
327 bb_error_msg("system does not support RLIMIT_%s",
333 limit(RLIMIT_CPU, limitt);
336 bb_error_msg("system does not support RLIMIT_%s",
347 // FIXME: chrooted jail must have /etc/passwd if we move this after chroot!
348 // OTOH chroot fails for non-roots!
349 // SOLUTION: cache uid/gid before chroot, apply uid/gid after
351 xget_uidgid(&ugid, env_user);
352 xsetenv("GID", utoa(ugid.gid));
353 xsetenv("UID", utoa(ugid.uid));
357 xget_uidgid(&ugid, set_user);
360 if (opt & OPT_root) {
366 if (setgroups(1, &ugid.gid) == -1)
367 bb_perror_msg_and_die("setgroups");
374 if (nice(xatoi(nicestr)) == -1)
375 bb_perror_msg_and_die("nice");
381 close(STDOUT_FILENO);
383 close(STDERR_FILENO);
385 BB_EXECVP(argv[0], argv);
386 bb_perror_msg_and_die("exec %s", argv[0]);