diff options
author | Damien Miller <djm@mindrot.org> | 2006-08-19 00:31:39 +1000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2006-08-19 00:31:39 +1000 |
commit | a1f6840a4fa1fd48ecbf5a3ebb2c3b18f3a6c587 (patch) | |
tree | 8e43bc8778518252c8ebba8fb11764d8f1927a50 | |
parent | 565ca3f60058f22d083572930833aaff2292ac20 (diff) |
- djm@cvs.openbsd.org 2006/08/16 11:47:15
[sshd.c]
factor inetd connection, TCP listen and main TCP accept loop out of
main() into separate functions to improve readability; ok markus@
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | sshd.c | 637 |
2 files changed, 337 insertions, 306 deletions
@@ -18,6 +18,10 @@ | |||
18 | [servconf.c servconf.h sshd_config.5] | 18 | [servconf.c servconf.h sshd_config.5] |
19 | Add ability to match groups to Match keyword in sshd_config. Feedback | 19 | Add ability to match groups to Match keyword in sshd_config. Feedback |
20 | djm@, stevesk@, ok stevesk@. | 20 | djm@, stevesk@, ok stevesk@. |
21 | - djm@cvs.openbsd.org 2006/08/16 11:47:15 | ||
22 | [sshd.c] | ||
23 | factor inetd connection, TCP listen and main TCP accept loop out of | ||
24 | main() into separate functions to improve readability; ok markus@ | ||
21 | 25 | ||
22 | 20060817 | 26 | 20060817 |
23 | - (dtucker) [openbsd-compat/fake-rfc2553.c openbsd-compat/setproctitle.c] | 27 | - (dtucker) [openbsd-compat/fake-rfc2553.c openbsd-compat/setproctitle.c] |
@@ -5239,4 +5243,4 @@ | |||
5239 | - (djm) Trim deprecated options from INSTALL. Mention UsePAM | 5243 | - (djm) Trim deprecated options from INSTALL. Mention UsePAM |
5240 | - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu | 5244 | - (djm) Fix quote handling in sftp; Patch from admorten AT umich.edu |
5241 | 5245 | ||
5242 | $Id: ChangeLog,v 1.4489 2006/08/18 14:23:15 djm Exp $ | 5246 | $Id: ChangeLog,v 1.4490 2006/08/18 14:31:39 djm Exp $ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sshd.c,v 1.344 2006/08/05 07:52:52 dtucker Exp $ */ | 1 | /* $OpenBSD: sshd.c,v 1.345 2006/08/16 11:47:15 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -905,6 +905,322 @@ recv_rexec_state(int fd, Buffer *conf) | |||
905 | debug3("%s: done", __func__); | 905 | debug3("%s: done", __func__); |
906 | } | 906 | } |
907 | 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 | if ((pid = fork()) == 0) { | ||
1160 | /* | ||
1161 | * Child. Close the listening and | ||
1162 | * max_startup sockets. Start using | ||
1163 | * the accepted socket. Reinitialize | ||
1164 | * logging (since our pid has changed). | ||
1165 | * We break out of the loop to handle | ||
1166 | * the connection. | ||
1167 | */ | ||
1168 | startup_pipe = startup_p[1]; | ||
1169 | close_startup_pipes(); | ||
1170 | close_listen_socks(); | ||
1171 | *sock_in = *newsock; | ||
1172 | *sock_out = *newsock; | ||
1173 | log_init(__progname, | ||
1174 | options.log_level, | ||
1175 | options.log_facility, | ||
1176 | log_stderr); | ||
1177 | if (rexec_flag) | ||
1178 | close(config_s[0]); | ||
1179 | break; | ||
1180 | } | ||
1181 | |||
1182 | /* Parent. Stay in the loop. */ | ||
1183 | if (pid < 0) | ||
1184 | error("fork: %.100s", strerror(errno)); | ||
1185 | else | ||
1186 | debug("Forked child %ld.", (long)pid); | ||
1187 | |||
1188 | close(startup_p[1]); | ||
1189 | |||
1190 | if (rexec_flag) { | ||
1191 | send_rexec_state(config_s[0], &cfg); | ||
1192 | close(config_s[0]); | ||
1193 | close(config_s[1]); | ||
1194 | } | ||
1195 | |||
1196 | /* | ||
1197 | * Mark that the key has been used (it | ||
1198 | * was "given" to the child). | ||
1199 | */ | ||
1200 | if ((options.protocol & SSH_PROTO_1) && | ||
1201 | key_used == 0) { | ||
1202 | /* Schedule server key regeneration alarm. */ | ||
1203 | signal(SIGALRM, key_regeneration_alarm); | ||
1204 | alarm(options.key_regeneration_time); | ||
1205 | key_used = 1; | ||
1206 | } | ||
1207 | |||
1208 | close(*newsock); | ||
1209 | |||
1210 | /* | ||
1211 | * Ensure that our random state differs | ||
1212 | * from that of the child | ||
1213 | */ | ||
1214 | arc4random_stir(); | ||
1215 | } | ||
1216 | |||
1217 | /* child process check (or debug mode) */ | ||
1218 | if (num_listen_socks < 0) | ||
1219 | break; | ||
1220 | } | ||
1221 | } | ||
1222 | |||
1223 | |||
908 | /* | 1224 | /* |
909 | * Main program for the daemon. | 1225 | * Main program for the daemon. |
910 | */ | 1226 | */ |
@@ -913,24 +1229,14 @@ main(int ac, char **av) | |||
913 | { | 1229 | { |
914 | extern char *optarg; | 1230 | extern char *optarg; |
915 | extern int optind; | 1231 | extern int optind; |
916 | int opt, j, i, on = 1; | 1232 | int opt, i, on = 1; |
917 | int sock_in = -1, sock_out = -1, newsock = -1; | 1233 | int sock_in = -1, sock_out = -1, newsock = -1; |
918 | pid_t pid; | ||
919 | socklen_t fromlen; | ||
920 | fd_set *fdset; | ||
921 | struct sockaddr_storage from; | ||
922 | const char *remote_ip; | 1234 | const char *remote_ip; |
923 | int remote_port; | 1235 | int remote_port; |
924 | FILE *f; | ||
925 | struct addrinfo *ai; | ||
926 | char ntop[NI_MAXHOST], strport[NI_MAXSERV]; | ||
927 | char *line; | 1236 | char *line; |
928 | int listen_sock, maxfd; | 1237 | int config_s[2] = { -1 , -1 }; |
929 | int startup_p[2] = { -1 , -1 }, config_s[2] = { -1 , -1 }; | ||
930 | int startups = 0; | ||
931 | Key *key; | 1238 | Key *key; |
932 | Authctxt *authctxt; | 1239 | Authctxt *authctxt; |
933 | int ret, key_used = 0; | ||
934 | 1240 | ||
935 | #ifdef HAVE_SECUREWARE | 1241 | #ifdef HAVE_SECUREWARE |
936 | (void)set_auth_parameters(ac, av); | 1242 | (void)set_auth_parameters(ac, av); |
@@ -1278,121 +1584,31 @@ main(int ac, char **av) | |||
1278 | /* ignore SIGPIPE */ | 1584 | /* ignore SIGPIPE */ |
1279 | signal(SIGPIPE, SIG_IGN); | 1585 | signal(SIGPIPE, SIG_IGN); |
1280 | 1586 | ||
1281 | /* Start listening for a socket, unless started from inetd. */ | 1587 | /* Get a connection, either from inetd or a listening TCP socket */ |
1282 | if (inetd_flag) { | 1588 | if (inetd_flag) { |
1283 | int fd; | 1589 | server_accept_inetd(&sock_in, &sock_out); |
1284 | 1590 | ||
1285 | startup_pipe = -1; | ||
1286 | if (rexeced_flag) { | ||
1287 | close(REEXEC_CONFIG_PASS_FD); | ||
1288 | sock_in = sock_out = dup(STDIN_FILENO); | ||
1289 | if (!debug_flag) { | ||
1290 | startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); | ||
1291 | close(REEXEC_STARTUP_PIPE_FD); | ||
1292 | } | ||
1293 | } else { | ||
1294 | sock_in = dup(STDIN_FILENO); | ||
1295 | sock_out = dup(STDOUT_FILENO); | ||
1296 | } | ||
1297 | /* | ||
1298 | * We intentionally do not close the descriptors 0, 1, and 2 | ||
1299 | * as our code for setting the descriptors won't work if | ||
1300 | * ttyfd happens to be one of those. | ||
1301 | */ | ||
1302 | if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { | ||
1303 | dup2(fd, STDIN_FILENO); | ||
1304 | dup2(fd, STDOUT_FILENO); | ||
1305 | if (fd > STDOUT_FILENO) | ||
1306 | close(fd); | ||
1307 | } | ||
1308 | debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); | ||
1309 | if ((options.protocol & SSH_PROTO_1) && | 1591 | if ((options.protocol & SSH_PROTO_1) && |
1310 | sensitive_data.server_key == NULL) | 1592 | sensitive_data.server_key == NULL) |
1311 | generate_ephemeral_server_key(); | 1593 | generate_ephemeral_server_key(); |
1312 | } else { | 1594 | } else { |
1313 | for (ai = options.listen_addrs; ai; ai = ai->ai_next) { | 1595 | server_listen(); |
1314 | if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) | ||
1315 | continue; | ||
1316 | if (num_listen_socks >= MAX_LISTEN_SOCKS) | ||
1317 | fatal("Too many listen sockets. " | ||
1318 | "Enlarge MAX_LISTEN_SOCKS"); | ||
1319 | if ((ret = getnameinfo(ai->ai_addr, ai->ai_addrlen, | ||
1320 | ntop, sizeof(ntop), strport, sizeof(strport), | ||
1321 | NI_NUMERICHOST|NI_NUMERICSERV)) != 0) { | ||
1322 | error("getnameinfo failed: %.100s", | ||
1323 | (ret != EAI_SYSTEM) ? gai_strerror(ret) : | ||
1324 | strerror(errno)); | ||
1325 | continue; | ||
1326 | } | ||
1327 | /* Create socket for listening. */ | ||
1328 | listen_sock = socket(ai->ai_family, ai->ai_socktype, | ||
1329 | ai->ai_protocol); | ||
1330 | if (listen_sock < 0) { | ||
1331 | /* kernel may not support ipv6 */ | ||
1332 | verbose("socket: %.100s", strerror(errno)); | ||
1333 | continue; | ||
1334 | } | ||
1335 | if (set_nonblock(listen_sock) == -1) { | ||
1336 | close(listen_sock); | ||
1337 | continue; | ||
1338 | } | ||
1339 | /* | ||
1340 | * Set socket options. | ||
1341 | * Allow local port reuse in TIME_WAIT. | ||
1342 | */ | ||
1343 | if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, | ||
1344 | &on, sizeof(on)) == -1) | ||
1345 | error("setsockopt SO_REUSEADDR: %s", strerror(errno)); | ||
1346 | |||
1347 | debug("Bind to port %s on %s.", strport, ntop); | ||
1348 | |||
1349 | /* Bind the socket to the desired port. */ | ||
1350 | if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { | ||
1351 | if (!ai->ai_next) | ||
1352 | error("Bind to port %s on %s failed: %.200s.", | ||
1353 | strport, ntop, strerror(errno)); | ||
1354 | close(listen_sock); | ||
1355 | continue; | ||
1356 | } | ||
1357 | listen_socks[num_listen_socks] = listen_sock; | ||
1358 | num_listen_socks++; | ||
1359 | |||
1360 | /* Start listening on the port. */ | ||
1361 | if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) | ||
1362 | fatal("listen on [%s]:%s: %.100s", | ||
1363 | ntop, strport, strerror(errno)); | ||
1364 | logit("Server listening on %s port %s.", ntop, strport); | ||
1365 | } | ||
1366 | freeaddrinfo(options.listen_addrs); | ||
1367 | |||
1368 | if (!num_listen_socks) | ||
1369 | fatal("Cannot bind any address."); | ||
1370 | 1596 | ||
1371 | if (options.protocol & SSH_PROTO_1) | 1597 | if (options.protocol & SSH_PROTO_1) |
1372 | generate_ephemeral_server_key(); | 1598 | generate_ephemeral_server_key(); |
1373 | 1599 | ||
1374 | /* | ||
1375 | * Arrange to restart on SIGHUP. The handler needs | ||
1376 | * listen_sock. | ||
1377 | */ | ||
1378 | signal(SIGHUP, sighup_handler); | 1600 | signal(SIGHUP, sighup_handler); |
1379 | 1601 | signal(SIGCHLD, main_sigchld_handler); | |
1380 | signal(SIGTERM, sigterm_handler); | 1602 | signal(SIGTERM, sigterm_handler); |
1381 | signal(SIGQUIT, sigterm_handler); | 1603 | signal(SIGQUIT, sigterm_handler); |
1382 | 1604 | ||
1383 | /* Arrange SIGCHLD to be caught. */ | 1605 | /* |
1384 | signal(SIGCHLD, main_sigchld_handler); | 1606 | * Write out the pid file after the sigterm handler |
1385 | 1607 | * is setup and the listen sockets are bound | |
1386 | /* Write out the pid file after the sigterm handler is setup */ | 1608 | */ |
1387 | if (!debug_flag) { | 1609 | if (!debug_flag) { |
1388 | /* | 1610 | FILE *f = fopen(options.pid_file, "w"); |
1389 | * Record our pid in /var/run/sshd.pid to make it | 1611 | |
1390 | * easier to kill the correct sshd. We don't want to | ||
1391 | * do this before the bind above because the bind will | ||
1392 | * fail if there already is a daemon, and this will | ||
1393 | * overwrite any old pid in the file. | ||
1394 | */ | ||
1395 | f = fopen(options.pid_file, "wb"); | ||
1396 | if (f == NULL) { | 1612 | if (f == NULL) { |
1397 | error("Couldn't create pid file \"%s\": %s", | 1613 | error("Couldn't create pid file \"%s\": %s", |
1398 | options.pid_file, strerror(errno)); | 1614 | options.pid_file, strerror(errno)); |
@@ -1402,198 +1618,9 @@ main(int ac, char **av) | |||
1402 | } | 1618 | } |
1403 | } | 1619 | } |
1404 | 1620 | ||
1405 | /* setup fd set for listen */ | 1621 | /* Accept a connection and return in a forked child */ |
1406 | fdset = NULL; | 1622 | server_accept_loop(&sock_in, &sock_out, |
1407 | maxfd = 0; | 1623 | &newsock, config_s); |
1408 | for (i = 0; i < num_listen_socks; i++) | ||
1409 | if (listen_socks[i] > maxfd) | ||
1410 | maxfd = listen_socks[i]; | ||
1411 | /* pipes connected to unauthenticated childs */ | ||
1412 | startup_pipes = xcalloc(options.max_startups, sizeof(int)); | ||
1413 | for (i = 0; i < options.max_startups; i++) | ||
1414 | startup_pipes[i] = -1; | ||
1415 | |||
1416 | /* | ||
1417 | * Stay listening for connections until the system crashes or | ||
1418 | * the daemon is killed with a signal. | ||
1419 | */ | ||
1420 | for (;;) { | ||
1421 | if (received_sighup) | ||
1422 | sighup_restart(); | ||
1423 | if (fdset != NULL) | ||
1424 | xfree(fdset); | ||
1425 | fdset = (fd_set *)xcalloc(howmany(maxfd + 1, NFDBITS), | ||
1426 | sizeof(fd_mask)); | ||
1427 | |||
1428 | for (i = 0; i < num_listen_socks; i++) | ||
1429 | FD_SET(listen_socks[i], fdset); | ||
1430 | for (i = 0; i < options.max_startups; i++) | ||
1431 | if (startup_pipes[i] != -1) | ||
1432 | FD_SET(startup_pipes[i], fdset); | ||
1433 | |||
1434 | /* Wait in select until there is a connection. */ | ||
1435 | ret = select(maxfd+1, fdset, NULL, NULL, NULL); | ||
1436 | if (ret < 0 && errno != EINTR) | ||
1437 | error("select: %.100s", strerror(errno)); | ||
1438 | if (received_sigterm) { | ||
1439 | logit("Received signal %d; terminating.", | ||
1440 | (int) received_sigterm); | ||
1441 | close_listen_socks(); | ||
1442 | unlink(options.pid_file); | ||
1443 | exit(255); | ||
1444 | } | ||
1445 | if (key_used && key_do_regen) { | ||
1446 | generate_ephemeral_server_key(); | ||
1447 | key_used = 0; | ||
1448 | key_do_regen = 0; | ||
1449 | } | ||
1450 | if (ret < 0) | ||
1451 | continue; | ||
1452 | |||
1453 | for (i = 0; i < options.max_startups; i++) | ||
1454 | if (startup_pipes[i] != -1 && | ||
1455 | FD_ISSET(startup_pipes[i], fdset)) { | ||
1456 | /* | ||
1457 | * the read end of the pipe is ready | ||
1458 | * if the child has closed the pipe | ||
1459 | * after successful authentication | ||
1460 | * or if the child has died | ||
1461 | */ | ||
1462 | close(startup_pipes[i]); | ||
1463 | startup_pipes[i] = -1; | ||
1464 | startups--; | ||
1465 | } | ||
1466 | for (i = 0; i < num_listen_socks; i++) { | ||
1467 | if (!FD_ISSET(listen_socks[i], fdset)) | ||
1468 | continue; | ||
1469 | fromlen = sizeof(from); | ||
1470 | newsock = accept(listen_socks[i], | ||
1471 | (struct sockaddr *)&from, &fromlen); | ||
1472 | if (newsock < 0) { | ||
1473 | if (errno != EINTR && errno != EWOULDBLOCK) | ||
1474 | error("accept: %.100s", strerror(errno)); | ||
1475 | continue; | ||
1476 | } | ||
1477 | if (unset_nonblock(newsock) == -1) { | ||
1478 | close(newsock); | ||
1479 | continue; | ||
1480 | } | ||
1481 | if (drop_connection(startups) == 1) { | ||
1482 | debug("drop connection #%d", startups); | ||
1483 | close(newsock); | ||
1484 | continue; | ||
1485 | } | ||
1486 | if (pipe(startup_p) == -1) { | ||
1487 | close(newsock); | ||
1488 | continue; | ||
1489 | } | ||
1490 | |||
1491 | if (rexec_flag && socketpair(AF_UNIX, | ||
1492 | SOCK_STREAM, 0, config_s) == -1) { | ||
1493 | error("reexec socketpair: %s", | ||
1494 | strerror(errno)); | ||
1495 | close(newsock); | ||
1496 | close(startup_p[0]); | ||
1497 | close(startup_p[1]); | ||
1498 | continue; | ||
1499 | } | ||
1500 | |||
1501 | for (j = 0; j < options.max_startups; j++) | ||
1502 | if (startup_pipes[j] == -1) { | ||
1503 | startup_pipes[j] = startup_p[0]; | ||
1504 | if (maxfd < startup_p[0]) | ||
1505 | maxfd = startup_p[0]; | ||
1506 | startups++; | ||
1507 | break; | ||
1508 | } | ||
1509 | |||
1510 | /* | ||
1511 | * Got connection. Fork a child to handle it, unless | ||
1512 | * we are in debugging mode. | ||
1513 | */ | ||
1514 | if (debug_flag) { | ||
1515 | /* | ||
1516 | * In debugging mode. Close the listening | ||
1517 | * socket, and start processing the | ||
1518 | * connection without forking. | ||
1519 | */ | ||
1520 | debug("Server will not fork when running in debugging mode."); | ||
1521 | close_listen_socks(); | ||
1522 | sock_in = newsock; | ||
1523 | sock_out = newsock; | ||
1524 | close(startup_p[0]); | ||
1525 | close(startup_p[1]); | ||
1526 | startup_pipe = -1; | ||
1527 | pid = getpid(); | ||
1528 | if (rexec_flag) { | ||
1529 | send_rexec_state(config_s[0], | ||
1530 | &cfg); | ||
1531 | close(config_s[0]); | ||
1532 | } | ||
1533 | break; | ||
1534 | } else { | ||
1535 | /* | ||
1536 | * Normal production daemon. Fork, and have | ||
1537 | * the child process the connection. The | ||
1538 | * parent continues listening. | ||
1539 | */ | ||
1540 | if ((pid = fork()) == 0) { | ||
1541 | /* | ||
1542 | * Child. Close the listening and | ||
1543 | * max_startup sockets. Start using | ||
1544 | * the accepted socket. Reinitialize | ||
1545 | * logging (since our pid has changed). | ||
1546 | * We break out of the loop to handle | ||
1547 | * the connection. | ||
1548 | */ | ||
1549 | startup_pipe = startup_p[1]; | ||
1550 | close_startup_pipes(); | ||
1551 | close_listen_socks(); | ||
1552 | sock_in = newsock; | ||
1553 | sock_out = newsock; | ||
1554 | log_init(__progname, | ||
1555 | options.log_level, | ||
1556 | options.log_facility, | ||
1557 | log_stderr); | ||
1558 | if (rexec_flag) | ||
1559 | close(config_s[0]); | ||
1560 | break; | ||
1561 | } | ||
1562 | } | ||
1563 | |||
1564 | /* Parent. Stay in the loop. */ | ||
1565 | if (pid < 0) | ||
1566 | error("fork: %.100s", strerror(errno)); | ||
1567 | else | ||
1568 | debug("Forked child %ld.", (long)pid); | ||
1569 | |||
1570 | close(startup_p[1]); | ||
1571 | |||
1572 | if (rexec_flag) { | ||
1573 | send_rexec_state(config_s[0], &cfg); | ||
1574 | close(config_s[0]); | ||
1575 | close(config_s[1]); | ||
1576 | } | ||
1577 | |||
1578 | /* | ||
1579 | * Mark that the key has been used (it | ||
1580 | * was "given" to the child). | ||
1581 | */ | ||
1582 | if ((options.protocol & SSH_PROTO_1) && | ||
1583 | key_used == 0) { | ||
1584 | /* Schedule server key regeneration alarm. */ | ||
1585 | signal(SIGALRM, key_regeneration_alarm); | ||
1586 | alarm(options.key_regeneration_time); | ||
1587 | key_used = 1; | ||
1588 | } | ||
1589 | |||
1590 | arc4random_stir(); | ||
1591 | close(newsock); | ||
1592 | } | ||
1593 | /* child process check (or debug mode) */ | ||
1594 | if (num_listen_socks < 0) | ||
1595 | break; | ||
1596 | } | ||
1597 | } | 1624 | } |
1598 | 1625 | ||
1599 | /* This is the child processing a new connection. */ | 1626 | /* This is the child processing a new connection. */ |