blob: de6a33764685d0f8224232fb2e00c3a89461a81e [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> */
29
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000030#include "busybox.h"
31
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000032#include <dirent.h>
33
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000034// Must match constants in chpst_main!
Denis Vlasenkoc12f5302006-10-06 09:49:47 +000035#define OPT_verbose (option_mask32 & 0x2000)
36#define OPT_pgrp (option_mask32 & 0x4000)
37#define OPT_nostdin (option_mask32 & 0x8000)
38#define OPT_nostdout (option_mask32 & 0x10000)
39#define OPT_nostderr (option_mask32 & 0x20000)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000040
41static char *set_user;
42static char *env_user;
43static const char *env_dir;
44static long limitd = -2;
45static long limits = -2;
46static long limitl = -2;
47static long limita = -2;
48static long limito = -2;
49static long limitp = -2;
50static long limitf = -2;
51static long limitc = -2;
52static long limitr = -2;
53static long limitt = -2;
Denis Vlasenko13858992006-10-08 12:49:22 +000054static int nicelvl;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000055static const char *root;
56
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000057static void suidgid(char *user)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000058{
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000059 struct bb_uidgid_t ugid;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000060
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000061 if (!uidgid_get(&ugid, user)) {
62 bb_error_msg_and_die("unknown user/group: %s", user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000063 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000064 if (setgroups(1, &ugid.gid) == -1)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000065 bb_perror_msg_and_die("setgroups");
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000066 xsetgid(ugid.gid);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000067 xsetuid(ugid.uid);
68}
69
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000070static void euidgid(char *user)
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000071{
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000072 struct bb_uidgid_t ugid;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000073
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000074 if (!uidgid_get(&ugid, user)) {
75 bb_error_msg_and_die("unknown user/group: %s", user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000076 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +000077 xsetenv("GID", utoa(ugid.gid));
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +000078 xsetenv("UID", utoa(ugid.uid));
79}
80
81static void edir(const char *directory_name)
82{
83 int wdir;
84 DIR *dir;
85 struct dirent *d;
86 int fd;
87
88 wdir = xopen(".", O_RDONLY | O_NDELAY);
89 xchdir(directory_name);
90 dir = opendir(".");
91 if (!dir)
92 bb_perror_msg_and_die("opendir %s", directory_name);
93 for (;;) {
94 errno = 0;
95 d = readdir(dir);
96 if (!d) {
97 if (errno) bb_perror_msg_and_die("readdir %s", directory_name);
98 break;
99 }
100 if (d->d_name[0] == '.') continue;
101 fd = open(d->d_name, O_RDONLY | O_NDELAY);
102 if (fd < 0) {
103 if ((errno == EISDIR) && env_dir) {
104 if (OPT_verbose)
105 bb_perror_msg("warning: %s/%s is a directory", directory_name,
106 d->d_name);
107 continue;
108 } else
109 bb_perror_msg_and_die("open %s/%s", directory_name, /* was exiting 111 */
110 d->d_name);
111 }
112 if (fd >= 0) {
113 char buf[256];
114 char *tail;
115 int size;
116
117 size = safe_read(fd, buf, sizeof(buf)-1);
118 if (size < 0)
119 bb_perror_msg_and_die("read %s/%s", directory_name, /* was exiting 111 */
120 d->d_name);
121 if (size == 0) {
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000122 unsetenv(d->d_name);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000123 continue;
124 }
125 buf[size] = '\n';
126 tail = memchr(buf, '\n', sizeof(buf));
127 /* skip trailing whitespace */;
128 while (1) {
129 if (tail[0]==' ') tail[0] = '\0';
130 if (tail[0]=='\t') tail[0] = '\0';
131 if (tail[0]=='\n') tail[0] = '\0';
132 if (tail == buf) break;
133 tail--;
134 }
135 xsetenv(d->d_name, buf);
136 }
137 }
138 closedir(dir);
139 if (fchdir(wdir) == -1) bb_perror_msg_and_die("fchdir");
140 close(wdir);
141}
142
143static void limit(int what, long l)
144{
145 struct rlimit r;
146
147 if (getrlimit(what, &r) == -1) bb_perror_msg_and_die("getrlimit");
148 if ((l < 0) || (l > r.rlim_max))
149 r.rlim_cur = r.rlim_max;
150 else
151 r.rlim_cur = l;
152 if (setrlimit(what, &r) == -1) bb_perror_msg_and_die("setrlimit");
153}
154
155static void slimit(void)
156{
157 if (limitd >= -1) {
158#ifdef RLIMIT_DATA
159 limit(RLIMIT_DATA, limitd);
160#else
161 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_DATA");
162#endif
163 }
164 if (limits >= -1) {
165#ifdef RLIMIT_STACK
166 limit(RLIMIT_STACK, limits);
167#else
168 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_STACK");
169#endif
170 }
171 if (limitl >= -1) {
172#ifdef RLIMIT_MEMLOCK
173 limit(RLIMIT_MEMLOCK, limitl);
174#else
175 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_MEMLOCK");
176#endif
177 }
178 if (limita >= -1) {
179#ifdef RLIMIT_VMEM
180 limit(RLIMIT_VMEM, limita);
181#else
182#ifdef RLIMIT_AS
183 limit(RLIMIT_AS, limita);
184#else
185 if (OPT_verbose)
186 bb_error_msg("system does not support %s", "RLIMIT_VMEM");
187#endif
188#endif
189 }
190 if (limito >= -1) {
191#ifdef RLIMIT_NOFILE
192 limit(RLIMIT_NOFILE, limito);
193#else
194#ifdef RLIMIT_OFILE
195 limit(RLIMIT_OFILE, limito);
196#else
197 if (OPT_verbose)
198 bb_error_msg("system does not support %s", "RLIMIT_NOFILE");
199#endif
200#endif
201 }
202 if (limitp >= -1) {
203#ifdef RLIMIT_NPROC
204 limit(RLIMIT_NPROC, limitp);
205#else
206 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_NPROC");
207#endif
208 }
209 if (limitf >= -1) {
210#ifdef RLIMIT_FSIZE
211 limit(RLIMIT_FSIZE, limitf);
212#else
213 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_FSIZE");
214#endif
215 }
216 if (limitc >= -1) {
217#ifdef RLIMIT_CORE
218 limit(RLIMIT_CORE, limitc);
219#else
220 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_CORE");
221#endif
222 }
223 if (limitr >= -1) {
224#ifdef RLIMIT_RSS
225 limit(RLIMIT_RSS, limitr);
226#else
227 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_RSS");
228#endif
229 }
230 if (limitt >= -1) {
231#ifdef RLIMIT_CPU
232 limit(RLIMIT_CPU, limitt);
233#else
234 if (OPT_verbose) bb_error_msg("system does not support %s", "RLIMIT_CPU");
235#endif
236 }
237}
238
239/* argv[0] */
240static void setuidgid(int, char **);
241static void envuidgid(int, char **);
242static void envdir(int, char **);
243static void softlimit(int, char **);
244
245int chpst_main(int argc, char **argv)
246{
Denis Vlasenko8f8f2682006-10-03 21:00:43 +0000247 if (applet_name[3] == 'd') envdir(argc, argv);
248 if (applet_name[1] == 'o') softlimit(argc, argv);
249 if (applet_name[0] == 's') setuidgid(argc, argv);
250 if (applet_name[0] == 'e') envuidgid(argc, argv);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000251 // otherwise we are.......... chpst
252
253 {
254 char *m,*d,*o,*p,*f,*c,*r,*t,*n;
Denis Vlasenkocba9ef52006-10-10 21:00:47 +0000255 getopt32(argc, argv, "+u:U:e:m:d:o:p:f:c:r:t:/:n:vP012",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000256 &set_user,&env_user,&env_dir,
257 &m,&d,&o,&p,&f,&c,&r,&t,&root,&n);
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000258 // if (option_mask32 & 0x1) // -u
259 // if (option_mask32 & 0x2) // -U
260 // if (option_mask32 & 0x4) // -e
Denis Vlasenko13858992006-10-08 12:49:22 +0000261 if (option_mask32 & 0x8) limits = limitl = limita = limitd = xatoul(m); // -m
262 if (option_mask32 & 0x10) limitd = xatoul(d); // -d
263 if (option_mask32 & 0x20) limito = xatoul(o); // -o
264 if (option_mask32 & 0x40) limitp = xatoul(p); // -p
265 if (option_mask32 & 0x80) limitf = xatoul(f); // -f
266 if (option_mask32 & 0x100) limitc = xatoul(c); // -c
267 if (option_mask32 & 0x200) limitr = xatoul(r); // -r
268 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000269 // if (option_mask32 & 0x800) // -/
Denis Vlasenko13858992006-10-08 12:49:22 +0000270 if (option_mask32 & 0x1000) nicelvl = xatoi(n); // -n
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000271 // The below consts should match #defines at top!
Denis Vlasenkoc12f5302006-10-06 09:49:47 +0000272 //if (option_mask32 & 0x2000) OPT_verbose = 1; // -v
273 //if (option_mask32 & 0x4000) OPT_pgrp = 1; // -P
274 //if (option_mask32 & 0x8000) OPT_nostdin = 1; // -0
275 //if (option_mask32 & 0x10000) OPT_nostdout = 1; // -1
276 //if (option_mask32 & 0x20000) OPT_nostderr = 1; // -2
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000277 }
Denis Vlasenko4e6ceb42006-10-06 08:54:49 +0000278 argv += optind;
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000279 if (!argv || !*argv) bb_show_usage();
280
281 if (OPT_pgrp) setsid();
282 if (env_dir) edir(env_dir);
283 if (root) {
284 xchdir(root);
285 if (chroot(".") == -1)
286 bb_perror_msg_and_die("chroot");
287 }
288 slimit();
289 if (nicelvl) {
290 errno = 0;
291 if (nice(nicelvl) == -1)
292 bb_perror_msg_and_die("nice");
293 }
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000294 if (env_user) euidgid(env_user);
295 if (set_user) suidgid(set_user);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000296 if (OPT_nostdin) close(0);
297 if (OPT_nostdout) close(1);
298 if (OPT_nostderr) close(2);
299 execvp(argv[0], argv);
300 bb_perror_msg_and_die("exec %s", argv[0]);
301}
302
303static void setuidgid(int argc, char **argv)
304{
305 const char *account;
306
307 account = *++argv;
308 if (!account) bb_show_usage();
309 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000310 suidgid((char*)account);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000311 execvp(argv[0], argv);
312 bb_perror_msg_and_die("exec %s", argv[0]);
313}
314
315static void envuidgid(int argc, char **argv)
316{
317 const char *account;
318
319 account = *++argv;
320 if (!account) bb_show_usage();
321 if (!*++argv) bb_show_usage();
Denis Vlasenkode59c0f2006-10-05 22:50:22 +0000322 euidgid((char*)account);
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000323 execvp(argv[0], argv);
324 bb_perror_msg_and_die("exec %s", argv[0]);
325}
326
327static void envdir(int argc, char **argv)
328{
329 const char *dir;
330
331 dir = *++argv;
332 if (!dir) bb_show_usage();
333 if (!*++argv) bb_show_usage();
334 edir(dir);
335 execvp(argv[0], argv);
336 bb_perror_msg_and_die("exec %s", argv[0]);
337}
338
339static void softlimit(int argc, char **argv)
340{
341 char *a,*c,*d,*f,*l,*m,*o,*p,*r,*s,*t;
Denis Vlasenkocba9ef52006-10-10 21:00:47 +0000342 getopt32(argc, argv, "+a:c:d:f:l:m:o:p:r:s:t:",
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000343 &a,&c,&d,&f,&l,&m,&o,&p,&r,&s,&t);
Denis Vlasenko13858992006-10-08 12:49:22 +0000344 if (option_mask32 & 0x001) limita = xatoul(a); // -a
345 if (option_mask32 & 0x002) limitc = xatoul(c); // -c
346 if (option_mask32 & 0x004) limitd = xatoul(d); // -d
347 if (option_mask32 & 0x008) limitf = xatoul(f); // -f
348 if (option_mask32 & 0x010) limitl = xatoul(l); // -l
349 if (option_mask32 & 0x020) limits = limitl = limita = limitd = xatoul(m); // -m
350 if (option_mask32 & 0x040) limito = xatoul(o); // -o
351 if (option_mask32 & 0x080) limitp = xatoul(p); // -p
352 if (option_mask32 & 0x100) limitr = xatoul(r); // -r
353 if (option_mask32 & 0x200) limits = xatoul(s); // -s
354 if (option_mask32 & 0x400) limitt = xatoul(t); // -t
Denis Vlasenkof0a97fb2006-10-03 17:52:24 +0000355 argv += optind;
356 if (!argv[0]) bb_show_usage();
357 slimit();
358 execvp(argv[0], argv);
359 bb_perror_msg_and_die("exec %s", argv[0]);
360}