1 /* $OpenBSD: monitor.c,v 1.20 2009/06/04 01:12:39 sthen Exp $ */ 2 3 /* 4 * Copyright (c) 2004 Moritz Jodeit <moritz@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/socket.h> 21 #include <sys/wait.h> 22 #include <netinet/in.h> 23 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <limits.h> 27 #include <paths.h> 28 #include <pwd.h> 29 #include <signal.h> 30 #include <stdarg.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <syslog.h> 35 #include <unistd.h> 36 37 #include "monitor.h" 38 #include "extern.h" 39 40 enum monitor_command { 41 CMD_USER, 42 CMD_PASS, 43 CMD_SOCKET, 44 CMD_BIND 45 }; 46 47 enum monitor_state { 48 PREAUTH, 49 POSTAUTH 50 }; 51 52 #ifdef HASSETPROCTITLE 53 extern char remotehost[]; 54 #endif 55 extern char ttyline[20]; 56 extern int debug; 57 58 extern void set_slave_signals(void); 59 60 int fd_monitor = -1; 61 int fd_slave = -1; 62 int nullfd; 63 pid_t slave_pid = -1; 64 enum monitor_state state = PREAUTH; 65 66 void send_data(int, void *, size_t); 67 void recv_data(int, void *, size_t); 68 void handle_cmds(void); 69 void set_monitor_signals(void); 70 void sig_pass_to_slave(int); 71 void sig_chld(int); 72 void fatalx(char *, ...); 73 void debugmsg(char *, ...); 74 75 /* 76 * Send data over a socket and exit if something fails. 77 */ 78 void 79 send_data(int sock, void *buf, size_t len) 80 { 81 ssize_t n; 82 size_t pos = 0; 83 char *ptr = buf; 84 85 while (len > pos) { 86 switch (n = write(sock, ptr + pos, len - pos)) { 87 case 0: 88 kill_slave("write failure"); 89 _exit(0); 90 /* NOTREACHED */ 91 case -1: 92 if (errno != EINTR && errno != EAGAIN) 93 fatalx("send_data: %m"); 94 break; 95 default: 96 pos += n; 97 } 98 } 99 } 100 101 /* 102 * Receive data from socket and exit if something fails. 103 */ 104 void 105 recv_data(int sock, void *buf, size_t len) 106 { 107 ssize_t n; 108 size_t pos = 0; 109 char *ptr = buf; 110 111 while (len > pos) { 112 switch (n = read(sock, ptr + pos, len - pos)) { 113 case 0: 114 kill_slave(NULL); 115 _exit(0); 116 /* NOTREACHED */ 117 case -1: 118 if (errno != EINTR && errno != EAGAIN) 119 fatalx("recv_data: %m"); 120 break; 121 default: 122 pos += n; 123 } 124 } 125 } 126 127 void 128 set_monitor_signals(void) 129 { 130 struct sigaction act; 131 int i; 132 133 sigfillset(&act.sa_mask); 134 act.sa_flags = SA_RESTART; 135 136 act.sa_handler = SIG_DFL; 137 for (i = 1; i < _NSIG; i++) 138 sigaction(i, &act, NULL); 139 140 act.sa_handler = sig_chld; 141 sigaction(SIGCHLD, &act, NULL); 142 143 act.sa_handler = sig_pass_to_slave; 144 sigaction(SIGHUP, &act, NULL); 145 sigaction(SIGINT, &act, NULL); 146 sigaction(SIGQUIT, &act, NULL); 147 sigaction(SIGTERM, &act, NULL); 148 } 149 150 /* 151 * Creates the privileged monitor process. It returns twice. 152 * It returns 1 for the unprivileged slave process and 0 for the 153 * user-privileged slave process after successful authentication. 154 */ 155 int 156 monitor_init(void) 157 { 158 struct passwd *pw; 159 int pair[2]; 160 161 if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, pair) == -1) 162 fatalx("socketpair failed"); 163 164 fd_monitor = pair[0]; 165 fd_slave = pair[1]; 166 167 set_monitor_signals(); 168 169 slave_pid = fork(); 170 if (slave_pid == -1) 171 fatalx("fork of unprivileged slave failed"); 172 if (slave_pid == 0) { 173 /* Unprivileged slave */ 174 set_slave_signals(); 175 176 if ((pw = getpwnam(FTPD_PRIVSEP_USER)) == NULL) 177 fatalx("privilege separation user %s not found", 178 FTPD_PRIVSEP_USER); 179 180 if (chroot(pw->pw_dir) == -1) 181 fatalx("chroot %s: %m", pw->pw_dir); 182 if (chdir("/") == -1) 183 fatalx("chdir /: %m"); 184 185 if (setgroups(1, &pw->pw_gid) == -1) 186 fatalx("setgroups: %m"); 187 if (setegid(pw->pw_gid) == -1) 188 fatalx("setegid failed"); 189 if (setgid(pw->pw_gid) == -1) 190 fatalx("setgid failed"); 191 if (seteuid(pw->pw_uid) == -1) 192 fatalx("seteuid failed"); 193 if (setuid(pw->pw_uid) == -1) 194 fatalx("setuid failed"); 195 196 endpwent(); 197 close(fd_slave); 198 return (1); 199 } 200 201 #ifdef HASSETPROCTITLE 202 setproctitle("%s: [priv pre-auth]", remotehost); 203 #endif 204 205 handle_cmds(); 206 207 /* User-privileged slave */ 208 return (0); 209 } 210 211 /* 212 * Creates the user-privileged slave process. It is called 213 * from the privileged monitor process and returns twice. It returns 0 214 * for the user-privileged slave process and 1 for the monitor process. 215 */ 216 int 217 monitor_post_auth() 218 { 219 slave_pid = fork(); 220 if (slave_pid == -1) 221 fatalx("fork of user-privileged slave failed"); 222 223 snprintf(ttyline, sizeof(ttyline), "ftp%ld", 224 slave_pid == 0 ? (long)getpid() : (long)slave_pid); 225 226 if (slave_pid == 0) { 227 /* User privileged slave */ 228 close(fd_slave); 229 set_slave_signals(); 230 return (0); 231 } 232 233 /* We have to keep stdout open, because reply() needs it. */ 234 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) 235 fatalx("cannot open %s: %m", _PATH_DEVNULL); 236 dup2(nullfd, STDIN_FILENO); 237 dup2(nullfd, STDERR_FILENO); 238 close(nullfd); 239 close(fd_monitor); 240 241 return (1); 242 } 243 244 /* 245 * Handles commands received from the slave process. It will not return 246 * except in one situation: After successful authentication it will 247 * return as the user-privileged slave process. 248 */ 249 void 250 handle_cmds(void) 251 { 252 enum monitor_command cmd; 253 enum auth_ret auth; 254 int err, s, slavequit, serrno, domain; 255 pid_t preauth_slave_pid; 256 size_t len; 257 union sockunion sa; 258 socklen_t salen; 259 char *name, *pw; 260 261 for (;;) { 262 recv_data(fd_slave, &cmd, sizeof(cmd)); 263 264 switch (cmd) { 265 case CMD_USER: 266 debugmsg("CMD_USER received"); 267 268 recv_data(fd_slave, &len, sizeof(len)); 269 if (len == SIZE_T_MAX) 270 fatalx("monitor received invalid user length"); 271 if ((name = malloc(len + 1)) == NULL) 272 fatalx("malloc: %m"); 273 if (len > 0) 274 recv_data(fd_slave, name, len); 275 name[len] = '\0'; 276 277 user(name); 278 free(name); 279 break; 280 case CMD_PASS: 281 debugmsg("CMD_PASS received"); 282 283 recv_data(fd_slave, &len, sizeof(len)); 284 if (len == SIZE_T_MAX) 285 fatalx("monitor received invalid pass length"); 286 if ((pw = malloc(len + 1)) == NULL) 287 fatalx("malloc: %m"); 288 if (len > 0) 289 recv_data(fd_slave, pw, len); 290 pw[len] = '\0'; 291 292 preauth_slave_pid = slave_pid; 293 294 auth = pass(pw); 295 bzero(pw, len); 296 free(pw); 297 298 switch (auth) { 299 case AUTH_FAILED: 300 /* Authentication failure */ 301 debugmsg("authentication failed"); 302 slavequit = 0; 303 send_data(fd_slave, &slavequit, 304 sizeof(slavequit)); 305 break; 306 case AUTH_SLAVE: 307 /* User-privileged slave */ 308 debugmsg("user-privileged slave started"); 309 return; 310 /* NOTREACHED */ 311 case AUTH_MONITOR: 312 /* Post-auth monitor */ 313 debugmsg("monitor went into post-auth phase"); 314 state = POSTAUTH; 315 #ifdef HASSETPROCTITLE 316 setproctitle("%s: [priv post-auth]", 317 remotehost); 318 #endif 319 slavequit = 1; 320 321 send_data(fd_slave, &slavequit, 322 sizeof(slavequit)); 323 324 while (waitpid(preauth_slave_pid, NULL, 0) < 0 && 325 errno == EINTR) 326 ; 327 break; 328 default: 329 fatalx("bad return value from pass()"); 330 /* NOTREACHED */ 331 } 332 break; 333 case CMD_SOCKET: 334 debugmsg("CMD_SOCKET received"); 335 336 if (state != POSTAUTH) 337 fatalx("CMD_SOCKET received in invalid state"); 338 339 recv_data(fd_slave, &domain, sizeof(domain)); 340 if (domain != AF_INET && domain != AF_INET6) 341 fatalx("monitor received invalid addr family"); 342 343 s = socket(domain, SOCK_STREAM, 0); 344 serrno = errno; 345 346 send_fd(fd_slave, s); 347 if (s == -1) 348 send_data(fd_slave, &serrno, sizeof(serrno)); 349 else 350 close(s); 351 break; 352 case CMD_BIND: 353 debugmsg("CMD_BIND received"); 354 355 if (state != POSTAUTH) 356 fatalx("CMD_BIND received in invalid state"); 357 358 s = recv_fd(fd_slave); 359 360 recv_data(fd_slave, &salen, sizeof(salen)); 361 if (salen == 0 || salen > sizeof(sa)) 362 fatalx("monitor received invalid sockaddr len"); 363 364 bzero(&sa, sizeof(sa)); 365 recv_data(fd_slave, &sa, salen); 366 367 if (sa.su_si.si_len != salen) 368 fatalx("monitor received invalid sockaddr len"); 369 370 if (sa.su_si.si_family != AF_INET && 371 sa.su_si.si_family != AF_INET6) 372 fatalx("monitor received invalid addr family"); 373 374 err = bind(s, (struct sockaddr *)&sa, salen); 375 serrno = errno; 376 377 if (s >= 0) 378 close(s); 379 380 send_data(fd_slave, &err, sizeof(err)); 381 if (err == -1) 382 send_data(fd_slave, &serrno, sizeof(serrno)); 383 break; 384 default: 385 fatalx("monitor received unknown command %d", cmd); 386 /* NOTREACHED */ 387 } 388 } 389 } 390 391 void 392 sig_pass_to_slave(int signo) 393 { 394 int olderrno = errno; 395 396 if (slave_pid > 0) 397 kill(slave_pid, signo); 398 399 errno = olderrno; 400 } 401 402 /* ARGSUSED */ 403 void 404 sig_chld(int signo) 405 { 406 pid_t pid; 407 int stat, olderrno = errno; 408 409 do { 410 pid = waitpid(slave_pid, &stat, WNOHANG); 411 if (pid > 0) 412 _exit(0); 413 } while (pid == -1 && errno == EINTR); 414 415 errno = olderrno; 416 } 417 418 void 419 kill_slave(char *reason) 420 { 421 if (slave_pid > 0) { 422 if (reason) 423 syslog(LOG_NOTICE, "kill slave %d: %s", 424 slave_pid, reason); 425 kill(slave_pid, SIGQUIT); 426 } 427 } 428 429 void 430 fatalx(char *fmt, ...) 431 { 432 va_list ap; 433 434 va_start(ap, fmt); 435 vsyslog(LOG_ERR, fmt, ap); 436 va_end(ap); 437 438 kill_slave("fatal error"); 439 440 _exit(0); 441 } 442 443 void 444 debugmsg(char *fmt, ...) 445 { 446 va_list ap; 447 448 if (debug) { 449 va_start(ap, fmt); 450 vsyslog(LOG_DEBUG, fmt, ap); 451 va_end(ap); 452 } 453 } 454 455 void 456 monitor_user(char *name) 457 { 458 enum monitor_command cmd; 459 size_t len; 460 461 cmd = CMD_USER; 462 send_data(fd_monitor, &cmd, sizeof(cmd)); 463 464 len = strlen(name); 465 send_data(fd_monitor, &len, sizeof(len)); 466 if (len > 0) 467 send_data(fd_monitor, name, len); 468 } 469 470 int 471 monitor_pass(char *pass) 472 { 473 enum monitor_command cmd; 474 int quitnow; 475 size_t len; 476 477 cmd = CMD_PASS; 478 send_data(fd_monitor, &cmd, sizeof(cmd)); 479 480 len = strlen(pass); 481 send_data(fd_monitor, &len, sizeof(len)); 482 if (len > 0) 483 send_data(fd_monitor, pass, len); 484 485 recv_data(fd_monitor, &quitnow, sizeof(quitnow)); 486 487 return (quitnow); 488 } 489 490 int 491 monitor_socket(int domain) 492 { 493 enum monitor_command cmd; 494 int s, serrno; 495 496 cmd = CMD_SOCKET; 497 send_data(fd_monitor, &cmd, sizeof(cmd)); 498 send_data(fd_monitor, &domain, sizeof(domain)); 499 500 s = recv_fd(fd_monitor); 501 if (s == -1) { 502 recv_data(fd_monitor, &serrno, sizeof(serrno)); 503 errno = serrno; 504 } 505 506 return (s); 507 } 508 509 int 510 monitor_bind(int s, struct sockaddr *name, socklen_t namelen) 511 { 512 enum monitor_command cmd; 513 int ret, serrno; 514 515 cmd = CMD_BIND; 516 send_data(fd_monitor, &cmd, sizeof(cmd)); 517 518 send_fd(fd_monitor, s); 519 send_data(fd_monitor, &namelen, sizeof(namelen)); 520 send_data(fd_monitor, name, namelen); 521 522 recv_data(fd_monitor, &ret, sizeof(ret)); 523 if (ret == -1) { 524 recv_data(fd_monitor, &serrno, sizeof(serrno)); 525 errno = serrno; 526 } 527 528 return (ret); 529 } 530