blob: b306974bb01ccaa1386499fe646179b5b58b566b [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 (;;) {
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 Vlasenko4e6d5112008-03-12 22:14:34 +0000174 /* Never fails under Linux (except if you pass it bad arguments) */
175 getrlimit(what, &r);
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);
Denis Vlasenko394eebe2008-02-25 20:30:24 +0000335 xchroot(".");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000336 }
337 slimit();
338 if (nicelvl) {
339 errno = 0;
340 if (nice(nicelvl) == -1)
341 bb_perror_msg_and_die("nice");
342 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000343 if (env_user) euidgid(env_user);
344 if (set_user) suidgid(set_user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000345 if (OPT_nostdin) close(0);
346 if (OPT_nostdout) close(1);
347 if (OPT_nostderr) close(2);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000348 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000349 bb_perror_msg_and_die("exec %s", argv[0]);
350}
351
352static void setuidgid(int argc, char **argv)
353{
354 const char *account;
355
356 account = *++argv;
357 if (!account) bb_show_usage();
358 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000359 suidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000360 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000361 bb_perror_msg_and_die("exec %s", argv[0]);
362}
363
364static void envuidgid(int argc, char **argv)
365{
366 const char *account;
367
368 account = *++argv;
369 if (!account) bb_show_usage();
370 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000371 euidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000372 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000373 bb_perror_msg_and_die("exec %s", argv[0]);
374}
375
376static void envdir(int argc, char **argv)
377{
378 const char *dir;
379
380 dir = *++argv;
381 if (!dir) bb_show_usage();
382 if (!*++argv) bb_show_usage();
383 edir(dir);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000384 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000385 bb_perror_msg_and_die("exec %s", argv[0]);
386}
387
388static void softlimit(int argc, char **argv)
389{
390 char *a,*c,*d,*f,*l,*m,*o,*p,*r,*s,*t;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000391 getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000392 &a,&c,&d,&f,&l,&m,&o,&p,&r,&s,&t);
Denis Vlasenko13858992006-10-08 12:49:22 +0000393 if (option_mask32 & 0x001) limita = xatoul(a); // -a
394 if (option_mask32 & 0x002) limitc = xatoul(c); // -c
395 if (option_mask32 & 0x004) limitd = xatoul(d); // -d
396 if (option_mask32 & 0x008) limitf = xatoul(f); // -f
397 if (option_mask32 & 0x010) limitl = xatoul(l); // -l
398 if (option_mask32 & 0x020) limits = limitl = limita = limitd = xatoul(m); // -m
399 if (option_mask32 & 0x040) limito = xatoul(o); // -o
400 if (option_mask32 & 0x080) limitp = xatoul(p); // -p
401 if (option_mask32 & 0x100) limitr = xatoul(r); // -r
402 if (option_mask32 & 0x200) limits = xatoul(s); // -s
403 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000404 argv += optind;
405 if (!argv[0]) bb_show_usage();
406 slimit();
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000407 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000408 bb_perror_msg_and_die("exec %s", argv[0]);
409}