diff options
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 783 |
1 files changed, 435 insertions, 348 deletions
@@ -1,3 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.349 2007/02/21 11:00:05 dtucker Exp $ */ | ||
1 | /* | 2 | /* |
2 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
3 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -42,7 +43,33 @@ | |||
42 | */ | 43 | */ |
43 | 44 | ||
44 | #include "includes.h" | 45 | #include "includes.h" |
45 | RCSID("$OpenBSD: sshd.c,v 1.318 2005/12/24 02:27:41 djm Exp $"); | 46 | |
47 | #include <sys/types.h> | ||
48 | #include <sys/ioctl.h> | ||
49 | #include <sys/socket.h> | ||
50 | #ifdef HAVE_SYS_STAT_H | ||
51 | # include <sys/stat.h> | ||
52 | #endif | ||
53 | #ifdef HAVE_SYS_TIME_H | ||
54 | # include <sys/time.h> | ||
55 | #endif | ||
56 | #include "openbsd-compat/sys-tree.h" | ||
57 | #include <sys/wait.h> | ||
58 | |||
59 | #include <errno.h> | ||
60 | #include <fcntl.h> | ||
61 | #include <netdb.h> | ||
62 | #ifdef HAVE_PATHS_H | ||
63 | #include <paths.h> | ||
64 | #endif | ||
65 | #include <grp.h> | ||
66 | #include <pwd.h> | ||
67 | #include <signal.h> | ||
68 | #include <stdarg.h> | ||
69 | #include <stdio.h> | ||
70 | #include <stdlib.h> | ||
71 | #include <string.h> | ||
72 | #include <unistd.h> | ||
46 | 73 | ||
47 | #include <openssl/dh.h> | 74 | #include <openssl/dh.h> |
48 | #include <openssl/bn.h> | 75 | #include <openssl/bn.h> |
@@ -53,28 +80,28 @@ RCSID("$OpenBSD: sshd.c,v 1.318 2005/12/24 02:27:41 djm Exp $"); | |||
53 | #include <prot.h> | 80 | #include <prot.h> |
54 | #endif | 81 | #endif |
55 | 82 | ||
83 | #include "xmalloc.h" | ||
56 | #include "ssh.h" | 84 | #include "ssh.h" |
57 | #include "ssh1.h" | 85 | #include "ssh1.h" |
58 | #include "ssh2.h" | 86 | #include "ssh2.h" |
59 | #include "xmalloc.h" | ||
60 | #include "rsa.h" | 87 | #include "rsa.h" |
61 | #include "sshpty.h" | 88 | #include "sshpty.h" |
62 | #include "packet.h" | 89 | #include "packet.h" |
63 | #include "log.h" | 90 | #include "log.h" |
91 | #include "buffer.h" | ||
64 | #include "servconf.h" | 92 | #include "servconf.h" |
65 | #include "uidswap.h" | 93 | #include "uidswap.h" |
66 | #include "compat.h" | 94 | #include "compat.h" |
67 | #include "buffer.h" | ||
68 | #include "bufaux.h" | ||
69 | #include "cipher.h" | 95 | #include "cipher.h" |
70 | #include "kex.h" | ||
71 | #include "key.h" | 96 | #include "key.h" |
97 | #include "kex.h" | ||
72 | #include "dh.h" | 98 | #include "dh.h" |
73 | #include "myproposal.h" | 99 | #include "myproposal.h" |
74 | #include "authfile.h" | 100 | #include "authfile.h" |
75 | #include "pathnames.h" | 101 | #include "pathnames.h" |
76 | #include "atomicio.h" | 102 | #include "atomicio.h" |
77 | #include "canohost.h" | 103 | #include "canohost.h" |
104 | #include "hostfile.h" | ||
78 | #include "auth.h" | 105 | #include "auth.h" |
79 | #include "misc.h" | 106 | #include "misc.h" |
80 | #include "msg.h" | 107 | #include "msg.h" |
@@ -83,8 +110,12 @@ RCSID("$OpenBSD: sshd.c,v 1.318 2005/12/24 02:27:41 djm Exp $"); | |||
83 | #include "session.h" | 110 | #include "session.h" |
84 | #include "monitor_mm.h" | 111 | #include "monitor_mm.h" |
85 | #include "monitor.h" | 112 | #include "monitor.h" |
113 | #ifdef GSSAPI | ||
114 | #include "ssh-gss.h" | ||
115 | #endif | ||
86 | #include "monitor_wrap.h" | 116 | #include "monitor_wrap.h" |
87 | #include "monitor_fdpass.h" | 117 | #include "monitor_fdpass.h" |
118 | #include "version.h" | ||
88 | 119 | ||
89 | #ifdef LIBWRAP | 120 | #ifdef LIBWRAP |
90 | #include <tcpd.h> | 121 | #include <tcpd.h> |
@@ -201,15 +232,21 @@ int *startup_pipes = NULL; | |||
201 | int startup_pipe; /* in child */ | 232 | int startup_pipe; /* in child */ |
202 | 233 | ||
203 | /* variables used for privilege separation */ | 234 | /* variables used for privilege separation */ |
204 | int use_privsep; | 235 | int use_privsep = -1; |
205 | struct monitor *pmonitor = NULL; | 236 | struct monitor *pmonitor = NULL; |
206 | 237 | ||
207 | /* global authentication context */ | 238 | /* global authentication context */ |
208 | Authctxt *the_authctxt = NULL; | 239 | Authctxt *the_authctxt = NULL; |
209 | 240 | ||
241 | /* sshd_config buffer */ | ||
242 | Buffer cfg; | ||
243 | |||
210 | /* message to be displayed after login */ | 244 | /* message to be displayed after login */ |
211 | Buffer loginmsg; | 245 | Buffer loginmsg; |
212 | 246 | ||
247 | /* Unprivileged user */ | ||
248 | struct passwd *privsep_pw = NULL; | ||
249 | |||
213 | /* Prototypes for various functions defined later in this file. */ | 250 | /* Prototypes for various functions defined later in this file. */ |
214 | void destroy_sensitive_data(void); | 251 | void destroy_sensitive_data(void); |
215 | void demote_sensitive_data(void); | 252 | void demote_sensitive_data(void); |
@@ -246,6 +283,8 @@ close_startup_pipes(void) | |||
246 | * the effect is to reread the configuration file (and to regenerate | 283 | * the effect is to reread the configuration file (and to regenerate |
247 | * the server key). | 284 | * the server key). |
248 | */ | 285 | */ |
286 | |||
287 | /*ARGSUSED*/ | ||
249 | static void | 288 | static void |
250 | sighup_handler(int sig) | 289 | sighup_handler(int sig) |
251 | { | 290 | { |
@@ -266,6 +305,7 @@ sighup_restart(void) | |||
266 | logit("Received SIGHUP; restarting."); | 305 | logit("Received SIGHUP; restarting."); |
267 | close_listen_socks(); | 306 | close_listen_socks(); |
268 | close_startup_pipes(); | 307 | close_startup_pipes(); |
308 | alarm(0); /* alarm timer persists across exec */ | ||
269 | execv(saved_argv[0], saved_argv); | 309 | execv(saved_argv[0], saved_argv); |
270 | logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], | 310 | logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], |
271 | strerror(errno)); | 311 | strerror(errno)); |
@@ -275,6 +315,7 @@ sighup_restart(void) | |||
275 | /* | 315 | /* |
276 | * Generic signal handler for terminating signals in the master daemon. | 316 | * Generic signal handler for terminating signals in the master daemon. |
277 | */ | 317 | */ |
318 | /*ARGSUSED*/ | ||
278 | static void | 319 | static void |
279 | sigterm_handler(int sig) | 320 | sigterm_handler(int sig) |
280 | { | 321 | { |
@@ -285,6 +326,7 @@ sigterm_handler(int sig) | |||
285 | * SIGCHLD handler. This is called whenever a child dies. This will then | 326 | * SIGCHLD handler. This is called whenever a child dies. This will then |
286 | * reap any zombies left by exited children. | 327 | * reap any zombies left by exited children. |
287 | */ | 328 | */ |
329 | /*ARGSUSED*/ | ||
288 | static void | 330 | static void |
289 | main_sigchld_handler(int sig) | 331 | main_sigchld_handler(int sig) |
290 | { | 332 | { |
@@ -303,16 +345,15 @@ main_sigchld_handler(int sig) | |||
303 | /* | 345 | /* |
304 | * Signal handler for the alarm after the login grace period has expired. | 346 | * Signal handler for the alarm after the login grace period has expired. |
305 | */ | 347 | */ |
348 | /*ARGSUSED*/ | ||
306 | static void | 349 | static void |
307 | grace_alarm_handler(int sig) | 350 | grace_alarm_handler(int sig) |
308 | { | 351 | { |
309 | /* XXX no idea how fix this signal handler */ | ||
310 | |||
311 | if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) | 352 | if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) |
312 | kill(pmonitor->m_pid, SIGALRM); | 353 | kill(pmonitor->m_pid, SIGALRM); |
313 | 354 | ||
314 | /* Log error and exit. */ | 355 | /* Log error and exit. */ |
315 | fatal("Timeout before authentication for %s", get_remote_ipaddr()); | 356 | sigdie("Timeout before authentication for %s", get_remote_ipaddr()); |
316 | } | 357 | } |
317 | 358 | ||
318 | /* | 359 | /* |
@@ -345,6 +386,7 @@ generate_ephemeral_server_key(void) | |||
345 | arc4random_stir(); | 386 | arc4random_stir(); |
346 | } | 387 | } |
347 | 388 | ||
389 | /*ARGSUSED*/ | ||
348 | static void | 390 | static void |
349 | key_regeneration_alarm(int sig) | 391 | key_regeneration_alarm(int sig) |
350 | { | 392 | { |
@@ -541,7 +583,6 @@ privsep_preauth_child(void) | |||
541 | { | 583 | { |
542 | u_int32_t rnd[256]; | 584 | u_int32_t rnd[256]; |
543 | gid_t gidset[1]; | 585 | gid_t gidset[1]; |
544 | struct passwd *pw; | ||
545 | int i; | 586 | int i; |
546 | 587 | ||
547 | /* Enable challenge-response authentication for privilege separation */ | 588 | /* Enable challenge-response authentication for privilege separation */ |
@@ -554,12 +595,6 @@ privsep_preauth_child(void) | |||
554 | /* Demote the private keys to public keys. */ | 595 | /* Demote the private keys to public keys. */ |
555 | demote_sensitive_data(); | 596 | demote_sensitive_data(); |
556 | 597 | ||
557 | if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) | ||
558 | fatal("Privilege separation user %s does not exist", | ||
559 | SSH_PRIVSEP_USER); | ||
560 | memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); | ||
561 | endpwent(); | ||
562 | |||
563 | /* Change our root directory */ | 598 | /* Change our root directory */ |
564 | if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) | 599 | if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) |
565 | fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, | 600 | fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, |
@@ -568,16 +603,16 @@ privsep_preauth_child(void) | |||
568 | fatal("chdir(\"/\"): %s", strerror(errno)); | 603 | fatal("chdir(\"/\"): %s", strerror(errno)); |
569 | 604 | ||
570 | /* Drop our privileges */ | 605 | /* Drop our privileges */ |
571 | debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, | 606 | debug3("privsep user:group %u:%u", (u_int)privsep_pw->pw_uid, |
572 | (u_int)pw->pw_gid); | 607 | (u_int)privsep_pw->pw_gid); |
573 | #if 0 | 608 | #if 0 |
574 | /* XXX not ready, too heavy after chroot */ | 609 | /* XXX not ready, too heavy after chroot */ |
575 | do_setusercontext(pw); | 610 | do_setusercontext(privsep_pw); |
576 | #else | 611 | #else |
577 | gidset[0] = pw->pw_gid; | 612 | gidset[0] = privsep_pw->pw_gid; |
578 | if (setgroups(1, gidset) < 0) | 613 | if (setgroups(1, gidset) < 0) |
579 | fatal("setgroups: %.100s", strerror(errno)); | 614 | fatal("setgroups: %.100s", strerror(errno)); |
580 | permanently_set_uid(pw); | 615 | permanently_set_uid(privsep_pw); |
581 | #endif | 616 | #endif |
582 | } | 617 | } |
583 | 618 | ||
@@ -866,6 +901,325 @@ recv_rexec_state(int fd, Buffer *conf) | |||
866 | debug3("%s: done", __func__); | 901 | debug3("%s: done", __func__); |
867 | } | 902 | } |
868 | 903 | ||
904 | /* Accept a connection from inetd */ | ||
905 | static void | ||
906 | server_accept_inetd(int *sock_in, int *sock_out) | ||
907 | { | ||
908 | int fd; | ||
909 | |||
910 | startup_pipe = -1; | ||
911 | if (rexeced_flag) { | ||
912 | close(REEXEC_CONFIG_PASS_FD); | ||
913 | *sock_in = *sock_out = dup(STDIN_FILENO); | ||
914 | if (!debug_flag) { | ||
915 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | ||
916 | close(REEXEC_STARTUP_PIPE_FD); | ||
917 | } | ||
918 | } else { | ||
919 | *sock_in = dup(STDIN_FILENO); | ||
920 | *sock_out = dup(STDOUT_FILENO); | ||
921 | } | ||
922 | /* | ||
923 | * We intentionally do not close the descriptors 0, 1, and 2 | ||
924 | * as our code for setting the descriptors won't work if | ||
925 | * ttyfd happens to be one of those. | ||
926 | */ | ||
927 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
928 | dup2(fd, STDIN_FILENO); | ||
929 | dup2(fd, STDOUT_FILENO); | ||
930 | if (fd > STDOUT_FILENO) | ||
931 | close(fd); | ||
932 | } | ||
933 | debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out); | ||
934 | } | ||
935 | |||
936 | /* | ||
937 | * Listen for TCP connections | ||
938 | */ | ||
939 | static void | ||
940 | server_listen(void) | ||
941 | { | ||
942 | int ret, listen_sock, on = 1; | ||
943 | struct addrinfo *ai; | ||
944 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | ||
945 | |||
946 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { | ||
947 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | ||
948 | continue; | ||
949 | if (num_listen_socks >= MAX_LISTEN_SOCKS) | ||
950 | fatal("Too many listen sockets. " | ||
951 | "Enlarge MAX_LISTEN_SOCKS"); | ||
952 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, | ||
953 | ntop, sizeof(ntop), strport, sizeof(strport), | ||
954 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | ||
955 | error("getnameinfo failed: %.100s", | ||
956 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | ||
957 | strerror(errno)); | ||
958 | continue; | ||
959 | } | ||
960 | /* Create socket for listening. */ | ||
961 | listen_sock = socket(ai->ai_family, ai->ai_socktype, | ||
962 | ai->ai_protocol); | ||
963 | if (listen_sock < 0) { | ||
964 | /* kernel may not support ipv6 */ | ||
965 | verbose("socket: %.100s", strerror(errno)); | ||
966 | continue; | ||
967 | } | ||
968 | if (set_nonblock(listen_sock) == -1) { | ||
969 | close(listen_sock); | ||
970 | continue; | ||
971 | } | ||
972 | /* | ||
973 | * Set socket options. | ||
974 | * Allow local port reuse in TIME_WAIT. | ||
975 | */ | ||
976 | if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, | ||
977 | &on, sizeof(on)) == -1) | ||
978 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | ||
979 | |||
980 | debug("Bind to port %s on %s.", strport, ntop); | ||
981 | |||
982 | /* Bind the socket to the desired port. */ | ||
983 | if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { | ||
984 | error("Bind to port %s on %s failed: %.200s.", | ||
985 | strport, ntop, strerror(errno)); | ||
986 | close(listen_sock); | ||
987 | continue; | ||
988 | } | ||
989 | listen_socks[num_listen_socks] = listen_sock; | ||
990 | num_listen_socks++; | ||
991 | |||
992 | /* Start listening on the port. */ | ||
993 | if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) | ||
994 | fatal("listen on [%s]:%s: %.100s", | ||
995 | ntop, strport, strerror(errno)); | ||
996 | logit("Server listening on %s port %s.", ntop, strport); | ||
997 | } | ||
998 | freeaddrinfo(options.listen_addrs); | ||
999 | |||
1000 | if (!num_listen_socks) | ||
1001 | fatal("Cannot bind any address."); | ||
1002 | } | ||
1003 | |||
1004 | /* | ||
1005 | * The main TCP accept loop. Note that, for the non-debug case, returns | ||
1006 | * from this function are in a forked subprocess. | ||
1007 | */ | ||
1008 | static void | ||
1009 | server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | ||
1010 | { | ||
1011 | fd_set *fdset; | ||
1012 | int i, j, ret, maxfd; | ||
1013 | int key_used = 0, startups = 0; | ||
1014 | int startup_p[2] = { -1 , -1 }; | ||
1015 | struct sockaddr_storage from; | ||
1016 | socklen_t fromlen; | ||
1017 | pid_t pid; | ||
1018 | |||
1019 | /* setup fd set for accept */ | ||
1020 | fdset = NULL; | ||
1021 | maxfd = 0; | ||
1022 | for (i = 0; i < num_listen_socks; i++) | ||
1023 | if (listen_socks[i] > maxfd) | ||
1024 | maxfd = listen_socks[i]; | ||
1025 | /* pipes connected to unauthenticated childs */ | ||
1026 | startup_pipes = xcalloc(options.max_startups, sizeof(int)); | ||
1027 | for (i = 0; i < options.max_startups; i++) | ||
1028 | startup_pipes[i] = -1; | ||
1029 | |||
1030 | /* | ||
1031 | * Stay listening for connections until the system crashes or | ||
1032 | * the daemon is killed with a signal. | ||
1033 | */ | ||
1034 | for (;;) { | ||
1035 | if (received_sighup) | ||
1036 | sighup_restart(); | ||
1037 | if (fdset != NULL) | ||
1038 | xfree(fdset); | ||
1039 | fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS), | ||
1040 | sizeof(fd_mask)); | ||
1041 | |||
1042 | for (i = 0; i < num_listen_socks; i++) | ||
1043 | FD_SET(listen_socks[i], fdset); | ||
1044 | for (i = 0; i < options.max_startups; i++) | ||
1045 | if (startup_pipes[i] != -1) | ||
1046 | FD_SET(startup_pipes[i], fdset); | ||
1047 | |||
1048 | /* Wait in select until there is a connection. */ | ||
1049 | ret = select(maxfd+1, fdset, NULL, NULL, NULL); | ||
1050 | if (ret < 0 && errno != EINTR) | ||
1051 | error("select: %.100s", strerror(errno)); | ||
1052 | if (received_sigterm) { | ||
1053 | logit("Received signal %d; terminating.", | ||
1054 | (int) received_sigterm); | ||
1055 | close_listen_socks(); | ||
1056 | unlink(options.pid_file); | ||
1057 | exit(255); | ||
1058 | } | ||
1059 | if (key_used && key_do_regen) { | ||
1060 | generate_ephemeral_server_key(); | ||
1061 | key_used = 0; | ||
1062 | key_do_regen = 0; | ||
1063 | } | ||
1064 | if (ret < 0) | ||
1065 | continue; | ||
1066 | |||
1067 | for (i = 0; i < options.max_startups; i++) | ||
1068 | if (startup_pipes[i] != -1 && | ||
1069 | FD_ISSET(startup_pipes[i], fdset)) { | ||
1070 | /* | ||
1071 | * the read end of the pipe is ready | ||
1072 | * if the child has closed the pipe | ||
1073 | * after successful authentication | ||
1074 | * or if the child has died | ||
1075 | */ | ||
1076 | close(startup_pipes[i]); | ||
1077 | startup_pipes[i] = -1; | ||
1078 | startups--; | ||
1079 | } | ||
1080 | for (i = 0; i < num_listen_socks; i++) { | ||
1081 | if (!FD_ISSET(listen_socks[i], fdset)) | ||
1082 | continue; | ||
1083 | fromlen = sizeof(from); | ||
1084 | *newsock = accept(listen_socks[i], | ||
1085 | (struct sockaddr *)&from, &fromlen); | ||
1086 | if (*newsock < 0) { | ||
1087 | if (errno != EINTR && errno != EWOULDBLOCK) | ||
1088 | error("accept: %.100s", strerror(errno)); | ||
1089 | continue; | ||
1090 | } | ||
1091 | if (unset_nonblock(*newsock) == -1) { | ||
1092 | close(*newsock); | ||
1093 | continue; | ||
1094 | } | ||
1095 | if (drop_connection(startups) == 1) { | ||
1096 | debug("drop connection #%d", startups); | ||
1097 | close(*newsock); | ||
1098 | continue; | ||
1099 | } | ||
1100 | if (pipe(startup_p) == -1) { | ||
1101 | close(*newsock); | ||
1102 | continue; | ||
1103 | } | ||
1104 | |||
1105 | if (rexec_flag && socketpair(AF_UNIX, | ||
1106 | SOCK_STREAM, 0, config_s) == -1) { | ||
1107 | error("reexec socketpair: %s", | ||
1108 | strerror(errno)); | ||
1109 | close(*newsock); | ||
1110 | close(startup_p[0]); | ||
1111 | close(startup_p[1]); | ||
1112 | continue; | ||
1113 | } | ||
1114 | |||
1115 | for (j = 0; j < options.max_startups; j++) | ||
1116 | if (startup_pipes[j] == -1) { | ||
1117 | startup_pipes[j] = startup_p[0]; | ||
1118 | if (maxfd < startup_p[0]) | ||
1119 | maxfd = startup_p[0]; | ||
1120 | startups++; | ||
1121 | break; | ||
1122 | } | ||
1123 | |||
1124 | /* | ||
1125 | * Got connection. Fork a child to handle it, unless | ||
1126 | * we are in debugging mode. | ||
1127 | */ | ||
1128 | if (debug_flag) { | ||
1129 | /* | ||
1130 | * In debugging mode. Close the listening | ||
1131 | * socket, and start processing the | ||
1132 | * connection without forking. | ||
1133 | */ | ||
1134 | debug("Server will not fork when running in debugging mode."); | ||
1135 | close_listen_socks(); | ||
1136 | *sock_in = *newsock; | ||
1137 | *sock_out = *newsock; | ||
1138 | close(startup_p[0]); | ||
1139 | close(startup_p[1]); | ||
1140 | startup_pipe = -1; | ||
1141 | pid = getpid(); | ||
1142 | if (rexec_flag) { | ||
1143 | send_rexec_state(config_s[0], | ||
1144 | &cfg); | ||
1145 | close(config_s[0]); | ||
1146 | } | ||
1147 | break; | ||
1148 | } | ||
1149 | |||
1150 | /* | ||
1151 | * Normal production daemon. Fork, and have | ||
1152 | * the child process the connection. The | ||
1153 | * parent continues listening. | ||
1154 | */ | ||
1155 | platform_pre_fork(); | ||
1156 | if ((pid = fork()) == 0) { | ||
1157 | /* | ||
1158 | * Child. Close the listening and | ||
1159 | * max_startup sockets. Start using | ||
1160 | * the accepted socket. Reinitialize | ||
1161 | * logging (since our pid has changed). | ||
1162 | * We break out of the loop to handle | ||
1163 | * the connection. | ||
1164 | */ | ||
1165 | platform_post_fork_child(); | ||
1166 | startup_pipe = startup_p[1]; | ||
1167 | close_startup_pipes(); | ||
1168 | close_listen_socks(); | ||
1169 | *sock_in = *newsock; | ||
1170 | *sock_out = *newsock; | ||
1171 | log_init(__progname, | ||
1172 | options.log_level, | ||
1173 | options.log_facility, | ||
1174 | log_stderr); | ||
1175 | if (rexec_flag) | ||
1176 | close(config_s[0]); | ||
1177 | break; | ||
1178 | } | ||
1179 | |||
1180 | /* Parent. Stay in the loop. */ | ||
1181 | platform_post_fork_parent(pid); | ||
1182 | if (pid < 0) | ||
1183 | error("fork: %.100s", strerror(errno)); | ||
1184 | else | ||
1185 | debug("Forked child %ld.", (long)pid); | ||
1186 | |||
1187 | close(startup_p[1]); | ||
1188 | |||
1189 | if (rexec_flag) { | ||
1190 | send_rexec_state(config_s[0], &cfg); | ||
1191 | close(config_s[0]); | ||
1192 | close(config_s[1]); | ||
1193 | } | ||
1194 | |||
1195 | /* | ||
1196 | * Mark that the key has been used (it | ||
1197 | * was "given" to the child). | ||
1198 | */ | ||
1199 | if ((options.protocol & SSH_PROTO_1) && | ||
1200 | key_used == 0) { | ||
1201 | /* Schedule server key regeneration alarm. */ | ||
1202 | signal(SIGALRM, key_regeneration_alarm); | ||
1203 | alarm(options.key_regeneration_time); | ||
1204 | key_used = 1; | ||
1205 | } | ||
1206 | |||
1207 | close(*newsock); | ||
1208 | |||
1209 | /* | ||
1210 | * Ensure that our random state differs | ||
1211 | * from that of the child | ||
1212 | */ | ||
1213 | arc4random_stir(); | ||
1214 | } | ||
1215 | |||
1216 | /* child process check (or debug mode) */ | ||
1217 | if (num_listen_socks < 0) | ||
1218 | break; | ||
1219 | } | ||
1220 | } | ||
1221 | |||
1222 | |||
869 | /* | 1223 | /* |
870 | * Main program for the daemon. | 1224 | * Main program for the daemon. |
871 | */ | 1225 | */ |
@@ -874,25 +1228,14 @@ main(int ac, char **av) | |||
874 | { | 1228 | { |
875 | extern char *optarg; | 1229 | extern char *optarg; |
876 | extern int optind; | 1230 | extern int optind; |
877 | int opt, j, i, fdsetsz, on = 1; | 1231 | int opt, i, on = 1; |
878 | int sock_in = -1, sock_out = -1, newsock = -1; | 1232 | int sock_in = -1, sock_out = -1, newsock = -1; |
879 | pid_t pid; | ||
880 | socklen_t fromlen; | ||
881 | fd_set *fdset; | ||
882 | struct sockaddr_storage from; | ||
883 | const char *remote_ip; | 1233 | const char *remote_ip; |
884 | int remote_port; | 1234 | int remote_port; |
885 | FILE *f; | ||
886 | struct addrinfo *ai; | ||
887 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | ||
888 | char *line; | 1235 | char *line; |
889 | int listen_sock, maxfd; | 1236 | int config_s[2] = { -1 , -1 }; |
890 | int startup_p[2] = { -1 , -1 }, config_s[2] = { -1 , -1 }; | ||
891 | int startups = 0; | ||
892 | Key *key; | 1237 | Key *key; |
893 | Authctxt *authctxt; | 1238 | Authctxt *authctxt; |
894 | int ret, key_used = 0; | ||
895 | Buffer cfg; | ||
896 | 1239 | ||
897 | #ifdef HAVE_SECUREWARE | 1240 | #ifdef HAVE_SECUREWARE |
898 | (void)set_auth_parameters(ac, av); | 1241 | (void)set_auth_parameters(ac, av); |
@@ -903,7 +1246,7 @@ main(int ac, char **av) | |||
903 | /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ | 1246 | /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ |
904 | saved_argc = ac; | 1247 | saved_argc = ac; |
905 | rexec_argc = ac; | 1248 | rexec_argc = ac; |
906 | saved_argv = xmalloc(sizeof(*saved_argv) * (ac + 1)); | 1249 | saved_argv = xcalloc(ac + 1, sizeof(*saved_argv)); |
907 | for (i = 0; i < ac; i++) | 1250 | for (i = 0; i < ac; i++) |
908 | saved_argv[i] = xstrdup(av[i]); | 1251 | saved_argv[i] = xstrdup(av[i]); |
909 | saved_argv[i] = NULL; | 1252 | saved_argv[i] = NULL; |
@@ -965,7 +1308,8 @@ main(int ac, char **av) | |||
965 | options.log_level = SYSLOG_LEVEL_QUIET; | 1308 | options.log_level = SYSLOG_LEVEL_QUIET; |
966 | break; | 1309 | break; |
967 | case 'b': | 1310 | case 'b': |
968 | options.server_key_bits = atoi(optarg); | 1311 | options.server_key_bits = (int)strtonum(optarg, 256, |
1312 | 32768, NULL); | ||
969 | break; | 1313 | break; |
970 | case 'p': | 1314 | case 'p': |
971 | options.ports_from_cmdline = 1; | 1315 | options.ports_from_cmdline = 1; |
@@ -1002,7 +1346,7 @@ main(int ac, char **av) | |||
1002 | test_flag = 1; | 1346 | test_flag = 1; |
1003 | break; | 1347 | break; |
1004 | case 'u': | 1348 | case 'u': |
1005 | utmp_len = atoi(optarg); | 1349 | utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL); |
1006 | if (utmp_len > MAXHOSTNAMELEN) { | 1350 | if (utmp_len > MAXHOSTNAMELEN) { |
1007 | fprintf(stderr, "Invalid utmp length.\n"); | 1351 | fprintf(stderr, "Invalid utmp length.\n"); |
1008 | exit(1); | 1352 | exit(1); |
@@ -1011,7 +1355,7 @@ main(int ac, char **av) | |||
1011 | case 'o': | 1355 | case 'o': |
1012 | line = xstrdup(optarg); | 1356 | line = xstrdup(optarg); |
1013 | if (process_server_config_line(&options, line, | 1357 | if (process_server_config_line(&options, line, |
1014 | "command-line", 0) != 0) | 1358 | "command-line", 0, NULL, NULL, NULL, NULL) != 0) |
1015 | exit(1); | 1359 | exit(1); |
1016 | xfree(line); | 1360 | xfree(line); |
1017 | break; | 1361 | break; |
@@ -1069,11 +1413,8 @@ main(int ac, char **av) | |||
1069 | else | 1413 | else |
1070 | load_server_config(config_file_name, &cfg); | 1414 | load_server_config(config_file_name, &cfg); |
1071 | 1415 | ||
1072 | parse_server_config(&options, | 1416 | parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, |
1073 | rexeced_flag ? "rexec" : config_file_name, &cfg); | 1417 | &cfg, NULL, NULL, NULL); |
1074 | |||
1075 | if (!rexec_flag) | ||
1076 | buffer_free(&cfg); | ||
1077 | 1418 | ||
1078 | seed_rng(); | 1419 | seed_rng(); |
1079 | 1420 | ||
@@ -1091,8 +1432,21 @@ main(int ac, char **av) | |||
1091 | 1432 | ||
1092 | debug("sshd version %.100s", SSH_RELEASE); | 1433 | debug("sshd version %.100s", SSH_RELEASE); |
1093 | 1434 | ||
1435 | /* Store privilege separation user for later use if required. */ | ||
1436 | if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { | ||
1437 | if (use_privsep || options.kerberos_authentication) | ||
1438 | fatal("Privilege separation user %s does not exist", | ||
1439 | SSH_PRIVSEP_USER); | ||
1440 | } else { | ||
1441 | memset(privsep_pw->pw_passwd, 0, strlen(privsep_pw->pw_passwd)); | ||
1442 | privsep_pw = pwcopy(privsep_pw); | ||
1443 | xfree(privsep_pw->pw_passwd); | ||
1444 | privsep_pw->pw_passwd = xstrdup("*"); | ||
1445 | } | ||
1446 | endpwent(); | ||
1447 | |||
1094 | /* load private host keys */ | 1448 | /* load private host keys */ |
1095 | sensitive_data.host_keys = xmalloc(options.num_host_key_files * | 1449 | sensitive_data.host_keys = xcalloc(options.num_host_key_files, |
1096 | sizeof(Key *)); | 1450 | sizeof(Key *)); |
1097 | for (i = 0; i < options.num_host_key_files; i++) | 1451 | for (i = 0; i < options.num_host_key_files; i++) |
1098 | sensitive_data.host_keys[i] = NULL; | 1452 | sensitive_data.host_keys[i] = NULL; |
@@ -1158,12 +1512,8 @@ main(int ac, char **av) | |||
1158 | } | 1512 | } |
1159 | 1513 | ||
1160 | if (use_privsep) { | 1514 | if (use_privsep) { |
1161 | struct passwd *pw; | ||
1162 | struct stat st; | 1515 | struct stat st; |
1163 | 1516 | ||
1164 | if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) | ||
1165 | fatal("Privilege separation user %s does not exist", | ||
1166 | SSH_PRIVSEP_USER); | ||
1167 | if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || | 1517 | if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || |
1168 | (S_ISDIR(st.st_mode) == 0)) | 1518 | (S_ISDIR(st.st_mode) == 0)) |
1169 | fatal("Missing privilege separation directory: %s", | 1519 | fatal("Missing privilege separation directory: %s", |
@@ -1195,7 +1545,7 @@ main(int ac, char **av) | |||
1195 | debug("setgroups() failed: %.200s", strerror(errno)); | 1545 | debug("setgroups() failed: %.200s", strerror(errno)); |
1196 | 1546 | ||
1197 | if (rexec_flag) { | 1547 | if (rexec_flag) { |
1198 | rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2)); | 1548 | rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *)); |
1199 | for (i = 0; i < rexec_argc; i++) { | 1549 | for (i = 0; i < rexec_argc; i++) { |
1200 | debug("rexec_argv[%d]='%s'", i, saved_argv[i]); | 1550 | debug("rexec_argv[%d]='%s'", i, saved_argv[i]); |
1201 | rexec_argv[i] = saved_argv[i]; | 1551 | rexec_argv[i] = saved_argv[i]; |
@@ -1243,121 +1593,31 @@ main(int ac, char **av) | |||
1243 | /* ignore SIGPIPE */ | 1593 | /* ignore SIGPIPE */ |
1244 | signal(SIGPIPE, SIG_IGN); | 1594 | signal(SIGPIPE, SIG_IGN); |
1245 | 1595 | ||
1246 | /* Start listening for a socket, unless started from inetd. */ | 1596 | /* Get a connection, either from inetd or a listening TCP socket */ |
1247 | if (inetd_flag) { | 1597 | if (inetd_flag) { |
1248 | int fd; | 1598 | server_accept_inetd(&sock_in, &sock_out); |
1249 | 1599 | ||
1250 | startup_pipe = -1; | ||
1251 | if (rexeced_flag) { | ||
1252 | close(REEXEC_CONFIG_PASS_FD); | ||
1253 | sock_in = sock_out = dup(STDIN_FILENO); | ||
1254 | if (!debug_flag) { | ||
1255 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | ||
1256 | close(REEXEC_STARTUP_PIPE_FD); | ||
1257 | } | ||
1258 | } else { | ||
1259 | sock_in = dup(STDIN_FILENO); | ||
1260 | sock_out = dup(STDOUT_FILENO); | ||
1261 | } | ||
1262 | /* | ||
1263 | * We intentionally do not close the descriptors 0, 1, and 2 | ||
1264 | * as our code for setting the descriptors won't work if | ||
1265 | * ttyfd happens to be one of those. | ||
1266 | */ | ||
1267 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
1268 | dup2(fd, STDIN_FILENO); | ||
1269 | dup2(fd, STDOUT_FILENO); | ||
1270 | if (fd > STDOUT_FILENO) | ||
1271 | close(fd); | ||
1272 | } | ||
1273 | debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); | ||
1274 | if ((options.protocol & SSH_PROTO_1) && | 1600 | if ((options.protocol & SSH_PROTO_1) && |
1275 | sensitive_data.server_key == NULL) | 1601 | sensitive_data.server_key == NULL) |
1276 | generate_ephemeral_server_key(); | 1602 | generate_ephemeral_server_key(); |
1277 | } else { | 1603 | } else { |
1278 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { | 1604 | server_listen(); |
1279 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | ||
1280 | continue; | ||
1281 | if (num_listen_socks >= MAX_LISTEN_SOCKS) | ||
1282 | fatal("Too many listen sockets. " | ||
1283 | "Enlarge MAX_LISTEN_SOCKS"); | ||
1284 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, | ||
1285 | ntop, sizeof(ntop), strport, sizeof(strport), | ||
1286 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | ||
1287 | error("getnameinfo failed: %.100s", | ||
1288 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | ||
1289 | strerror(errno)); | ||
1290 | continue; | ||
1291 | } | ||
1292 | /* Create socket for listening. */ | ||
1293 | listen_sock = socket(ai->ai_family, ai->ai_socktype, | ||
1294 | ai->ai_protocol); | ||
1295 | if (listen_sock < 0) { | ||
1296 | /* kernel may not support ipv6 */ | ||
1297 | verbose("socket: %.100s", strerror(errno)); | ||
1298 | continue; | ||
1299 | } | ||
1300 | if (set_nonblock(listen_sock) == -1) { | ||
1301 | close(listen_sock); | ||
1302 | continue; | ||
1303 | } | ||
1304 | /* | ||
1305 | * Set socket options. | ||
1306 | * Allow local port reuse in TIME_WAIT. | ||
1307 | */ | ||
1308 | if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, | ||
1309 | &on, sizeof(on)) == -1) | ||
1310 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | ||
1311 | |||
1312 | debug("Bind to port %s on %s.", strport, ntop); | ||
1313 | |||
1314 | /* Bind the socket to the desired port. */ | ||
1315 | if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { | ||
1316 | if (!ai->ai_next) | ||
1317 | error("Bind to port %s on %s failed: %.200s.", | ||
1318 | strport, ntop, strerror(errno)); | ||
1319 | close(listen_sock); | ||
1320 | continue; | ||
1321 | } | ||
1322 | listen_socks[num_listen_socks] = listen_sock; | ||
1323 | num_listen_socks++; | ||
1324 | |||
1325 | /* Start listening on the port. */ | ||
1326 | logit("Server listening on %s port %s.", ntop, strport); | ||
1327 | if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) | ||
1328 | fatal("listen: %.100s", strerror(errno)); | ||
1329 | |||
1330 | } | ||
1331 | freeaddrinfo(options.listen_addrs); | ||
1332 | |||
1333 | if (!num_listen_socks) | ||
1334 | fatal("Cannot bind any address."); | ||
1335 | 1605 | ||
1336 | if (options.protocol & SSH_PROTO_1) | 1606 | if (options.protocol & SSH_PROTO_1) |
1337 | generate_ephemeral_server_key(); | 1607 | generate_ephemeral_server_key(); |
1338 | 1608 | ||
1339 | /* | ||
1340 | * Arrange to restart on SIGHUP. The handler needs | ||
1341 | * listen_sock. | ||
1342 | */ | ||
1343 | signal(SIGHUP, sighup_handler); | 1609 | signal(SIGHUP, sighup_handler); |
1344 | 1610 | signal(SIGCHLD, main_sigchld_handler); | |
1345 | signal(SIGTERM, sigterm_handler); | 1611 | signal(SIGTERM, sigterm_handler); |
1346 | signal(SIGQUIT, sigterm_handler); | 1612 | signal(SIGQUIT, sigterm_handler); |
1347 | 1613 | ||
1348 | /* Arrange SIGCHLD to be caught. */ | 1614 | /* |
1349 | signal(SIGCHLD, main_sigchld_handler); | 1615 | * Write out the pid file after the sigterm handler |
1350 | 1616 | * is setup and the listen sockets are bound | |
1351 | /* Write out the pid file after the sigterm handler is setup */ | 1617 | */ |
1352 | if (!debug_flag) { | 1618 | if (!debug_flag) { |
1353 | /* | 1619 | FILE *f = fopen(options.pid_file, "w"); |
1354 | * Record our pid in /var/run/sshd.pid to make it | 1620 | |
1355 | * easier to kill the correct sshd. We don't want to | ||
1356 | * do this before the bind above because the bind will | ||
1357 | * fail if there already is a daemon, and this will | ||
1358 | * overwrite any old pid in the file. | ||
1359 | */ | ||
1360 | f = fopen(options.pid_file, "wb"); | ||
1361 | if (f == NULL) { | 1621 | if (f == NULL) { |
1362 | error("Couldn't create pid file \"%s\": %s", | 1622 | error("Couldn't create pid file \"%s\": %s", |
1363 | options.pid_file, strerror(errno)); | 1623 | options.pid_file, strerror(errno)); |
@@ -1367,194 +1627,9 @@ main(int ac, char **av) | |||
1367 | } | 1627 | } |
1368 | } | 1628 | } |
1369 | 1629 | ||
1370 | /* setup fd set for listen */ | 1630 | /* Accept a connection and return in a forked child */ |
1371 | fdset = NULL; | 1631 | server_accept_loop(&sock_in, &sock_out, |
1372 | maxfd = 0; | 1632 | &newsock, config_s); |
1373 | for (i = 0; i < num_listen_socks; i++) | ||
1374 | if (listen_socks[i] > maxfd) | ||
1375 | maxfd = listen_socks[i]; | ||
1376 | /* pipes connected to unauthenticated childs */ | ||
1377 | startup_pipes = xmalloc(options.max_startups * sizeof(int)); | ||
1378 | for (i = 0; i < options.max_startups; i++) | ||
1379 | startup_pipes[i] = -1; | ||
1380 | |||
1381 | /* | ||
1382 | * Stay listening for connections until the system crashes or | ||
1383 | * the daemon is killed with a signal. | ||
1384 | */ | ||
1385 | for (;;) { | ||
1386 | if (received_sighup) | ||
1387 | sighup_restart(); | ||
1388 | if (fdset != NULL) | ||
1389 | xfree(fdset); | ||
1390 | fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); | ||
1391 | fdset = (fd_set *)xmalloc(fdsetsz); | ||
1392 | memset(fdset, 0, fdsetsz); | ||
1393 | |||
1394 | for (i = 0; i < num_listen_socks; i++) | ||
1395 | FD_SET(listen_socks[i], fdset); | ||
1396 | for (i = 0; i < options.max_startups; i++) | ||
1397 | if (startup_pipes[i] != -1) | ||
1398 | FD_SET(startup_pipes[i], fdset); | ||
1399 | |||
1400 | /* Wait in select until there is a connection. */ | ||
1401 | ret = select(maxfd+1, fdset, NULL, NULL, NULL); | ||
1402 | if (ret < 0 && errno != EINTR) | ||
1403 | error("select: %.100s", strerror(errno)); | ||
1404 | if (received_sigterm) { | ||
1405 | logit("Received signal %d; terminating.", | ||
1406 | (int) received_sigterm); | ||
1407 | close_listen_socks(); | ||
1408 | unlink(options.pid_file); | ||
1409 | exit(255); | ||
1410 | } | ||
1411 | if (key_used && key_do_regen) { | ||
1412 | generate_ephemeral_server_key(); | ||
1413 | key_used = 0; | ||
1414 | key_do_regen = 0; | ||
1415 | } | ||
1416 | if (ret < 0) | ||
1417 | continue; | ||
1418 | |||
1419 | for (i = 0; i < options.max_startups; i++) | ||
1420 | if (startup_pipes[i] != -1 && | ||
1421 | FD_ISSET(startup_pipes[i], fdset)) { | ||
1422 | /* | ||
1423 | * the read end of the pipe is ready | ||
1424 | * if the child has closed the pipe | ||
1425 | * after successful authentication | ||
1426 | * or if the child has died | ||
1427 | */ | ||
1428 | close(startup_pipes[i]); | ||
1429 | startup_pipes[i] = -1; | ||
1430 | startups--; | ||
1431 | } | ||
1432 | for (i = 0; i < num_listen_socks; i++) { | ||
1433 | if (!FD_ISSET(listen_socks[i], fdset)) | ||
1434 | continue; | ||
1435 | fromlen = sizeof(from); | ||
1436 | newsock = accept(listen_socks[i], (struct sockaddr *)&from, | ||
1437 | &fromlen); | ||
1438 | if (newsock < 0) { | ||
1439 | if (errno != EINTR && errno != EWOULDBLOCK) | ||
1440 | error("accept: %.100s", strerror(errno)); | ||
1441 | continue; | ||
1442 | } | ||
1443 | if (unset_nonblock(newsock) == -1) { | ||
1444 | close(newsock); | ||
1445 | continue; | ||
1446 | } | ||
1447 | if (drop_connection(startups) == 1) { | ||
1448 | debug("drop connection #%d", startups); | ||
1449 | close(newsock); | ||
1450 | continue; | ||
1451 | } | ||
1452 | if (pipe(startup_p) == -1) { | ||
1453 | close(newsock); | ||
1454 | continue; | ||
1455 | } | ||
1456 | |||
1457 | if (rexec_flag && socketpair(AF_UNIX, | ||
1458 | SOCK_STREAM, 0, config_s) == -1) { | ||
1459 | error("reexec socketpair: %s", | ||
1460 | strerror(errno)); | ||
1461 | close(newsock); | ||
1462 | close(startup_p[0]); | ||
1463 | close(startup_p[1]); | ||
1464 | continue; | ||
1465 | } | ||
1466 | |||
1467 | for (j = 0; j < options.max_startups; j++) | ||
1468 | if (startup_pipes[j] == -1) { | ||
1469 | startup_pipes[j] = startup_p[0]; | ||
1470 | if (maxfd < startup_p[0]) | ||
1471 | maxfd = startup_p[0]; | ||
1472 | startups++; | ||
1473 | break; | ||
1474 | } | ||
1475 | |||
1476 | /* | ||
1477 | * Got connection. Fork a child to handle it, unless | ||
1478 | * we are in debugging mode. | ||
1479 | */ | ||
1480 | if (debug_flag) { | ||
1481 | /* | ||
1482 | * In debugging mode. Close the listening | ||
1483 | * socket, and start processing the | ||
1484 | * connection without forking. | ||
1485 | */ | ||
1486 | debug("Server will not fork when running in debugging mode."); | ||
1487 | close_listen_socks(); | ||
1488 | sock_in = newsock; | ||
1489 | sock_out = newsock; | ||
1490 | close(startup_p[0]); | ||
1491 | close(startup_p[1]); | ||
1492 | startup_pipe = -1; | ||
1493 | pid = getpid(); | ||
1494 | if (rexec_flag) { | ||
1495 | send_rexec_state(config_s[0], | ||
1496 | &cfg); | ||
1497 | close(config_s[0]); | ||
1498 | } | ||
1499 | break; | ||
1500 | } else { | ||
1501 | /* | ||
1502 | * Normal production daemon. Fork, and have | ||
1503 | * the child process the connection. The | ||
1504 | * parent continues listening. | ||
1505 | */ | ||
1506 | if ((pid = fork()) == 0) { | ||
1507 | /* | ||
1508 | * Child. Close the listening and max_startup | ||
1509 | * sockets. Start using the accepted socket. | ||
1510 | * Reinitialize logging (since our pid has | ||
1511 | * changed). We break out of the loop to handle | ||
1512 | * the connection. | ||
1513 | */ | ||
1514 | startup_pipe = startup_p[1]; | ||
1515 | close_startup_pipes(); | ||
1516 | close_listen_socks(); | ||
1517 | sock_in = newsock; | ||
1518 | sock_out = newsock; | ||
1519 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | ||
1520 | if (rexec_flag) | ||
1521 | close(config_s[0]); | ||
1522 | break; | ||
1523 | } | ||
1524 | } | ||
1525 | |||
1526 | /* Parent. Stay in the loop. */ | ||
1527 | if (pid < 0) | ||
1528 | error("fork: %.100s", strerror(errno)); | ||
1529 | else | ||
1530 | debug("Forked child %ld.", (long)pid); | ||
1531 | |||
1532 | close(startup_p[1]); | ||
1533 | |||
1534 | if (rexec_flag) { | ||
1535 | send_rexec_state(config_s[0], &cfg); | ||
1536 | close(config_s[0]); | ||
1537 | close(config_s[1]); | ||
1538 | } | ||
1539 | |||
1540 | /* Mark that the key has been used (it was "given" to the child). */ | ||
1541 | if ((options.protocol & SSH_PROTO_1) && | ||
1542 | key_used == 0) { | ||
1543 | /* Schedule server key regeneration alarm. */ | ||
1544 | signal(SIGALRM, key_regeneration_alarm); | ||
1545 | alarm(options.key_regeneration_time); | ||
1546 | key_used = 1; | ||
1547 | } | ||
1548 | |||
1549 | arc4random_stir(); | ||
1550 | |||
1551 | /* Close the new socket (the child is now taking care of it). */ | ||
1552 | close(newsock); | ||
1553 | } | ||
1554 | /* child process check (or debug mode) */ | ||
1555 | if (num_listen_socks < 0) | ||
1556 | break; | ||
1557 | } | ||
1558 | } | 1633 | } |
1559 | 1634 | ||
1560 | /* This is the child processing a new connection. */ | 1635 | /* This is the child processing a new connection. */ |
@@ -1649,7 +1724,13 @@ main(int ac, char **av) | |||
1649 | * We use get_canonical_hostname with usedns = 0 instead of | 1724 | * We use get_canonical_hostname with usedns = 0 instead of |
1650 | * get_remote_ipaddr here so IP options will be checked. | 1725 | * get_remote_ipaddr here so IP options will be checked. |
1651 | */ | 1726 | */ |
1652 | remote_ip = get_canonical_hostname(0); | 1727 | (void) get_canonical_hostname(0); |
1728 | /* | ||
1729 | * The rest of the code depends on the fact that | ||
1730 | * get_remote_ipaddr() caches the remote ip, even if | ||
1731 | * the socket goes away. | ||
1732 | */ | ||
1733 | remote_ip = get_remote_ipaddr(); | ||
1653 | 1734 | ||
1654 | #ifdef SSH_AUDIT_EVENTS | 1735 | #ifdef SSH_AUDIT_EVENTS |
1655 | audit_connection_from(remote_ip, remote_port); | 1736 | audit_connection_from(remote_ip, remote_port); |
@@ -1691,8 +1772,7 @@ main(int ac, char **av) | |||
1691 | packet_set_nonblocking(); | 1772 | packet_set_nonblocking(); |
1692 | 1773 | ||
1693 | /* allocate authentication context */ | 1774 | /* allocate authentication context */ |
1694 | authctxt = xmalloc(sizeof(*authctxt)); | 1775 | authctxt = xcalloc(1, sizeof(*authctxt)); |
1695 | memset(authctxt, 0, sizeof(*authctxt)); | ||
1696 | 1776 | ||
1697 | authctxt->loginmsg = &loginmsg; | 1777 | authctxt->loginmsg = &loginmsg; |
1698 | 1778 | ||
@@ -1731,6 +1811,7 @@ main(int ac, char **av) | |||
1731 | */ | 1811 | */ |
1732 | alarm(0); | 1812 | alarm(0); |
1733 | signal(SIGALRM, SIG_DFL); | 1813 | signal(SIGALRM, SIG_DFL); |
1814 | authctxt->authenticated = 1; | ||
1734 | if (startup_pipe != -1) { | 1815 | if (startup_pipe != -1) { |
1735 | close(startup_pipe); | 1816 | close(startup_pipe); |
1736 | startup_pipe = -1; | 1817 | startup_pipe = -1; |
@@ -1783,11 +1864,14 @@ ssh1_session_key(BIGNUM *session_key_int) | |||
1783 | { | 1864 | { |
1784 | int rsafail = 0; | 1865 | int rsafail = 0; |
1785 | 1866 | ||
1786 | if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { | 1867 | if (BN_cmp(sensitive_data.server_key->rsa->n, |
1868 | sensitive_data.ssh1_host_key->rsa->n) > 0) { | ||
1787 | /* Server key has bigger modulus. */ | 1869 | /* Server key has bigger modulus. */ |
1788 | if (BN_num_bits(sensitive_data.server_key->rsa->n) < | 1870 | if (BN_num_bits(sensitive_data.server_key->rsa->n) < |
1789 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { | 1871 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + |
1790 | fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", | 1872 | SSH_KEY_BITS_RESERVED) { |
1873 | fatal("do_connection: %s: " | ||
1874 | "server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", | ||
1791 | get_remote_ipaddr(), | 1875 | get_remote_ipaddr(), |
1792 | BN_num_bits(sensitive_data.server_key->rsa->n), | 1876 | BN_num_bits(sensitive_data.server_key->rsa->n), |
1793 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), | 1877 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), |
@@ -1802,8 +1886,10 @@ ssh1_session_key(BIGNUM *session_key_int) | |||
1802 | } else { | 1886 | } else { |
1803 | /* Host key has bigger modulus (or they are equal). */ | 1887 | /* Host key has bigger modulus (or they are equal). */ |
1804 | if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < | 1888 | if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < |
1805 | BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { | 1889 | BN_num_bits(sensitive_data.server_key->rsa->n) + |
1806 | fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", | 1890 | SSH_KEY_BITS_RESERVED) { |
1891 | fatal("do_connection: %s: " | ||
1892 | "host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", | ||
1807 | get_remote_ipaddr(), | 1893 | get_remote_ipaddr(), |
1808 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), | 1894 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), |
1809 | BN_num_bits(sensitive_data.server_key->rsa->n), | 1895 | BN_num_bits(sensitive_data.server_key->rsa->n), |
@@ -1928,10 +2014,10 @@ do_ssh1_kex(void) | |||
1928 | * key is in the highest bits. | 2014 | * key is in the highest bits. |
1929 | */ | 2015 | */ |
1930 | if (!rsafail) { | 2016 | if (!rsafail) { |
1931 | BN_mask_bits(session_key_int, sizeof(session_key) * 8); | 2017 | (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8); |
1932 | len = BN_num_bytes(session_key_int); | 2018 | len = BN_num_bytes(session_key_int); |
1933 | if (len < 0 || (u_int)len > sizeof(session_key)) { | 2019 | if (len < 0 || (u_int)len > sizeof(session_key)) { |
1934 | error("do_connection: bad session key len from %s: " | 2020 | error("do_ssh1_kex: bad session key len from %s: " |
1935 | "session_key_int %d > sizeof(session_key) %lu", | 2021 | "session_key_int %d > sizeof(session_key) %lu", |
1936 | get_remote_ipaddr(), len, (u_long)sizeof(session_key)); | 2022 | get_remote_ipaddr(), len, (u_long)sizeof(session_key)); |
1937 | rsafail++; | 2023 | rsafail++; |
@@ -2024,7 +2110,7 @@ do_ssh2_kex(void) | |||
2024 | myproposal[PROPOSAL_COMP_ALGS_CTOS] = | 2110 | myproposal[PROPOSAL_COMP_ALGS_CTOS] = |
2025 | myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; | 2111 | myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; |
2026 | } | 2112 | } |
2027 | 2113 | ||
2028 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); | 2114 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); |
2029 | 2115 | ||
2030 | /* start key exchange */ | 2116 | /* start key exchange */ |
@@ -2032,6 +2118,7 @@ do_ssh2_kex(void) | |||
2032 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; | 2118 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; |
2033 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; | 2119 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; |
2034 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; | 2120 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
2121 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; | ||
2035 | kex->server = 1; | 2122 | kex->server = 1; |
2036 | kex->client_version_string=client_version_string; | 2123 | kex->client_version_string=client_version_string; |
2037 | kex->server_version_string=server_version_string; | 2124 | kex->server_version_string=server_version_string; |