blob: 0f605cc455ffbae8af072ba838a17ad1275f22b8 [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
28/* Busyboxed by Denis 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 (;;) {
117 errno = 0;
118 d = readdir(dir);
119 if (!d) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000120 if (errno)
121 bb_perror_msg_and_die("readdir %s",
122 directory_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000123 break;
124 }
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000125 if (d->d_name[0] == '.')
126 continue;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000127 fd = open(d->d_name, O_RDONLY | O_NDELAY);
128 if (fd < 0) {
129 if ((errno == EISDIR) && env_dir) {
130 if (OPT_verbose)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000131 bb_perror_msg("warning: %s/%s is a directory",
132 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000133 continue;
134 } else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000135 bb_perror_msg_and_die("open %s/%s",
136 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000137 }
138 if (fd >= 0) {
139 char buf[256];
140 char *tail;
141 int size;
142
143 size = safe_read(fd, buf, sizeof(buf)-1);
144 if (size < 0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000145 bb_perror_msg_and_die("read %s/%s",
146 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000147 if (size == 0) {
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000148 unsetenv(d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000149 continue;
150 }
151 buf[size] = '\n';
152 tail = memchr(buf, '\n', sizeof(buf));
153 /* skip trailing whitespace */;
154 while (1) {
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000155 if (tail[0] == ' ') tail[0] = '\0';
156 if (tail[0] == '\t') tail[0] = '\0';
157 if (tail[0] == '\n') tail[0] = '\0';
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000158 if (tail == buf) break;
159 tail--;
160 }
161 xsetenv(d->d_name, buf);
162 }
163 }
164 closedir(dir);
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000165 if (fchdir(wdir) == -1)
166 bb_perror_msg_and_die("fchdir");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000167 close(wdir);
168}
169
170static void limit(int what, long l)
171{
172 struct rlimit r;
173
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000174 if (getrlimit(what, &r) == -1)
175 bb_perror_msg_and_die("getrlimit");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000176 if ((l < 0) || (l > r.rlim_max))
177 r.rlim_cur = r.rlim_max;
178 else
179 r.rlim_cur = l;
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000180 if (setrlimit(what, &r) == -1)
181 bb_perror_msg_and_die("setrlimit");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000182}
183
184static void slimit(void)
185{
186 if (limitd >= -1) {
187#ifdef RLIMIT_DATA
188 limit(RLIMIT_DATA, limitd);
189#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000190 if (OPT_verbose)
191 bb_error_msg("system does not support RLIMIT_%s",
192 "DATA");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000193#endif
194 }
195 if (limits >= -1) {
196#ifdef RLIMIT_STACK
197 limit(RLIMIT_STACK, limits);
198#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000199 if (OPT_verbose)
200 bb_error_msg("system does not support RLIMIT_%s",
201 "STACK");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000202#endif
203 }
204 if (limitl >= -1) {
205#ifdef RLIMIT_MEMLOCK
206 limit(RLIMIT_MEMLOCK, limitl);
207#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000208 if (OPT_verbose)
209 bb_error_msg("system does not support RLIMIT_%s",
210 "MEMLOCK");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000211#endif
212 }
213 if (limita >= -1) {
214#ifdef RLIMIT_VMEM
215 limit(RLIMIT_VMEM, limita);
216#else
217#ifdef RLIMIT_AS
218 limit(RLIMIT_AS, limita);
219#else
220 if (OPT_verbose)
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000221 bb_error_msg("system does not support RLIMIT_%s",
222 "VMEM");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000223#endif
224#endif
225 }
226 if (limito >= -1) {
227#ifdef RLIMIT_NOFILE
228 limit(RLIMIT_NOFILE, limito);
229#else
230#ifdef RLIMIT_OFILE
231 limit(RLIMIT_OFILE, limito);
232#else
233 if (OPT_verbose)
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000234 bb_error_msg("system does not support RLIMIT_%s",
235 "NOFILE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000236#endif
237#endif
238 }
239 if (limitp >= -1) {
240#ifdef RLIMIT_NPROC
241 limit(RLIMIT_NPROC, limitp);
242#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000243 if (OPT_verbose)
244 bb_error_msg("system does not support RLIMIT_%s",
245 "NPROC");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000246#endif
247 }
248 if (limitf >= -1) {
249#ifdef RLIMIT_FSIZE
250 limit(RLIMIT_FSIZE, limitf);
251#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000252 if (OPT_verbose)
253 bb_error_msg("system does not support RLIMIT_%s",
254 "FSIZE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000255#endif
256 }
257 if (limitc >= -1) {
258#ifdef RLIMIT_CORE
259 limit(RLIMIT_CORE, limitc);
260#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000261 if (OPT_verbose)
262 bb_error_msg("system does not support RLIMIT_%s",
263 "CORE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000264#endif
265 }
266 if (limitr >= -1) {
267#ifdef RLIMIT_RSS
268 limit(RLIMIT_RSS, limitr);
269#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000270 if (OPT_verbose)
271 bb_error_msg("system does not support RLIMIT_%s",
272 "RSS");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000273#endif
274 }
275 if (limitt >= -1) {
276#ifdef RLIMIT_CPU
277 limit(RLIMIT_CPU, limitt);
278#else
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000279 if (OPT_verbose)
280 bb_error_msg("system does not support RLIMIT_%s",
281 "CPU");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000282#endif
283 }
284}
285
286/* argv[0] */
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000287static void setuidgid(int, char **) ATTRIBUTE_NORETURN;
288static void envuidgid(int, char **) ATTRIBUTE_NORETURN;
289static void envdir(int, char **) ATTRIBUTE_NORETURN;
290static void softlimit(int, char **) ATTRIBUTE_NORETURN;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000291
Denis Vlasenko9b49a5e2007-10-11 10:05:36 +0000292int chpst_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000293int chpst_main(int argc, char **argv)
294{
Denis Vlasenko23e3e252007-10-05 21:23:49 +0000295 INIT_G();
296
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000297 if (applet_name[3] == 'd') envdir(argc, argv);
298 if (applet_name[1] == 'o') softlimit(argc, argv);
299 if (applet_name[0] == 's') setuidgid(argc, argv);
300 if (applet_name[0] == 'e') envuidgid(argc, argv);
Denis Vlasenkod031ffa2006-11-24 21:54:44 +0000301 // otherwise we are chpst
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000302
303 {
304 char *m,*d,*o,*p,*f,*c,*r,*t,*n;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000305 getopt32(argv, "+u:U:e:m:d:o:p:f:c:r:t:/:n:vP012",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000306 &set_user,&env_user,&env_dir,
307 &m,&d,&o,&p,&f,&c,&r,&t,&root,&n);
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000308 // if (option_mask32 & 0x1) // -u
309 // if (option_mask32 & 0x2) // -U
310 // if (option_mask32 & 0x4) // -e
Denis Vlasenko13858992006-10-08 12:49:22 +0000311 if (option_mask32 & 0x8) limits = limitl = limita = limitd = xatoul(m); // -m
312 if (option_mask32 & 0x10) limitd = xatoul(d); // -d
313 if (option_mask32 & 0x20) limito = xatoul(o); // -o
314 if (option_mask32 & 0x40) limitp = xatoul(p); // -p
315 if (option_mask32 & 0x80) limitf = xatoul(f); // -f
316 if (option_mask32 & 0x100) limitc = xatoul(c); // -c
317 if (option_mask32 & 0x200) limitr = xatoul(r); // -r
318 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000319 // if (option_mask32 & 0x800) // -/
Denis Vlasenko13858992006-10-08 12:49:22 +0000320 if (option_mask32 & 0x1000) nicelvl = xatoi(n); // -n
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000321 // The below consts should match #defines at top!
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000322 //if (option_mask32 & 0x2000) OPT_verbose = 1; // -v
323 //if (option_mask32 & 0x4000) OPT_pgrp = 1; // -P
324 //if (option_mask32 & 0x8000) OPT_nostdin = 1; // -0
325 //if (option_mask32 & 0x10000) OPT_nostdout = 1; // -1
326 //if (option_mask32 & 0x20000) OPT_nostderr = 1; // -2
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000327 }
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000328 argv += optind;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000329 if (!argv || !*argv) bb_show_usage();
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000330
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000331 if (OPT_pgrp) setsid();
332 if (env_dir) edir(env_dir);
333 if (root) {
334 xchdir(root);
335 if (chroot(".") == -1)
336 bb_perror_msg_and_die("chroot");
337 }
338 slimit();
339 if (nicelvl) {
340 errno = 0;
341 if (nice(nicelvl) == -1)
342 bb_perror_msg_and_die("nice");
343 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000344 if (env_user) euidgid(env_user);
345 if (set_user) suidgid(set_user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000346 if (OPT_nostdin) close(0);
347 if (OPT_nostdout) close(1);
348 if (OPT_nostderr) close(2);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000349 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000350 bb_perror_msg_and_die("exec %s", argv[0]);
351}
352
353static void setuidgid(int argc, char **argv)
354{
355 const char *account;
356
357 account = *++argv;
358 if (!account) bb_show_usage();
359 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000360 suidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000361 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000362 bb_perror_msg_and_die("exec %s", argv[0]);
363}
364
365static void envuidgid(int argc, char **argv)
366{
367 const char *account;
368
369 account = *++argv;
370 if (!account) bb_show_usage();
371 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000372 euidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000373 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000374 bb_perror_msg_and_die("exec %s", argv[0]);
375}
376
377static void envdir(int argc, char **argv)
378{
379 const char *dir;
380
381 dir = *++argv;
382 if (!dir) bb_show_usage();
383 if (!*++argv) bb_show_usage();
384 edir(dir);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000385 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000386 bb_perror_msg_and_die("exec %s", argv[0]);
387}
388
389static void softlimit(int argc, char **argv)
390{
391 char *a,*c,*d,*f,*l,*m,*o,*p,*r,*s,*t;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000392 getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000393 &a,&c,&d,&f,&l,&m,&o,&p,&r,&s,&t);
Denis Vlasenko13858992006-10-08 12:49:22 +0000394 if (option_mask32 & 0x001) limita = xatoul(a); // -a
395 if (option_mask32 & 0x002) limitc = xatoul(c); // -c
396 if (option_mask32 & 0x004) limitd = xatoul(d); // -d
397 if (option_mask32 & 0x008) limitf = xatoul(f); // -f
398 if (option_mask32 & 0x010) limitl = xatoul(l); // -l
399 if (option_mask32 & 0x020) limits = limitl = limita = limitd = xatoul(m); // -m
400 if (option_mask32 & 0x040) limito = xatoul(o); // -o
401 if (option_mask32 & 0x080) limitp = xatoul(p); // -p
402 if (option_mask32 & 0x100) limitr = xatoul(r); // -r
403 if (option_mask32 & 0x200) limits = xatoul(s); // -s
404 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000405 argv += optind;
406 if (!argv[0]) bb_show_usage();
407 slimit();
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000408 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000409 bb_perror_msg_and_die("exec %s", argv[0]);
410}