style fixes, no code changes
[oweals/busybox.git] / runit / chpst.c
1 /*
2 Copyright (c) 2001-2006, Gerrit Pape
3 All rights reserved.
4
5 Redistribution and use in source and binary forms, with or without
6 modification, 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
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /* Busyboxed by Denis Vlasenko <vda.linux@googlemail.com> */
29 /* Dependencies on runit_lib.c removed */
30
31 #include "busybox.h"
32
33 #include <dirent.h>
34
35 // Must match constants in chpst_main!
36 #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)
41
42 static char *set_user;
43 static char *env_user;
44 static const char *env_dir;
45 static long limitd = -2;
46 static long limits = -2;
47 static long limitl = -2;
48 static long limita = -2;
49 static long limito = -2;
50 static long limitp = -2;
51 static long limitf = -2;
52 static long limitc = -2;
53 static long limitr = -2;
54 static long limitt = -2;
55 static int nicelvl;
56 static const char *root;
57
58 static void suidgid(char *user)
59 {
60         struct bb_uidgid_t ugid;
61
62         if (!get_uidgid(&ugid, user, 1)) {
63                 bb_error_msg_and_die("unknown user/group: %s", user);
64         }
65         if (setgroups(1, &ugid.gid) == -1)
66                 bb_perror_msg_and_die("setgroups");
67         xsetgid(ugid.gid);
68         xsetuid(ugid.uid);
69 }
70
71 static void euidgid(char *user)
72 {
73         struct bb_uidgid_t ugid;
74
75         if (!get_uidgid(&ugid, user, 1)) {
76                 bb_error_msg_and_die("unknown user/group: %s", user);
77         }
78         xsetenv("GID", utoa(ugid.gid));
79         xsetenv("UID", utoa(ugid.uid));
80 }
81
82 static 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) {
98                         if (errno)
99                                 bb_perror_msg_and_die("readdir %s",
100                                                 directory_name);
101                         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)
108                                         bb_perror_msg("warning: %s/%s is a directory",
109                                                 directory_name, d->d_name);
110                                 continue;
111                         } else
112                                 bb_perror_msg_and_die("open %s/%s",
113                                                 directory_name, d->d_name);
114                 }
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)
122                                 bb_perror_msg_and_die("read %s/%s",
123                                                 directory_name, d->d_name);
124                         if (size == 0) {
125                                 unsetenv(d->d_name);
126                                 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
146 static 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
158 static void slimit(void)
159 {
160         if (limitd >= -1) {
161 #ifdef RLIMIT_DATA
162                 limit(RLIMIT_DATA, limitd);
163 #else
164                 if (OPT_verbose) bb_error_msg("system does not support %s",
165                                 "RLIMIT_DATA");
166 #endif
167         }
168         if (limits >= -1) {
169 #ifdef RLIMIT_STACK
170                 limit(RLIMIT_STACK, limits);
171 #else
172                 if (OPT_verbose) bb_error_msg("system does not support %s",
173                                 "RLIMIT_STACK");
174 #endif
175         }
176         if (limitl >= -1) {
177 #ifdef RLIMIT_MEMLOCK
178                 limit(RLIMIT_MEMLOCK, limitl);
179 #else
180                 if (OPT_verbose) bb_error_msg("system does not support %s",
181                                 "RLIMIT_MEMLOCK");
182 #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)
192                         bb_error_msg("system does not support %s",
193                                 "RLIMIT_VMEM");
194 #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)
205                         bb_error_msg("system does not support %s",
206                                 "RLIMIT_NOFILE");
207 #endif
208 #endif
209         }
210         if (limitp >= -1) {
211 #ifdef RLIMIT_NPROC
212                 limit(RLIMIT_NPROC, limitp);
213 #else
214                 if (OPT_verbose) bb_error_msg("system does not support %s",
215                                 "RLIMIT_NPROC");
216 #endif
217         }
218         if (limitf >= -1) {
219 #ifdef RLIMIT_FSIZE
220                 limit(RLIMIT_FSIZE, limitf);
221 #else
222                 if (OPT_verbose) bb_error_msg("system does not support %s",
223                                 "RLIMIT_FSIZE");
224 #endif
225         }
226         if (limitc >= -1) {
227 #ifdef RLIMIT_CORE
228                 limit(RLIMIT_CORE, limitc);
229 #else
230                 if (OPT_verbose) bb_error_msg("system does not support %s",
231                                 "RLIMIT_CORE");
232 #endif
233         }
234         if (limitr >= -1) {
235 #ifdef RLIMIT_RSS
236                 limit(RLIMIT_RSS, limitr);
237 #else
238                 if (OPT_verbose) bb_error_msg("system does not support %s",
239                                 "RLIMIT_RSS");
240 #endif
241         }
242         if (limitt >= -1) {
243 #ifdef RLIMIT_CPU
244                 limit(RLIMIT_CPU, limitt);
245 #else
246                 if (OPT_verbose) bb_error_msg("system does not support %s",
247                                 "RLIMIT_CPU");
248 #endif
249         }
250 }
251
252 /* argv[0] */
253 static void setuidgid(int, char **);
254 static void envuidgid(int, char **);
255 static void envdir(int, char **);
256 static void softlimit(int, char **);
257
258 int chpst_main(int argc, char **argv);
259 int chpst_main(int argc, char **argv)
260 {
261         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);
265         // otherwise we are chpst
266
267         {
268                 char *m,*d,*o,*p,*f,*c,*r,*t,*n;
269                 getopt32(argc, argv, "+u:U:e:m:d:o:p:f:c:r:t:/:n:vP012",
270                                 &set_user,&env_user,&env_dir,
271                                 &m,&d,&o,&p,&f,&c,&r,&t,&root,&n);
272                 // if (option_mask32 & 0x1) // -u
273                 // if (option_mask32 & 0x2) // -U
274                 // if (option_mask32 & 0x4) // -e
275                 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
283                 // if (option_mask32 & 0x800) // -/
284                 if (option_mask32 & 0x1000) nicelvl = xatoi(n); // -n
285                 // The below consts should match #defines at top!
286                 //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
291         }
292         argv += optind;
293         if (!argv || !*argv) bb_show_usage();
294
295         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         }
308         if (env_user) euidgid(env_user);
309         if (set_user) suidgid(set_user);
310         if (OPT_nostdin) close(0);
311         if (OPT_nostdout) close(1);
312         if (OPT_nostderr) close(2);
313         BB_EXECVP(argv[0], argv);
314         bb_perror_msg_and_die("exec %s", argv[0]);
315 }
316
317 static 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();
324         suidgid((char*)account);
325         BB_EXECVP(argv[0], argv);
326         bb_perror_msg_and_die("exec %s", argv[0]);
327 }
328
329 static 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();
336         euidgid((char*)account);
337         BB_EXECVP(argv[0], argv);
338         bb_perror_msg_and_die("exec %s", argv[0]);
339 }
340
341 static 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);
349         BB_EXECVP(argv[0], argv);
350         bb_perror_msg_and_die("exec %s", argv[0]);
351 }
352
353 static void softlimit(int argc, char **argv)
354 {
355         char *a,*c,*d,*f,*l,*m,*o,*p,*r,*s,*t;
356         getopt32(argc, argv, "+a:c:d:f:l:m:o:p:r:s:t:",
357                         &a,&c,&d,&f,&l,&m,&o,&p,&r,&s,&t);
358         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
369         argv += optind;
370         if (!argv[0]) bb_show_usage();
371         slimit();
372         BB_EXECVP(argv[0], argv);
373         bb_perror_msg_and_die("exec %s", argv[0]);
374 }