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 static void edir(const char *directory_name)
102 wdir = xopen(".", O_RDONLY | O_NDELAY);
103 xchdir(directory_name);
106 bb_perror_msg_and_die("opendir %s", directory_name);
116 bb_perror_msg_and_die("readdir %s",
120 if (d->d_name[0] == '.')
122 fd = open(d->d_name, O_RDONLY | O_NDELAY);
124 if ((errno == EISDIR) && directory_name) {
125 if (option_mask32 & OPT_v)
126 bb_perror_msg("warning: %s/%s is a directory",
127 directory_name, d->d_name);
130 bb_perror_msg_and_die("open %s/%s",
131 directory_name, d->d_name);
133 size = full_read(fd, buf, sizeof(buf)-1);
136 bb_perror_msg_and_die("read %s/%s",
137 directory_name, d->d_name);
143 tail = strchr(buf, '\n');
144 /* skip trailing whitespace */
148 if (tail < buf || !isspace(*tail))
151 xsetenv(d->d_name, buf);
154 if (fchdir(wdir) == -1)
155 bb_perror_msg_and_die("fchdir");
159 static void limit(int what, long l)
163 /* Never fails under Linux (except if you pass it bad arguments) */
165 if ((l < 0) || (l > r.rlim_max))
166 r.rlim_cur = r.rlim_max;
169 if (setrlimit(what, &r) == -1)
170 bb_perror_msg_and_die("setrlimit");
173 int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
174 int chpst_main(int argc UNUSED_PARAM, char **argv)
176 struct bb_uidgid_t ugid;
177 char *set_user = set_user; /* for compiler */
178 char *env_user = env_user;
179 char *env_dir = env_dir;
195 if ((ENABLE_CHPST && applet_name[0] == 'c')
196 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
198 // FIXME: can we live with int-sized limits?
199 // can we live with 40000 days?
200 // if yes -> getopt converts strings to numbers for us
201 opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
202 opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
203 USE_CHPST("/:n:vP012"),
204 &limita, &limitc, &limitd, &limitf, &limitl,
205 &limitm, &limito, &limitp, &limitr, &limits, &limitt,
206 &set_user, &env_user, &env_dir
207 USE_CHPST(, &root, &nicestr));
209 if (opt & OPT_m) { // -m means -asld
210 limita = limits = limitl = limitd = limitm;
211 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
214 option_mask32 = opt = 0;
219 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
225 if (ENABLE_SETUIDGID && applet_name[0] == 's') {
231 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
236 // we must have PROG [ARGS]
243 limit(RLIMIT_DATA, limitd);
246 bb_error_msg("system does not support RLIMIT_%s",
252 limit(RLIMIT_STACK, limits);
255 bb_error_msg("system does not support RLIMIT_%s",
260 #ifdef RLIMIT_MEMLOCK
261 limit(RLIMIT_MEMLOCK, limitl);
264 bb_error_msg("system does not support RLIMIT_%s",
270 limit(RLIMIT_VMEM, limita);
273 limit(RLIMIT_AS, limita);
276 bb_error_msg("system does not support RLIMIT_%s",
283 limit(RLIMIT_NOFILE, limito);
286 limit(RLIMIT_OFILE, limito);
289 bb_error_msg("system does not support RLIMIT_%s",
296 limit(RLIMIT_NPROC, limitp);
299 bb_error_msg("system does not support RLIMIT_%s",
305 limit(RLIMIT_FSIZE, limitf);
308 bb_error_msg("system does not support RLIMIT_%s",
314 limit(RLIMIT_CORE, limitc);
317 bb_error_msg("system does not support RLIMIT_%s",
323 limit(RLIMIT_RSS, limitr);
326 bb_error_msg("system does not support RLIMIT_%s",
332 limit(RLIMIT_CPU, limitt);
335 bb_error_msg("system does not support RLIMIT_%s",
346 // FIXME: chrooted jail must have /etc/passwd if we move this after chroot!
347 // OTOH chroot fails for non-roots!
348 // SOLUTION: cache uid/gid before chroot, apply uid/gid after
350 xget_uidgid(&ugid, env_user);
351 xsetenv("GID", utoa(ugid.gid));
352 xsetenv("UID", utoa(ugid.uid));
356 xget_uidgid(&ugid, set_user);
359 if (opt & OPT_root) {
365 if (setgroups(1, &ugid.gid) == -1)
366 bb_perror_msg_and_die("setgroups");
373 if (nice(xatoi(nicestr)) == -1)
374 bb_perror_msg_and_die("nice");
380 close(STDOUT_FILENO);
382 close(STDERR_FILENO);
384 BB_EXECVP(argv[0], argv);
385 bb_perror_msg_and_die("exec %s", argv[0]);