1/* 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/* Dependencies on runit_lib.c removed */ 30 31#include "libbb.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 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; 55static int nicelvl; 56static const char *root; 57 58static 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 71static 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 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) { 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 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 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] */ 253static void setuidgid(int, char **); 254static void envuidgid(int, char **); 255static void envdir(int, char **); 256static void softlimit(int, char **); 257 258int chpst_main(int argc, char **argv); 259int 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(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 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(); 324 suidgid((char*)account); 325 BB_EXECVP(argv[0], argv); 326 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(); 336 euidgid((char*)account); 337 BB_EXECVP(argv[0], argv); 338 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); 349 BB_EXECVP(argv[0], argv); 350 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; 356 getopt32(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} 375