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