monitor.c revision 1.10
1/* $OpenBSD: monitor.c,v 1.10 2005/05/24 02:24:57 moritz 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 <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include <syslog.h> 34#include <unistd.h> 35 36#include "extern.h" 37#include "monitor.h" 38 39enum monitor_command { 40 CMD_USER, 41 CMD_PASS, 42 CMD_BIND 43}; 44 45enum monitor_state { 46 PREAUTH, 47 POSTAUTH 48}; 49 50#ifdef HASSETPROCTITLE 51extern char remotehost[]; 52#endif 53extern char ttyline[20]; 54extern int debug; 55 56extern void set_slave_signals(void); 57 58int fd_monitor = -1; 59int fd_slave = -1; 60int nullfd; 61pid_t slave_pid = -1; 62enum monitor_state state = PREAUTH; 63 64void send_data(int, void *, size_t); 65void recv_data(int, void *, size_t); 66void handle_cmds(void); 67void set_monitor_signals(void); 68void sig_pass_to_slave(int); 69void sig_chld(int); 70void fatalx(char *, ...); 71void debugmsg(char *, ...); 72 73/* 74 * Send data over a socket and exit if something fails. 75 */ 76void 77send_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(); 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 */ 102void 103recv_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(); 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 125void 126set_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 */ 153int 154monitor_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 (setegid(pw->pw_gid) == -1) 186 fatalx("setegid failed"); 187 if (setgid(pw->pw_gid) == -1) 188 fatalx("setgid failed"); 189 if (seteuid(pw->pw_uid) == -1) 190 fatalx("seteuid failed"); 191 if (setuid(pw->pw_uid) == -1) 192 fatalx("setuid failed"); 193 194 endpwent(); 195 close(fd_slave); 196 return (1); 197 } 198 199#ifdef HASSETPROCTITLE 200 setproctitle("%s: [priv pre-auth]", remotehost); 201#endif 202 203 handle_cmds(); 204 205 /* User-privileged slave */ 206 return (0); 207} 208 209/* 210 * Creates the user-privileged slave process. It is called 211 * from the privileged monitor process and returns twice. It returns 0 212 * for the user-privileged slave process and 1 for the monitor process. 213 */ 214int 215monitor_post_auth() 216{ 217 slave_pid = fork(); 218 if (slave_pid == -1) 219 fatalx("fork of user-privileged slave failed"); 220 221 snprintf(ttyline, sizeof(ttyline), "ftp%ld", 222 slave_pid == 0 ? (long)getpid() : (long)slave_pid); 223 224 if (slave_pid == 0) { 225 /* User privileged slave */ 226 close(fd_slave); 227 set_slave_signals(); 228 return (0); 229 } 230 231 /* We have to keep stdout open, because reply() needs it. */ 232 if ((nullfd = open(_PATH_DEVNULL, O_RDWR, 0)) == -1) 233 fatalx("cannot open %s: %m", _PATH_DEVNULL); 234 dup2(nullfd, STDIN_FILENO); 235 dup2(nullfd, STDERR_FILENO); 236 close(nullfd); 237 close(fd_monitor); 238 239 return (1); 240} 241 242/* 243 * Handles commands received from the slave process. It will not return 244 * except in one situation: After successful authentication it will 245 * return as the user-privileged slave process. 246 */ 247void 248handle_cmds(void) 249{ 250 enum monitor_command cmd; 251 enum auth_ret auth; 252 int err, s, slavequit, serrno; 253 pid_t preauth_slave_pid; 254 size_t len; 255 struct sockaddr sa; 256 socklen_t salen; 257 char *name, *pw; 258 259 for (;;) { 260 recv_data(fd_slave, &cmd, sizeof(cmd)); 261 262 switch (cmd) { 263 case CMD_USER: 264 debugmsg("CMD_USER received"); 265 266 recv_data(fd_slave, &len, sizeof(len)); 267 if ((name = malloc(len + 1)) == NULL) 268 fatalx("malloc: %m"); 269 if (len > 0) 270 recv_data(fd_slave, name, len); 271 name[len] = '\0'; 272 273 user(name); 274 free(name); 275 break; 276 case CMD_PASS: 277 debugmsg("CMD_PASS received"); 278 279 recv_data(fd_slave, &len, sizeof(len)); 280 if ((pw = malloc(len + 1)) == NULL) 281 fatalx("malloc: %m"); 282 if (len > 0) 283 recv_data(fd_slave, pw, len); 284 pw[len] = '\0'; 285 286 preauth_slave_pid = slave_pid; 287 288 auth = pass(pw); 289 bzero(pw, len); 290 free(pw); 291 292 switch (auth) { 293 case AUTH_FAILED: 294 /* Authentication failure */ 295 debugmsg("authentication failed"); 296 slavequit = 0; 297 send_data(fd_slave, &slavequit, 298 sizeof(slavequit)); 299 break; 300 case AUTH_SLAVE: 301 /* User-privileged slave */ 302 debugmsg("user-privileged slave started"); 303 return; 304 /* NOTREACHED */ 305 case AUTH_MONITOR: 306 /* Post-auth monitor */ 307 debugmsg("monitor went into post-auth phase"); 308 state = POSTAUTH; 309#ifdef HASSETPROCTITLE 310 setproctitle("%s: [priv post-auth]", 311 remotehost); 312#endif 313 slavequit = 1; 314 315 send_data(fd_slave, &slavequit, 316 sizeof(slavequit)); 317 318 while (waitpid(preauth_slave_pid, NULL, 0) < 0 319 && errno == EINTR) 320 ; 321 break; 322 default: 323 fatalx("bad return value from pass()"); 324 /* NOTREACHED */ 325 } 326 break; 327 case CMD_BIND: 328 debugmsg("CMD_BIND received"); 329 330 if (state != POSTAUTH) 331 fatalx("CMD_BIND received in invalid state"); 332 333 s = recv_fd(fd_slave); 334 335 recv_data(fd_slave, &salen, sizeof(salen)); 336 if (salen == 0 || salen > sizeof(sa)) 337 fatalx("monitor received invalid sockaddr len"); 338 339 bzero(&sa, sizeof(sa)); 340 recv_data(fd_slave, &sa, salen); 341 342 if (sa.sa_len != salen) 343 fatalx("monitor received invalid sockaddr len"); 344 345 if (sa.sa_family != AF_INET && sa.sa_family != AF_INET6) 346 fatalx("monitor received invalid addr family"); 347 348 err = bind(s, &sa, salen); 349 serrno = errno; 350 351 if (s >= 0) 352 close(s); 353 354 send_data(fd_slave, &err, sizeof(err)); 355 if (err == -1) 356 send_data(fd_slave, &serrno, sizeof(serrno)); 357 break; 358 default: 359 fatalx("monitor received unknown command %d", cmd); 360 /* NOTREACHED */ 361 } 362 } 363 /* NOTREACHED */ 364} 365 366void 367sig_pass_to_slave(int signo) 368{ 369 int olderrno = errno; 370 371 if (slave_pid > 0) 372 kill(slave_pid, signo); 373 374 errno = olderrno; 375} 376 377/* ARGSUSED */ 378void 379sig_chld(int signo) 380{ 381 pid_t pid; 382 int stat, olderrno = errno; 383 384 do { 385 pid = waitpid(slave_pid, &stat, WNOHANG); 386 if (pid > 0) 387 _exit(0); 388 } while (pid == -1 && errno == EINTR); 389 390 errno = olderrno; 391} 392 393void 394kill_slave(void) 395{ 396 if (slave_pid > 0) 397 kill(slave_pid, SIGQUIT); 398} 399 400void 401fatalx(char *fmt, ...) 402{ 403 va_list ap; 404 405 va_start(ap, fmt); 406 vsyslog(LOG_ERR, fmt, ap); 407 va_end(ap); 408 409 kill_slave(); 410 411 _exit(0); 412} 413 414void 415debugmsg(char *fmt, ...) 416{ 417 va_list ap; 418 419 if (debug) { 420 va_start(ap, fmt); 421 vsyslog(LOG_DEBUG, fmt, ap); 422 va_end(ap); 423 } 424} 425 426void 427monitor_user(char *name) 428{ 429 enum monitor_command cmd; 430 size_t len; 431 432 cmd = CMD_USER; 433 send_data(fd_monitor, &cmd, sizeof(cmd)); 434 435 len = strlen(name); 436 send_data(fd_monitor, &len, sizeof(len)); 437 if (len > 0) 438 send_data(fd_monitor, name, len); 439} 440 441int 442monitor_pass(char *pass) 443{ 444 enum monitor_command cmd; 445 int quitnow; 446 size_t len; 447 448 cmd = CMD_PASS; 449 send_data(fd_monitor, &cmd, sizeof(cmd)); 450 451 len = strlen(pass); 452 send_data(fd_monitor, &len, sizeof(len)); 453 if (len > 0) 454 send_data(fd_monitor, pass, len); 455 456 recv_data(fd_monitor, &quitnow, sizeof(quitnow)); 457 458 return (quitnow); 459} 460 461int 462monitor_bind(int s, struct sockaddr *name, socklen_t namelen) 463{ 464 enum monitor_command cmd; 465 int ret, serrno; 466 467 cmd = CMD_BIND; 468 send_data(fd_monitor, &cmd, sizeof(cmd)); 469 470 send_fd(fd_monitor, s); 471 send_data(fd_monitor, &namelen, sizeof(namelen)); 472 send_data(fd_monitor, name, namelen); 473 474 recv_data(fd_monitor, &ret, sizeof(ret)); 475 if (ret == -1) { 476 recv_data(fd_monitor, &serrno, sizeof(serrno)); 477 errno = serrno; 478 } 479 480 return (ret); 481} 482