1 /* $OpenBSD: proc.c,v 1.7 2011/05/09 11:27:08 reyk Exp $ */ 2 3 /* 4 * Copyright (c) 2010,2011 Reyk Floeter <reyk@openbsd.org> 5 * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/queue.h> 22 #include <sys/tree.h> 23 #include <sys/param.h> 24 #include <sys/wait.h> 25 #include <sys/socket.h> 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <string.h> 31 #include <errno.h> 32 #include <signal.h> 33 #include <pwd.h> 34 #include <event.h> 35 36 #include <openssl/rand.h> 37 38 #include "iked.h" 39 40 void proc_setup(struct privsep *); 41 void proc_shutdown(struct privsep_proc *); 42 void proc_sig_handler(int, short, void *); 43 44 void 45 proc_init(struct privsep *ps, struct privsep_proc *p, u_int nproc) 46 { 47 u_int i; 48 49 /* 50 * Called from parent 51 */ 52 privsep_process = PROC_PARENT; 53 ps->ps_title[PROC_PARENT] = "parent"; 54 ps->ps_pid[PROC_PARENT] = getpid(); 55 56 proc_setup(ps); 57 58 /* Engage! */ 59 for (i = 0; i < nproc; i++, p++) { 60 ps->ps_title[p->p_id] = p->p_title; 61 ps->ps_pid[p->p_id] = (*p->p_init)(ps, p); 62 } 63 } 64 65 void 66 proc_kill(struct privsep *ps) 67 { 68 pid_t pid; 69 u_int i; 70 71 if (privsep_process != PROC_PARENT) 72 return; 73 74 for (i = 0; i < PROC_MAX; i++) { 75 if (ps->ps_pid[i] == 0) 76 continue; 77 kill(ps->ps_pid[i], SIGTERM); 78 } 79 80 do { 81 pid = waitpid(WAIT_ANY, NULL, 0); 82 } while (pid != -1 || (pid == -1 && errno == EINTR)); 83 } 84 85 void 86 proc_setup(struct privsep *ps) 87 { 88 int i, j, sockpair[2]; 89 90 for (i = 0; i < PROC_MAX; i++) 91 for (j = 0; j < PROC_MAX; j++) { 92 if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, 93 sockpair) == -1) 94 fatal("sockpair"); 95 ps->ps_pipes[i][j] = sockpair[0]; 96 ps->ps_pipes[j][i] = sockpair[1]; 97 socket_set_blockmode(ps->ps_pipes[i][j], 98 BM_NONBLOCK); 99 socket_set_blockmode(ps->ps_pipes[j][i], 100 BM_NONBLOCK); 101 } 102 } 103 104 void 105 proc_config(struct privsep *ps, struct privsep_proc *p, u_int nproc) 106 { 107 u_int src, dst, i, j, k, found; 108 109 src = privsep_process; 110 111 /* 112 * close unused pipes 113 */ 114 for (i = 0; i < PROC_MAX; i++) { 115 if (i != privsep_process) { 116 for (j = 0; j < PROC_MAX; j++) { 117 close(ps->ps_pipes[i][j]); 118 ps->ps_pipes[i][j] = -1; 119 } 120 } else { 121 for (j = found = 0; j < PROC_MAX; j++, found = 0) { 122 for (k = 0; k < nproc; k++) { 123 if (p[k].p_id == j) 124 found++; 125 } 126 if (!found) { 127 close(ps->ps_pipes[i][j]); 128 ps->ps_pipes[i][j] = -1; 129 } 130 } 131 } 132 } 133 134 /* 135 * listen on appropriate pipes 136 */ 137 for (i = 0; i < nproc; i++, p++) { 138 dst = p->p_id; 139 p->p_ps = ps; 140 p->p_env = ps->ps_env; 141 142 imsg_init(&ps->ps_ievs[dst].ibuf, 143 ps->ps_pipes[src][dst]); 144 ps->ps_ievs[dst].handler = proc_dispatch; 145 ps->ps_ievs[dst].events = EV_READ; 146 ps->ps_ievs[dst].data = p; 147 ps->ps_ievs[dst].name = p->p_title; 148 event_set(&ps->ps_ievs[dst].ev, 149 ps->ps_ievs[dst].ibuf.fd, 150 ps->ps_ievs[dst].events, 151 ps->ps_ievs[dst].handler, 152 ps->ps_ievs[dst].data); 153 event_add(&ps->ps_ievs[dst].ev, NULL); 154 } 155 } 156 157 void 158 proc_shutdown(struct privsep_proc *p) 159 { 160 struct privsep *ps = p->p_ps; 161 162 if (p->p_id == PROC_CONTROL && ps) 163 control_cleanup(&ps->ps_csock); 164 165 log_info("%s exiting", p->p_title); 166 _exit(0); 167 } 168 169 void 170 proc_sig_handler(int sig, short event, void *arg) 171 { 172 struct privsep_proc *p = arg; 173 174 switch (sig) { 175 case SIGINT: 176 case SIGTERM: 177 proc_shutdown(p); 178 break; 179 case SIGCHLD: 180 case SIGHUP: 181 case SIGPIPE: 182 /* ignore */ 183 break; 184 default: 185 fatalx("proc_sig_handler: unexpected signal"); 186 /* NOTREACHED */ 187 } 188 } 189 190 pid_t 191 proc_run(struct privsep *ps, struct privsep_proc *p, 192 struct privsep_proc *procs, u_int nproc, 193 void (*init)(struct privsep *, void *), void *arg) 194 { 195 pid_t pid; 196 struct passwd *pw; 197 const char *root; 198 u_int32_t seed[256]; 199 200 switch (pid = fork()) { 201 case -1: 202 fatal("proc_run: cannot fork"); 203 case 0: 204 break; 205 default: 206 return (pid); 207 } 208 209 pw = ps->ps_pw; 210 211 if (p->p_id == PROC_CONTROL) { 212 if (control_init(ps, &ps->ps_csock) == -1) 213 fatalx(p->p_title); 214 } 215 216 /* Change root directory */ 217 if (p->p_chroot != NULL) 218 root = p->p_chroot; 219 else 220 root = pw->pw_dir; 221 222 #ifndef DEBUG 223 if (chroot(root) == -1) 224 fatal("proc_run: chroot"); 225 if (chdir("/") == -1) 226 fatal("proc_run: chdir(\"/\")"); 227 #else 228 #warning disabling privilege revocation and chroot in DEBUG MODE 229 if (p->p_chroot != NULL) { 230 if (chroot(root) == -1) 231 fatal("proc_run: chroot"); 232 if (chdir("/") == -1) 233 fatal("proc_run: chdir(\"/\")"); 234 } 235 #endif 236 237 privsep_process = p->p_id; 238 239 setproctitle("%s", p->p_title); 240 241 #ifndef DEBUG 242 if (setgroups(1, &pw->pw_gid) || 243 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) || 244 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid)) 245 fatal("proc_run: cannot drop privileges"); 246 #endif 247 248 event_init(); 249 250 signal_set(&ps->ps_evsigint, SIGINT, proc_sig_handler, p); 251 signal_set(&ps->ps_evsigterm, SIGTERM, proc_sig_handler, p); 252 signal_set(&ps->ps_evsigchld, SIGCHLD, proc_sig_handler, p); 253 signal_set(&ps->ps_evsighup, SIGHUP, proc_sig_handler, p); 254 signal_set(&ps->ps_evsigpipe, SIGPIPE, proc_sig_handler, p); 255 256 signal_add(&ps->ps_evsigint, NULL); 257 signal_add(&ps->ps_evsigterm, NULL); 258 signal_add(&ps->ps_evsigchld, NULL); 259 signal_add(&ps->ps_evsighup, NULL); 260 signal_add(&ps->ps_evsigpipe, NULL); 261 262 proc_config(ps, procs, nproc); 263 264 arc4random_buf(seed, sizeof(seed)); 265 RAND_seed(seed, sizeof(seed)); 266 267 if (p->p_id == PROC_CONTROL) { 268 TAILQ_INIT(&ctl_conns); 269 if (control_listen(&ps->ps_csock) == -1) 270 fatalx(p->p_title); 271 } 272 273 if (init != NULL) 274 init(ps, arg); 275 276 event_dispatch(); 277 278 proc_shutdown(p); 279 280 return (0); 281 } 282 283 void 284 proc_dispatch(int fd, short event, void *arg) 285 { 286 struct privsep_proc *p = (struct privsep_proc *)arg; 287 struct privsep *ps = p->p_ps; 288 struct imsgev *iev; 289 struct imsgbuf *ibuf; 290 struct imsg imsg; 291 ssize_t n; 292 int verbose; 293 const char *title; 294 295 title = ps->ps_title[privsep_process]; 296 iev = &ps->ps_ievs[p->p_id]; 297 ibuf = &iev->ibuf; 298 299 if (event & EV_READ) { 300 if ((n = imsg_read(ibuf)) == -1) 301 fatal(title); 302 if (n == 0) { 303 /* this pipe is dead, so remove the event handler */ 304 event_del(&iev->ev); 305 event_loopexit(NULL); 306 return; 307 } 308 } 309 310 if (event & EV_WRITE) { 311 if (msgbuf_write(&ibuf->w) == -1) 312 fatal(title); 313 } 314 315 for (;;) { 316 if ((n = imsg_get(ibuf, &imsg)) == -1) 317 fatal(title); 318 if (n == 0) 319 break; 320 321 /* 322 * Check the message with the program callback 323 */ 324 if ((p->p_cb)(fd, p, &imsg) == 0) { 325 /* Message was handled by the callback, continue */ 326 imsg_free(&imsg); 327 continue; 328 } 329 330 /* 331 * Generic message handling 332 */ 333 switch (imsg.hdr.type) { 334 case IMSG_CTL_VERBOSE: 335 IMSG_SIZE_CHECK(&imsg, &verbose); 336 337 memcpy(&verbose, imsg.data, sizeof(verbose)); 338 log_verbose(verbose); 339 break; 340 default: 341 log_warnx("%s: %s got imsg %d", __func__, p->p_title, 342 imsg.hdr.type); 343 fatalx(title); 344 } 345 imsg_free(&imsg); 346 } 347 imsg_event_add(iev); 348 } 349 350 void 351 imsg_event_add(struct imsgev *iev) 352 { 353 if (iev->handler == NULL) { 354 imsg_flush(&iev->ibuf); 355 return; 356 } 357 358 iev->events = EV_READ; 359 if (iev->ibuf.w.queued) 360 iev->events |= EV_WRITE; 361 362 event_del(&iev->ev); 363 event_set(&iev->ev, iev->ibuf.fd, iev->events, iev->handler, iev->data); 364 event_add(&iev->ev, NULL); 365 } 366 367 int 368 imsg_compose_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 369 pid_t pid, int fd, void *data, u_int16_t datalen) 370 { 371 int ret; 372 373 if ((ret = imsg_compose(&iev->ibuf, type, peerid, 374 pid, fd, data, datalen)) == -1) 375 return (ret); 376 imsg_event_add(iev); 377 return (ret); 378 } 379 380 int 381 imsg_composev_event(struct imsgev *iev, u_int16_t type, u_int32_t peerid, 382 pid_t pid, int fd, const struct iovec *iov, int iovcnt) 383 { 384 int ret; 385 386 if ((ret = imsg_composev(&iev->ibuf, type, peerid, 387 pid, fd, iov, iovcnt)) == -1) 388 return (ret); 389 imsg_event_add(iev); 390 return (ret); 391 } 392 393 int 394 proc_compose_imsg(struct iked *env, enum privsep_procid id, 395 u_int16_t type, int fd, void *data, u_int16_t datalen) 396 { 397 return (imsg_compose_event(&env->sc_ps.ps_ievs[id], 398 type, -1, 0, fd, data, datalen)); 399 } 400 401 int 402 proc_composev_imsg(struct iked *env, enum privsep_procid id, 403 u_int16_t type, int fd, const struct iovec *iov, int iovcnt) 404 { 405 return (imsg_composev_event(&env->sc_ps.ps_ievs[id], 406 type, -1, 0, fd, iov, iovcnt)); 407 } 408 409 int 410 proc_forward_imsg(struct iked *env, struct imsg *imsg, 411 enum privsep_procid id) 412 { 413 return (proc_compose_imsg(env, id, imsg->hdr.type, 414 imsg->fd, imsg->data, IMSG_DATA_SIZE(imsg))); 415 } 416 417 void 418 proc_flush_imsg(struct iked *env, enum privsep_procid id) 419 { 420 imsg_flush(&env->sc_ps.ps_ievs[id].ibuf); 421 } 422