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