blob: 87cd8e04a281b8ab218f488f5f0eac72bcdb11fe [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
42static char *set_user;
43static char *env_user;
44static const char *env_dir;
45static long limitd = -2;
46static long limits = -2;
47static long limitl = -2;
48static long limita = -2;
49static long limito = -2;
50static long limitp = -2;
51static long limitf = -2;
52static long limitc = -2;
53static long limitr = -2;
54static long limitt = -2;
Denis Vlasenko13858992006-10-08 12:49:22 +000055static int nicelvl;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000056static const char *root;
57
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000058static void suidgid(char *user)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000059{
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000060 struct bb_uidgid_t ugid;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000061
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000062 if (!get_uidgid(&ugid, user, 1)) {
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000063 bb_error_msg_and_die("unknown user/group: %s", user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000064 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000065 if (setgroups(1, &ugid.gid) == -1)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000066 bb_perror_msg_and_die("setgroups");
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000067 xsetgid(ugid.gid);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000068 xsetuid(ugid.uid);
69}
70
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000071static void euidgid(char *user)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000072{
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000073 struct bb_uidgid_t ugid;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000074
Denis Vlasenko9a44c4f2006-12-28 05:44:47 +000075 if (!get_uidgid(&ugid, user, 1)) {
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000076 bb_error_msg_and_die("unknown user/group: %s", user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000077 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000078 xsetenv("GID", utoa(ugid.gid));
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000079 xsetenv("UID", utoa(ugid.uid));
80}
81
82static void edir(const char *directory_name)
83{
84 int wdir;
85 DIR *dir;
86 struct dirent *d;
87 int fd;
88
89 wdir = xopen(".", O_RDONLY | O_NDELAY);
90 xchdir(directory_name);
91 dir = opendir(".");
92 if (!dir)
93 bb_perror_msg_and_die("opendir %s", directory_name);
94 for (;;) {
95 errno = 0;
96 d = readdir(dir);
97 if (!d) {
Denis Vlasenko83ea6432006-11-16 02:27:24 +000098 if (errno)
99 bb_perror_msg_and_die("readdir %s",
100 directory_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000101 break;
102 }
103 if (d->d_name[0] == '.') continue;
104 fd = open(d->d_name, O_RDONLY | O_NDELAY);
105 if (fd < 0) {
106 if ((errno == EISDIR) && env_dir) {
107 if (OPT_verbose)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000108 bb_perror_msg("warning: %s/%s is a directory",
109 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000110 continue;
111 } else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000112 bb_perror_msg_and_die("open %s/%s",
113 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000114 }
115 if (fd >= 0) {
116 char buf[256];
117 char *tail;
118 int size;
119
120 size = safe_read(fd, buf, sizeof(buf)-1);
121 if (size < 0)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000122 bb_perror_msg_and_die("read %s/%s",
123 directory_name, d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000124 if (size == 0) {
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000125 unsetenv(d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000126 continue;
127 }
128 buf[size] = '\n';
129 tail = memchr(buf, '\n', sizeof(buf));
130 /* skip trailing whitespace */;
131 while (1) {
132 if (tail[0]==' ') tail[0] = '\0';
133 if (tail[0]=='\t') tail[0] = '\0';
134 if (tail[0]=='\n') tail[0] = '\0';
135 if (tail == buf) break;
136 tail--;
137 }
138 xsetenv(d->d_name, buf);
139 }
140 }
141 closedir(dir);
142 if (fchdir(wdir) == -1) bb_perror_msg_and_die("fchdir");
143 close(wdir);
144}
145
146static void limit(int what, long l)
147{
148 struct rlimit r;
149
150 if (getrlimit(what, &r) == -1) bb_perror_msg_and_die("getrlimit");
151 if ((l < 0) || (l > r.rlim_max))
152 r.rlim_cur = r.rlim_max;
153 else
154 r.rlim_cur = l;
155 if (setrlimit(what, &r) == -1) bb_perror_msg_and_die("setrlimit");
156}
157
158static void slimit(void)
159{
160 if (limitd >= -1) {
161#ifdef RLIMIT_DATA
162 limit(RLIMIT_DATA, limitd);
163#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000164 if (OPT_verbose) bb_error_msg("system does not support %s",
165 "RLIMIT_DATA");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000166#endif
167 }
168 if (limits >= -1) {
169#ifdef RLIMIT_STACK
170 limit(RLIMIT_STACK, limits);
171#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000172 if (OPT_verbose) bb_error_msg("system does not support %s",
173 "RLIMIT_STACK");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000174#endif
175 }
176 if (limitl >= -1) {
177#ifdef RLIMIT_MEMLOCK
178 limit(RLIMIT_MEMLOCK, limitl);
179#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000180 if (OPT_verbose) bb_error_msg("system does not support %s",
181 "RLIMIT_MEMLOCK");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000182#endif
183 }
184 if (limita >= -1) {
185#ifdef RLIMIT_VMEM
186 limit(RLIMIT_VMEM, limita);
187#else
188#ifdef RLIMIT_AS
189 limit(RLIMIT_AS, limita);
190#else
191 if (OPT_verbose)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000192 bb_error_msg("system does not support %s",
193 "RLIMIT_VMEM");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000194#endif
195#endif
196 }
197 if (limito >= -1) {
198#ifdef RLIMIT_NOFILE
199 limit(RLIMIT_NOFILE, limito);
200#else
201#ifdef RLIMIT_OFILE
202 limit(RLIMIT_OFILE, limito);
203#else
204 if (OPT_verbose)
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000205 bb_error_msg("system does not support %s",
206 "RLIMIT_NOFILE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000207#endif
208#endif
209 }
210 if (limitp >= -1) {
211#ifdef RLIMIT_NPROC
212 limit(RLIMIT_NPROC, limitp);
213#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000214 if (OPT_verbose) bb_error_msg("system does not support %s",
215 "RLIMIT_NPROC");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000216#endif
217 }
218 if (limitf >= -1) {
219#ifdef RLIMIT_FSIZE
220 limit(RLIMIT_FSIZE, limitf);
221#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000222 if (OPT_verbose) bb_error_msg("system does not support %s",
223 "RLIMIT_FSIZE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000224#endif
225 }
226 if (limitc >= -1) {
227#ifdef RLIMIT_CORE
228 limit(RLIMIT_CORE, limitc);
229#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000230 if (OPT_verbose) bb_error_msg("system does not support %s",
231 "RLIMIT_CORE");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000232#endif
233 }
234 if (limitr >= -1) {
235#ifdef RLIMIT_RSS
236 limit(RLIMIT_RSS, limitr);
237#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000238 if (OPT_verbose) bb_error_msg("system does not support %s",
239 "RLIMIT_RSS");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000240#endif
241 }
242 if (limitt >= -1) {
243#ifdef RLIMIT_CPU
244 limit(RLIMIT_CPU, limitt);
245#else
Denis Vlasenko83ea6432006-11-16 02:27:24 +0000246 if (OPT_verbose) bb_error_msg("system does not support %s",
247 "RLIMIT_CPU");
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000248#endif
249 }
250}
251
252/* argv[0] */
253static void setuidgid(int, char **);
254static void envuidgid(int, char **);
255static void envdir(int, char **);
256static void softlimit(int, char **);
257
Denis Vlasenko06af2162007-02-03 17:28:39 +0000258int chpst_main(int argc, char **argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000259int chpst_main(int argc, char **argv)
260{
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000261 if (applet_name[3] == 'd') envdir(argc, argv);
262 if (applet_name[1] == 'o') softlimit(argc, argv);
263 if (applet_name[0] == 's') setuidgid(argc, argv);
264 if (applet_name[0] == 'e') envuidgid(argc, argv);
Denis Vlasenkod031ffa2006-11-24 21:54:44 +0000265 // otherwise we are chpst
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000266
267 {
268 char *m,*d,*o,*p,*f,*c,*r,*t,*n;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000269 getopt32(argv, "+u:U:e:m:d:o:p:f:c:r:t:/:n:vP012",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000270 &set_user,&env_user,&env_dir,
271 &m,&d,&o,&p,&f,&c,&r,&t,&root,&n);
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000272 // if (option_mask32 & 0x1) // -u
273 // if (option_mask32 & 0x2) // -U
274 // if (option_mask32 & 0x4) // -e
Denis Vlasenko13858992006-10-08 12:49:22 +0000275 if (option_mask32 & 0x8) limits = limitl = limita = limitd = xatoul(m); // -m
276 if (option_mask32 & 0x10) limitd = xatoul(d); // -d
277 if (option_mask32 & 0x20) limito = xatoul(o); // -o
278 if (option_mask32 & 0x40) limitp = xatoul(p); // -p
279 if (option_mask32 & 0x80) limitf = xatoul(f); // -f
280 if (option_mask32 & 0x100) limitc = xatoul(c); // -c
281 if (option_mask32 & 0x200) limitr = xatoul(r); // -r
282 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000283 // if (option_mask32 & 0x800) // -/
Denis Vlasenko13858992006-10-08 12:49:22 +0000284 if (option_mask32 & 0x1000) nicelvl = xatoi(n); // -n
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000285 // The below consts should match #defines at top!
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000286 //if (option_mask32 & 0x2000) OPT_verbose = 1; // -v
287 //if (option_mask32 & 0x4000) OPT_pgrp = 1; // -P
288 //if (option_mask32 & 0x8000) OPT_nostdin = 1; // -0
289 //if (option_mask32 & 0x10000) OPT_nostdout = 1; // -1
290 //if (option_mask32 & 0x20000) OPT_nostderr = 1; // -2
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000291 }
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000292 argv += optind;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000293 if (!argv || !*argv) bb_show_usage();
Denis Vlasenkof7996f32007-01-11 17:20:00 +0000294
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000295 if (OPT_pgrp) setsid();
296 if (env_dir) edir(env_dir);
297 if (root) {
298 xchdir(root);
299 if (chroot(".") == -1)
300 bb_perror_msg_and_die("chroot");
301 }
302 slimit();
303 if (nicelvl) {
304 errno = 0;
305 if (nice(nicelvl) == -1)
306 bb_perror_msg_and_die("nice");
307 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000308 if (env_user) euidgid(env_user);
309 if (set_user) suidgid(set_user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000310 if (OPT_nostdin) close(0);
311 if (OPT_nostdout) close(1);
312 if (OPT_nostderr) close(2);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000313 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000314 bb_perror_msg_and_die("exec %s", argv[0]);
315}
316
317static void setuidgid(int argc, char **argv)
318{
319 const char *account;
320
321 account = *++argv;
322 if (!account) bb_show_usage();
323 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000324 suidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000325 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000326 bb_perror_msg_and_die("exec %s", argv[0]);
327}
328
329static void envuidgid(int argc, char **argv)
330{
331 const char *account;
332
333 account = *++argv;
334 if (!account) bb_show_usage();
335 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000336 euidgid((char*)account);
Denis Vlasenko1d76f432007-02-06 01:20:12 +0000337 BB_EXECVP(argv[0], argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000338 bb_perror_msg_and_die("exec %s", argv[0]);
339}
340
341static void envdir(int argc, char **argv)
342{
343 const char *dir;
344
345 dir = *++argv;
346 if (!dir) bb_show_usage();
347 if (!*++argv) bb_show_usage();
348 edir(dir);
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 softlimit(int argc, char **argv)
354{
355 char *a,*c,*d,*f,*l,*m,*o,*p,*r,*s,*t;
Denis Vlasenkofe7cd642007-08-18 15:32:12 +0000356 getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000357 &a,&c,&d,&f,&l,&m,&o,&p,&r,&s,&t);
Denis Vlasenko13858992006-10-08 12:49:22 +0000358 if (option_mask32 & 0x001) limita = xatoul(a); // -a
359 if (option_mask32 & 0x002) limitc = xatoul(c); // -c
360 if (option_mask32 & 0x004) limitd = xatoul(d); // -d
361 if (option_mask32 & 0x008) limitf = xatoul(f); // -f
362 if (option_mask32 & 0x010) limitl = xatoul(l); // -l
363 if (option_mask32 & 0x020) limits = limitl = limita = limitd = xatoul(m); // -m
364 if (option_mask32 & 0x040) limito = xatoul(o); // -o
365 if (option_mask32 & 0x080) limitp = xatoul(p); // -p
366 if (option_mask32 & 0x100) limitr = xatoul(r); // -r
367 if (option_mask32 & 0x200) limits = xatoul(s); // -s
368 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000369 argv += optind;
370 if (!argv[0]) bb_show_usage();
371 slimit();
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}