=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sshd.c,v retrieving revision 1.276.2.2 retrieving revision 1.277 diff -u -r1.276.2.2 -r1.277 --- src/usr.bin/ssh/sshd.c 2004/08/19 22:37:33 1.276.2.2 +++ src/usr.bin/ssh/sshd.c 2003/09/19 11:33:09 1.277 @@ -42,7 +42,7 @@ */ #include "includes.h" -RCSID("$OpenBSD: sshd.c,v 1.276.2.2 2004/08/19 22:37:33 brad Exp $"); +RCSID("$OpenBSD: sshd.c,v 1.277 2003/09/19 11:33:09 markus Exp $"); #include #include @@ -56,12 +56,12 @@ #include "rsa.h" #include "sshpty.h" #include "packet.h" +#include "mpaux.h" #include "log.h" #include "servconf.h" #include "uidswap.h" #include "compat.h" #include "buffer.h" -#include "bufaux.h" #include "cipher.h" #include "kex.h" #include "key.h" @@ -73,7 +73,6 @@ #include "canohost.h" #include "auth.h" #include "misc.h" -#include "msg.h" #include "dispatch.h" #include "channels.h" #include "session.h" @@ -93,12 +92,6 @@ #define O_NOCTTY 0 #endif -/* Re-exec fds */ -#define REEXEC_DEVCRYPTO_RESERVED_FD (STDERR_FILENO + 1) -#define REEXEC_STARTUP_PIPE_FD (STDERR_FILENO + 2) -#define REEXEC_CONFIG_PASS_FD (STDERR_FILENO + 3) -#define REEXEC_MIN_FREE_FD (STDERR_FILENO + 4) - extern char *__progname; /* Server configuration options. */ @@ -136,12 +129,6 @@ /* Saved arguments to main(). */ char **saved_argv; -/* re-exec */ -int rexeced_flag = 0; -int rexec_flag = 1; -int rexec_argc = 0; -char **rexec_argv; - /* * The sockets that the server is listening; this is used in the SIGHUP * signal handler. @@ -203,14 +190,8 @@ /* variables used for privilege separation */ int use_privsep; -struct monitor *pmonitor = NULL; +struct monitor *pmonitor; -/* global authentication context */ -Authctxt *the_authctxt = NULL; - -/* message to be displayed after login */ -Buffer loginmsg; - /* Prototypes for various functions defined later in this file. */ void destroy_sensitive_data(void); void demote_sensitive_data(void); @@ -309,9 +290,6 @@ { /* XXX no idea how fix this signal handler */ - if (use_privsep && pmonitor != NULL && pmonitor->m_pid > 0) - kill(pmonitor->m_pid, SIGALRM); - /* Log error and exit. */ fatal("Timeout before authentication for %s", get_remote_ipaddr()); } @@ -385,7 +363,7 @@ strlen(server_version_string)) != strlen(server_version_string)) { logit("Could not write ident string to %s", get_remote_ipaddr()); - cleanup_exit(255); + fatal_cleanup(); } /* Read other sides version identification. */ @@ -394,7 +372,7 @@ if (atomicio(read, sock_in, &buf[i], 1) != 1) { logit("Did not receive identification string from %s", get_remote_ipaddr()); - cleanup_exit(255); + fatal_cleanup(); } if (buf[i] == '\r') { buf[i] = 0; @@ -424,7 +402,7 @@ close(sock_out); logit("Bad protocol version identification '%.100s' from %s", client_version_string, get_remote_ipaddr()); - cleanup_exit(255); + fatal_cleanup(); } debug("Client protocol version %d.%d; client software version %.100s", remote_major, remote_minor, remote_version); @@ -434,13 +412,13 @@ if (datafellows & SSH_BUG_PROBE) { logit("probed from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); - cleanup_exit(255); + fatal_cleanup(); } if (datafellows & SSH_BUG_SCANNER) { logit("scanned from %s with %s. Don't panic.", get_remote_ipaddr(), client_version_string); - cleanup_exit(255); + fatal_cleanup(); } mismatch = 0; @@ -486,7 +464,7 @@ logit("Protocol major versions differ for %s: %.200s vs. %.200s", get_remote_ipaddr(), server_version_string, client_version_string); - cleanup_exit(255); + fatal_cleanup(); } } @@ -571,7 +549,7 @@ debug3("privsep user:group %u:%u", (u_int)pw->pw_uid, (u_int)pw->pw_gid); #if 0 - /* XXX not ready, too heavy after chroot */ + /* XXX not ready, to heavy after chroot */ do_setusercontext(pw); #else gidset[0] = pw->pw_gid; @@ -581,9 +559,10 @@ #endif } -static int -privsep_preauth(Authctxt *authctxt) +static Authctxt * +privsep_preauth(void) { + Authctxt *authctxt = NULL; int status; pid_t pid; @@ -599,8 +578,7 @@ debug2("Network child is on pid %ld", (long)pid); close(pmonitor->m_recvfd); - pmonitor->m_pid = pid; - monitor_child_preauth(authctxt, pmonitor); + authctxt = monitor_child_preauth(pmonitor); close(pmonitor->m_sendfd); /* Sync memory */ @@ -610,7 +588,7 @@ while (waitpid(pid, &status, 0) < 0) if (errno != EINTR) break; - return (1); + return (authctxt); } else { /* child */ @@ -621,12 +599,17 @@ privsep_preauth_child(); setproctitle("%s", "[net]"); } - return (0); + return (NULL); } static void privsep_postauth(Authctxt *authctxt) { + extern Authctxt *x_authctxt; + + /* XXX - Remote port forwarding */ + x_authctxt = authctxt; + if (authctxt->pw->pw_uid == 0 || options.use_login) { /* File descriptor passing is broken or root login */ monitor_apply_keystate(pmonitor); @@ -672,8 +655,7 @@ list_hostkey_types(void) { Buffer b; - const char *p; - char *ret; + char *p; int i; buffer_init(&b); @@ -692,10 +674,10 @@ } } buffer_append(&b, "\0", 1); - ret = xstrdup(buffer_ptr(&b)); + p = xstrdup(buffer_ptr(&b)); buffer_free(&b); - debug("list_hostkey_types: %s", ret); - return ret; + debug("list_hostkey_types: %s", p); + return p; } Key * @@ -763,96 +745,28 @@ static void usage(void) { - fprintf(stderr, "%s, %s\n", - SSH_VERSION, SSLeay_version(SSLEAY_VERSION)); - fprintf(stderr, -"usage: sshd [-46Ddeiqt] [-b bits] [-f config_file] [-g login_grace_time]\n" -" [-h host_key_file] [-k key_gen_time] [-o option] [-p port] [-u len]\n" - ); + fprintf(stderr, "sshd version %s\n", SSH_VERSION); + fprintf(stderr, "Usage: %s [options]\n", __progname); + fprintf(stderr, "Options:\n"); + fprintf(stderr, " -f file Configuration file (default %s)\n", _PATH_SERVER_CONFIG_FILE); + fprintf(stderr, " -d Debugging mode (multiple -d means more debugging)\n"); + fprintf(stderr, " -i Started from inetd\n"); + fprintf(stderr, " -D Do not fork into daemon mode\n"); + fprintf(stderr, " -t Only test configuration file and keys\n"); + fprintf(stderr, " -q Quiet (no logging)\n"); + fprintf(stderr, " -p port Listen on the specified port (default: 22)\n"); + fprintf(stderr, " -k seconds Regenerate server key every this many seconds (default: 3600)\n"); + fprintf(stderr, " -g seconds Grace period for authentication (default: 600)\n"); + fprintf(stderr, " -b bits Size of server RSA key (default: 768 bits)\n"); + fprintf(stderr, " -h file File from which to read host key (default: %s)\n", + _PATH_HOST_KEY_FILE); + fprintf(stderr, " -u len Maximum hostname length for utmp recording\n"); + fprintf(stderr, " -4 Use IPv4 only\n"); + fprintf(stderr, " -6 Use IPv6 only\n"); + fprintf(stderr, " -o option Process the option as if it was read from a configuration file.\n"); exit(1); } -static void -send_rexec_state(int fd, Buffer *conf) -{ - Buffer m; - - debug3("%s: entering fd = %d config len %d", __func__, fd, - buffer_len(conf)); - - /* - * Protocol from reexec master to child: - * string configuration - * u_int ephemeral_key_follows - * bignum e (only if ephemeral_key_follows == 1) - * bignum n " - * bignum d " - * bignum iqmp " - * bignum p " - * bignum q " - */ - buffer_init(&m); - buffer_put_cstring(&m, buffer_ptr(conf)); - - if (sensitive_data.server_key != NULL && - sensitive_data.server_key->type == KEY_RSA1) { - buffer_put_int(&m, 1); - buffer_put_bignum(&m, sensitive_data.server_key->rsa->e); - buffer_put_bignum(&m, sensitive_data.server_key->rsa->n); - buffer_put_bignum(&m, sensitive_data.server_key->rsa->d); - buffer_put_bignum(&m, sensitive_data.server_key->rsa->iqmp); - buffer_put_bignum(&m, sensitive_data.server_key->rsa->p); - buffer_put_bignum(&m, sensitive_data.server_key->rsa->q); - } else - buffer_put_int(&m, 0); - - if (ssh_msg_send(fd, 0, &m) == -1) - fatal("%s: ssh_msg_send failed", __func__); - - buffer_free(&m); - - debug3("%s: done", __func__); -} - -static void -recv_rexec_state(int fd, Buffer *conf) -{ - Buffer m; - char *cp; - u_int len; - - debug3("%s: entering fd = %d", __func__, fd); - - buffer_init(&m); - - if (ssh_msg_recv(fd, &m) == -1) - fatal("%s: ssh_msg_recv failed", __func__); - if (buffer_get_char(&m) != 0) - fatal("%s: rexec version mismatch", __func__); - - cp = buffer_get_string(&m, &len); - if (conf != NULL) - buffer_append(conf, cp, len + 1); - xfree(cp); - - if (buffer_get_int(&m)) { - if (sensitive_data.server_key != NULL) - key_free(sensitive_data.server_key); - sensitive_data.server_key = key_new_private(KEY_RSA1); - buffer_get_bignum(&m, sensitive_data.server_key->rsa->e); - buffer_get_bignum(&m, sensitive_data.server_key->rsa->n); - buffer_get_bignum(&m, sensitive_data.server_key->rsa->d); - buffer_get_bignum(&m, sensitive_data.server_key->rsa->iqmp); - buffer_get_bignum(&m, sensitive_data.server_key->rsa->p); - buffer_get_bignum(&m, sensitive_data.server_key->rsa->q); - rsa_generate_additional_parameters( - sensitive_data.server_key->rsa); - } - buffer_free(&m); - - debug3("%s: done", __func__); -} - /* * Main program for the daemon. */ @@ -861,8 +775,7 @@ { extern char *optarg; extern int optind; - int opt, j, i, fdsetsz, on = 1; - int sock_in = -1, sock_out = -1, newsock = -1; + int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1; pid_t pid; socklen_t fromlen; fd_set *fdset; @@ -872,24 +785,21 @@ FILE *f; struct addrinfo *ai; char ntop[NI_MAXHOST], strport[NI_MAXSERV]; - char *line; int listen_sock, maxfd; - int startup_p[2], config_s[2]; + int startup_p[2]; int startups = 0; - Key *key; Authctxt *authctxt; + Key *key; int ret, key_used = 0; - Buffer cfg; /* Save argv. */ saved_argv = av; - rexec_argc = ac; /* Initialize configuration options to their default values. */ initialize_server_options(&options); /* Parse command-line arguments. */ - while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqrtQR46")) != -1) { + while ((opt = getopt(ac, av, "f:p:b:k:h:g:u:o:dDeiqtQ46")) != -1) { switch (opt) { case '4': IPv4or6 = AF_INET; @@ -916,13 +826,6 @@ case 'i': inetd_flag = 1; break; - case 'r': - rexec_flag = 0; - break; - case 'R': - rexeced_flag = 1; - inetd_flag = 1; - break; case 'Q': /* ignored */ break; @@ -974,11 +877,9 @@ } break; case 'o': - line = xstrdup(optarg); - if (process_server_config_line(&options, line, + if (process_server_config_line(&options, optarg, "command-line", 0) != 0) exit(1); - xfree(line); break; case '?': default: @@ -986,15 +887,6 @@ break; } } - if (rexeced_flag || inetd_flag) - rexec_flag = 0; - if (rexec_flag && (av[0] == NULL || *av[0] != '/')) - fatal("sshd re-exec requires execution with an absolute path"); - if (rexeced_flag) - closefrom(REEXEC_MIN_FREE_FD); - else - closefrom(REEXEC_DEVCRYPTO_RESERVED_FD); - SSLeay_add_all_algorithms(); channel_set_af(IPv4or6); @@ -1009,24 +901,9 @@ SYSLOG_FACILITY_AUTH : options.log_facility, log_stderr || !inetd_flag); - sensitive_data.server_key = NULL; - sensitive_data.ssh1_host_key = NULL; - sensitive_data.have_ssh1_key = 0; - sensitive_data.have_ssh2_key = 0; + /* Read server configuration options from the configuration file. */ + read_server_config(&options, config_file_name); - /* Fetch our configuration */ - buffer_init(&cfg); - if (rexeced_flag) - recv_rexec_state(REEXEC_CONFIG_PASS_FD, &cfg); - else - load_server_config(config_file_name, &cfg); - - parse_server_config(&options, - rexeced_flag ? "rexec" : config_file_name, &cfg); - - if (!rexec_flag) - buffer_free(&cfg); - /* Fill in default values for those options not explicitly set. */ fill_default_server_options(&options); @@ -1043,6 +920,10 @@ sizeof(Key *)); for (i = 0; i < options.num_host_key_files; i++) sensitive_data.host_keys[i] = NULL; + sensitive_data.server_key = NULL; + sensitive_data.ssh1_host_key = NULL; + sensitive_data.have_ssh1_key = 0; + sensitive_data.have_ssh2_key = 0; for (i = 0; i < options.num_host_key_files; i++) { key = key_load_private(options.host_key_files[i], "", NULL); @@ -1124,16 +1005,6 @@ if (test_flag) exit(0); - if (rexec_flag) { - rexec_argv = xmalloc(sizeof(char *) * (rexec_argc + 2)); - for (i = 0; i < rexec_argc; i++) { - debug("rexec_argv[%d]='%s'", i, saved_argv[i]); - rexec_argv[i] = saved_argv[i]; - } - rexec_argv[rexec_argc] = "-R"; - rexec_argv[rexec_argc + 1] = NULL; - } - /* Initialize the log (it is reinitialized below in case we forked). */ if (debug_flag && !inetd_flag) log_stderr = 1; @@ -1175,34 +1046,19 @@ /* Start listening for a socket, unless started from inetd. */ if (inetd_flag) { - int fd; - + int s1; + s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */ + dup(s1); + sock_in = dup(0); + sock_out = dup(1); startup_pipe = -1; - if (rexeced_flag) { - close(REEXEC_CONFIG_PASS_FD); - sock_in = sock_out = dup(STDIN_FILENO); - if (!debug_flag) { - startup_pipe = dup(REEXEC_STARTUP_PIPE_FD); - close(REEXEC_STARTUP_PIPE_FD); - } - } else { - sock_in = dup(STDIN_FILENO); - sock_out = dup(STDOUT_FILENO); - } /* * We intentionally do not close the descriptors 0, 1, and 2 - * as our code for setting the descriptors won't work if + * as our code for setting the descriptors won\'t work if * ttyfd happens to be one of those. */ - if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - if (fd > STDOUT_FILENO) - close(fd); - } debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); - if ((options.protocol & SSH_PROTO_1) && - sensitive_data.server_key == NULL) + if (options.protocol & SSH_PROTO_1) generate_ephemeral_server_key(); } else { for (ai = options.listen_addrs; ai; ai = ai->ai_next) { @@ -1225,7 +1081,8 @@ verbose("socket: %.100s", strerror(errno)); continue; } - if (set_nonblock(listen_sock) == -1) { + if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) { + error("listen_sock O_NONBLOCK: %s", strerror(errno)); close(listen_sock); continue; } @@ -1251,7 +1108,7 @@ /* Start listening on the port. */ logit("Server listening on %s port %s.", ntop, strport); - if (listen(listen_sock, SSH_LISTEN_BACKLOG) < 0) + if (listen(listen_sock, 5) < 0) fatal("listen: %.100s", strerror(errno)); } @@ -1367,7 +1224,8 @@ error("accept: %.100s", strerror(errno)); continue; } - if (unset_nonblock(newsock) == -1) { + if (fcntl(newsock, F_SETFL, 0) < 0) { + error("newsock del O_NONBLOCK: %s", strerror(errno)); close(newsock); continue; } @@ -1381,16 +1239,6 @@ continue; } - if (rexec_flag && socketpair(AF_UNIX, - SOCK_STREAM, 0, config_s) == -1) { - error("reexec socketpair: %s", - strerror(errno)); - close(newsock); - close(startup_p[0]); - close(startup_p[1]); - continue; - } - for (j = 0; j < options.max_startups; j++) if (startup_pipes[j] == -1) { startup_pipes[j] = startup_p[0]; @@ -1414,15 +1262,8 @@ close_listen_socks(); sock_in = newsock; sock_out = newsock; - close(startup_p[0]); - close(startup_p[1]); startup_pipe = -1; pid = getpid(); - if (rexec_flag) { - send_rexec_state(config_s[0], - &cfg); - close(config_s[0]); - } break; } else { /* @@ -1444,7 +1285,6 @@ sock_in = newsock; sock_out = newsock; log_init(__progname, options.log_level, options.log_facility, log_stderr); - close(config_s[0]); break; } } @@ -1457,12 +1297,6 @@ close(startup_p[1]); - if (rexec_flag) { - send_rexec_state(config_s[0], &cfg); - close(config_s[0]); - close(config_s[1]); - } - /* Mark that the key has been used (it was "given" to the child). */ if ((options.protocol & SSH_PROTO_1) && key_used == 0) { @@ -1484,7 +1318,6 @@ } /* This is the child processing a new connection. */ - setproctitle("%s", "[accepted]"); /* * Create a new session and process group since the 4.4BSD @@ -1494,46 +1327,6 @@ if (!debug_flag && !inetd_flag && setsid() < 0) error("setsid: %.100s", strerror(errno)); - if (rexec_flag) { - int fd; - - debug("rexec start in %d out %d newsock %d pipe %d sock %d", - sock_in, sock_out, newsock, startup_pipe, config_s[0]); - dup2(newsock, STDIN_FILENO); - dup2(STDIN_FILENO, STDOUT_FILENO); - if (startup_pipe == -1) - close(REEXEC_STARTUP_PIPE_FD); - else - dup2(startup_pipe, REEXEC_STARTUP_PIPE_FD); - - dup2(config_s[1], REEXEC_CONFIG_PASS_FD); - close(config_s[1]); - if (startup_pipe != -1) - close(startup_pipe); - - execv(rexec_argv[0], rexec_argv); - - /* Reexec has failed, fall back and continue */ - error("rexec of %s failed: %s", rexec_argv[0], strerror(errno)); - recv_rexec_state(REEXEC_CONFIG_PASS_FD, NULL); - log_init(__progname, options.log_level, - options.log_facility, log_stderr); - - /* Clean up fds */ - startup_pipe = REEXEC_STARTUP_PIPE_FD; - close(config_s[1]); - close(REEXEC_CONFIG_PASS_FD); - newsock = sock_out = sock_in = dup(STDIN_FILENO); - if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) { - dup2(fd, STDIN_FILENO); - dup2(fd, STDOUT_FILENO); - if (fd > STDERR_FILENO) - close(fd); - } - debug("rexec cleanup in %d out %d newsock %d pipe %d sock %d", - sock_in, sock_out, newsock, startup_pipe, config_s[0]); - } - /* * 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 @@ -1546,8 +1339,8 @@ signal(SIGQUIT, SIG_DFL); signal(SIGCHLD, SIG_DFL); - /* Set SO_KEEPALIVE if requested. */ - if (options.tcp_keep_alive && + /* Set keepalives if requested. */ + if (options.keepalives && setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, sizeof(on)) < 0) error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); @@ -1563,7 +1356,7 @@ #ifdef LIBWRAP /* Check whether logins are denied from this host. */ - if (packet_connection_is_on_socket()) { + { struct request_info req; request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); @@ -1597,28 +1390,18 @@ packet_set_nonblocking(); - /* allocate authentication context */ - authctxt = xmalloc(sizeof(*authctxt)); - memset(authctxt, 0, sizeof(*authctxt)); - - /* XXX global for cleanup, access from other modules */ - the_authctxt = authctxt; - if (use_privsep) - if (privsep_preauth(authctxt) == 1) + if ((authctxt = privsep_preauth()) != NULL) goto authenticated; - /* prepare buffer to collect messages to display to user after login */ - buffer_init(&loginmsg); - /* perform the key exchange */ /* authenticate user and start session */ if (compat20) { do_ssh2_kex(); - do_authentication2(authctxt); + authctxt = do_authentication2(); } else { do_ssh1_kex(); - do_authentication(authctxt); + authctxt = do_authentication(); } /* * If we use privilege separation, the unprivileged child transfers @@ -1641,7 +1424,7 @@ destroy_sensitive_data(); } - /* Start session. */ + /* Perform session preparation. */ do_authenticated(authctxt); /* The connection has been terminated. */ @@ -1820,10 +1603,9 @@ BN_bn2bin(session_key_int, session_key + sizeof(session_key) - len); - derive_ssh1_session_id( + compute_session_id(session_id, cookie, sensitive_data.ssh1_host_key->rsa->n, - sensitive_data.server_key->rsa->n, - cookie, session_id); + sensitive_data.server_key->rsa->n); /* * Xor the first 16 bytes of the session key with the * session id. @@ -1906,7 +1688,6 @@ /* start key exchange */ kex = kex_setup(myproposal); kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; - kex->kex[KEX_DH_GRP14_SHA1] = kexdh_server; kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; kex->server = 1; kex->client_version_string=client_version_string; @@ -1929,13 +1710,4 @@ packet_write_wait(); #endif debug("KEX done"); -} - -/* server specific fatal cleanup */ -void -cleanup_exit(int i) -{ - if (the_authctxt) - do_cleanup(the_authctxt); - _exit(i); }