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 */
34 Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
36 Only softlimit and chpst are taking options:
39 -o N Limit number of open files per process
40 -p N Limit number of processes per uid
41 -m BYTES Same as -d BYTES -s BYTES -l BYTES [-a BYTES]
42 -d BYTES Limit data segment
43 -f BYTES Limit output file sizes
44 -c BYTES Limit core file size
46 -a BYTES Limit total size of all segments
47 -s BYTES Limit stack segment
48 -l BYTES Limit locked memory size
49 -r BYTES Limit resident set size
52 -u USER[:GRP] Set uid and gid
53 -U USER[:GRP] Set $UID and $GID in environment
54 -e DIR Set environment variables as specified by files in DIR
56 -n NICE Add NICE to nice value
58 -P Create new process group
59 -0 -1 -2 Close fd 0,1,2
61 Even though we accept all these options for both softlimit and chpst,
62 they are not to be advertised on their help texts.
63 We have enough problems with feature creep in other people's
64 software, don't want to add our own.
66 envdir, envuidgid, setuidgid take no options, but they reuse code which
67 handles -e, -U and -u.
71 OPT_a
= (1 << 0) * ENABLE_SOFTLIMIT
,
72 OPT_c
= (1 << 1) * (ENABLE_SOFTLIMIT
|| ENABLE_CHPST
),
73 OPT_d
= (1 << 2) * (ENABLE_SOFTLIMIT
|| ENABLE_CHPST
),
74 OPT_f
= (1 << 3) * (ENABLE_SOFTLIMIT
|| ENABLE_CHPST
),
75 OPT_l
= (1 << 4) * ENABLE_SOFTLIMIT
,
76 OPT_m
= (1 << 5) * (ENABLE_SOFTLIMIT
|| ENABLE_CHPST
),
77 OPT_o
= (1 << 6) * (ENABLE_SOFTLIMIT
|| ENABLE_CHPST
),
78 OPT_p
= (1 << 7) * (ENABLE_SOFTLIMIT
|| ENABLE_CHPST
),
79 OPT_r
= (1 << 8) * ENABLE_SOFTLIMIT
,
80 OPT_s
= (1 << 9) * ENABLE_SOFTLIMIT
,
81 OPT_t
= (1 << 10) * ENABLE_SOFTLIMIT
,
82 OPT_u
= (1 << 11) * (ENABLE_CHPST
|| ENABLE_SETUIDGID
),
83 OPT_U
= (1 << 12) * (ENABLE_CHPST
|| ENABLE_ENVUIDGID
),
84 OPT_e
= (1 << 13) * (ENABLE_CHPST
|| ENABLE_ENVDIR
),
85 OPT_root
= (1 << 14) * ENABLE_CHPST
,
86 OPT_n
= (1 << 15) * ENABLE_CHPST
,
87 OPT_v
= (1 << 16) * ENABLE_CHPST
,
88 OPT_P
= (1 << 17) * ENABLE_CHPST
,
89 OPT_0
= (1 << 18) * ENABLE_CHPST
,
90 OPT_1
= (1 << 19) * ENABLE_CHPST
,
91 OPT_2
= (1 << 20) * ENABLE_CHPST
,
94 /* TODO: use recursive_action? */
95 static NOINLINE
void edir(const char *directory_name
)
102 wdir
= xopen(".", O_RDONLY
| O_NDELAY
);
103 xchdir(directory_name
);
114 bb_perror_msg_and_die("readdir %s",
118 if (d
->d_name
[0] == '.')
120 fd
= open(d
->d_name
, O_RDONLY
| O_NDELAY
);
122 if ((errno
== EISDIR
) && directory_name
) {
123 if (option_mask32
& OPT_v
)
124 bb_perror_msg("warning: %s/%s is a directory",
125 directory_name
, d
->d_name
);
128 bb_perror_msg_and_die("open %s/%s",
129 directory_name
, d
->d_name
);
131 size
= full_read(fd
, buf
, sizeof(buf
)-1);
134 bb_perror_msg_and_die("read %s/%s",
135 directory_name
, d
->d_name
);
141 tail
= strchr(buf
, '\n');
142 /* skip trailing whitespace */
146 if (tail
< buf
|| !isspace(*tail
))
149 xsetenv(d
->d_name
, buf
);
152 if (fchdir(wdir
) == -1)
153 bb_perror_msg_and_die("fchdir");
157 static void limit(int what
, long l
)
161 /* Never fails under Linux (except if you pass it bad arguments) */
163 if ((l
< 0) || (l
> r
.rlim_max
))
164 r
.rlim_cur
= r
.rlim_max
;
167 if (setrlimit(what
, &r
) == -1)
168 bb_perror_msg_and_die("setrlimit");
171 int chpst_main(int argc
, char **argv
) MAIN_EXTERNALLY_VISIBLE
;
172 int chpst_main(int argc UNUSED_PARAM
, char **argv
)
174 struct bb_uidgid_t ugid
;
175 char *set_user
= set_user
; /* for compiler */
176 char *env_user
= env_user
;
177 char *env_dir
= env_dir
;
193 if ((ENABLE_CHPST
&& applet_name
[0] == 'c')
194 || (ENABLE_SOFTLIMIT
&& applet_name
[1] == 'o')
196 // FIXME: can we live with int-sized limits?
197 // can we live with 40000 days?
198 // if yes -> getopt converts strings to numbers for us
199 opt_complementary
= "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
200 opt
= getopt32(argv
, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
201 IF_CHPST("/:n:vP012"),
202 &limita
, &limitc
, &limitd
, &limitf
, &limitl
,
203 &limitm
, &limito
, &limitp
, &limitr
, &limits
, &limitt
,
204 &set_user
, &env_user
, &env_dir
205 IF_CHPST(, &root
, &nicestr
));
207 if (opt
& OPT_m
) { // -m means -asld
208 limita
= limits
= limitl
= limitd
= limitm
;
209 opt
|= (OPT_s
| OPT_l
| OPT_a
| OPT_d
);
212 option_mask32
= opt
= 0;
219 if (ENABLE_ENVDIR
&& applet_name
[3] == 'd') {
225 if (ENABLE_SETUIDGID
&& applet_name
[1] == 'e') {
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_or_die(argv
);