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;
221 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
227 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
233 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
238 // we must have PROG [ARGS]
245 limit(RLIMIT_DATA, limitd);
248 bb_error_msg("system does not support RLIMIT_%s",
254 limit(RLIMIT_STACK, limits);
257 bb_error_msg("system does not support RLIMIT_%s",
262 #ifdef RLIMIT_MEMLOCK
263 limit(RLIMIT_MEMLOCK, limitl);
266 bb_error_msg("system does not support RLIMIT_%s",
272 limit(RLIMIT_VMEM, limita);
275 limit(RLIMIT_AS, limita);
278 bb_error_msg("system does not support RLIMIT_%s",
285 limit(RLIMIT_NOFILE, limito);
288 limit(RLIMIT_OFILE, limito);
291 bb_error_msg("system does not support RLIMIT_%s",
298 limit(RLIMIT_NPROC, limitp);
301 bb_error_msg("system does not support RLIMIT_%s",
307 limit(RLIMIT_FSIZE, limitf);
310 bb_error_msg("system does not support RLIMIT_%s",
316 limit(RLIMIT_CORE, limitc);
319 bb_error_msg("system does not support RLIMIT_%s",
325 limit(RLIMIT_RSS, limitr);
328 bb_error_msg("system does not support RLIMIT_%s",
334 limit(RLIMIT_CPU, limitt);
337 bb_error_msg("system does not support RLIMIT_%s",
348 // FIXME: chrooted jail must have /etc/passwd if we move this after chroot!
349 // OTOH chroot fails for non-roots!
350 // SOLUTION: cache uid/gid before chroot, apply uid/gid after
352 xget_uidgid(&ugid, env_user);
353 xsetenv("GID", utoa(ugid.gid));
354 xsetenv("UID", utoa(ugid.uid));
358 xget_uidgid(&ugid, set_user);
361 if (opt & OPT_root) {
367 if (setgroups(1, &ugid.gid) == -1)
368 bb_perror_msg_and_die("setgroups");
375 if (nice(xatoi(nicestr)) == -1)
376 bb_perror_msg_and_die("nice");
382 close(STDOUT_FILENO);
384 close(STDERR_FILENO);
386 BB_EXECVP(argv[0], argv);
387 bb_perror_msg_and_die("exec %s", argv[0]);