diff options
author | Colin Watson <cjwatson@debian.org> | 2007-06-12 16:16:35 +0000 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2007-06-12 16:16:35 +0000 |
commit | b7e40fa9da0b5491534a429dadb321eab5a77558 (patch) | |
tree | bed1da11e9f829925797aa093e379fc0b5868ecd /sshd.c | |
parent | 4f84beedf1005e44ff33c854abd6b711ffc0adb7 (diff) | |
parent | 086ea76990b1e6287c24b6db74adffd4605eb3b0 (diff) |
* New upstream release (closes: #395507, #397961, #420035). Important
changes not previously backported to 4.3p2:
- 4.4/4.4p1 (http://www.openssh.org/txt/release-4.4):
+ On portable OpenSSH, fix a GSSAPI authentication abort that could be
used to determine the validity of usernames on some platforms.
+ Implemented conditional configuration in sshd_config(5) using the
"Match" directive. This allows some configuration options to be
selectively overridden if specific criteria (based on user, group,
hostname and/or address) are met. So far a useful subset of
post-authentication options are supported and more are expected to
be added in future releases.
+ Add support for Diffie-Hellman group exchange key agreement with a
final hash of SHA256.
+ Added a "ForceCommand" directive to sshd_config(5). Similar to the
command="..." option accepted in ~/.ssh/authorized_keys, this forces
the execution of the specified command regardless of what the user
requested. This is very useful in conjunction with the new "Match"
option.
+ Add a "PermitOpen" directive to sshd_config(5). This mirrors the
permitopen="..." authorized_keys option, allowing fine-grained
control over the port-forwardings that a user is allowed to
establish.
+ Add optional logging of transactions to sftp-server(8).
+ ssh(1) will now record port numbers for hosts stored in
~/.ssh/known_hosts when a non-standard port has been requested
(closes: #50612).
+ Add an "ExitOnForwardFailure" option to cause ssh(1) to exit (with a
non-zero exit code) when requested port forwardings could not be
established.
+ Extend sshd_config(5) "SubSystem" declarations to allow the
specification of command-line arguments.
+ Replacement of all integer overflow susceptible invocations of
malloc(3) and realloc(3) with overflow-checking equivalents.
+ Many manpage fixes and improvements.
+ Add optional support for OpenSSL hardware accelerators (engines),
enabled using the --with-ssl-engine configure option.
+ Tokens in configuration files may be double-quoted in order to
contain spaces (closes: #319639).
+ Move a debug() call out of a SIGCHLD handler, fixing a hang when the
session exits very quickly (closes: #307890).
+ Fix some incorrect buffer allocation calculations (closes: #410599).
+ ssh-add doesn't ask for a passphrase if key file permissions are too
liberal (closes: #103677).
+ Likewise, ssh doesn't ask either (closes: #99675).
- 4.6/4.6p1 (http://www.openssh.org/txt/release-4.6):
+ sshd now allows the enabling and disabling of authentication methods
on a per user, group, host and network basis via the Match directive
in sshd_config.
+ Fixed an inconsistent check for a terminal when displaying scp
progress meter (closes: #257524).
+ Fix "hang on exit" when background processes are running at the time
of exit on a ttyful/login session (closes: #88337).
* Update to current GSSAPI patch from
http://www.sxw.org.uk/computing/patches/openssh-4.6p1-gsskex-20070312.patch;
install ChangeLog.gssapi.
Diffstat (limited to 'sshd.c')
-rw-r--r-- | sshd.c | 809 |
1 files changed, 447 insertions, 362 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 USE_SECURITY_SESSION_API | 120 | #ifdef USE_SECURITY_SESSION_API |
90 | #include <Security/AuthSession.h> | 121 | #include <Security/AuthSession.h> |
@@ -205,15 +236,21 @@ int *startup_pipes = NULL; | |||
205 | int startup_pipe; /* in child */ | 236 | int startup_pipe; /* in child */ |
206 | 237 | ||
207 | /* variables used for privilege separation */ | 238 | /* variables used for privilege separation */ |
208 | int use_privsep; | 239 | int use_privsep = -1; |
209 | struct monitor *pmonitor = NULL; | 240 | struct monitor *pmonitor = NULL; |
210 | 241 | ||
211 | /* global authentication context */ | 242 | /* global authentication context */ |
212 | Authctxt *the_authctxt = NULL; | 243 | Authctxt *the_authctxt = NULL; |
213 | 244 | ||
245 | /* sshd_config buffer */ | ||
246 | Buffer cfg; | ||
247 | |||
214 | /* message to be displayed after login */ | 248 | /* message to be displayed after login */ |
215 | Buffer loginmsg; | 249 | Buffer loginmsg; |
216 | 250 | ||
251 | /* Unprivileged user */ | ||
252 | struct passwd *privsep_pw = NULL; | ||
253 | |||
217 | /* Prototypes for various functions defined later in this file. */ | 254 | /* Prototypes for various functions defined later in this file. */ |
218 | void destroy_sensitive_data(void); | 255 | void destroy_sensitive_data(void); |
219 | void demote_sensitive_data(void); | 256 | void demote_sensitive_data(void); |
@@ -250,6 +287,8 @@ close_startup_pipes(void) | |||
250 | * the effect is to reread the configuration file (and to regenerate | 287 | * the effect is to reread the configuration file (and to regenerate |
251 | * the server key). | 288 | * the server key). |
252 | */ | 289 | */ |
290 | |||
291 | /*ARGSUSED*/ | ||
253 | static void | 292 | static void |
254 | sighup_handler(int sig) | 293 | sighup_handler(int sig) |
255 | { | 294 | { |
@@ -270,6 +309,7 @@ sighup_restart(void) | |||
270 | logit("Received SIGHUP; restarting."); | 309 | logit("Received SIGHUP; restarting."); |
271 | close_listen_socks(); | 310 | close_listen_socks(); |
272 | close_startup_pipes(); | 311 | close_startup_pipes(); |
312 | alarm(0); /* alarm timer persists across exec */ | ||
273 | execv(saved_argv[0], saved_argv); | 313 | execv(saved_argv[0], saved_argv); |
274 | logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], | 314 | logit("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], |
275 | strerror(errno)); | 315 | strerror(errno)); |
@@ -279,6 +319,7 @@ sighup_restart(void) | |||
279 | /* | 319 | /* |
280 | * Generic signal handler for terminating signals in the master daemon. | 320 | * Generic signal handler for terminating signals in the master daemon. |
281 | */ | 321 | */ |
322 | /*ARGSUSED*/ | ||
282 | static void | 323 | static void |
283 | sigterm_handler(int sig) | 324 | sigterm_handler(int sig) |
284 | { | 325 | { |
@@ -289,6 +330,7 @@ sigterm_handler(int sig) | |||
289 | * SIGCHLD handler. This is called whenever a child dies. This will then | 330 | * SIGCHLD handler. This is called whenever a child dies. This will then |
290 | * reap any zombies left by exited children. | 331 | * reap any zombies left by exited children. |
291 | */ | 332 | */ |
333 | /*ARGSUSED*/ | ||
292 | static void | 334 | static void |
293 | main_sigchld_handler(int sig) | 335 | main_sigchld_handler(int sig) |
294 | { | 336 | { |
@@ -307,6 +349,7 @@ main_sigchld_handler(int sig) | |||
307 | /* | 349 | /* |
308 | * Signal handler for the alarm after the login grace period has expired. | 350 | * Signal handler for the alarm after the login grace period has expired. |
309 | */ | 351 | */ |
352 | /*ARGSUSED*/ | ||
310 | static void | 353 | static void |
311 | grace_alarm_handler(int sig) | 354 | grace_alarm_handler(int sig) |
312 | { | 355 | { |
@@ -347,6 +390,7 @@ generate_ephemeral_server_key(void) | |||
347 | arc4random_stir(); | 390 | arc4random_stir(); |
348 | } | 391 | } |
349 | 392 | ||
393 | /*ARGSUSED*/ | ||
350 | static void | 394 | static void |
351 | key_regeneration_alarm(int sig) | 395 | key_regeneration_alarm(int sig) |
352 | { | 396 | { |
@@ -543,7 +587,6 @@ privsep_preauth_child(void) | |||
543 | { | 587 | { |
544 | u_int32_t rnd[256]; | 588 | u_int32_t rnd[256]; |
545 | gid_t gidset[1]; | 589 | gid_t gidset[1]; |
546 | struct passwd *pw; | ||
547 | int i; | 590 | int i; |
548 | 591 | ||
549 | /* Enable challenge-response authentication for privilege separation */ | 592 | /* Enable challenge-response authentication for privilege separation */ |
@@ -556,12 +599,6 @@ privsep_preauth_child(void) | |||
556 | /* Demote the private keys to public keys. */ | 599 | /* Demote the private keys to public keys. */ |
557 | demote_sensitive_data(); | 600 | demote_sensitive_data(); |
558 | 601 | ||
559 | if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) | ||
560 | fatal("Privilege separation user %s does not exist", | ||
561 | SSH_PRIVSEP_USER); | ||
562 | memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); | ||
563 | endpwent(); | ||
564 | |||
565 | /* Change our root directory */ | 602 | /* Change our root directory */ |
566 | if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) | 603 | if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) |
567 | fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, | 604 | fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, |
@@ -570,16 +607,16 @@ privsep_preauth_child(void) | |||
570 | fatal("chdir(\"/\"): %s", strerror(errno)); | 607 | fatal("chdir(\"/\"): %s", strerror(errno)); |
571 | 608 | ||
572 | /* Drop our privileges */ | 609 | /* Drop our privileges */ |
573 | debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, | 610 | debug3("privsep user:group %u:%u", (u_int)privsep_pw->pw_uid, |
574 | (u_int)pw->pw_gid); | 611 | (u_int)privsep_pw->pw_gid); |
575 | #if 0 | 612 | #if 0 |
576 | /* XXX not ready, too heavy after chroot */ | 613 | /* XXX not ready, too heavy after chroot */ |
577 | do_setusercontext(pw); | 614 | do_setusercontext(privsep_pw); |
578 | #else | 615 | #else |
579 | gidset[0] = pw->pw_gid; | 616 | gidset[0] = privsep_pw->pw_gid; |
580 | if (setgroups(1, gidset) < 0) | 617 | if (setgroups(1, gidset) < 0) |
581 | fatal("setgroups: %.100s", strerror(errno)); | 618 | fatal("setgroups: %.100s", strerror(errno)); |
582 | permanently_set_uid(pw); | 619 | permanently_set_uid(privsep_pw); |
583 | #endif | 620 | #endif |
584 | } | 621 | } |
585 | 622 | ||
@@ -868,6 +905,325 @@ recv_rexec_state(int fd, Buffer *conf) | |||
868 | debug3("%s: done", __func__); | 905 | debug3("%s: done", __func__); |
869 | } | 906 | } |
870 | 907 | ||
908 | /* Accept a connection from inetd */ | ||
909 | static void | ||
910 | server_accept_inetd(int *sock_in, int *sock_out) | ||
911 | { | ||
912 | int fd; | ||
913 | |||
914 | startup_pipe = -1; | ||
915 | if (rexeced_flag) { | ||
916 | close(REEXEC_CONFIG_PASS_FD); | ||
917 | *sock_in = *sock_out = dup(STDIN_FILENO); | ||
918 | if (!debug_flag) { | ||
919 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | ||
920 | close(REEXEC_STARTUP_PIPE_FD); | ||
921 | } | ||
922 | } else { | ||
923 | *sock_in = dup(STDIN_FILENO); | ||
924 | *sock_out = dup(STDOUT_FILENO); | ||
925 | } | ||
926 | /* | ||
927 | * We intentionally do not close the descriptors 0, 1, and 2 | ||
928 | * as our code for setting the descriptors won't work if | ||
929 | * ttyfd happens to be one of those. | ||
930 | */ | ||
931 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
932 | dup2(fd, STDIN_FILENO); | ||
933 | dup2(fd, STDOUT_FILENO); | ||
934 | if (fd > STDOUT_FILENO) | ||
935 | close(fd); | ||
936 | } | ||
937 | debug("inetd sockets after dupping: %d, %d", *sock_in, *sock_out); | ||
938 | } | ||
939 | |||
940 | /* | ||
941 | * Listen for TCP connections | ||
942 | */ | ||
943 | static void | ||
944 | server_listen(void) | ||
945 | { | ||
946 | int ret, listen_sock, on = 1; | ||
947 | struct addrinfo *ai; | ||
948 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | ||
949 | |||
950 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { | ||
951 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | ||
952 | continue; | ||
953 | if (num_listen_socks >= MAX_LISTEN_SOCKS) | ||
954 | fatal("Too many listen sockets. " | ||
955 | "Enlarge MAX_LISTEN_SOCKS"); | ||
956 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, | ||
957 | ntop, sizeof(ntop), strport, sizeof(strport), | ||
958 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | ||
959 | error("getnameinfo failed: %.100s", | ||
960 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | ||
961 | strerror(errno)); | ||
962 | continue; | ||
963 | } | ||
964 | /* Create socket for listening. */ | ||
965 | listen_sock = socket(ai->ai_family, ai->ai_socktype, | ||
966 | ai->ai_protocol); | ||
967 | if (listen_sock < 0) { | ||
968 | /* kernel may not support ipv6 */ | ||
969 | verbose("socket: %.100s", strerror(errno)); | ||
970 | continue; | ||
971 | } | ||
972 | if (set_nonblock(listen_sock) == -1) { | ||
973 | close(listen_sock); | ||
974 | continue; | ||
975 | } | ||
976 | /* | ||
977 | * Set socket options. | ||
978 | * Allow local port reuse in TIME_WAIT. | ||
979 | */ | ||
980 | if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, | ||
981 | &on, sizeof(on)) == -1) | ||
982 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | ||
983 | |||
984 | debug("Bind to port %s on %s.", strport, ntop); | ||
985 | |||
986 | /* Bind the socket to the desired port. */ | ||
987 | if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { | ||
988 | error("Bind to port %s on %s failed: %.200s.", | ||
989 | strport, ntop, strerror(errno)); | ||
990 | close(listen_sock); | ||
991 | continue; | ||
992 | } | ||
993 | listen_socks[num_listen_socks] = listen_sock; | ||
994 | num_listen_socks++; | ||
995 | |||
996 | /* Start listening on the port. */ | ||
997 | if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) | ||
998 | fatal("listen on [%s]:%s: %.100s", | ||
999 | ntop, strport, strerror(errno)); | ||
1000 | logit("Server listening on %s port %s.", ntop, strport); | ||
1001 | } | ||
1002 | freeaddrinfo(options.listen_addrs); | ||
1003 | |||
1004 | if (!num_listen_socks) | ||
1005 | fatal("Cannot bind any address."); | ||
1006 | } | ||
1007 | |||
1008 | /* | ||
1009 | * The main TCP accept loop. Note that, for the non-debug case, returns | ||
1010 | * from this function are in a forked subprocess. | ||
1011 | */ | ||
1012 | static void | ||
1013 | server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) | ||
1014 | { | ||
1015 | fd_set *fdset; | ||
1016 | int i, j, ret, maxfd; | ||
1017 | int key_used = 0, startups = 0; | ||
1018 | int startup_p[2] = { -1 , -1 }; | ||
1019 | struct sockaddr_storage from; | ||
1020 | socklen_t fromlen; | ||
1021 | pid_t pid; | ||
1022 | |||
1023 | /* setup fd set for accept */ | ||
1024 | fdset = NULL; | ||
1025 | maxfd = 0; | ||
1026 | for (i = 0; i < num_listen_socks; i++) | ||
1027 | if (listen_socks[i] > maxfd) | ||
1028 | maxfd = listen_socks[i]; | ||
1029 | /* pipes connected to unauthenticated childs */ | ||
1030 | startup_pipes = xcalloc(options.max_startups, sizeof(int)); | ||
1031 | for (i = 0; i < options.max_startups; i++) | ||
1032 | startup_pipes[i] = -1; | ||
1033 | |||
1034 | /* | ||
1035 | * Stay listening for connections until the system crashes or | ||
1036 | * the daemon is killed with a signal. | ||
1037 | */ | ||
1038 | for (;;) { | ||
1039 | if (received_sighup) | ||
1040 | sighup_restart(); | ||
1041 | if (fdset != NULL) | ||
1042 | xfree(fdset); | ||
1043 | fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS), | ||
1044 | sizeof(fd_mask)); | ||
1045 | |||
1046 | for (i = 0; i < num_listen_socks; i++) | ||
1047 | FD_SET(listen_socks[i], fdset); | ||
1048 | for (i = 0; i < options.max_startups; i++) | ||
1049 | if (startup_pipes[i] != -1) | ||
1050 | FD_SET(startup_pipes[i], fdset); | ||
1051 | |||
1052 | /* Wait in select until there is a connection. */ | ||
1053 | ret = select(maxfd+1, fdset, NULL, NULL, NULL); | ||
1054 | if (ret < 0 && errno != EINTR) | ||
1055 | error("select: %.100s", strerror(errno)); | ||
1056 | if (received_sigterm) { | ||
1057 | logit("Received signal %d; terminating.", | ||
1058 | (int) received_sigterm); | ||
1059 | close_listen_socks(); | ||
1060 | unlink(options.pid_file); | ||
1061 | exit(255); | ||
1062 | } | ||
1063 | if (key_used && key_do_regen) { | ||
1064 | generate_ephemeral_server_key(); | ||
1065 | key_used = 0; | ||
1066 | key_do_regen = 0; | ||
1067 | } | ||
1068 | if (ret < 0) | ||
1069 | continue; | ||
1070 | |||
1071 | for (i = 0; i < options.max_startups; i++) | ||
1072 | if (startup_pipes[i] != -1 && | ||
1073 | FD_ISSET(startup_pipes[i], fdset)) { | ||
1074 | /* | ||
1075 | * the read end of the pipe is ready | ||
1076 | * if the child has closed the pipe | ||
1077 | * after successful authentication | ||
1078 | * or if the child has died | ||
1079 | */ | ||
1080 | close(startup_pipes[i]); | ||
1081 | startup_pipes[i] = -1; | ||
1082 | startups--; | ||
1083 | } | ||
1084 | for (i = 0; i < num_listen_socks; i++) { | ||
1085 | if (!FD_ISSET(listen_socks[i], fdset)) | ||
1086 | continue; | ||
1087 | fromlen = sizeof(from); | ||
1088 | *newsock = accept(listen_socks[i], | ||
1089 | (struct sockaddr *)&from, &fromlen); | ||
1090 | if (*newsock < 0) { | ||
1091 | if (errno != EINTR && errno != EWOULDBLOCK) | ||
1092 | error("accept: %.100s", strerror(errno)); | ||
1093 | continue; | ||
1094 | } | ||
1095 | if (unset_nonblock(*newsock) == -1) { | ||
1096 | close(*newsock); | ||
1097 | continue; | ||
1098 | } | ||
1099 | if (drop_connection(startups) == 1) { | ||
1100 | debug("drop connection #%d", startups); | ||
1101 | close(*newsock); | ||
1102 | continue; | ||
1103 | } | ||
1104 | if (pipe(startup_p) == -1) { | ||
1105 | close(*newsock); | ||
1106 | continue; | ||
1107 | } | ||
1108 | |||
1109 | if (rexec_flag && socketpair(AF_UNIX, | ||
1110 | SOCK_STREAM, 0, config_s) == -1) { | ||
1111 | error("reexec socketpair: %s", | ||
1112 | strerror(errno)); | ||
1113 | close(*newsock); | ||
1114 | close(startup_p[0]); | ||
1115 | close(startup_p[1]); | ||
1116 | continue; | ||
1117 | } | ||
1118 | |||
1119 | for (j = 0; j < options.max_startups; j++) | ||
1120 | if (startup_pipes[j] == -1) { | ||
1121 | startup_pipes[j] = startup_p[0]; | ||
1122 | if (maxfd < startup_p[0]) | ||
1123 | maxfd = startup_p[0]; | ||
1124 | startups++; | ||
1125 | break; | ||
1126 | } | ||
1127 | |||
1128 | /* | ||
1129 | * Got connection. Fork a child to handle it, unless | ||
1130 | * we are in debugging mode. | ||
1131 | */ | ||
1132 | if (debug_flag) { | ||
1133 | /* | ||
1134 | * In debugging mode. Close the listening | ||
1135 | * socket, and start processing the | ||
1136 | * connection without forking. | ||
1137 | */ | ||
1138 | debug("Server will not fork when running in debugging mode."); | ||
1139 | close_listen_socks(); | ||
1140 | *sock_in = *newsock; | ||
1141 | *sock_out = *newsock; | ||
1142 | close(startup_p[0]); | ||
1143 | close(startup_p[1]); | ||
1144 | startup_pipe = -1; | ||
1145 | pid = getpid(); | ||
1146 | if (rexec_flag) { | ||
1147 | send_rexec_state(config_s[0], | ||
1148 | &cfg); | ||
1149 | close(config_s[0]); | ||
1150 | } | ||
1151 | break; | ||
1152 | } | ||
1153 | |||
1154 | /* | ||
1155 | * Normal production daemon. Fork, and have | ||
1156 | * the child process the connection. The | ||
1157 | * parent continues listening. | ||
1158 | */ | ||
1159 | platform_pre_fork(); | ||
1160 | if ((pid = fork()) == 0) { | ||
1161 | /* | ||
1162 | * Child. Close the listening and | ||
1163 | * max_startup sockets. Start using | ||
1164 | * the accepted socket. Reinitialize | ||
1165 | * logging (since our pid has changed). | ||
1166 | * We break out of the loop to handle | ||
1167 | * the connection. | ||
1168 | */ | ||
1169 | platform_post_fork_child(); | ||
1170 | startup_pipe = startup_p[1]; | ||
1171 | close_startup_pipes(); | ||
1172 | close_listen_socks(); | ||
1173 | *sock_in = *newsock; | ||
1174 | *sock_out = *newsock; | ||
1175 | log_init(__progname, | ||
1176 | options.log_level, | ||
1177 | options.log_facility, | ||
1178 | log_stderr); | ||
1179 | if (rexec_flag) | ||
1180 | close(config_s[0]); | ||
1181 | break; | ||
1182 | } | ||
1183 | |||
1184 | /* Parent. Stay in the loop. */ | ||
1185 | platform_post_fork_parent(pid); | ||
1186 | if (pid < 0) | ||
1187 | error("fork: %.100s", strerror(errno)); | ||
1188 | else | ||
1189 | debug("Forked child %ld.", (long)pid); | ||
1190 | |||
1191 | close(startup_p[1]); | ||
1192 | |||
1193 | if (rexec_flag) { | ||
1194 | send_rexec_state(config_s[0], &cfg); | ||
1195 | close(config_s[0]); | ||
1196 | close(config_s[1]); | ||
1197 | } | ||
1198 | |||
1199 | /* | ||
1200 | * Mark that the key has been used (it | ||
1201 | * was "given" to the child). | ||
1202 | */ | ||
1203 | if ((options.protocol & SSH_PROTO_1) && | ||
1204 | key_used == 0) { | ||
1205 | /* Schedule server key regeneration alarm. */ | ||
1206 | signal(SIGALRM, key_regeneration_alarm); | ||
1207 | alarm(options.key_regeneration_time); | ||
1208 | key_used = 1; | ||
1209 | } | ||
1210 | |||
1211 | close(*newsock); | ||
1212 | |||
1213 | /* | ||
1214 | * Ensure that our random state differs | ||
1215 | * from that of the child | ||
1216 | */ | ||
1217 | arc4random_stir(); | ||
1218 | } | ||
1219 | |||
1220 | /* child process check (or debug mode) */ | ||
1221 | if (num_listen_socks < 0) | ||
1222 | break; | ||
1223 | } | ||
1224 | } | ||
1225 | |||
1226 | |||
871 | /* | 1227 | /* |
872 | * Main program for the daemon. | 1228 | * Main program for the daemon. |
873 | */ | 1229 | */ |
@@ -876,25 +1232,14 @@ main(int ac, char **av) | |||
876 | { | 1232 | { |
877 | extern char *optarg; | 1233 | extern char *optarg; |
878 | extern int optind; | 1234 | extern int optind; |
879 | int opt, j, i, fdsetsz, on = 1; | 1235 | int opt, i, on = 1; |
880 | int sock_in = -1, sock_out = -1, newsock = -1; | 1236 | int sock_in = -1, sock_out = -1, newsock = -1; |
881 | pid_t pid; | ||
882 | socklen_t fromlen; | ||
883 | fd_set *fdset; | ||
884 | struct sockaddr_storage from; | ||
885 | const char *remote_ip; | 1237 | const char *remote_ip; |
886 | int remote_port; | 1238 | int remote_port; |
887 | FILE *f; | ||
888 | struct addrinfo *ai; | ||
889 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | ||
890 | char *line; | 1239 | char *line; |
891 | int listen_sock, maxfd; | 1240 | int config_s[2] = { -1 , -1 }; |
892 | int startup_p[2] = { -1 , -1 }, config_s[2] = { -1 , -1 }; | ||
893 | int startups = 0; | ||
894 | Key *key; | 1241 | Key *key; |
895 | Authctxt *authctxt; | 1242 | Authctxt *authctxt; |
896 | int ret, key_used = 0; | ||
897 | Buffer cfg; | ||
898 | 1243 | ||
899 | #ifdef HAVE_SECUREWARE | 1244 | #ifdef HAVE_SECUREWARE |
900 | (void)set_auth_parameters(ac, av); | 1245 | (void)set_auth_parameters(ac, av); |
@@ -905,7 +1250,7 @@ main(int ac, char **av) | |||
905 | /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ | 1250 | /* Save argv. Duplicate so setproctitle emulation doesn't clobber it */ |
906 | saved_argc = ac; | 1251 | saved_argc = ac; |
907 | rexec_argc = ac; | 1252 | rexec_argc = ac; |
908 | saved_argv = xmalloc(sizeof(*saved_argv) * (ac + 1)); | 1253 | saved_argv = xcalloc(ac + 1, sizeof(*saved_argv)); |
909 | for (i = 0; i < ac; i++) | 1254 | for (i = 0; i < ac; i++) |
910 | saved_argv[i] = xstrdup(av[i]); | 1255 | saved_argv[i] = xstrdup(av[i]); |
911 | saved_argv[i] = NULL; | 1256 | saved_argv[i] = NULL; |
@@ -972,7 +1317,8 @@ main(int ac, char **av) | |||
972 | } | 1317 | } |
973 | break; | 1318 | break; |
974 | case 'b': | 1319 | case 'b': |
975 | options.server_key_bits = atoi(optarg); | 1320 | options.server_key_bits = (int)strtonum(optarg, 256, |
1321 | 32768, NULL); | ||
976 | break; | 1322 | break; |
977 | case 'p': | 1323 | case 'p': |
978 | options.ports_from_cmdline = 1; | 1324 | options.ports_from_cmdline = 1; |
@@ -1009,7 +1355,7 @@ main(int ac, char **av) | |||
1009 | test_flag = 1; | 1355 | test_flag = 1; |
1010 | break; | 1356 | break; |
1011 | case 'u': | 1357 | case 'u': |
1012 | utmp_len = atoi(optarg); | 1358 | utmp_len = (u_int)strtonum(optarg, 0, MAXHOSTNAMELEN+1, NULL); |
1013 | if (utmp_len > MAXHOSTNAMELEN) { | 1359 | if (utmp_len > MAXHOSTNAMELEN) { |
1014 | fprintf(stderr, "Invalid utmp length.\n"); | 1360 | fprintf(stderr, "Invalid utmp length.\n"); |
1015 | exit(1); | 1361 | exit(1); |
@@ -1018,7 +1364,7 @@ main(int ac, char **av) | |||
1018 | case 'o': | 1364 | case 'o': |
1019 | line = xstrdup(optarg); | 1365 | line = xstrdup(optarg); |
1020 | if (process_server_config_line(&options, line, | 1366 | if (process_server_config_line(&options, line, |
1021 | "command-line", 0) != 0) | 1367 | "command-line", 0, NULL, NULL, NULL, NULL) != 0) |
1022 | exit(1); | 1368 | exit(1); |
1023 | xfree(line); | 1369 | xfree(line); |
1024 | break; | 1370 | break; |
@@ -1076,11 +1422,8 @@ main(int ac, char **av) | |||
1076 | else | 1422 | else |
1077 | load_server_config(config_file_name, &cfg); | 1423 | load_server_config(config_file_name, &cfg); |
1078 | 1424 | ||
1079 | parse_server_config(&options, | 1425 | parse_server_config(&options, rexeced_flag ? "rexec" : config_file_name, |
1080 | rexeced_flag ? "rexec" : config_file_name, &cfg); | 1426 | &cfg, NULL, NULL, NULL); |
1081 | |||
1082 | if (!rexec_flag) | ||
1083 | buffer_free(&cfg); | ||
1084 | 1427 | ||
1085 | seed_rng(); | 1428 | seed_rng(); |
1086 | 1429 | ||
@@ -1098,8 +1441,21 @@ main(int ac, char **av) | |||
1098 | 1441 | ||
1099 | debug("sshd version %.100s", SSH_RELEASE); | 1442 | debug("sshd version %.100s", SSH_RELEASE); |
1100 | 1443 | ||
1444 | /* Store privilege separation user for later use if required. */ | ||
1445 | if ((privsep_pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) { | ||
1446 | if (use_privsep || options.kerberos_authentication) | ||
1447 | fatal("Privilege separation user %s does not exist", | ||
1448 | SSH_PRIVSEP_USER); | ||
1449 | } else { | ||
1450 | memset(privsep_pw->pw_passwd, 0, strlen(privsep_pw->pw_passwd)); | ||
1451 | privsep_pw = pwcopy(privsep_pw); | ||
1452 | xfree(privsep_pw->pw_passwd); | ||
1453 | privsep_pw->pw_passwd = xstrdup("*"); | ||
1454 | } | ||
1455 | endpwent(); | ||
1456 | |||
1101 | /* load private host keys */ | 1457 | /* load private host keys */ |
1102 | sensitive_data.host_keys = xmalloc(options.num_host_key_files * | 1458 | sensitive_data.host_keys = xcalloc(options.num_host_key_files, |
1103 | sizeof(Key *)); | 1459 | sizeof(Key *)); |
1104 | for (i = 0; i < options.num_host_key_files; i++) | 1460 | for (i = 0; i < options.num_host_key_files; i++) |
1105 | sensitive_data.host_keys[i] = NULL; | 1461 | sensitive_data.host_keys[i] = NULL; |
@@ -1168,12 +1524,8 @@ main(int ac, char **av) | |||
1168 | } | 1524 | } |
1169 | 1525 | ||
1170 | if (use_privsep) { | 1526 | if (use_privsep) { |
1171 | struct passwd *pw; | ||
1172 | struct stat st; | 1527 | struct stat st; |
1173 | 1528 | ||
1174 | if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) | ||
1175 | fatal("Privilege separation user %s does not exist", | ||
1176 | SSH_PRIVSEP_USER); | ||
1177 | if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || | 1529 | if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || |
1178 | (S_ISDIR(st.st_mode) == 0)) | 1530 | (S_ISDIR(st.st_mode) == 0)) |
1179 | fatal("Missing privilege separation directory: %s", | 1531 | fatal("Missing privilege separation directory: %s", |
@@ -1205,7 +1557,7 @@ main(int ac, char **av) | |||
1205 | debug("setgroups() failed: %.200s", strerror(errno)); | 1557 | debug("setgroups() failed: %.200s", strerror(errno)); |
1206 | 1558 | ||
1207 | if (rexec_flag) { | 1559 | if (rexec_flag) { |
1208 | rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2)); | 1560 | rexec_argv = xcalloc(rexec_argc + 2, sizeof(char *)); |
1209 | for (i = 0; i < rexec_argc; i++) { | 1561 | for (i = 0; i < rexec_argc; i++) { |
1210 | debug("rexec_argv[%d]='%s'", i, saved_argv[i]); | 1562 | debug("rexec_argv[%d]='%s'", i, saved_argv[i]); |
1211 | rexec_argv[i] = saved_argv[i]; | 1563 | rexec_argv[i] = saved_argv[i]; |
@@ -1253,121 +1605,31 @@ main(int ac, char **av) | |||
1253 | /* ignore SIGPIPE */ | 1605 | /* ignore SIGPIPE */ |
1254 | signal(SIGPIPE, SIG_IGN); | 1606 | signal(SIGPIPE, SIG_IGN); |
1255 | 1607 | ||
1256 | /* Start listening for a socket, unless started from inetd. */ | 1608 | /* Get a connection, either from inetd or a listening TCP socket */ |
1257 | if (inetd_flag) { | 1609 | if (inetd_flag) { |
1258 | int fd; | 1610 | server_accept_inetd(&sock_in, &sock_out); |
1259 | 1611 | ||
1260 | startup_pipe = -1; | ||
1261 | if (rexeced_flag) { | ||
1262 | close(REEXEC_CONFIG_PASS_FD); | ||
1263 | sock_in = sock_out = dup(STDIN_FILENO); | ||
1264 | if (!debug_flag) { | ||
1265 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | ||
1266 | close(REEXEC_STARTUP_PIPE_FD); | ||
1267 | } | ||
1268 | } else { | ||
1269 | sock_in = dup(STDIN_FILENO); | ||
1270 | sock_out = dup(STDOUT_FILENO); | ||
1271 | } | ||
1272 | /* | ||
1273 | * We intentionally do not close the descriptors 0, 1, and 2 | ||
1274 | * as our code for setting the descriptors won't work if | ||
1275 | * ttyfd happens to be one of those. | ||
1276 | */ | ||
1277 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
1278 | dup2(fd, STDIN_FILENO); | ||
1279 | dup2(fd, STDOUT_FILENO); | ||
1280 | if (fd > STDOUT_FILENO) | ||
1281 | close(fd); | ||
1282 | } | ||
1283 | debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); | ||
1284 | if ((options.protocol & SSH_PROTO_1) && | 1612 | if ((options.protocol & SSH_PROTO_1) && |
1285 | sensitive_data.server_key == NULL) | 1613 | sensitive_data.server_key == NULL) |
1286 | generate_ephemeral_server_key(); | 1614 | generate_ephemeral_server_key(); |
1287 | } else { | 1615 | } else { |
1288 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { | 1616 | server_listen(); |
1289 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | ||
1290 | continue; | ||
1291 | if (num_listen_socks >= MAX_LISTEN_SOCKS) | ||
1292 | fatal("Too many listen sockets. " | ||
1293 | "Enlarge MAX_LISTEN_SOCKS"); | ||
1294 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, | ||
1295 | ntop, sizeof(ntop), strport, sizeof(strport), | ||
1296 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | ||
1297 | error("getnameinfo failed: %.100s", | ||
1298 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | ||
1299 | strerror(errno)); | ||
1300 | continue; | ||
1301 | } | ||
1302 | /* Create socket for listening. */ | ||
1303 | listen_sock = socket(ai->ai_family, ai->ai_socktype, | ||
1304 | ai->ai_protocol); | ||
1305 | if (listen_sock < 0) { | ||
1306 | /* kernel may not support ipv6 */ | ||
1307 | verbose("socket: %.100s", strerror(errno)); | ||
1308 | continue; | ||
1309 | } | ||
1310 | if (set_nonblock(listen_sock) == -1) { | ||
1311 | close(listen_sock); | ||
1312 | continue; | ||
1313 | } | ||
1314 | /* | ||
1315 | * Set socket options. | ||
1316 | * Allow local port reuse in TIME_WAIT. | ||
1317 | */ | ||
1318 | if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, | ||
1319 | &on, sizeof(on)) == -1) | ||
1320 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | ||
1321 | |||
1322 | debug("Bind to port %s on %s.", strport, ntop); | ||
1323 | |||
1324 | /* Bind the socket to the desired port. */ | ||
1325 | if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { | ||
1326 | if (!num_listen_socks && !ai->ai_next) | ||
1327 | error("Bind to port %s on %s failed: %.200s.", | ||
1328 | strport, ntop, strerror(errno)); | ||
1329 | close(listen_sock); | ||
1330 | continue; | ||
1331 | } | ||
1332 | listen_socks[num_listen_socks] = listen_sock; | ||
1333 | num_listen_socks++; | ||
1334 | |||
1335 | /* Start listening on the port. */ | ||
1336 | logit("Server listening on %s port %s.", ntop, strport); | ||
1337 | if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) | ||
1338 | fatal("listen: %.100s", strerror(errno)); | ||
1339 | |||
1340 | } | ||
1341 | freeaddrinfo(options.listen_addrs); | ||
1342 | |||
1343 | if (!num_listen_socks) | ||
1344 | fatal("Cannot bind any address."); | ||
1345 | 1617 | ||
1346 | if (options.protocol & SSH_PROTO_1) | 1618 | if (options.protocol & SSH_PROTO_1) |
1347 | generate_ephemeral_server_key(); | 1619 | generate_ephemeral_server_key(); |
1348 | 1620 | ||
1349 | /* | ||
1350 | * Arrange to restart on SIGHUP. The handler needs | ||
1351 | * listen_sock. | ||
1352 | */ | ||
1353 | signal(SIGHUP, sighup_handler); | 1621 | signal(SIGHUP, sighup_handler); |
1354 | 1622 | signal(SIGCHLD, main_sigchld_handler); | |
1355 | signal(SIGTERM, sigterm_handler); | 1623 | signal(SIGTERM, sigterm_handler); |
1356 | signal(SIGQUIT, sigterm_handler); | 1624 | signal(SIGQUIT, sigterm_handler); |
1357 | 1625 | ||
1358 | /* Arrange SIGCHLD to be caught. */ | 1626 | /* |
1359 | signal(SIGCHLD, main_sigchld_handler); | 1627 | * Write out the pid file after the sigterm handler |
1360 | 1628 | * is setup and the listen sockets are bound | |
1361 | /* Write out the pid file after the sigterm handler is setup */ | 1629 | */ |
1362 | if (!debug_flag) { | 1630 | if (!debug_flag) { |
1363 | /* | 1631 | FILE *f = fopen(options.pid_file, "w"); |
1364 | * Record our pid in /var/run/sshd.pid to make it | 1632 | |
1365 | * easier to kill the correct sshd. We don't want to | ||
1366 | * do this before the bind above because the bind will | ||
1367 | * fail if there already is a daemon, and this will | ||
1368 | * overwrite any old pid in the file. | ||
1369 | */ | ||
1370 | f = fopen(options.pid_file, "wb"); | ||
1371 | if (f == NULL) { | 1633 | if (f == NULL) { |
1372 | error("Couldn't create pid file \"%s\": %s", | 1634 | error("Couldn't create pid file \"%s\": %s", |
1373 | options.pid_file, strerror(errno)); | 1635 | options.pid_file, strerror(errno)); |
@@ -1377,194 +1639,9 @@ main(int ac, char **av) | |||
1377 | } | 1639 | } |
1378 | } | 1640 | } |
1379 | 1641 | ||
1380 | /* setup fd set for listen */ | 1642 | /* Accept a connection and return in a forked child */ |
1381 | fdset = NULL; | 1643 | server_accept_loop(&sock_in, &sock_out, |
1382 | maxfd = 0; | 1644 | &newsock, config_s); |
1383 | for (i = 0; i < num_listen_socks; i++) | ||
1384 | if (listen_socks[i] > maxfd) | ||
1385 | maxfd = listen_socks[i]; | ||
1386 | /* pipes connected to unauthenticated childs */ | ||
1387 | startup_pipes = xmalloc(options.max_startups * sizeof(int)); | ||
1388 | for (i = 0; i < options.max_startups; i++) | ||
1389 | startup_pipes[i] = -1; | ||
1390 | |||
1391 | /* | ||
1392 | * Stay listening for connections until the system crashes or | ||
1393 | * the daemon is killed with a signal. | ||
1394 | */ | ||
1395 | for (;;) { | ||
1396 | if (received_sighup) | ||
1397 | sighup_restart(); | ||
1398 | if (fdset != NULL) | ||
1399 | xfree(fdset); | ||
1400 | fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); | ||
1401 | fdset = (fd_set *)xmalloc(fdsetsz); | ||
1402 | memset(fdset, 0, fdsetsz); | ||
1403 | |||
1404 | for (i = 0; i < num_listen_socks; i++) | ||
1405 | FD_SET(listen_socks[i], fdset); | ||
1406 | for (i = 0; i < options.max_startups; i++) | ||
1407 | if (startup_pipes[i] != -1) | ||
1408 | FD_SET(startup_pipes[i], fdset); | ||
1409 | |||
1410 | /* Wait in select until there is a connection. */ | ||
1411 | ret = select(maxfd+1, fdset, NULL, NULL, NULL); | ||
1412 | if (ret < 0 && errno != EINTR) | ||
1413 | error("select: %.100s", strerror(errno)); | ||
1414 | if (received_sigterm) { | ||
1415 | logit("Received signal %d; terminating.", | ||
1416 | (int) received_sigterm); | ||
1417 | close_listen_socks(); | ||
1418 | unlink(options.pid_file); | ||
1419 | exit(255); | ||
1420 | } | ||
1421 | if (key_used && key_do_regen) { | ||
1422 | generate_ephemeral_server_key(); | ||
1423 | key_used = 0; | ||
1424 | key_do_regen = 0; | ||
1425 | } | ||
1426 | if (ret < 0) | ||
1427 | continue; | ||
1428 | |||
1429 | for (i = 0; i < options.max_startups; i++) | ||
1430 | if (startup_pipes[i] != -1 && | ||
1431 | FD_ISSET(startup_pipes[i], fdset)) { | ||
1432 | /* | ||
1433 | * the read end of the pipe is ready | ||
1434 | * if the child has closed the pipe | ||
1435 | * after successful authentication | ||
1436 | * or if the child has died | ||
1437 | */ | ||
1438 | close(startup_pipes[i]); | ||
1439 | startup_pipes[i] = -1; | ||
1440 | startups--; | ||
1441 | } | ||
1442 | for (i = 0; i < num_listen_socks; i++) { | ||
1443 | if (!FD_ISSET(listen_socks[i], fdset)) | ||
1444 | continue; | ||
1445 | fromlen = sizeof(from); | ||
1446 | newsock = accept(listen_socks[i], (struct sockaddr *)&from, | ||
1447 | &fromlen); | ||
1448 | if (newsock < 0) { | ||
1449 | if (errno != EINTR && errno != EWOULDBLOCK) | ||
1450 | error("accept: %.100s", strerror(errno)); | ||
1451 | continue; | ||
1452 | } | ||
1453 | if (unset_nonblock(newsock) == -1) { | ||
1454 | close(newsock); | ||
1455 | continue; | ||
1456 | } | ||
1457 | if (drop_connection(startups) == 1) { | ||
1458 | debug("drop connection #%d", startups); | ||
1459 | close(newsock); | ||
1460 | continue; | ||
1461 | } | ||
1462 | if (pipe(startup_p) == -1) { | ||
1463 | close(newsock); | ||
1464 | continue; | ||
1465 | } | ||
1466 | |||
1467 | if (rexec_flag && socketpair(AF_UNIX, | ||
1468 | SOCK_STREAM, 0, config_s) == -1) { | ||
1469 | error("reexec socketpair: %s", | ||
1470 | strerror(errno)); | ||
1471 | close(newsock); | ||
1472 | close(startup_p[0]); | ||
1473 | close(startup_p[1]); | ||
1474 | continue; | ||
1475 | } | ||
1476 | |||
1477 | for (j = 0; j < options.max_startups; j++) | ||
1478 | if (startup_pipes[j] == -1) { | ||
1479 | startup_pipes[j] = startup_p[0]; | ||
1480 | if (maxfd < startup_p[0]) | ||
1481 | maxfd = startup_p[0]; | ||
1482 | startups++; | ||
1483 | break; | ||
1484 | } | ||
1485 | |||
1486 | /* | ||
1487 | * Got connection. Fork a child to handle it, unless | ||
1488 | * we are in debugging mode. | ||
1489 | */ | ||
1490 | if (debug_flag) { | ||
1491 | /* | ||
1492 | * In debugging mode. Close the listening | ||
1493 | * socket, and start processing the | ||
1494 | * connection without forking. | ||
1495 | */ | ||
1496 | debug("Server will not fork when running in debugging mode."); | ||
1497 | close_listen_socks(); | ||
1498 | sock_in = newsock; | ||
1499 | sock_out = newsock; | ||
1500 | close(startup_p[0]); | ||
1501 | close(startup_p[1]); | ||
1502 | startup_pipe = -1; | ||
1503 | pid = getpid(); | ||
1504 | if (rexec_flag) { | ||
1505 | send_rexec_state(config_s[0], | ||
1506 | &cfg); | ||
1507 | close(config_s[0]); | ||
1508 | } | ||
1509 | break; | ||
1510 | } else { | ||
1511 | /* | ||
1512 | * Normal production daemon. Fork, and have | ||
1513 | * the child process the connection. The | ||
1514 | * parent continues listening. | ||
1515 | */ | ||
1516 | if ((pid = fork()) == 0) { | ||
1517 | /* | ||
1518 | * Child. Close the listening and max_startup | ||
1519 | * sockets. Start using the accepted socket. | ||
1520 | * Reinitialize logging (since our pid has | ||
1521 | * changed). We break out of the loop to handle | ||
1522 | * the connection. | ||
1523 | */ | ||
1524 | startup_pipe = startup_p[1]; | ||
1525 | close_startup_pipes(); | ||
1526 | close_listen_socks(); | ||
1527 | sock_in = newsock; | ||
1528 | sock_out = newsock; | ||
1529 | log_init(__progname, options.log_level, options.log_facility, log_stderr); | ||
1530 | if (rexec_flag) | ||
1531 | close(config_s[0]); | ||
1532 | break; | ||
1533 | } | ||
1534 | } | ||
1535 | |||
1536 | /* Parent. Stay in the loop. */ | ||
1537 | if (pid < 0) | ||
1538 | error("fork: %.100s", strerror(errno)); | ||
1539 | else | ||
1540 | debug("Forked child %ld.", (long)pid); | ||
1541 | |||
1542 | close(startup_p[1]); | ||
1543 | |||
1544 | if (rexec_flag) { | ||
1545 | send_rexec_state(config_s[0], &cfg); | ||
1546 | close(config_s[0]); | ||
1547 | close(config_s[1]); | ||
1548 | } | ||
1549 | |||
1550 | /* Mark that the key has been used (it was "given" to the child). */ | ||
1551 | if ((options.protocol & SSH_PROTO_1) && | ||
1552 | key_used == 0) { | ||
1553 | /* Schedule server key regeneration alarm. */ | ||
1554 | signal(SIGALRM, key_regeneration_alarm); | ||
1555 | alarm(options.key_regeneration_time); | ||
1556 | key_used = 1; | ||
1557 | } | ||
1558 | |||
1559 | arc4random_stir(); | ||
1560 | |||
1561 | /* Close the new socket (the child is now taking care of it). */ | ||
1562 | close(newsock); | ||
1563 | } | ||
1564 | /* child process check (or debug mode) */ | ||
1565 | if (num_listen_socks < 0) | ||
1566 | break; | ||
1567 | } | ||
1568 | } | 1645 | } |
1569 | 1646 | ||
1570 | /* This is the child processing a new connection. */ | 1647 | /* This is the child processing a new connection. */ |
@@ -1659,7 +1736,13 @@ main(int ac, char **av) | |||
1659 | * We use get_canonical_hostname with usedns = 0 instead of | 1736 | * We use get_canonical_hostname with usedns = 0 instead of |
1660 | * get_remote_ipaddr here so IP options will be checked. | 1737 | * get_remote_ipaddr here so IP options will be checked. |
1661 | */ | 1738 | */ |
1662 | remote_ip = get_canonical_hostname(0); | 1739 | (void) get_canonical_hostname(0); |
1740 | /* | ||
1741 | * The rest of the code depends on the fact that | ||
1742 | * get_remote_ipaddr() caches the remote ip, even if | ||
1743 | * the socket goes away. | ||
1744 | */ | ||
1745 | remote_ip = get_remote_ipaddr(); | ||
1663 | 1746 | ||
1664 | #ifdef SSH_AUDIT_EVENTS | 1747 | #ifdef SSH_AUDIT_EVENTS |
1665 | audit_connection_from(remote_ip, remote_port); | 1748 | audit_connection_from(remote_ip, remote_port); |
@@ -1755,8 +1838,7 @@ main(int ac, char **av) | |||
1755 | packet_set_nonblocking(); | 1838 | packet_set_nonblocking(); |
1756 | 1839 | ||
1757 | /* allocate authentication context */ | 1840 | /* allocate authentication context */ |
1758 | authctxt = xmalloc(sizeof(*authctxt)); | 1841 | authctxt = xcalloc(1, sizeof(*authctxt)); |
1759 | memset(authctxt, 0, sizeof(*authctxt)); | ||
1760 | 1842 | ||
1761 | authctxt->loginmsg = &loginmsg; | 1843 | authctxt->loginmsg = &loginmsg; |
1762 | 1844 | ||
@@ -1848,11 +1930,14 @@ ssh1_session_key(BIGNUM *session_key_int) | |||
1848 | { | 1930 | { |
1849 | int rsafail = 0; | 1931 | int rsafail = 0; |
1850 | 1932 | ||
1851 | if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { | 1933 | if (BN_cmp(sensitive_data.server_key->rsa->n, |
1934 | sensitive_data.ssh1_host_key->rsa->n) > 0) { | ||
1852 | /* Server key has bigger modulus. */ | 1935 | /* Server key has bigger modulus. */ |
1853 | if (BN_num_bits(sensitive_data.server_key->rsa->n) < | 1936 | if (BN_num_bits(sensitive_data.server_key->rsa->n) < |
1854 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { | 1937 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + |
1855 | fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", | 1938 | SSH_KEY_BITS_RESERVED) { |
1939 | fatal("do_connection: %s: " | ||
1940 | "server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", | ||
1856 | get_remote_ipaddr(), | 1941 | get_remote_ipaddr(), |
1857 | BN_num_bits(sensitive_data.server_key->rsa->n), | 1942 | BN_num_bits(sensitive_data.server_key->rsa->n), |
1858 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), | 1943 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), |
@@ -1867,8 +1952,10 @@ ssh1_session_key(BIGNUM *session_key_int) | |||
1867 | } else { | 1952 | } else { |
1868 | /* Host key has bigger modulus (or they are equal). */ | 1953 | /* Host key has bigger modulus (or they are equal). */ |
1869 | if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < | 1954 | if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < |
1870 | BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { | 1955 | BN_num_bits(sensitive_data.server_key->rsa->n) + |
1871 | fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", | 1956 | SSH_KEY_BITS_RESERVED) { |
1957 | fatal("do_connection: %s: " | ||
1958 | "host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", | ||
1872 | get_remote_ipaddr(), | 1959 | get_remote_ipaddr(), |
1873 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), | 1960 | BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), |
1874 | BN_num_bits(sensitive_data.server_key->rsa->n), | 1961 | BN_num_bits(sensitive_data.server_key->rsa->n), |
@@ -1993,10 +2080,10 @@ do_ssh1_kex(void) | |||
1993 | * key is in the highest bits. | 2080 | * key is in the highest bits. |
1994 | */ | 2081 | */ |
1995 | if (!rsafail) { | 2082 | if (!rsafail) { |
1996 | BN_mask_bits(session_key_int, sizeof(session_key) * 8); | 2083 | (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8); |
1997 | len = BN_num_bytes(session_key_int); | 2084 | len = BN_num_bytes(session_key_int); |
1998 | if (len < 0 || (u_int)len > sizeof(session_key)) { | 2085 | if (len < 0 || (u_int)len > sizeof(session_key)) { |
1999 | error("do_connection: bad session key len from %s: " | 2086 | error("do_ssh1_kex: bad session key len from %s: " |
2000 | "session_key_int %d > sizeof(session_key) %lu", | 2087 | "session_key_int %d > sizeof(session_key) %lu", |
2001 | get_remote_ipaddr(), len, (u_long)sizeof(session_key)); | 2088 | get_remote_ipaddr(), len, (u_long)sizeof(session_key)); |
2002 | rsafail++; | 2089 | rsafail++; |
@@ -2089,11 +2176,9 @@ do_ssh2_kex(void) | |||
2089 | myproposal[PROPOSAL_COMP_ALGS_CTOS] = | 2176 | myproposal[PROPOSAL_COMP_ALGS_CTOS] = |
2090 | myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; | 2177 | myproposal[PROPOSAL_COMP_ALGS_STOC] = "none,zlib@openssh.com"; |
2091 | } | 2178 | } |
2092 | 2179 | ||
2093 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); | 2180 | myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); |
2094 | 2181 | ||
2095 | /* start key exchange */ | ||
2096 | |||
2097 | #ifdef GSSAPI | 2182 | #ifdef GSSAPI |
2098 | { | 2183 | { |
2099 | char *orig; | 2184 | char *orig; |
@@ -2102,8 +2187,8 @@ do_ssh2_kex(void) | |||
2102 | orig = myproposal[PROPOSAL_KEX_ALGS]; | 2187 | orig = myproposal[PROPOSAL_KEX_ALGS]; |
2103 | 2188 | ||
2104 | /* | 2189 | /* |
2105 | * If we don't have a host key, then there's no point advertising | 2190 | * If we don't have a host key, then there's no point advertising |
2106 | * the other key exchange algorithms | 2191 | * the other key exchange algorithms |
2107 | */ | 2192 | */ |
2108 | 2193 | ||
2109 | if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) | 2194 | if (strlen(myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS]) == 0) |
@@ -2114,15 +2199,13 @@ do_ssh2_kex(void) | |||
2114 | else | 2199 | else |
2115 | gss = NULL; | 2200 | gss = NULL; |
2116 | 2201 | ||
2117 | if (gss && orig) { | 2202 | if (gss && orig) |
2118 | int len = strlen(orig) + strlen(gss) + 2; | 2203 | xasprintf(&newstr, "%s,%s", gss, orig); |
2119 | newstr = xmalloc(len); | 2204 | else if (gss) |
2120 | snprintf(newstr, len, "%s,%s", gss, orig); | ||
2121 | } else if (gss) { | ||
2122 | newstr = gss; | 2205 | newstr = gss; |
2123 | } else if (orig) { | 2206 | else if (orig) |
2124 | newstr = orig; | 2207 | newstr = orig; |
2125 | } | 2208 | |
2126 | /* | 2209 | /* |
2127 | * If we've got GSSAPI mechanisms, then we've got the 'null' host | 2210 | * If we've got GSSAPI mechanisms, then we've got the 'null' host |
2128 | * key alg, but we can't tell people about it unless its the only | 2211 | * key alg, but we can't tell people about it unless its the only |
@@ -2138,18 +2221,20 @@ do_ssh2_kex(void) | |||
2138 | } | 2221 | } |
2139 | #endif | 2222 | #endif |
2140 | 2223 | ||
2141 | /* start key exchange */ | 2224 | /* start key exchange */ |
2142 | kex = kex_setup(myproposal); | 2225 | kex = kex_setup(myproposal); |
2143 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; | 2226 | kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; |
2144 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; | 2227 | kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; |
2145 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; | 2228 | kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; |
2229 | kex->kex[KEX_DH_GEX_SHA256] = kexgex_server; | ||
2146 | #ifdef GSSAPI | 2230 | #ifdef GSSAPI |
2147 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; | 2231 | kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; |
2232 | kex->kex[KEX_GSS_GRP14_SHA1] = kexgss_server; | ||
2148 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; | 2233 | kex->kex[KEX_GSS_GEX_SHA1] = kexgss_server; |
2149 | #endif | 2234 | #endif |
2150 | kex->server = 1; | 2235 | kex->server = 1; |
2151 | kex->client_version_string=client_version_string; | 2236 | kex->client_version_string=client_version_string; |
2152 | kex->server_version_string=server_version_string; | 2237 | kex->server_version_string=server_version_string; |
2153 | kex->load_host_key=&get_hostkey_by_type; | 2238 | kex->load_host_key=&get_hostkey_by_type; |
2154 | kex->host_key_index=&get_hostkey_index; | 2239 | kex->host_key_index=&get_hostkey_index; |
2155 | 2240 | ||