blob: 4de53f0513a03509f546be34b32aea61cb49bb0f [file] [log] [blame]
Denis Vlasenko9bff26c2006-10-20 19:40:44 +00001/*
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
Denis Vlasenkod18f52b2008-03-02 12:53:15 +000028/* Busyboxed by Denys Vlasenko <vda.linux@googlemail.com> */
Denis Vlasenko83ea6432006-11-16 02:27:24 +000029/* Dependencies on runit_lib.c removed */
Denis Vlasenko9bff26c2006-10-20 19:40:44 +000030
Denis Vlasenkob6adbf12007-05-26 19:00:18 +000031#include "libbb.h"
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000032
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000033#include <dirent.h>
34
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000035// Must match constants in chpst_main!
Denis Vlasenkoc12f5302006-10-06 09:49:47 +000036#define OPT_verbose (option_mask32 & 0x2000)
37#define OPT_pgrp (option_mask32 & 0x4000)
38#define OPT_nostdin (option_mask32 & 0x8000)
39#define OPT_nostdout (option_mask32 & 0x10000)
40#define OPT_nostderr (option_mask32 & 0x20000)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000041
Denis Vlasenko23e3e252007-10-05 21:23:49 +000042struct globals {
43 char *set_user;
44 char *env_user;
45 const char *env_dir;
46 const char *root;
47 long limitd; /* limitX are initialized to -2 */
48 long limits;
49 long limitl;
50 long limita;
51 long limito;
52 long limitp;
53 long limitf;
54 long limitc;
55 long limitr;
56 long limitt;
Denis Vlasenko339936b2007-10-05 22:11:06 +000057 int nicelvl;
Denis Vlasenko23e3e252007-10-05 21:23:49 +000058};
59#define G (*(struct globals*)&bb_common_bufsiz1)
60#define set_user (G.set_user)
61#define env_user (G.env_user)
62#define env_dir (G.env_dir )
63#define root (G.root )
64#define limitd (G.limitd )
65#define limits (G.limits )
66#define limitl (G.limitl )
67#define limita (G.limita )
68#define limito (G.limito )
69#define limitp (G.limitp )
70#define limitf (G.limitf )
71#define limitc (G.limitc )
72#define limitr (G.limitr )
73#define limitt (G.limitt )
74#define nicelvl (G.nicelvl )
75#define INIT_G() do { \
76 long *p = &limitd; \
77 do *p++ = -2; while (p <= &limitt); \
78} while (0)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000079
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000080static void suidgid(char *user)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000081{
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000082 struct bb_uidgid_t ugid;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000083
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000084 if (!get_uidgid(&ugid, user, 1)) {
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000085 bb_error_msg_and_die("unknown user/group: %s", user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000086 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000087 if (setgroups(1, &ugid.gid) == -1)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000088 bb_perror_msg_and_die("setgroups");
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000089 xsetgid(ugid.gid);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000090 xsetuid(ugid.uid);
91}
92
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000093static void euidgid(char *user)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000094{
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000095 struct bb_uidgid_t ugid;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000096
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000097 if (!get_uidgid(&ugid, user, 1)) {
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000098 bb_error_msg_and_die("unknown user/group: %s", user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000099 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000100 xsetenv("GID", utoa(ugid.gid));
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000101 xsetenv("UID", utoa(ugid.uid));
102}
103
104static void edir(const char *directory_name)
105{
106 int wdir;
107 DIR *dir;
108 struct dirent *d;
109 int fd;
110
111 wdir = xopen(".", O_RDONLY | O_NDELAY);
112 xchdir(directory_name);
113 dir = opendir(".");
114 if (!dir)
115 bb_perror_msg_and_die("opendir %s", directory_name);
116 for (;;) {
Denis Vlasenko9895dfd2008-04-01 16:13:14 +0000117 char buf[256];
118 char *tail;
119 int size;
120
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000121 errno = 0;
122 d = readdir(dir);
123 if (!d) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000124 if (errno)
125 bb_perror_msg_and_die("readdir %s",
126 directory_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000127 break;
128 }
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000129 if (d->d_name[0] == '.')
130 continue;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000131 fd = open(d->d_name, O_RDONLY | O_NDELAY);
132 if (fd < 0) {
133 if ((errno == EISDIR) && env_dir) {
134 if (OPT_verbose)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000135 bb_perror_msg("warning: %s/%s is a directory",
136 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000137 continue;
138 } else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000139 bb_perror_msg_and_die("open %s/%s",
140 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000141 }
Denis Vlasenko9895dfd2008-04-01 16:13:14 +0000142 size = full_read(fd, buf, sizeof(buf)-1);
143 close(fd);
144 if (size < 0)
145 bb_perror_msg_and_die("read %s/%s",
146 directory_name, d->d_name);
147 if (size == 0) {
148 unsetenv(d->d_name);
149 continue;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000150 }
Denis Vlasenko9895dfd2008-04-01 16:13:14 +0000151 buf[size] = '\n';
152 tail = strchr(buf, '\n');
153 /* skip trailing whitespace */
154 while (1) {
155 *tail = '\0';
156 tail--;
157 if (tail < buf || !isspace(*tail))
158 break;
159 }
160 xsetenv(d->d_name, buf);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000161 }
162 closedir(dir);
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000163 if (fchdir(wdir) == -1)
164 bb_perror_msg_and_die("fchdir");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000165 close(wdir);
166}
167
168static void limit(int what, long l)
169{
170 struct rlimit r;
171
Denis Vlasenko4e6d5112008-03-12 22:14:34 +0000172 /* Never fails under Linux (except if you pass it bad arguments) */
173 getrlimit(what, &r);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000174 if ((l < 0) || (l > r.rlim_max))
175 r.rlim_cur = r.rlim_max;
176 else
177 r.rlim_cur = l;
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000178 if (setrlimit(what, &r) == -1)
179 bb_perror_msg_and_die("setrlimit");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000180}
181
182static void slimit(void)
183{
184 if (limitd >= -1) {
185#ifdef RLIMIT_DATA
186 limit(RLIMIT_DATA, limitd);
187#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000188 if (OPT_verbose)
189 bb_error_msg("system does not support RLIMIT_%s",
190 "DATA");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000191#endif
192 }
193 if (limits >= -1) {
194#ifdef RLIMIT_STACK
195 limit(RLIMIT_STACK, limits);
196#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000197 if (OPT_verbose)
198 bb_error_msg("system does not support RLIMIT_%s",
199 "STACK");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000200#endif
201 }
202 if (limitl >= -1) {
203#ifdef RLIMIT_MEMLOCK
204 limit(RLIMIT_MEMLOCK, limitl);
205#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000206 if (OPT_verbose)
207 bb_error_msg("system does not support RLIMIT_%s",
208 "MEMLOCK");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000209#endif
210 }
211 if (limita >= -1) {
212#ifdef RLIMIT_VMEM
213 limit(RLIMIT_VMEM, limita);
214#else
215#ifdef RLIMIT_AS
216 limit(RLIMIT_AS, limita);
217#else
218 if (OPT_verbose)
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000219 bb_error_msg("system does not support RLIMIT_%s",
220 "VMEM");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000221#endif
222#endif
223 }
224 if (limito >= -1) {
225#ifdef RLIMIT_NOFILE
226 limit(RLIMIT_NOFILE, limito);
227#else
228#ifdef RLIMIT_OFILE
229 limit(RLIMIT_OFILE, limito);
230#else
231 if (OPT_verbose)
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000232 bb_error_msg("system does not support RLIMIT_%s",
233 "NOFILE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000234#endif
235#endif
236 }
237 if (limitp >= -1) {
238#ifdef RLIMIT_NPROC
239 limit(RLIMIT_NPROC, limitp);
240#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000241 if (OPT_verbose)
242 bb_error_msg("system does not support RLIMIT_%s",
243 "NPROC");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000244#endif
245 }
246 if (limitf >= -1) {
247#ifdef RLIMIT_FSIZE
248 limit(RLIMIT_FSIZE, limitf);
249#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000250 if (OPT_verbose)
251 bb_error_msg("system does not support RLIMIT_%s",
252 "FSIZE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000253#endif
254 }
255 if (limitc >= -1) {
256#ifdef RLIMIT_CORE
257 limit(RLIMIT_CORE, limitc);
258#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000259 if (OPT_verbose)
260 bb_error_msg("system does not support RLIMIT_%s",
261 "CORE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000262#endif
263 }
264 if (limitr >= -1) {
265#ifdef RLIMIT_RSS
266 limit(RLIMIT_RSS, limitr);
267#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000268 if (OPT_verbose)
269 bb_error_msg("system does not support RLIMIT_%s",
270 "RSS");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000271#endif
272 }
273 if (limitt >= -1) {
274#ifdef RLIMIT_CPU
275 limit(RLIMIT_CPU, limitt);
276#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000277 if (OPT_verbose)
278 bb_error_msg("system does not support RLIMIT_%s",
279 "CPU");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000280#endif
281 }
282}
283
284/* argv[0] */
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000285static void setuidgid(int, char **) ATTRIBUTE_NORETURN;
286static void envuidgid(int, char **) ATTRIBUTE_NORETURN;
287static void envdir(int, char **) ATTRIBUTE_NORETURN;
288static void softlimit(int, char **) ATTRIBUTE_NORETURN;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000289
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000290int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenko68404f12008-03-17 09:00:54 +0000291int chpst_main(int argc ATTRIBUTE_UNUSED, char **argv)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000292{
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000293 INIT_G();
294
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000295 if (applet_name[3] == 'd') envdir(argc, argv);
296 if (applet_name[1] == 'o') softlimit(argc, argv);
297 if (applet_name[0] == 's') setuidgid(argc, argv);
298 if (applet_name[0] == 'e') envuidgid(argc, argv);
Denis Vlasenkod031ffa2006-11-24 21:54:44 +0000299 // otherwise we are chpst
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000300
301 {
302 char *m,*d,*o,*p,*f,*c,*r,*t,*n;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000303 getopt32(argv, "+u:U:e:m:d:o:p:f:c:r:t:/:n:vP012",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000304 &set_user,&env_user,&env_dir,
305 &m,&d,&o,&p,&f,&c,&r,&t,&root,&n);
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000306 // if (option_mask32 & 0x1) // -u
307 // if (option_mask32 & 0x2) // -U
308 // if (option_mask32 & 0x4) // -e
Denis Vlasenko13858992006-10-08 12:49:22 +0000309 if (option_mask32 & 0x8) limits = limitl = limita = limitd = xatoul(m); // -m
310 if (option_mask32 & 0x10) limitd = xatoul(d); // -d
311 if (option_mask32 & 0x20) limito = xatoul(o); // -o
312 if (option_mask32 & 0x40) limitp = xatoul(p); // -p
313 if (option_mask32 & 0x80) limitf = xatoul(f); // -f
314 if (option_mask32 & 0x100) limitc = xatoul(c); // -c
315 if (option_mask32 & 0x200) limitr = xatoul(r); // -r
316 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000317 // if (option_mask32 & 0x800) // -/
Denis Vlasenko13858992006-10-08 12:49:22 +0000318 if (option_mask32 & 0x1000) nicelvl = xatoi(n); // -n
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000319 // The below consts should match #defines at top!
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000320 //if (option_mask32 & 0x2000) OPT_verbose = 1; // -v
321 //if (option_mask32 & 0x4000) OPT_pgrp = 1; // -P
322 //if (option_mask32 & 0x8000) OPT_nostdin = 1; // -0
323 //if (option_mask32 & 0x10000) OPT_nostdout = 1; // -1
324 //if (option_mask32 & 0x20000) OPT_nostderr = 1; // -2
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000325 }
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000326 argv += optind;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000327 if (!argv || !*argv) bb_show_usage();
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000328
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000329 if (OPT_pgrp) setsid();
330 if (env_dir) edir(env_dir);
331 if (root) {
332 xchdir(root);
Denis Vlasenko394eebe2008-02-25 20:30:24 +0000333 xchroot(".");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000334 }
335 slimit();
336 if (nicelvl) {
337 errno = 0;
338 if (nice(nicelvl) == -1)
339 bb_perror_msg_and_die("nice");
340 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000341 if (env_user) euidgid(env_user);
342 if (set_user) suidgid(set_user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000343 if (OPT_nostdin) close(0);
344 if (OPT_nostdout) close(1);
345 if (OPT_nostderr) close(2);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000346 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000347 bb_perror_msg_and_die("exec %s", argv[0]);
348}
349
Denis Vlasenko68404f12008-03-17 09:00:54 +0000350static void setuidgid(int argc ATTRIBUTE_UNUSED, char **argv)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000351{
352 const char *account;
353
354 account = *++argv;
355 if (!account) bb_show_usage();
356 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000357 suidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000358 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000359 bb_perror_msg_and_die("exec %s", argv[0]);
360}
361
Denis Vlasenko68404f12008-03-17 09:00:54 +0000362static void envuidgid(int argc ATTRIBUTE_UNUSED, char **argv)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000363{
364 const char *account;
365
366 account = *++argv;
367 if (!account) bb_show_usage();
368 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000369 euidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000370 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000371 bb_perror_msg_and_die("exec %s", argv[0]);
372}
373
Denis Vlasenko68404f12008-03-17 09:00:54 +0000374static void envdir(int argc ATTRIBUTE_UNUSED, char **argv)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000375{
376 const char *dir;
377
378 dir = *++argv;
379 if (!dir) bb_show_usage();
380 if (!*++argv) bb_show_usage();
381 edir(dir);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000382 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000383 bb_perror_msg_and_die("exec %s", argv[0]);
384}
385
Denis Vlasenko68404f12008-03-17 09:00:54 +0000386static void softlimit(int argc ATTRIBUTE_UNUSED, char **argv)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000387{
388 char *a,*c,*d,*f,*l,*m,*o,*p,*r,*s,*t;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000389 getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000390 &a,&c,&d,&f,&l,&m,&o,&p,&r,&s,&t);
Denis Vlasenko13858992006-10-08 12:49:22 +0000391 if (option_mask32 & 0x001) limita = xatoul(a); // -a
392 if (option_mask32 & 0x002) limitc = xatoul(c); // -c
393 if (option_mask32 & 0x004) limitd = xatoul(d); // -d
394 if (option_mask32 & 0x008) limitf = xatoul(f); // -f
395 if (option_mask32 & 0x010) limitl = xatoul(l); // -l
396 if (option_mask32 & 0x020) limits = limitl = limita = limitd = xatoul(m); // -m
397 if (option_mask32 & 0x040) limito = xatoul(o); // -o
398 if (option_mask32 & 0x080) limitp = xatoul(p); // -p
399 if (option_mask32 & 0x100) limitr = xatoul(r); // -r
400 if (option_mask32 & 0x200) limits = xatoul(s); // -s
401 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000402 argv += optind;
403 if (!argv[0]) bb_show_usage();
404 slimit();
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000405 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000406 bb_perror_msg_and_die("exec %s", argv[0]);
407}