fiss

Friedel's Initialization and Service Supervision
Log | Files | Refs | LICENSE

chpst.c (7089B)


      1 
      2 #include "parse.h"
      3 
      4 #include <arg.h>
      5 #include <common.h>
      6 #include <fcntl.h>
      7 #include <fmt.h>
      8 #include <grp.h>
      9 #include <stdbool.h>
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <sys/file.h>
     13 #include <sys/resource.h>
     14 #include <unistd.h>
     15 
     16 void usage(void) {
     17 	print("Usage:\n"
     18 	      "  chpst [-vP012] [-u user[:group]] [-U user[:group]] [-b argv0] [-e dir]\n"
     19 	      "      [-/ root] [-C pwd] [-n nice] [-l|-L lock] [-m n] [-d n] [-o n] [-p n] [-f n]\n"
     20 	      "      [-c n] command ...\n"
     21 	      "  softlimit [-m n] [-a n] [-d n] [-o n] [-p n] [-f n] [-c n] [-r n] [-t n]\n"
     22 	      "      [-l n] [-s n]  command ...\n"
     23 	      "  setuidgid user[:group] command ...\n"
     24 	      "  envuidgid user[:group] command ...\n"
     25 	      "  pgrphack command ...\n"
     26 	      "  setlock [-nNxX] lock command ...\n");
     27 }
     28 
     29 void limit(int what, long l) {
     30 	struct rlimit r;
     31 
     32 	if (getrlimit(what, &r) == -1)
     33 		fprint(1, "error: unable to getrlimit: %r\n");
     34 
     35 	if (l < 0) {
     36 		r.rlim_cur = 0;
     37 	} else if ((unsigned long) l > r.rlim_max)
     38 		r.rlim_cur = r.rlim_max;
     39 	else
     40 		r.rlim_cur = l;
     41 
     42 	if (setrlimit(what, &r) == -1)
     43 		fprint(1, "error: unable to setrlimit: %r\n");
     44 }
     45 
     46 
     47 int main(int argc, char** argv) {
     48 	int   lockfd, lockflags = 0, gid_len = 0;
     49 	char *arg0 = NULL, *root = NULL, *cd = NULL, *lock = NULL;
     50 	uid_t uid = 0;
     51 	gid_t gid[61];
     52 
     53 	argv0 = argv[0];
     54 
     55 	long limitd      = -2,
     56 	     limits      = -2,
     57 	     limitl      = -2,
     58 	     limita      = -2,
     59 	     limito      = -2,
     60 	     limitp      = -2,
     61 	     limitf      = -2,
     62 	     limitc      = -2,
     63 	     limitr      = -2,
     64 	     limitt      = -2;
     65 	long nicelevel   = 0;
     66 	bool ssid        = false;
     67 	bool closestd[3] = { false, false, false };
     68 
     69 	if (streq(argv0, "setuidgid") || streq(argv0, "envuidgid")) {
     70 		if (argc < 2) {
     71 			fprint(1, "%s <uid-gid> command...", argv0);
     72 			return 1;
     73 		}
     74 		gid_len = parse_ugid(argv[1], &uid, gid);
     75 		SHIFT(2);
     76 	} else if (streq(argv0, "pgrphack")) {
     77 		ssid = true;
     78 		SHIFT(1);
     79 	} else if (streq(argv0, "setlock")) {
     80 		ARGBEGIN {
     81 			case 'n':
     82 				lockflags = LOCK_EX | LOCK_NB;
     83 				break;
     84 			case 'N':
     85 				lockflags = LOCK_EX;
     86 				break;
     87 			case 'x':
     88 			case 'X':
     89 				fprint(1, "warning: '-%c' is ignored\n", ARGC());
     90 				break;
     91 			default:
     92 				usage();
     93 				return 1;
     94 		}
     95 		ARGEND;
     96 
     97 		if (argc < 1) {
     98 			fprint(1, "%s [-xXnN] command...", argv0);
     99 			return 1;
    100 		}
    101 		lock = argv[1];
    102 		SHIFT(1);
    103 	} else if (streq(argv0, "softlimit")) {
    104 		ARGBEGIN {
    105 			case 'm':
    106 				limits = limitl = limita = limitd = atol(EARGF(usage()));
    107 				break;
    108 			case 'a':
    109 				limita = atol(EARGF(usage()));
    110 				break;
    111 			case 'd':
    112 				limitd = atol(EARGF(usage()));
    113 				break;
    114 			case 'o':
    115 				limito = atol(EARGF(usage()));
    116 				break;
    117 			case 'p':
    118 				limitp = atol(EARGF(usage()));
    119 				break;
    120 			case 'f':
    121 				limitf = atol(EARGF(usage()));
    122 				break;
    123 			case 'c':
    124 				limitc = atol(EARGF(usage()));
    125 				break;
    126 			case 'r':
    127 				limitr = atol(EARGF(usage()));
    128 				break;
    129 			case 't':
    130 				limitt = atol(EARGF(usage()));
    131 				break;
    132 			case 'l':
    133 				limitl = atol(EARGF(usage()));
    134 				break;
    135 			case 's':
    136 				limits = atol(EARGF(usage()));
    137 				break;
    138 			default:
    139 				usage();
    140 				return 1;
    141 		}
    142 		ARGEND;
    143 	} else {
    144 		ARGBEGIN {
    145 			case 'u':
    146 			case 'U':
    147 				gid_len = parse_ugid(EARGF(usage()), &uid, gid);
    148 				break;
    149 			case 'b':
    150 				arg0 = EARGF(usage());
    151 				break;
    152 			case '/':
    153 				root = EARGF(usage());
    154 				break;
    155 			case 'C':
    156 				cd = EARGF(usage());
    157 				break;
    158 			case 'n':
    159 				nicelevel = atol(EARGF(usage()));
    160 				break;
    161 			case 'l':
    162 				lock      = EARGF(usage());
    163 				lockflags = LOCK_EX | LOCK_NB;
    164 				break;
    165 			case 'L':
    166 				lock      = EARGF(usage());
    167 				lockflags = LOCK_EX;
    168 				break;
    169 			case 'v':    // ignored
    170 				break;
    171 			case 'P':
    172 				ssid = true;
    173 				break;
    174 			case '0':
    175 			case '1':
    176 			case '2':
    177 				closestd[ARGC() - '0'] = true;
    178 				break;
    179 			case 'm':
    180 				limits = limitl = limita = limitd = atol(EARGF(usage()));
    181 				break;
    182 			case 'd':
    183 				limitd = atol(EARGF(usage()));
    184 				break;
    185 			case 'o':
    186 				limito = atol(EARGF(usage()));
    187 				break;
    188 			case 'p':
    189 				limitp = atol(EARGF(usage()));
    190 				break;
    191 			case 'f':
    192 				limitf = atol(EARGF(usage()));
    193 				break;
    194 			case 'c':
    195 				limitc = atol(EARGF(usage()));
    196 				break;
    197 			case 'r':
    198 				limitr = atol(EARGF(usage()));
    199 				break;
    200 			case 't':
    201 				limitt = atol(EARGF(usage()));
    202 				break;
    203 			case 'e':
    204 				fprint(1, "warning: '-%c' is ignored\n", ARGC());
    205 				break;
    206 			default:
    207 				usage();
    208 				return 1;
    209 		}
    210 		ARGEND;
    211 	}
    212 
    213 	if (argc == 0) {
    214 		fprint(1, "%s: command required\n", argv0);
    215 		return 1;
    216 	}
    217 
    218 	if (ssid) {
    219 		setsid();
    220 	}
    221 
    222 	if (uid) {
    223 		setgroups(gid_len, gid);
    224 		setgid(gid[0]);
    225 		setuid(uid);
    226 		// $EUID
    227 	}
    228 
    229 	if (root) {
    230 		if (chroot(root) == -1)
    231 			fprint(1, "unable to change root directory: %r\n");
    232 
    233 		// chdir to '/', otherwise the next command will complain 'directory not found'
    234 		chdir("/");
    235 	}
    236 
    237 	if (cd) {
    238 		chdir(cd);
    239 	}
    240 
    241 	if (nicelevel != 0) {
    242 		if (nice(nicelevel) == -1)
    243 			fprint(1, "unable to set nice level: %r\n");
    244 	}
    245 
    246 	if (limitd >= -1) {
    247 #ifdef RLIMIT_DATA
    248 		limit(RLIMIT_DATA, limitd);
    249 #else
    250 		if (verbose)
    251 			fprint(1, "system does not support RLIMIT_DATA\n");
    252 #endif
    253 	}
    254 	if (limits >= -1) {
    255 #ifdef RLIMIT_STACK
    256 		limit(RLIMIT_STACK, limits);
    257 #else
    258 		if (verbose)
    259 			fprint(1, "system does not support RLIMIT_STACK\n");
    260 #endif
    261 	}
    262 	if (limitl >= -1) {
    263 #ifdef RLIMIT_MEMLOCK
    264 		limit(RLIMIT_MEMLOCK, limitl);
    265 #else
    266 		if (verbose)
    267 			fprint(1, "system does not support RLIMIT_MEMLOCK\n");
    268 #endif
    269 	}
    270 	if (limita >= -1) {
    271 #ifdef RLIMIT_VMEM
    272 		limit(RLIMIT_VMEM, limita);
    273 #else
    274 #	ifdef RLIMIT_AS
    275 		limit(RLIMIT_AS, limita);
    276 #	else
    277 		if (verbose)
    278 			fprint(1, "system does neither support RLIMIT_VMEM nor RLIMIT_AS\n");
    279 #	endif
    280 #endif
    281 	}
    282 	if (limito >= -1) {
    283 #ifdef RLIMIT_NOFILE
    284 		limit(RLIMIT_NOFILE, limito);
    285 #else
    286 #	ifdef RLIMIT_OFILE
    287 		limit(RLIMIT_OFILE, limito);
    288 #	else
    289 		if (verbose)
    290 			fprint(1, "system does neither support RLIMIT_NOFILE nor RLIMIT_OFILE\n");
    291 #	endif
    292 #endif
    293 	}
    294 	if (limitp >= -1) {
    295 #ifdef RLIMIT_NPROC
    296 		limit(RLIMIT_NPROC, limitp);
    297 #else
    298 		if (verbose)
    299 			fprint(1, "system does not support RLIMIT_NPROC\n");
    300 #endif
    301 	}
    302 	if (limitf >= -1) {
    303 #ifdef RLIMIT_FSIZE
    304 		limit(RLIMIT_FSIZE, limitf);
    305 #else
    306 		if (verbose)
    307 			fprint(1, "system does not support RLIMIT_FSIZE\n");
    308 #endif
    309 	}
    310 	if (limitc >= -1) {
    311 #ifdef RLIMIT_CORE
    312 		limit(RLIMIT_CORE, limitc);
    313 #else
    314 		if (verbose)
    315 			fprint(1, "system does not support RLIMIT_CORE\n");
    316 #endif
    317 	}
    318 	if (limitr >= -1) {
    319 #ifdef RLIMIT_RSS
    320 		limit(RLIMIT_RSS, limitr);
    321 #else
    322 		if (verbose)
    323 			fprint(1, "system does not support RLIMIT_RSS\n");
    324 #endif
    325 	}
    326 	if (limitt >= -1) {
    327 #ifdef RLIMIT_CPU
    328 		limit(RLIMIT_CPU, limitt);
    329 #else
    330 		if (verbose)
    331 			fprint(1, "system does not support RLIMIT_CPU\n");
    332 #endif
    333 	}
    334 
    335 	if (lock) {
    336 		if ((lockfd = open(lock, O_WRONLY | O_APPEND)) == -1)
    337 			fprint(1, "unable to open lock: %r\n");
    338 
    339 		if (flock(lockfd, lockflags) == -1)
    340 			fprint(1, "unable to lock: %r\n");
    341 	}
    342 
    343 	for (int i = 0; i < 3; i++)
    344 		if (closestd[i] && close(i) == -1)
    345 			fprint(1, "unable to close std-%d: %r\n", i);
    346 
    347 	execvp(arg0 ? arg0 : *argv, argv);
    348 	fprint(1, "cannot execute: %r\n");
    349 }