=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshd.c,v retrieving revision 1.239.2.5 retrieving revision 1.240 diff -u -r1.239.2.5 -r1.240 --- src/usr.bin/ssh/sshd.c 2003/04/03 22:35:18 1.239.2.5 +++ src/usr.bin/ssh/sshd.c 2002/04/23 22:16:29 1.240 @@ -42,7 +42,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.239.2.5 2003/04/03 22:35:18 miod Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.240 2002/04/23 22:16:29 djm Exp $"); #include #include @@ -189,8 +189,8 @@ int startup_pipe; /* in child */ /* variables used for privilege separation */ -int use_privsep; -struct monitor *pmonitor; +extern struct monitor *monitor; +extern int use_privsep; /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); @@ -206,7 +206,6 @@ close_listen_socks(void) { int i; - for (i = 0; i < num_listen_socks; i++) close(listen_socks[i]); num_listen_socks = -1; @@ -216,7 +215,6 @@ close_startup_pipes(void) { int i; - if (startup_pipes) for (i = 0; i < options.max_startups; i++) if (startup_pipes[i] != -1) @@ -249,8 +247,7 @@ close_listen_socks(); close_startup_pipes(); execv(saved_argv[0], saved_argv); - log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], - strerror(errno)); + log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], strerror(errno)); exit(1); } @@ -270,8 +267,8 @@ static void main_sigchld_handler(int sig) { - int save_errno = errno; pid_t pid; + int save_errno = errno; int status; while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || @@ -290,8 +287,11 @@ { /* XXX no idea how fix this signal handler */ + /* Close the connection. */ + packet_close(); + /* Log error and exit. */ - fatal("Timeout before authentication for %s", get_remote_ipaddr()); + fatal("Timeout before authentication for %s.", get_remote_ipaddr()); } /* @@ -304,7 +304,7 @@ static void generate_ephemeral_server_key(void) { - u_int32_t rnd = 0; + u_int32_t rand = 0; int i; verbose("Generating %s%d bit RSA key.", @@ -317,9 +317,9 @@ for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { if (i % 4 == 0) - rnd = arc4random(); - sensitive_data.ssh1_cookie[i] = rnd & 0xff; - rnd >>= 8; + rand = arc4random(); + sensitive_data.ssh1_cookie[i] = rand & 0xff; + rand >>= 8; } arc4random_stir(); } @@ -328,7 +328,6 @@ key_regeneration_alarm(int sig) { int save_errno = errno; - signal(SIGALRM, SIG_DFL); errno = save_errno; key_do_regen = 1; @@ -360,14 +359,13 @@ if (client_version_string == NULL) { /* Send our protocol version identification. */ - if (atomicio(write, sock_out, server_version_string, - strlen(server_version_string)) + if (atomicio(write, sock_out, server_version_string, strlen(server_version_string)) != strlen(server_version_string)) { log("Could not write ident string to %s", get_remote_ipaddr()); fatal_cleanup(); } - /* Read other sides version identification. */ + /* Read other side's version identification. */ memset(buf, 0, sizeof(buf)); for (i = 0; i < sizeof(buf) - 1; i++) { if (atomicio(read, sock_in, &buf[i], 1) != 1) { @@ -411,12 +409,6 @@ compat_datafellows(remote_version); - if (datafellows & SSH_BUG_PROBE) { - log("probed from %s with %s. Don't panic.", - get_remote_ipaddr(), client_version_string); - fatal_cleanup(); - } - if (datafellows & SSH_BUG_SCANNER) { log("scanned from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); @@ -470,6 +462,7 @@ } } + /* Destroy the host and server keys. They will no longer be needed. */ void destroy_sensitive_data(void) @@ -519,17 +512,16 @@ static void privsep_preauth_child(void) { - u_int32_t rnd[256]; - gid_t gidset[1]; - struct passwd *pw; + u_int32_t rand[256]; int i; + struct passwd *pw; /* Enable challenge-response authentication for privilege separation */ privsep_challenge_enable(); for (i = 0; i < 256; i++) - rnd[i] = arc4random(); - RAND_seed(rnd, sizeof(rnd)); + rand[i] = arc4random(); + RAND_seed(rand, sizeof(rand)); /* Demote the private keys to public keys. */ demote_sensitive_data(); @@ -540,7 +532,7 @@ memset(pw->pw_passwd, 0, strlen(pw->pw_passwd)); endpwent(); - /* Change our root directory */ + /* Change our root directory*/ if (chroot(_PATH_PRIVSEP_CHROOT_DIR) == -1) fatal("chroot(\"%s\"): %s", _PATH_PRIVSEP_CHROOT_DIR, strerror(errno)); @@ -550,20 +542,10 @@ /* Drop our privileges */ debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, (u_int)pw->pw_gid); -#if 0 - /* XXX not ready, to heavy after chroot */ do_setusercontext(pw); -#else - gidset[0] = pw->pw_gid; - if (setgid(pw->pw_gid) < 0) - fatal("setgid failed for %u", pw->pw_gid ); - if (setgroups(1, gidset) < 0) - fatal("setgroups: %.100s", strerror(errno)); - permanently_set_uid(pw); -#endif } -static Authctxt * +static Authctxt* privsep_preauth(void) { Authctxt *authctxt = NULL; @@ -571,38 +553,32 @@ pid_t pid; /* Set up unprivileged child process to deal with network data */ - pmonitor = monitor_init(); + monitor = monitor_init(); /* Store a pointer to the kex for later rekeying */ - pmonitor->m_pkex = &xxx_kex; + monitor->m_pkex = &xxx_kex; pid = fork(); if (pid == -1) { fatal("fork of unprivileged child failed"); } else if (pid != 0) { - fatal_remove_cleanup((void (*) (void *)) packet_close, NULL); + debug2("Network child is on pid %d", pid); - debug2("Network child is on pid %ld", (long)pid); + close(monitor->m_recvfd); + authctxt = monitor_child_preauth(monitor); + close(monitor->m_sendfd); - close(pmonitor->m_recvfd); - authctxt = monitor_child_preauth(pmonitor); - close(pmonitor->m_sendfd); - /* Sync memory */ - monitor_sync(pmonitor); + monitor_sync(monitor); /* Wait for the child's exit status */ while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) break; - - /* Reinstall, since the child has finished */ - fatal_add_cleanup((void (*) (void *)) packet_close, NULL); - return (authctxt); } else { /* child */ - close(pmonitor->m_sendfd); + close(monitor->m_sendfd); /* Demote the child */ if (getuid() == 0 || geteuid() == 0) @@ -622,7 +598,7 @@ if (authctxt->pw->pw_uid == 0 || options.use_login) { /* File descriptor passing is broken or root login */ - monitor_apply_keystate(pmonitor); + monitor_apply_keystate(monitor); use_privsep = 0; return; } @@ -635,23 +611,21 @@ } /* New socket pair */ - monitor_reinit(pmonitor); + monitor_reinit(monitor); - pmonitor->m_pid = fork(); - if (pmonitor->m_pid == -1) + monitor->m_pid = fork(); + if (monitor->m_pid == -1) fatal("fork of unprivileged child failed"); - else if (pmonitor->m_pid != 0) { - fatal_remove_cleanup((void (*) (void *)) packet_close, NULL); + else if (monitor->m_pid != 0) { + debug2("User child is on pid %d", monitor->m_pid); + close(monitor->m_recvfd); + monitor_child_postauth(monitor); - debug2("User child is on pid %ld", (long)pmonitor->m_pid); - close(pmonitor->m_recvfd); - monitor_child_postauth(pmonitor); - /* NEVERREACHED */ exit(0); } - close(pmonitor->m_sendfd); + close(monitor->m_sendfd); /* Demote the private keys to public keys. */ demote_sensitive_data(); @@ -660,7 +634,7 @@ do_setusercontext(authctxt->pw); /* It is safe now to apply the key state */ - monitor_apply_keystate(pmonitor); + monitor_apply_keystate(monitor); } static char * @@ -696,7 +670,6 @@ get_hostkey_by_type(int type) { int i; - for (i = 0; i < options.num_host_key_files; i++) { Key *key = sensitive_data.host_keys[i]; if (key != NULL && key->type == type) @@ -717,7 +690,6 @@ get_hostkey_index(Key *key) { int i; - for (i = 0; i < options.num_host_key_files; i++) { if (key == sensitive_data.host_keys[i]) return (i); @@ -795,6 +767,7 @@ const char *remote_ip; int remote_port; FILE *f; + struct linger linger; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; int listen_sock, maxfd; @@ -892,10 +865,6 @@ break; case 'u': utmp_len = atoi(optarg); - if (utmp_len > MAXHOSTNAMELEN) { - fprintf(stderr, "Invalid utmp length.\n"); - exit(1); - } break; case 'o': if (process_server_config_line(&options, optarg, @@ -920,7 +889,7 @@ SYSLOG_LEVEL_INFO : options.log_level, options.log_facility == SYSLOG_FACILITY_NOT_SET ? SYSLOG_FACILITY_AUTH : options.log_facility, - log_stderr || !inetd_flag); + !inetd_flag); /* Read server configuration options from the configuration file. */ read_server_config(&options, config_file_name); @@ -937,8 +906,7 @@ debug("sshd version %.100s", SSH_VERSION); /* load private host keys */ - sensitive_data.host_keys = xmalloc(options.num_host_key_files * - sizeof(Key *)); + sensitive_data.host_keys = xmalloc(options.num_host_key_files*sizeof(Key*)); for (i = 0; i < options.num_host_key_files; i++) sensitive_data.host_keys[i] = NULL; sensitive_data.server_key = NULL; @@ -994,34 +962,16 @@ * hate software patents. I dont know if this can go? Niels */ if (options.server_key_bits > - BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - - SSH_KEY_BITS_RESERVED && options.server_key_bits < - BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + - SSH_KEY_BITS_RESERVED) { + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - SSH_KEY_BITS_RESERVED && + options.server_key_bits < + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = - BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + - SSH_KEY_BITS_RESERVED; + BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); } } - if (use_privsep) { - struct passwd *pw; - struct stat st; - - if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL) - fatal("Privilege separation user %s does not exist", - SSH_PRIVSEP_USER); - if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) || - (S_ISDIR(st.st_mode) == 0)) - fatal("Missing privilege separation directory: %s", - _PATH_PRIVSEP_CHROOT_DIR); - if (st.st_uid != 0 || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0) - fatal("%s must be owned by root and not group or " - "world-writable.", _PATH_PRIVSEP_CHROOT_DIR); - } - /* Configuration looks good, so exit if in test mode. */ if (test_flag) exit(0); @@ -1107,12 +1057,17 @@ continue; } /* - * Set socket options. - * Allow local port reuse in TIME_WAIT. + * Set socket options. We try to make the port + * reusable and have it close as fast as possible + * without waiting in unnecessary wait states on + * close. */ - if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, - &on, sizeof(on)) == -1) - error("setsockopt SO_REUSEADDR: %s", strerror(errno)); + setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, + &on, sizeof(on)); + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(listen_sock, SOL_SOCKET, SO_LINGER, + &linger, sizeof(linger)); debug("Bind to port %s on %s.", strport, ntop); @@ -1163,7 +1118,7 @@ */ f = fopen(options.pid_file, "w"); if (f) { - fprintf(f, "%ld\n", (long) getpid()); + fprintf(f, "%u\n", (u_int) getpid()); fclose(f); } } @@ -1310,7 +1265,7 @@ if (pid < 0) error("fork: %.100s", strerror(errno)); else - debug("Forked child %ld.", (long)pid); + debug("Forked child %d.", pid); close(startup_p[1]); @@ -1337,14 +1292,6 @@ /* This is the child processing a new connection. */ /* - * Create a new session and process group since the 4.4BSD - * setlogin() affects the entire process group. We don't - * want the child to be able to affect the parent. - */ - if (!debug_flag && !inetd_flag && setsid() < 0) - error("setsid: %.100s", strerror(errno)); - - /* * Disable the key regeneration alarm. We will not regenerate the * key since we are no longer in a position to give it to anyone. We * will not restart on SIGHUP since it no longer makes sense. @@ -1356,6 +1303,16 @@ signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); + /* + * Set socket options for the connection. We want the socket to + * close as fast as possible without waiting for anything. If the + * connection is not a socket, these will do nothing. + */ + /* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */ + linger.l_onoff = 1; + linger.l_linger = 5; + setsockopt(sock_in, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); + /* Set keepalives if requested. */ if (options.keepalives && setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, @@ -1406,7 +1363,7 @@ sshd_exchange_identification(sock_in, sock_out); /* * Check that the connection comes from a privileged port. - * Rhosts-Authentication only makes sense from privileged + * Rhosts-Authentication only makes sense from priviledged * programs. Of course, if the intruder has root access on his local * machine, he can connect from any port. So do not use these * authentication methods from machines that you do not trust. @@ -1453,7 +1410,7 @@ * the current keystate and exits */ if (use_privsep) { - mm_send_keystate(pmonitor); + mm_send_keystate(monitor); exit(0); } @@ -1538,7 +1495,7 @@ u_char session_key[SSH_SESSION_KEY_LENGTH]; u_char cookie[8]; u_int cipher_type, auth_mask, protocol_flags; - u_int32_t rnd = 0; + u_int32_t rand = 0; /* * Generate check bytes that the client must send back in the user @@ -1551,9 +1508,9 @@ */ for (i = 0; i < 8; i++) { if (i % 4 == 0) - rnd = arc4random(); - cookie[i] = rnd & 0xff; - rnd >>= 8; + rand = arc4random(); + cookie[i] = rand & 0xff; + rand >>= 8; } /* @@ -1711,7 +1668,7 @@ debug("Received session key; encryption turned on."); - /* Send an acknowledgment packet. Note that this packet is sent encrypted. */ + /* Send an acknowledgement packet. Note that this packet is sent encrypted. */ packet_start(SSH_SMSG_SUCCESS); packet_send(); packet_write_wait(); @@ -1738,16 +1695,10 @@ myproposal[PROPOSAL_MAC_ALGS_CTOS] = myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; } - if (!options.compression) { - myproposal[PROPOSAL_COMP_ALGS_CTOS] = - myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; - } myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); /* start key exchange */ kex = kex_setup(myproposal); - kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; - kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->server = 1; kex->client_version_string=client_version_string; kex->server_version_string=server_version_string;