source: MondoRescue/branches/2.2.9/mindi-busybox/runit/chpst.c

Last change on this file was 3320, checked in by Bruno Cornec, 9 years ago
  • Re-add (thanks git BTW) the 2.2.9 branch which had been destroyed in the move to 3.0
  • Property svn:eol-style set to native
File size: 9.5 KB
Line 
1/*
2Copyright (c) 2001-2006, Gerrit Pape
3All rights reserved.
4
5Redistribution and use in source and binary forms, with or without
6modification, are permitted provided that the following conditions are met:
7
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.
15
16THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*/
27
28/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
29/* Dependencies on runit_lib.c removed */
30
31#include "libbb.h"
32
33/*
34Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit.
35
36Only softlimit and chpst are taking options:
37
38# common
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
45# softlimit
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
50-t N Limit CPU time
51# chpst
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
55-/ DIR Chroot to DIR
56-n NICE Add NICE to nice value
57-v Verbose
58-P Create new process group
59-0 -1 -2 Close fd 0,1,2
60
61Even though we accept all these options for both softlimit and chpst,
62they are not to be advertised on their help texts.
63We have enough problems with feature creep in other people's
64software, don't want to add our own.
65
66envdir, envuidgid, setuidgid take no options, but they reuse code which
67handles -e, -U and -u.
68*/
69
70enum {
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,
92};
93
94/* TODO: use recursive_action? */
95static NOINLINE void edir(const char *directory_name)
96{
97 int wdir;
98 DIR *dir;
99 struct dirent *d;
100 int fd;
101
102 wdir = xopen(".", O_RDONLY | O_NDELAY);
103 xchdir(directory_name);
104 dir = xopendir(".");
105 for (;;) {
106 char buf[256];
107 char *tail;
108 int size;
109
110 errno = 0;
111 d = readdir(dir);
112 if (!d) {
113 if (errno)
114 bb_perror_msg_and_die("readdir %s",
115 directory_name);
116 break;
117 }
118 if (d->d_name[0] == '.')
119 continue;
120 fd = open(d->d_name, O_RDONLY | O_NDELAY);
121 if (fd < 0) {
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);
126 continue;
127 }
128 bb_perror_msg_and_die("open %s/%s",
129 directory_name, d->d_name);
130 }
131 size = full_read(fd, buf, sizeof(buf)-1);
132 close(fd);
133 if (size < 0)
134 bb_perror_msg_and_die("read %s/%s",
135 directory_name, d->d_name);
136 if (size == 0) {
137 unsetenv(d->d_name);
138 continue;
139 }
140 buf[size] = '\n';
141 tail = strchr(buf, '\n');
142 /* skip trailing whitespace */
143 while (1) {
144 *tail = '\0';
145 tail--;
146 if (tail < buf || !isspace(*tail))
147 break;
148 }
149 xsetenv(d->d_name, buf);
150 }
151 closedir(dir);
152 if (fchdir(wdir) == -1)
153 bb_perror_msg_and_die("fchdir");
154 close(wdir);
155}
156
157static void limit(int what, long l)
158{
159 struct rlimit r;
160
161 /* Never fails under Linux (except if you pass it bad arguments) */
162 getrlimit(what, &r);
163 if ((l < 0) || (l > r.rlim_max))
164 r.rlim_cur = r.rlim_max;
165 else
166 r.rlim_cur = l;
167 if (setrlimit(what, &r) == -1)
168 bb_perror_msg_and_die("setrlimit");
169}
170
171int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
172int chpst_main(int argc UNUSED_PARAM, char **argv)
173{
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;
178 char *root;
179 char *nicestr;
180 unsigned limita;
181 unsigned limitc;
182 unsigned limitd;
183 unsigned limitf;
184 unsigned limitl;
185 unsigned limitm;
186 unsigned limito;
187 unsigned limitp;
188 unsigned limitr;
189 unsigned limits;
190 unsigned limitt;
191 unsigned opt;
192
193 if ((ENABLE_CHPST && applet_name[0] == 'c')
194 || (ENABLE_SOFTLIMIT && applet_name[1] == 'o')
195 ) {
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));
206 argv += optind;
207 if (opt & OPT_m) { // -m means -asld
208 limita = limits = limitl = limitd = limitm;
209 opt |= (OPT_s | OPT_l | OPT_a | OPT_d);
210 }
211 } else {
212 option_mask32 = opt = 0;
213 argv++;
214 if (!*argv)
215 bb_show_usage();
216 }
217
218 // envdir?
219 if (ENABLE_ENVDIR && applet_name[3] == 'd') {
220 env_dir = *argv++;
221 opt |= OPT_e;
222 }
223
224 // setuidgid?
225 if (ENABLE_SETUIDGID && applet_name[1] == 'e') {
226 set_user = *argv++;
227 opt |= OPT_u;
228 }
229
230 // envuidgid?
231 if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') {
232 env_user = *argv++;
233 opt |= OPT_U;
234 }
235
236 // we must have PROG [ARGS]
237 if (!*argv)
238 bb_show_usage();
239
240 // set limits
241 if (opt & OPT_d) {
242#ifdef RLIMIT_DATA
243 limit(RLIMIT_DATA, limitd);
244#else
245 if (opt & OPT_v)
246 bb_error_msg("system does not support RLIMIT_%s",
247 "DATA");
248#endif
249 }
250 if (opt & OPT_s) {
251#ifdef RLIMIT_STACK
252 limit(RLIMIT_STACK, limits);
253#else
254 if (opt & OPT_v)
255 bb_error_msg("system does not support RLIMIT_%s",
256 "STACK");
257#endif
258 }
259 if (opt & OPT_l) {
260#ifdef RLIMIT_MEMLOCK
261 limit(RLIMIT_MEMLOCK, limitl);
262#else
263 if (opt & OPT_v)
264 bb_error_msg("system does not support RLIMIT_%s",
265 "MEMLOCK");
266#endif
267 }
268 if (opt & OPT_a) {
269#ifdef RLIMIT_VMEM
270 limit(RLIMIT_VMEM, limita);
271#else
272#ifdef RLIMIT_AS
273 limit(RLIMIT_AS, limita);
274#else
275 if (opt & OPT_v)
276 bb_error_msg("system does not support RLIMIT_%s",
277 "VMEM");
278#endif
279#endif
280 }
281 if (opt & OPT_o) {
282#ifdef RLIMIT_NOFILE
283 limit(RLIMIT_NOFILE, limito);
284#else
285#ifdef RLIMIT_OFILE
286 limit(RLIMIT_OFILE, limito);
287#else
288 if (opt & OPT_v)
289 bb_error_msg("system does not support RLIMIT_%s",
290 "NOFILE");
291#endif
292#endif
293 }
294 if (opt & OPT_p) {
295#ifdef RLIMIT_NPROC
296 limit(RLIMIT_NPROC, limitp);
297#else
298 if (opt & OPT_v)
299 bb_error_msg("system does not support RLIMIT_%s",
300 "NPROC");
301#endif
302 }
303 if (opt & OPT_f) {
304#ifdef RLIMIT_FSIZE
305 limit(RLIMIT_FSIZE, limitf);
306#else
307 if (opt & OPT_v)
308 bb_error_msg("system does not support RLIMIT_%s",
309 "FSIZE");
310#endif
311 }
312 if (opt & OPT_c) {
313#ifdef RLIMIT_CORE
314 limit(RLIMIT_CORE, limitc);
315#else
316 if (opt & OPT_v)
317 bb_error_msg("system does not support RLIMIT_%s",
318 "CORE");
319#endif
320 }
321 if (opt & OPT_r) {
322#ifdef RLIMIT_RSS
323 limit(RLIMIT_RSS, limitr);
324#else
325 if (opt & OPT_v)
326 bb_error_msg("system does not support RLIMIT_%s",
327 "RSS");
328#endif
329 }
330 if (opt & OPT_t) {
331#ifdef RLIMIT_CPU
332 limit(RLIMIT_CPU, limitt);
333#else
334 if (opt & OPT_v)
335 bb_error_msg("system does not support RLIMIT_%s",
336 "CPU");
337#endif
338 }
339
340 if (opt & OPT_P)
341 setsid();
342
343 if (opt & OPT_e)
344 edir(env_dir);
345
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
349 if (opt & OPT_U) {
350 xget_uidgid(&ugid, env_user);
351 xsetenv("GID", utoa(ugid.gid));
352 xsetenv("UID", utoa(ugid.uid));
353 }
354
355 if (opt & OPT_u) {
356 xget_uidgid(&ugid, set_user);
357 }
358
359 if (opt & OPT_root) {
360 xchdir(root);
361 xchroot(".");
362 }
363
364 if (opt & OPT_u) {
365 if (setgroups(1, &ugid.gid) == -1)
366 bb_perror_msg_and_die("setgroups");
367 xsetgid(ugid.gid);
368 xsetuid(ugid.uid);
369 }
370
371 if (opt & OPT_n) {
372 errno = 0;
373 if (nice(xatoi(nicestr)) == -1)
374 bb_perror_msg_and_die("nice");
375 }
376
377 if (opt & OPT_0)
378 close(STDIN_FILENO);
379 if (opt & OPT_1)
380 close(STDOUT_FILENO);
381 if (opt & OPT_2)
382 close(STDERR_FILENO);
383
384 BB_EXECVP_or_die(argv);
385}
Note: See TracBrowser for help on using the repository browser.