10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * Author: Tatu Ylonen <ylo@cs.hut.fi> 30Sstevel@tonic-gate * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 40Sstevel@tonic-gate * All rights reserved 50Sstevel@tonic-gate * This program is the ssh daemon. It listens for connections from clients, 60Sstevel@tonic-gate * and performs authentication, executes use commands or shell, and forwards 70Sstevel@tonic-gate * information to/from the application to the user client over an encrypted 80Sstevel@tonic-gate * connection. This can also handle forwarding of X11, TCP/IP, and 90Sstevel@tonic-gate * authentication agent connections. 100Sstevel@tonic-gate * 110Sstevel@tonic-gate * As far as I am concerned, the code I have written for this software 120Sstevel@tonic-gate * can be used freely for any purpose. Any derived versions of this 130Sstevel@tonic-gate * software must be clearly marked as such, and if the derived work is 140Sstevel@tonic-gate * incompatible with the protocol description in the RFC file, it must be 150Sstevel@tonic-gate * called by a name other than "ssh" or "Secure Shell". 160Sstevel@tonic-gate * 170Sstevel@tonic-gate * SSH2 implementation: 180Sstevel@tonic-gate * Privilege Separation: 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. 210Sstevel@tonic-gate * Copyright (c) 2002 Niels Provos. All rights reserved. 220Sstevel@tonic-gate * 230Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 240Sstevel@tonic-gate * modification, are permitted provided that the following conditions 250Sstevel@tonic-gate * are met: 260Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 270Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 280Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 290Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 300Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 310Sstevel@tonic-gate * 320Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 330Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 340Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 350Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 360Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 370Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 380Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 390Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 400Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 410Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 420Sstevel@tonic-gate */ 430Sstevel@tonic-gate /* 448658SJan.Pechanec@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 450Sstevel@tonic-gate * Use is subject to license terms. 460Sstevel@tonic-gate */ 470Sstevel@tonic-gate 480Sstevel@tonic-gate #include "includes.h" 490Sstevel@tonic-gate RCSID("$OpenBSD: sshd.c,v 1.260 2002/09/27 10:42:09 mickey Exp $"); 500Sstevel@tonic-gate 510Sstevel@tonic-gate #include <openssl/dh.h> 520Sstevel@tonic-gate #include <openssl/bn.h> 530Sstevel@tonic-gate #include <openssl/md5.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #include <openssl/rand.h> 560Sstevel@tonic-gate #ifdef HAVE_SECUREWARE 570Sstevel@tonic-gate #include <sys/security.h> 580Sstevel@tonic-gate #include <prot.h> 590Sstevel@tonic-gate #endif 600Sstevel@tonic-gate 610Sstevel@tonic-gate #include "ssh.h" 620Sstevel@tonic-gate #include "ssh1.h" 630Sstevel@tonic-gate #include "ssh2.h" 640Sstevel@tonic-gate #include "xmalloc.h" 650Sstevel@tonic-gate #include "rsa.h" 660Sstevel@tonic-gate #include "sshpty.h" 670Sstevel@tonic-gate #include "packet.h" 680Sstevel@tonic-gate #include "mpaux.h" 690Sstevel@tonic-gate #include "log.h" 700Sstevel@tonic-gate #include "servconf.h" 710Sstevel@tonic-gate #include "uidswap.h" 720Sstevel@tonic-gate #include "compat.h" 730Sstevel@tonic-gate #include "buffer.h" 740Sstevel@tonic-gate #include "cipher.h" 750Sstevel@tonic-gate #include "kex.h" 760Sstevel@tonic-gate #include "key.h" 770Sstevel@tonic-gate #include "dh.h" 780Sstevel@tonic-gate #include "myproposal.h" 790Sstevel@tonic-gate #include "authfile.h" 800Sstevel@tonic-gate #include "pathnames.h" 810Sstevel@tonic-gate #include "atomicio.h" 820Sstevel@tonic-gate #include "canohost.h" 830Sstevel@tonic-gate #include "auth.h" 840Sstevel@tonic-gate #include "misc.h" 850Sstevel@tonic-gate #include "dispatch.h" 860Sstevel@tonic-gate #include "channels.h" 870Sstevel@tonic-gate #include "session.h" 880Sstevel@tonic-gate #include "g11n.h" 890Sstevel@tonic-gate #include "sshlogin.h" 900Sstevel@tonic-gate #include "xlist.h" 917574SJan.Pechanec@Sun.COM #include "engine.h" 920Sstevel@tonic-gate 930Sstevel@tonic-gate #ifdef HAVE_BSM 940Sstevel@tonic-gate #include "bsmaudit.h" 950Sstevel@tonic-gate #endif /* HAVE_BSM */ 960Sstevel@tonic-gate 970Sstevel@tonic-gate #ifdef ALTPRIVSEP 980Sstevel@tonic-gate #include "altprivsep.h" 990Sstevel@tonic-gate #endif /* ALTPRIVSEP */ 1000Sstevel@tonic-gate 1010Sstevel@tonic-gate #ifdef HAVE_SOLARIS_CONTRACTS 1020Sstevel@tonic-gate #include <sys/ctfs.h> 1030Sstevel@tonic-gate #include <sys/contract.h> 1040Sstevel@tonic-gate #include <sys/contract/process.h> 1050Sstevel@tonic-gate #include <libcontract.h> 1060Sstevel@tonic-gate #endif /* HAVE_SOLARIS_CONTRACTS */ 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate #ifdef GSSAPI 1090Sstevel@tonic-gate #include "ssh-gss.h" 1100Sstevel@tonic-gate #endif /* GSSAPI */ 1110Sstevel@tonic-gate 1120Sstevel@tonic-gate #ifdef LIBWRAP 1130Sstevel@tonic-gate #include <tcpd.h> 1140Sstevel@tonic-gate #include <syslog.h> 1150Sstevel@tonic-gate #ifndef lint 1160Sstevel@tonic-gate int allow_severity = LOG_INFO; 1170Sstevel@tonic-gate int deny_severity = LOG_WARNING; 1180Sstevel@tonic-gate #endif /* lint */ 1190Sstevel@tonic-gate #endif /* LIBWRAP */ 1200Sstevel@tonic-gate 1210Sstevel@tonic-gate #ifndef O_NOCTTY 1220Sstevel@tonic-gate #define O_NOCTTY 0 1230Sstevel@tonic-gate #endif 1240Sstevel@tonic-gate 1250Sstevel@tonic-gate #ifdef HAVE___PROGNAME 1260Sstevel@tonic-gate extern char *__progname; 1270Sstevel@tonic-gate #else 1280Sstevel@tonic-gate char *__progname; 1290Sstevel@tonic-gate #endif 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate /* Server configuration options. */ 1320Sstevel@tonic-gate ServerOptions options; 1330Sstevel@tonic-gate 1340Sstevel@tonic-gate /* Name of the server configuration file. */ 1350Sstevel@tonic-gate static char *config_file_name = _PATH_SERVER_CONFIG_FILE; 1360Sstevel@tonic-gate 1370Sstevel@tonic-gate /* 1380Sstevel@tonic-gate * Flag indicating whether IPv4 or IPv6. This can be set on the command line. 1390Sstevel@tonic-gate * Default value is AF_UNSPEC means both IPv4 and IPv6. 1400Sstevel@tonic-gate */ 1410Sstevel@tonic-gate #ifdef IPV4_DEFAULT 1420Sstevel@tonic-gate int IPv4or6 = AF_INET; 1430Sstevel@tonic-gate #else 1440Sstevel@tonic-gate int IPv4or6 = AF_UNSPEC; 1450Sstevel@tonic-gate #endif 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate /* 1480Sstevel@tonic-gate * Debug mode flag. This can be set on the command line. If debug 1490Sstevel@tonic-gate * mode is enabled, extra debugging output will be sent to the system 1500Sstevel@tonic-gate * log, the daemon will not go to background, and will exit after processing 1510Sstevel@tonic-gate * the first connection. 1520Sstevel@tonic-gate */ 1530Sstevel@tonic-gate int debug_flag = 0; 1540Sstevel@tonic-gate 1550Sstevel@tonic-gate /* Flag indicating that the daemon should only test the configuration and keys. */ 1560Sstevel@tonic-gate static int test_flag = 0; 1570Sstevel@tonic-gate 1580Sstevel@tonic-gate /* Flag indicating that the daemon is being started from inetd. */ 1590Sstevel@tonic-gate static int inetd_flag = 0; 1600Sstevel@tonic-gate 1610Sstevel@tonic-gate /* Flag indicating that sshd should not detach and become a daemon. */ 1620Sstevel@tonic-gate static int no_daemon_flag = 0; 1630Sstevel@tonic-gate 1640Sstevel@tonic-gate /* debug goes to stderr unless inetd_flag is set */ 1650Sstevel@tonic-gate int log_stderr = 0; 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate /* Saved arguments to main(). */ 1680Sstevel@tonic-gate static char **saved_argv; 1690Sstevel@tonic-gate static int saved_argc; 1700Sstevel@tonic-gate 1710Sstevel@tonic-gate /* 1720Sstevel@tonic-gate * The sockets that the server is listening; this is used in the SIGHUP 1730Sstevel@tonic-gate * signal handler. 1740Sstevel@tonic-gate */ 1750Sstevel@tonic-gate #define MAX_LISTEN_SOCKS 16 1760Sstevel@tonic-gate static int listen_socks[MAX_LISTEN_SOCKS]; 1770Sstevel@tonic-gate static int num_listen_socks = 0; 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* 1800Sstevel@tonic-gate * the client's version string, passed by sshd2 in compat mode. if != NULL, 1810Sstevel@tonic-gate * sshd will skip the version-number exchange 1820Sstevel@tonic-gate */ 1830Sstevel@tonic-gate static char *client_version_string = NULL; 1840Sstevel@tonic-gate static char *server_version_string = NULL; 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* for rekeying XXX fixme */ 1870Sstevel@tonic-gate Kex *xxx_kex; 1880Sstevel@tonic-gate 1890Sstevel@tonic-gate /* 1900Sstevel@tonic-gate * Any really sensitive data in the application is contained in this 1910Sstevel@tonic-gate * structure. The idea is that this structure could be locked into memory so 1920Sstevel@tonic-gate * that the pages do not get written into swap. However, there are some 1930Sstevel@tonic-gate * problems. The private key contains BIGNUMs, and we do not (in principle) 1940Sstevel@tonic-gate * have access to the internals of them, and locking just the structure is 1950Sstevel@tonic-gate * not very useful. Currently, memory locking is not implemented. 1960Sstevel@tonic-gate */ 1970Sstevel@tonic-gate static struct { 1980Sstevel@tonic-gate Key *server_key; /* ephemeral server key */ 1990Sstevel@tonic-gate Key *ssh1_host_key; /* ssh1 host key */ 2000Sstevel@tonic-gate Key **host_keys; /* all private host keys */ 2010Sstevel@tonic-gate int have_ssh1_key; 2020Sstevel@tonic-gate int have_ssh2_key; 2030Sstevel@tonic-gate u_char ssh1_cookie[SSH_SESSION_KEY_LENGTH]; 2040Sstevel@tonic-gate } sensitive_data; 2050Sstevel@tonic-gate 2060Sstevel@tonic-gate /* 2070Sstevel@tonic-gate * Flag indicating whether the RSA server key needs to be regenerated. 2080Sstevel@tonic-gate * Is set in the SIGALRM handler and cleared when the key is regenerated. 2090Sstevel@tonic-gate */ 2100Sstevel@tonic-gate static volatile sig_atomic_t key_do_regen = 0; 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate /* This is set to true when a signal is received. */ 2130Sstevel@tonic-gate static volatile sig_atomic_t received_sighup = 0; 2140Sstevel@tonic-gate static volatile sig_atomic_t received_sigterm = 0; 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate /* session identifier, used by RSA-auth */ 2170Sstevel@tonic-gate u_char session_id[16]; 2180Sstevel@tonic-gate 2190Sstevel@tonic-gate /* same for ssh2 */ 2200Sstevel@tonic-gate u_char *session_id2 = NULL; 2210Sstevel@tonic-gate int session_id2_len = 0; 2220Sstevel@tonic-gate 2230Sstevel@tonic-gate /* record remote hostname or ip */ 2240Sstevel@tonic-gate u_int utmp_len = MAXHOSTNAMELEN; 2250Sstevel@tonic-gate 2260Sstevel@tonic-gate /* options.max_startup sized array of fd ints */ 2270Sstevel@tonic-gate static int *startup_pipes = NULL; 2280Sstevel@tonic-gate static int startup_pipe = -1; /* in child */ 2290Sstevel@tonic-gate 2300Sstevel@tonic-gate #ifdef GSSAPI 2310Sstevel@tonic-gate static gss_OID_set mechs = GSS_C_NULL_OID_SET; 2320Sstevel@tonic-gate #endif /* GSSAPI */ 2330Sstevel@tonic-gate 2340Sstevel@tonic-gate /* Prototypes for various functions defined later in this file. */ 2350Sstevel@tonic-gate void destroy_sensitive_data(void); 2360Sstevel@tonic-gate static void demote_sensitive_data(void); 2370Sstevel@tonic-gate 2380Sstevel@tonic-gate static void do_ssh1_kex(void); 2390Sstevel@tonic-gate static void do_ssh2_kex(void); 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate /* 2420Sstevel@tonic-gate * Close all listening sockets 2430Sstevel@tonic-gate */ 2440Sstevel@tonic-gate static void 2450Sstevel@tonic-gate close_listen_socks(void) 2460Sstevel@tonic-gate { 2470Sstevel@tonic-gate int i; 2480Sstevel@tonic-gate 2490Sstevel@tonic-gate for (i = 0; i < num_listen_socks; i++) 2500Sstevel@tonic-gate (void) close(listen_socks[i]); 2510Sstevel@tonic-gate num_listen_socks = -1; 2520Sstevel@tonic-gate } 2530Sstevel@tonic-gate 2540Sstevel@tonic-gate static void 2550Sstevel@tonic-gate close_startup_pipes(void) 2560Sstevel@tonic-gate { 2570Sstevel@tonic-gate int i; 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate if (startup_pipes) 2600Sstevel@tonic-gate for (i = 0; i < options.max_startups; i++) 2610Sstevel@tonic-gate if (startup_pipes[i] != -1) 2620Sstevel@tonic-gate (void) close(startup_pipes[i]); 2630Sstevel@tonic-gate } 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* 2660Sstevel@tonic-gate * Signal handler for SIGHUP. Sshd execs itself when it receives SIGHUP; 2670Sstevel@tonic-gate * the effect is to reread the configuration file (and to regenerate 2680Sstevel@tonic-gate * the server key). 2690Sstevel@tonic-gate */ 2700Sstevel@tonic-gate static void 2710Sstevel@tonic-gate sighup_handler(int sig) 2720Sstevel@tonic-gate { 2730Sstevel@tonic-gate int save_errno = errno; 2740Sstevel@tonic-gate 2750Sstevel@tonic-gate received_sighup = 1; 2760Sstevel@tonic-gate (void) signal(SIGHUP, sighup_handler); 2770Sstevel@tonic-gate errno = save_errno; 2780Sstevel@tonic-gate } 2790Sstevel@tonic-gate 2800Sstevel@tonic-gate /* 2810Sstevel@tonic-gate * Called from the main program after receiving SIGHUP. 2820Sstevel@tonic-gate * Restarts the server. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate static void 2850Sstevel@tonic-gate sighup_restart(void) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate log("Received SIGHUP; restarting."); 2880Sstevel@tonic-gate close_listen_socks(); 2890Sstevel@tonic-gate close_startup_pipes(); 2900Sstevel@tonic-gate (void) execv(saved_argv[0], saved_argv); 2910Sstevel@tonic-gate log("RESTART FAILED: av[0]='%.100s', error: %.100s.", saved_argv[0], 2920Sstevel@tonic-gate strerror(errno)); 2930Sstevel@tonic-gate exit(1); 2940Sstevel@tonic-gate } 2950Sstevel@tonic-gate 2960Sstevel@tonic-gate /* 2970Sstevel@tonic-gate * Generic signal handler for terminating signals in the master daemon. 2980Sstevel@tonic-gate */ 2990Sstevel@tonic-gate static void 3000Sstevel@tonic-gate sigterm_handler(int sig) 3010Sstevel@tonic-gate { 3020Sstevel@tonic-gate received_sigterm = sig; 3030Sstevel@tonic-gate } 3040Sstevel@tonic-gate 3050Sstevel@tonic-gate /* 3060Sstevel@tonic-gate * SIGCHLD handler. This is called whenever a child dies. This will then 3070Sstevel@tonic-gate * reap any zombies left by exited children. 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate static void 3100Sstevel@tonic-gate main_sigchld_handler(int sig) 3110Sstevel@tonic-gate { 3120Sstevel@tonic-gate int save_errno = errno; 3130Sstevel@tonic-gate pid_t pid; 3140Sstevel@tonic-gate int status; 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate while ((pid = waitpid(-1, &status, WNOHANG)) > 0 || 3170Sstevel@tonic-gate (pid < 0 && errno == EINTR)) 3180Sstevel@tonic-gate ; 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate (void) signal(SIGCHLD, main_sigchld_handler); 3210Sstevel@tonic-gate errno = save_errno; 3220Sstevel@tonic-gate } 3230Sstevel@tonic-gate 3240Sstevel@tonic-gate /* 3250Sstevel@tonic-gate * Signal handler for the alarm after the login grace period has expired. 3260Sstevel@tonic-gate */ 3270Sstevel@tonic-gate static void 3280Sstevel@tonic-gate grace_alarm_handler(int sig) 3290Sstevel@tonic-gate { 3300Sstevel@tonic-gate /* XXX no idea how fix this signal handler */ 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* Log error and exit. */ 3330Sstevel@tonic-gate fatal("Timeout before authentication for %s", get_remote_ipaddr()); 3340Sstevel@tonic-gate } 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate #ifdef HAVE_SOLARIS_CONTRACTS 3370Sstevel@tonic-gate static int contracts_fd = -1; 3380Sstevel@tonic-gate void 3390Sstevel@tonic-gate contracts_pre_fork() 3400Sstevel@tonic-gate { 3410Sstevel@tonic-gate const char *during = "opening process contract template"; 3420Sstevel@tonic-gate 3430Sstevel@tonic-gate /* 3440Sstevel@tonic-gate * Failure should not be treated as fatal on the theory that 3450Sstevel@tonic-gate * it's better to start with children in the same contract as 3460Sstevel@tonic-gate * the master listener than not at all. 3470Sstevel@tonic-gate */ 3480Sstevel@tonic-gate 3490Sstevel@tonic-gate if (contracts_fd == -1) { 3500Sstevel@tonic-gate if ((contracts_fd = open64(CTFS_ROOT "/process/template", 3510Sstevel@tonic-gate O_RDWR)) == -1) 3520Sstevel@tonic-gate goto cleanup; 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate during = "setting sundry contract terms"; 3550Sstevel@tonic-gate if ((errno = ct_pr_tmpl_set_param(contracts_fd, CT_PR_PGRPONLY))) 3560Sstevel@tonic-gate goto cleanup; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if ((errno = ct_tmpl_set_informative(contracts_fd, CT_PR_EV_HWERR))) 3590Sstevel@tonic-gate goto cleanup; 3600Sstevel@tonic-gate 3610Sstevel@tonic-gate if ((errno = ct_pr_tmpl_set_fatal(contracts_fd, CT_PR_EV_HWERR))) 3620Sstevel@tonic-gate goto cleanup; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate if ((errno = ct_tmpl_set_critical(contracts_fd, 0))) 3650Sstevel@tonic-gate goto cleanup; 3660Sstevel@tonic-gate } 3670Sstevel@tonic-gate 3680Sstevel@tonic-gate during = "setting active template"; 3690Sstevel@tonic-gate if ((errno = ct_tmpl_activate(contracts_fd))) 3700Sstevel@tonic-gate goto cleanup; 3710Sstevel@tonic-gate 3720Sstevel@tonic-gate debug3("Set active contract"); 3730Sstevel@tonic-gate return; 3740Sstevel@tonic-gate 3750Sstevel@tonic-gate cleanup: 3760Sstevel@tonic-gate if (contracts_fd != -1) 3770Sstevel@tonic-gate (void) close(contracts_fd); 3780Sstevel@tonic-gate 3790Sstevel@tonic-gate contracts_fd = -1; 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate if (errno) 3820Sstevel@tonic-gate debug2("Error while trying to set up active contract" 3830Sstevel@tonic-gate " template: %s while %s", strerror(errno), during); 3840Sstevel@tonic-gate } 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate void 3870Sstevel@tonic-gate contracts_post_fork_child() 3880Sstevel@tonic-gate { 3890Sstevel@tonic-gate /* Clear active template so fork() creates no new contracts. */ 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate if (contracts_fd == -1) 3920Sstevel@tonic-gate return; 3930Sstevel@tonic-gate 3940Sstevel@tonic-gate if ((errno = (ct_tmpl_clear(contracts_fd)))) 3950Sstevel@tonic-gate debug2("Error while trying to clear active contract template" 3960Sstevel@tonic-gate " (child): %s", strerror(errno)); 3970Sstevel@tonic-gate else 3980Sstevel@tonic-gate debug3("Cleared active contract template (child)"); 3990Sstevel@tonic-gate 4000Sstevel@tonic-gate (void) close(contracts_fd); 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate contracts_fd = -1; 4030Sstevel@tonic-gate } 4040Sstevel@tonic-gate 4050Sstevel@tonic-gate void 4060Sstevel@tonic-gate contracts_post_fork_parent(int fork_succeeded) 4070Sstevel@tonic-gate { 4080Sstevel@tonic-gate char path[PATH_MAX]; 4090Sstevel@tonic-gate int cfd, n; 4100Sstevel@tonic-gate ct_stathdl_t st; 4110Sstevel@tonic-gate ctid_t latest; 4120Sstevel@tonic-gate 4130Sstevel@tonic-gate /* Clear active template, abandon latest contract. */ 4140Sstevel@tonic-gate if (contracts_fd == -1) 4150Sstevel@tonic-gate return; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate if ((errno = ct_tmpl_clear(contracts_fd))) 4180Sstevel@tonic-gate debug2("Error while clearing active contract template: %s", 4190Sstevel@tonic-gate strerror(errno)); 4200Sstevel@tonic-gate else 4210Sstevel@tonic-gate debug3("Cleared active contract template (parent)"); 4220Sstevel@tonic-gate 4230Sstevel@tonic-gate if (!fork_succeeded) 4240Sstevel@tonic-gate return; 4250Sstevel@tonic-gate 4260Sstevel@tonic-gate if ((cfd = open64(CTFS_ROOT "/process/latest", O_RDONLY)) == -1) { 4270Sstevel@tonic-gate debug2("Error while getting latest contract: %s", 4280Sstevel@tonic-gate strerror(errno)); 4290Sstevel@tonic-gate return; 4300Sstevel@tonic-gate } 4310Sstevel@tonic-gate 4320Sstevel@tonic-gate if ((errno = ct_status_read(cfd, CTD_COMMON, &st)) != 0) { 4330Sstevel@tonic-gate debug2("Error while getting latest contract ID: %s", 4340Sstevel@tonic-gate strerror(errno)); 4350Sstevel@tonic-gate (void) close(cfd); 4360Sstevel@tonic-gate return; 4370Sstevel@tonic-gate } 4380Sstevel@tonic-gate 4390Sstevel@tonic-gate latest = ct_status_get_id(st); 4400Sstevel@tonic-gate ct_status_free(st); 4410Sstevel@tonic-gate (void) close(cfd); 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate n = snprintf(path, PATH_MAX, CTFS_ROOT "/all/%ld/ctl", latest); 4440Sstevel@tonic-gate 4450Sstevel@tonic-gate if (n >= PATH_MAX) { 4460Sstevel@tonic-gate debug2("Error while opening the latest contract ctl file: %s", 4470Sstevel@tonic-gate strerror(ENAMETOOLONG)); 4480Sstevel@tonic-gate return; 4490Sstevel@tonic-gate } 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate if ((cfd = open64(path, O_WRONLY)) == -1) { 4520Sstevel@tonic-gate debug2("Error while opening the latest contract ctl file: %s", 4530Sstevel@tonic-gate strerror(errno)); 4540Sstevel@tonic-gate return; 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if ((errno = ct_ctl_abandon(cfd))) 4580Sstevel@tonic-gate debug2("Error while abandoning latest contract: %s", 4590Sstevel@tonic-gate strerror(errno)); 4600Sstevel@tonic-gate else 4610Sstevel@tonic-gate debug3("Abandoned latest contract"); 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate (void) close(cfd); 4640Sstevel@tonic-gate } 4650Sstevel@tonic-gate #endif /* HAVE_SOLARIS_CONTRACTS */ 4660Sstevel@tonic-gate 4670Sstevel@tonic-gate /* 4680Sstevel@tonic-gate * Signal handler for the key regeneration alarm. Note that this 4690Sstevel@tonic-gate * alarm only occurs in the daemon waiting for connections, and it does not 4700Sstevel@tonic-gate * do anything with the private key or random state before forking. 4710Sstevel@tonic-gate * Thus there should be no concurrency control/asynchronous execution 4720Sstevel@tonic-gate * problems. 4730Sstevel@tonic-gate */ 4740Sstevel@tonic-gate static void 4750Sstevel@tonic-gate generate_ephemeral_server_key(void) 4760Sstevel@tonic-gate { 4770Sstevel@tonic-gate u_int32_t rnd = 0; 4780Sstevel@tonic-gate int i; 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate verbose("Generating %s%d bit RSA key.", 4810Sstevel@tonic-gate sensitive_data.server_key ? "new " : "", options.server_key_bits); 4820Sstevel@tonic-gate if (sensitive_data.server_key != NULL) 4830Sstevel@tonic-gate key_free(sensitive_data.server_key); 4840Sstevel@tonic-gate sensitive_data.server_key = key_generate(KEY_RSA1, 4850Sstevel@tonic-gate options.server_key_bits); 4860Sstevel@tonic-gate verbose("RSA key generation complete."); 4870Sstevel@tonic-gate 4880Sstevel@tonic-gate for (i = 0; i < SSH_SESSION_KEY_LENGTH; i++) { 4890Sstevel@tonic-gate if (i % 4 == 0) 4900Sstevel@tonic-gate rnd = arc4random(); 4910Sstevel@tonic-gate sensitive_data.ssh1_cookie[i] = rnd & 0xff; 4920Sstevel@tonic-gate rnd >>= 8; 4930Sstevel@tonic-gate } 4940Sstevel@tonic-gate arc4random_stir(); 4950Sstevel@tonic-gate } 4960Sstevel@tonic-gate 4970Sstevel@tonic-gate static void 4980Sstevel@tonic-gate key_regeneration_alarm(int sig) 4990Sstevel@tonic-gate { 5000Sstevel@tonic-gate int save_errno = errno; 5010Sstevel@tonic-gate 5020Sstevel@tonic-gate (void) signal(SIGALRM, SIG_DFL); 5030Sstevel@tonic-gate errno = save_errno; 5040Sstevel@tonic-gate key_do_regen = 1; 5050Sstevel@tonic-gate } 5060Sstevel@tonic-gate 5070Sstevel@tonic-gate static void 5080Sstevel@tonic-gate sshd_exchange_identification(int sock_in, int sock_out) 5090Sstevel@tonic-gate { 5100Sstevel@tonic-gate int i, mismatch; 5110Sstevel@tonic-gate int remote_major, remote_minor; 5120Sstevel@tonic-gate int major, minor; 5130Sstevel@tonic-gate char *s; 5140Sstevel@tonic-gate char buf[256]; /* Must not be larger than remote_version. */ 5150Sstevel@tonic-gate char remote_version[256]; /* Must be at least as big as buf. */ 5160Sstevel@tonic-gate 5170Sstevel@tonic-gate if ((options.protocol & SSH_PROTO_1) && 5180Sstevel@tonic-gate (options.protocol & SSH_PROTO_2)) { 5190Sstevel@tonic-gate major = PROTOCOL_MAJOR_1; 5200Sstevel@tonic-gate minor = 99; 5210Sstevel@tonic-gate } else if (options.protocol & SSH_PROTO_2) { 5220Sstevel@tonic-gate major = PROTOCOL_MAJOR_2; 5230Sstevel@tonic-gate minor = PROTOCOL_MINOR_2; 5240Sstevel@tonic-gate } else { 5250Sstevel@tonic-gate major = PROTOCOL_MAJOR_1; 5260Sstevel@tonic-gate minor = PROTOCOL_MINOR_1; 5270Sstevel@tonic-gate } 5280Sstevel@tonic-gate (void) snprintf(buf, sizeof buf, "SSH-%d.%d-%.100s\n", major, minor, SSH_VERSION); 5290Sstevel@tonic-gate server_version_string = xstrdup(buf); 5300Sstevel@tonic-gate 5310Sstevel@tonic-gate if (client_version_string == NULL) { 5320Sstevel@tonic-gate /* Send our protocol version identification. */ 5330Sstevel@tonic-gate if (atomicio(write, sock_out, server_version_string, 5340Sstevel@tonic-gate strlen(server_version_string)) 5350Sstevel@tonic-gate != strlen(server_version_string)) { 5360Sstevel@tonic-gate log("Could not write ident string to %s", get_remote_ipaddr()); 5370Sstevel@tonic-gate fatal_cleanup(); 5380Sstevel@tonic-gate } 5390Sstevel@tonic-gate 5400Sstevel@tonic-gate /* Read other sides version identification. */ 5410Sstevel@tonic-gate (void) memset(buf, 0, sizeof(buf)); 5420Sstevel@tonic-gate for (i = 0; i < sizeof(buf) - 1; i++) { 5430Sstevel@tonic-gate if (atomicio(read, sock_in, &buf[i], 1) != 1) { 5440Sstevel@tonic-gate log("Did not receive identification string from %s", 5450Sstevel@tonic-gate get_remote_ipaddr()); 5460Sstevel@tonic-gate fatal_cleanup(); 5470Sstevel@tonic-gate } 5480Sstevel@tonic-gate if (buf[i] == '\r') { 5490Sstevel@tonic-gate buf[i] = 0; 5500Sstevel@tonic-gate /* Kludge for F-Secure Macintosh < 1.0.2 */ 5510Sstevel@tonic-gate if (i == 12 && 5520Sstevel@tonic-gate strncmp(buf, "SSH-1.5-W1.0", 12) == 0) 5530Sstevel@tonic-gate break; 5540Sstevel@tonic-gate continue; 5550Sstevel@tonic-gate } 5560Sstevel@tonic-gate if (buf[i] == '\n') { 5570Sstevel@tonic-gate buf[i] = 0; 5580Sstevel@tonic-gate break; 5590Sstevel@tonic-gate } 5600Sstevel@tonic-gate } 5610Sstevel@tonic-gate buf[sizeof(buf) - 1] = 0; 5620Sstevel@tonic-gate client_version_string = xstrdup(buf); 5630Sstevel@tonic-gate } 5640Sstevel@tonic-gate 5650Sstevel@tonic-gate /* 5660Sstevel@tonic-gate * Check that the versions match. In future this might accept 5670Sstevel@tonic-gate * several versions and set appropriate flags to handle them. 5680Sstevel@tonic-gate */ 5690Sstevel@tonic-gate if (sscanf(client_version_string, "SSH-%d.%d-%[^\n]\n", 5700Sstevel@tonic-gate &remote_major, &remote_minor, remote_version) != 3) { 5710Sstevel@tonic-gate s = "Protocol mismatch.\n"; 5720Sstevel@tonic-gate (void) atomicio(write, sock_out, s, strlen(s)); 5730Sstevel@tonic-gate (void) close(sock_in); 5740Sstevel@tonic-gate (void) close(sock_out); 5750Sstevel@tonic-gate log("Bad protocol version identification '%.100s' from %s", 5760Sstevel@tonic-gate client_version_string, get_remote_ipaddr()); 5770Sstevel@tonic-gate fatal_cleanup(); 5780Sstevel@tonic-gate } 5790Sstevel@tonic-gate debug("Client protocol version %d.%d; client software version %.100s", 5800Sstevel@tonic-gate remote_major, remote_minor, remote_version); 5810Sstevel@tonic-gate 5820Sstevel@tonic-gate compat_datafellows(remote_version); 5830Sstevel@tonic-gate 5840Sstevel@tonic-gate if (datafellows & SSH_BUG_PROBE) { 5850Sstevel@tonic-gate log("probed from %s with %s. Don't panic.", 5860Sstevel@tonic-gate get_remote_ipaddr(), client_version_string); 5870Sstevel@tonic-gate fatal_cleanup(); 5880Sstevel@tonic-gate } 5890Sstevel@tonic-gate 5900Sstevel@tonic-gate if (datafellows & SSH_BUG_SCANNER) { 5910Sstevel@tonic-gate log("scanned from %s with %s. Don't panic.", 5920Sstevel@tonic-gate get_remote_ipaddr(), client_version_string); 5930Sstevel@tonic-gate fatal_cleanup(); 5940Sstevel@tonic-gate } 5950Sstevel@tonic-gate 5960Sstevel@tonic-gate mismatch = 0; 5970Sstevel@tonic-gate switch (remote_major) { 5980Sstevel@tonic-gate case 1: 5990Sstevel@tonic-gate if (remote_minor == 99) { 6000Sstevel@tonic-gate if (options.protocol & SSH_PROTO_2) 6010Sstevel@tonic-gate enable_compat20(); 6020Sstevel@tonic-gate else 6030Sstevel@tonic-gate mismatch = 1; 6040Sstevel@tonic-gate break; 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate if (!(options.protocol & SSH_PROTO_1)) { 6070Sstevel@tonic-gate mismatch = 1; 6080Sstevel@tonic-gate break; 6090Sstevel@tonic-gate } 6100Sstevel@tonic-gate if (remote_minor < 3) { 6110Sstevel@tonic-gate packet_disconnect("Your ssh version is too old and " 6120Sstevel@tonic-gate "is no longer supported. Please install a newer version."); 6130Sstevel@tonic-gate } else if (remote_minor == 3) { 6140Sstevel@tonic-gate /* note that this disables agent-forwarding */ 6150Sstevel@tonic-gate enable_compat13(); 6160Sstevel@tonic-gate } 6170Sstevel@tonic-gate break; 6180Sstevel@tonic-gate case 2: 6190Sstevel@tonic-gate if (options.protocol & SSH_PROTO_2) { 6200Sstevel@tonic-gate enable_compat20(); 6210Sstevel@tonic-gate break; 6220Sstevel@tonic-gate } 6230Sstevel@tonic-gate /* FALLTHROUGH */ 6240Sstevel@tonic-gate default: 6250Sstevel@tonic-gate mismatch = 1; 6260Sstevel@tonic-gate break; 6270Sstevel@tonic-gate } 6280Sstevel@tonic-gate chop(server_version_string); 6290Sstevel@tonic-gate debug("Local version string %.200s", server_version_string); 6300Sstevel@tonic-gate 6310Sstevel@tonic-gate if (mismatch) { 6320Sstevel@tonic-gate s = "Protocol major versions differ.\n"; 6330Sstevel@tonic-gate (void) atomicio(write, sock_out, s, strlen(s)); 6340Sstevel@tonic-gate (void) close(sock_in); 6350Sstevel@tonic-gate (void) close(sock_out); 6360Sstevel@tonic-gate log("Protocol major versions differ for %s: %.200s vs. %.200s", 6370Sstevel@tonic-gate get_remote_ipaddr(), 6380Sstevel@tonic-gate server_version_string, client_version_string); 6390Sstevel@tonic-gate fatal_cleanup(); 6400Sstevel@tonic-gate } 6410Sstevel@tonic-gate } 6420Sstevel@tonic-gate 6430Sstevel@tonic-gate /* Destroy the host and server keys. They will no longer be needed. */ 6440Sstevel@tonic-gate void 6450Sstevel@tonic-gate destroy_sensitive_data(void) 6460Sstevel@tonic-gate { 6470Sstevel@tonic-gate int i; 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate if (sensitive_data.server_key) { 6500Sstevel@tonic-gate key_free(sensitive_data.server_key); 6510Sstevel@tonic-gate sensitive_data.server_key = NULL; 6520Sstevel@tonic-gate } 6530Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) { 6540Sstevel@tonic-gate if (sensitive_data.host_keys[i]) { 6550Sstevel@tonic-gate key_free(sensitive_data.host_keys[i]); 6560Sstevel@tonic-gate sensitive_data.host_keys[i] = NULL; 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate } 6590Sstevel@tonic-gate sensitive_data.ssh1_host_key = NULL; 6600Sstevel@tonic-gate (void) memset(sensitive_data.ssh1_cookie, 0, SSH_SESSION_KEY_LENGTH); 6610Sstevel@tonic-gate } 6620Sstevel@tonic-gate 6630Sstevel@tonic-gate /* Demote private to public keys for network child */ 6640Sstevel@tonic-gate static void 6650Sstevel@tonic-gate demote_sensitive_data(void) 6660Sstevel@tonic-gate { 6670Sstevel@tonic-gate Key *tmp; 6680Sstevel@tonic-gate int i; 6690Sstevel@tonic-gate 6700Sstevel@tonic-gate if (sensitive_data.server_key) { 6710Sstevel@tonic-gate tmp = key_demote(sensitive_data.server_key); 6720Sstevel@tonic-gate key_free(sensitive_data.server_key); 6730Sstevel@tonic-gate sensitive_data.server_key = tmp; 6740Sstevel@tonic-gate } 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) { 6770Sstevel@tonic-gate if (sensitive_data.host_keys[i]) { 6780Sstevel@tonic-gate tmp = key_demote(sensitive_data.host_keys[i]); 6790Sstevel@tonic-gate key_free(sensitive_data.host_keys[i]); 6800Sstevel@tonic-gate sensitive_data.host_keys[i] = tmp; 6810Sstevel@tonic-gate if (tmp->type == KEY_RSA1) 6820Sstevel@tonic-gate sensitive_data.ssh1_host_key = tmp; 6830Sstevel@tonic-gate } 6840Sstevel@tonic-gate } 6850Sstevel@tonic-gate 6860Sstevel@tonic-gate /* We do not clear ssh1_host key and cookie. XXX - Okay Niels? */ 6870Sstevel@tonic-gate } 6880Sstevel@tonic-gate 6890Sstevel@tonic-gate static char * 6900Sstevel@tonic-gate list_hostkey_types(void) 6910Sstevel@tonic-gate { 6920Sstevel@tonic-gate Buffer b; 6930Sstevel@tonic-gate char *p; 6940Sstevel@tonic-gate int i; 6950Sstevel@tonic-gate 6960Sstevel@tonic-gate buffer_init(&b); 6970Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) { 6980Sstevel@tonic-gate Key *key = sensitive_data.host_keys[i]; 6990Sstevel@tonic-gate if (key == NULL) 7000Sstevel@tonic-gate continue; 7010Sstevel@tonic-gate switch (key->type) { 7020Sstevel@tonic-gate case KEY_RSA: 7030Sstevel@tonic-gate case KEY_DSA: 7040Sstevel@tonic-gate if (buffer_len(&b) > 0) 7050Sstevel@tonic-gate buffer_append(&b, ",", 1); 7060Sstevel@tonic-gate p = key_ssh_name(key); 7070Sstevel@tonic-gate buffer_append(&b, p, strlen(p)); 7080Sstevel@tonic-gate break; 7090Sstevel@tonic-gate } 7100Sstevel@tonic-gate } 7110Sstevel@tonic-gate buffer_append(&b, "\0", 1); 7120Sstevel@tonic-gate p = xstrdup(buffer_ptr(&b)); 7130Sstevel@tonic-gate buffer_free(&b); 7140Sstevel@tonic-gate debug("list_hostkey_types: %s", p); 7150Sstevel@tonic-gate return p; 7160Sstevel@tonic-gate } 7170Sstevel@tonic-gate 7180Sstevel@tonic-gate #ifdef lint 7190Sstevel@tonic-gate static 7200Sstevel@tonic-gate #endif /* lint */ 7210Sstevel@tonic-gate Key * 7220Sstevel@tonic-gate get_hostkey_by_type(int type) 7230Sstevel@tonic-gate { 7240Sstevel@tonic-gate int i; 7250Sstevel@tonic-gate 7260Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) { 7270Sstevel@tonic-gate Key *key = sensitive_data.host_keys[i]; 7280Sstevel@tonic-gate if (key != NULL && key->type == type) 7290Sstevel@tonic-gate return key; 7300Sstevel@tonic-gate } 7310Sstevel@tonic-gate return NULL; 7320Sstevel@tonic-gate } 7330Sstevel@tonic-gate 7340Sstevel@tonic-gate #ifdef lint 7350Sstevel@tonic-gate static 7360Sstevel@tonic-gate #endif /* lint */ 7370Sstevel@tonic-gate Key * 7380Sstevel@tonic-gate get_hostkey_by_index(int ind) 7390Sstevel@tonic-gate { 7400Sstevel@tonic-gate if (ind < 0 || ind >= options.num_host_key_files) 7410Sstevel@tonic-gate return (NULL); 7420Sstevel@tonic-gate return (sensitive_data.host_keys[ind]); 7430Sstevel@tonic-gate } 7440Sstevel@tonic-gate 7450Sstevel@tonic-gate #ifdef lint 7460Sstevel@tonic-gate static 7470Sstevel@tonic-gate #endif /* lint */ 7480Sstevel@tonic-gate int 7490Sstevel@tonic-gate get_hostkey_index(Key *key) 7500Sstevel@tonic-gate { 7510Sstevel@tonic-gate int i; 7520Sstevel@tonic-gate 7530Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) { 7540Sstevel@tonic-gate if (key == sensitive_data.host_keys[i]) 7550Sstevel@tonic-gate return (i); 7560Sstevel@tonic-gate } 7570Sstevel@tonic-gate return (-1); 7580Sstevel@tonic-gate } 7590Sstevel@tonic-gate 7600Sstevel@tonic-gate /* 7610Sstevel@tonic-gate * returns 1 if connection should be dropped, 0 otherwise. 7620Sstevel@tonic-gate * dropping starts at connection #max_startups_begin with a probability 7630Sstevel@tonic-gate * of (max_startups_rate/100). the probability increases linearly until 7640Sstevel@tonic-gate * all connections are dropped for startups > max_startups 7650Sstevel@tonic-gate */ 7660Sstevel@tonic-gate static int 7670Sstevel@tonic-gate drop_connection(int startups) 7680Sstevel@tonic-gate { 7690Sstevel@tonic-gate double p, r; 7700Sstevel@tonic-gate 7710Sstevel@tonic-gate if (startups < options.max_startups_begin) 7720Sstevel@tonic-gate return 0; 7730Sstevel@tonic-gate if (startups >= options.max_startups) 7740Sstevel@tonic-gate return 1; 7750Sstevel@tonic-gate if (options.max_startups_rate == 100) 7760Sstevel@tonic-gate return 1; 7770Sstevel@tonic-gate 7780Sstevel@tonic-gate p = 100 - options.max_startups_rate; 7790Sstevel@tonic-gate p *= startups - options.max_startups_begin; 7800Sstevel@tonic-gate p /= (double) (options.max_startups - options.max_startups_begin); 7810Sstevel@tonic-gate p += options.max_startups_rate; 7820Sstevel@tonic-gate p /= 100.0; 7830Sstevel@tonic-gate r = arc4random() / (double) UINT_MAX; 7840Sstevel@tonic-gate 7850Sstevel@tonic-gate debug("drop_connection: p %g, r %g", p, r); 7860Sstevel@tonic-gate return (r < p) ? 1 : 0; 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate static void 7900Sstevel@tonic-gate usage(void) 7910Sstevel@tonic-gate { 7920Sstevel@tonic-gate (void) fprintf(stderr, gettext("sshd version %s\n"), SSH_VERSION); 7930Sstevel@tonic-gate (void) fprintf(stderr, 7940Sstevel@tonic-gate gettext("Usage: %s [options]\n" 7950Sstevel@tonic-gate "Options:\n" 7960Sstevel@tonic-gate " -f file Configuration file (default %s)\n" 7970Sstevel@tonic-gate " -d Debugging mode (multiple -d means more " 7980Sstevel@tonic-gate "debugging)\n" 7990Sstevel@tonic-gate " -i Started from inetd\n" 8000Sstevel@tonic-gate " -D Do not fork into daemon mode\n" 8010Sstevel@tonic-gate " -t Only test configuration file and keys\n" 8020Sstevel@tonic-gate " -q Quiet (no logging)\n" 8030Sstevel@tonic-gate " -p port Listen on the specified port (default: 22)\n" 8040Sstevel@tonic-gate " -k seconds Regenerate server key every this many seconds " 8050Sstevel@tonic-gate "(default: 3600)\n" 8060Sstevel@tonic-gate " -g seconds Grace period for authentication (default: 600)\n" 8070Sstevel@tonic-gate " -b bits Size of server RSA key (default: 768 bits)\n" 8080Sstevel@tonic-gate " -h file File from which to read host key (default: %s)\n" 8090Sstevel@tonic-gate " -4 Use IPv4 only\n" 8100Sstevel@tonic-gate " -6 Use IPv6 only\n" 8110Sstevel@tonic-gate " -o option Process the option as if it was read from " 8120Sstevel@tonic-gate "a configuration file.\n"), 8130Sstevel@tonic-gate __progname, _PATH_SERVER_CONFIG_FILE, _PATH_HOST_KEY_FILE); 8140Sstevel@tonic-gate exit(1); 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * Main program for the daemon. 8190Sstevel@tonic-gate */ 8200Sstevel@tonic-gate int 8210Sstevel@tonic-gate main(int ac, char **av) 8220Sstevel@tonic-gate { 8230Sstevel@tonic-gate extern char *optarg; 8240Sstevel@tonic-gate extern int optind; 8257574SJan.Pechanec@Sun.COM int opt, j, i, fdsetsz, sock_in = 0, sock_out = 0, newsock = -1, on = 1; 8260Sstevel@tonic-gate pid_t pid; 8270Sstevel@tonic-gate socklen_t fromlen; 8280Sstevel@tonic-gate fd_set *fdset; 8290Sstevel@tonic-gate struct sockaddr_storage from; 8300Sstevel@tonic-gate const char *remote_ip; 8310Sstevel@tonic-gate int remote_port; 8320Sstevel@tonic-gate FILE *f; 8330Sstevel@tonic-gate struct addrinfo *ai; 8340Sstevel@tonic-gate char ntop[NI_MAXHOST], strport[NI_MAXSERV]; 8350Sstevel@tonic-gate int listen_sock, maxfd; 8360Sstevel@tonic-gate int startup_p[2]; 8370Sstevel@tonic-gate int startups = 0; 8387574SJan.Pechanec@Sun.COM Authctxt *authctxt = NULL; 8390Sstevel@tonic-gate Key *key; 8400Sstevel@tonic-gate int ret, key_used = 0; 8410Sstevel@tonic-gate #ifdef HAVE_BSM 8420Sstevel@tonic-gate au_id_t auid = AU_NOAUDITID; 8430Sstevel@tonic-gate #endif /* HAVE_BSM */ 8447574SJan.Pechanec@Sun.COM int mpipe; 8450Sstevel@tonic-gate 8460Sstevel@tonic-gate __progname = get_progname(av[0]); 8470Sstevel@tonic-gate 8480Sstevel@tonic-gate (void) g11n_setlocale(LC_ALL, ""); 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate #ifdef HAVE_SECUREWARE 8510Sstevel@tonic-gate (void)set_auth_parameters(ac, av); 8520Sstevel@tonic-gate #endif 8530Sstevel@tonic-gate 8540Sstevel@tonic-gate init_rng(); 8550Sstevel@tonic-gate 8560Sstevel@tonic-gate /* Save argv. */ 8570Sstevel@tonic-gate saved_argc = ac; 8580Sstevel@tonic-gate saved_argv = av; 8590Sstevel@tonic-gate 8600Sstevel@tonic-gate /* Initialize configuration options to their default values. */ 8610Sstevel@tonic-gate initialize_server_options(&options); 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate /* Parse command-line arguments. */ 8640Sstevel@tonic-gate while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:u:o:dDeiqtQ46")) != -1) { 8650Sstevel@tonic-gate switch (opt) { 8660Sstevel@tonic-gate case '4': 8670Sstevel@tonic-gate IPv4or6 = AF_INET; 8680Sstevel@tonic-gate break; 8690Sstevel@tonic-gate case '6': 8700Sstevel@tonic-gate IPv4or6 = AF_INET6; 8710Sstevel@tonic-gate break; 8720Sstevel@tonic-gate case 'f': 8730Sstevel@tonic-gate config_file_name = optarg; 8740Sstevel@tonic-gate break; 8750Sstevel@tonic-gate case 'd': 8760Sstevel@tonic-gate if (0 == debug_flag) { 8770Sstevel@tonic-gate debug_flag = 1; 8780Sstevel@tonic-gate options.log_level = SYSLOG_LEVEL_DEBUG1; 8790Sstevel@tonic-gate } else if (options.log_level < SYSLOG_LEVEL_DEBUG3) { 8800Sstevel@tonic-gate options.log_level++; 8810Sstevel@tonic-gate } else { 8820Sstevel@tonic-gate (void) fprintf(stderr, 8830Sstevel@tonic-gate gettext("Debug level too high.\n")); 8840Sstevel@tonic-gate exit(1); 8850Sstevel@tonic-gate } 8860Sstevel@tonic-gate break; 8870Sstevel@tonic-gate case 'D': 8880Sstevel@tonic-gate no_daemon_flag = 1; 8890Sstevel@tonic-gate break; 8900Sstevel@tonic-gate case 'e': 8910Sstevel@tonic-gate log_stderr = 1; 8920Sstevel@tonic-gate break; 8930Sstevel@tonic-gate case 'i': 8940Sstevel@tonic-gate inetd_flag = 1; 8950Sstevel@tonic-gate break; 8960Sstevel@tonic-gate case 'Q': 8970Sstevel@tonic-gate /* ignored */ 8980Sstevel@tonic-gate break; 8990Sstevel@tonic-gate case 'q': 9000Sstevel@tonic-gate options.log_level = SYSLOG_LEVEL_QUIET; 9010Sstevel@tonic-gate break; 9020Sstevel@tonic-gate case 'b': 9030Sstevel@tonic-gate options.server_key_bits = atoi(optarg); 9040Sstevel@tonic-gate break; 9050Sstevel@tonic-gate case 'p': 9060Sstevel@tonic-gate options.ports_from_cmdline = 1; 9070Sstevel@tonic-gate if (options.num_ports >= MAX_PORTS) { 9080Sstevel@tonic-gate (void) fprintf(stderr, gettext("too many ports.\n")); 9090Sstevel@tonic-gate exit(1); 9100Sstevel@tonic-gate } 9110Sstevel@tonic-gate options.ports[options.num_ports++] = a2port(optarg); 9120Sstevel@tonic-gate if (options.ports[options.num_ports-1] == 0) { 9130Sstevel@tonic-gate (void) fprintf(stderr, gettext("Bad port number.\n")); 9140Sstevel@tonic-gate exit(1); 9150Sstevel@tonic-gate } 9160Sstevel@tonic-gate break; 9170Sstevel@tonic-gate case 'g': 9180Sstevel@tonic-gate if ((options.login_grace_time = convtime(optarg)) == -1) { 9190Sstevel@tonic-gate (void) fprintf(stderr, 9200Sstevel@tonic-gate gettext("Invalid login grace time.\n")); 9210Sstevel@tonic-gate exit(1); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate break; 9240Sstevel@tonic-gate case 'k': 9250Sstevel@tonic-gate if ((options.key_regeneration_time = convtime(optarg)) == -1) { 9260Sstevel@tonic-gate (void) fprintf(stderr, 9270Sstevel@tonic-gate gettext("Invalid key regeneration " 9280Sstevel@tonic-gate "interval.\n")); 9290Sstevel@tonic-gate exit(1); 9300Sstevel@tonic-gate } 9310Sstevel@tonic-gate break; 9320Sstevel@tonic-gate case 'h': 9330Sstevel@tonic-gate if (options.num_host_key_files >= MAX_HOSTKEYS) { 9340Sstevel@tonic-gate (void) fprintf(stderr, 9350Sstevel@tonic-gate gettext("too many host keys.\n")); 9360Sstevel@tonic-gate exit(1); 9370Sstevel@tonic-gate } 9380Sstevel@tonic-gate options.host_key_files[options.num_host_key_files++] = optarg; 9390Sstevel@tonic-gate break; 9400Sstevel@tonic-gate case 'V': 9410Sstevel@tonic-gate client_version_string = optarg; 9420Sstevel@tonic-gate /* only makes sense with inetd_flag, i.e. no listen() */ 9430Sstevel@tonic-gate inetd_flag = 1; 9440Sstevel@tonic-gate break; 9450Sstevel@tonic-gate case 't': 9460Sstevel@tonic-gate test_flag = 1; 9470Sstevel@tonic-gate break; 9480Sstevel@tonic-gate case 'o': 9490Sstevel@tonic-gate if (process_server_config_line(&options, optarg, 9500Sstevel@tonic-gate "command-line", 0) != 0) 9510Sstevel@tonic-gate exit(1); 9520Sstevel@tonic-gate break; 9530Sstevel@tonic-gate case '?': 9540Sstevel@tonic-gate default: 9550Sstevel@tonic-gate usage(); 9560Sstevel@tonic-gate break; 9570Sstevel@tonic-gate } 9580Sstevel@tonic-gate } 9597574SJan.Pechanec@Sun.COM 9607574SJan.Pechanec@Sun.COM /* 9617574SJan.Pechanec@Sun.COM * There is no need to use the PKCS#11 engine in the master SSH process. 9627574SJan.Pechanec@Sun.COM */ 9630Sstevel@tonic-gate SSLeay_add_all_algorithms(); 9647574SJan.Pechanec@Sun.COM seed_rng(); 9650Sstevel@tonic-gate channel_set_af(IPv4or6); 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate /* 9680Sstevel@tonic-gate * Force logging to stderr until we have loaded the private host 9690Sstevel@tonic-gate * key (unless started from inetd) 9700Sstevel@tonic-gate */ 9710Sstevel@tonic-gate log_init(__progname, 9720Sstevel@tonic-gate options.log_level == SYSLOG_LEVEL_NOT_SET ? 9730Sstevel@tonic-gate SYSLOG_LEVEL_INFO : options.log_level, 9740Sstevel@tonic-gate options.log_facility == SYSLOG_FACILITY_NOT_SET ? 9750Sstevel@tonic-gate SYSLOG_FACILITY_AUTH : options.log_facility, 9760Sstevel@tonic-gate !inetd_flag); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate #ifdef _UNICOS 9790Sstevel@tonic-gate /* Cray can define user privs drop all prives now! 9800Sstevel@tonic-gate * Not needed on PRIV_SU systems! 9810Sstevel@tonic-gate */ 9820Sstevel@tonic-gate drop_cray_privs(); 9830Sstevel@tonic-gate #endif 9840Sstevel@tonic-gate 9850Sstevel@tonic-gate /* Read server configuration options from the configuration file. */ 9860Sstevel@tonic-gate read_server_config(&options, config_file_name); 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate /* Fill in default values for those options not explicitly set. */ 9890Sstevel@tonic-gate fill_default_server_options(&options); 9900Sstevel@tonic-gate 9910Sstevel@tonic-gate utmp_len = options.lookup_client_hostnames ? utmp_len : 0; 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate /* Check that there are no remaining arguments. */ 9940Sstevel@tonic-gate if (optind < ac) { 9950Sstevel@tonic-gate (void) fprintf(stderr, gettext("Extra argument %s.\n"), av[optind]); 9960Sstevel@tonic-gate exit(1); 9970Sstevel@tonic-gate } 9980Sstevel@tonic-gate 9990Sstevel@tonic-gate debug("sshd version %.100s", SSH_VERSION); 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate /* load private host keys */ 10020Sstevel@tonic-gate if (options.num_host_key_files > 0) 10030Sstevel@tonic-gate sensitive_data.host_keys = 10040Sstevel@tonic-gate xmalloc(options.num_host_key_files * sizeof(Key *)); 10050Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) 10060Sstevel@tonic-gate sensitive_data.host_keys[i] = NULL; 10070Sstevel@tonic-gate sensitive_data.server_key = NULL; 10080Sstevel@tonic-gate sensitive_data.ssh1_host_key = NULL; 10090Sstevel@tonic-gate sensitive_data.have_ssh1_key = 0; 10100Sstevel@tonic-gate sensitive_data.have_ssh2_key = 0; 10110Sstevel@tonic-gate 10120Sstevel@tonic-gate for (i = 0; i < options.num_host_key_files; i++) { 10130Sstevel@tonic-gate key = key_load_private(options.host_key_files[i], "", NULL); 10140Sstevel@tonic-gate sensitive_data.host_keys[i] = key; 10150Sstevel@tonic-gate if (key == NULL) { 10160Sstevel@tonic-gate error("Could not load host key: %s", 10170Sstevel@tonic-gate options.host_key_files[i]); 10180Sstevel@tonic-gate sensitive_data.host_keys[i] = NULL; 10190Sstevel@tonic-gate continue; 10200Sstevel@tonic-gate } 10210Sstevel@tonic-gate switch (key->type) { 10220Sstevel@tonic-gate case KEY_RSA1: 10230Sstevel@tonic-gate sensitive_data.ssh1_host_key = key; 10240Sstevel@tonic-gate sensitive_data.have_ssh1_key = 1; 10250Sstevel@tonic-gate break; 10260Sstevel@tonic-gate case KEY_RSA: 10270Sstevel@tonic-gate case KEY_DSA: 10280Sstevel@tonic-gate sensitive_data.have_ssh2_key = 1; 10290Sstevel@tonic-gate break; 10300Sstevel@tonic-gate } 10310Sstevel@tonic-gate debug("private host key: #%d type %d %s", i, key->type, 10320Sstevel@tonic-gate key_type(key)); 10330Sstevel@tonic-gate } 10340Sstevel@tonic-gate if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) { 10350Sstevel@tonic-gate log("Disabling protocol version 1. Could not load host key"); 10360Sstevel@tonic-gate options.protocol &= ~SSH_PROTO_1; 10370Sstevel@tonic-gate } 10380Sstevel@tonic-gate if ((options.protocol & SSH_PROTO_2) && 10390Sstevel@tonic-gate !sensitive_data.have_ssh2_key) { 10400Sstevel@tonic-gate #ifdef GSSAPI 10410Sstevel@tonic-gate if (options.gss_keyex) 10420Sstevel@tonic-gate ssh_gssapi_server_mechs(&mechs); 10430Sstevel@tonic-gate 10440Sstevel@tonic-gate if (mechs == GSS_C_NULL_OID_SET) { 10450Sstevel@tonic-gate log("Disabling protocol version 2. Could not load host" 10460Sstevel@tonic-gate "key or GSS-API mechanisms"); 10470Sstevel@tonic-gate options.protocol &= ~SSH_PROTO_2; 10480Sstevel@tonic-gate } 10490Sstevel@tonic-gate #else 10500Sstevel@tonic-gate log("Disabling protocol version 2. Could not load host key"); 10510Sstevel@tonic-gate options.protocol &= ~SSH_PROTO_2; 10520Sstevel@tonic-gate #endif /* GSSAPI */ 10530Sstevel@tonic-gate } 10540Sstevel@tonic-gate if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) { 10550Sstevel@tonic-gate log("sshd: no hostkeys available -- exiting."); 10560Sstevel@tonic-gate exit(1); 10570Sstevel@tonic-gate } 10580Sstevel@tonic-gate 10590Sstevel@tonic-gate /* Check certain values for sanity. */ 10600Sstevel@tonic-gate if (options.protocol & SSH_PROTO_1) { 10610Sstevel@tonic-gate if (options.server_key_bits < 512 || 10620Sstevel@tonic-gate options.server_key_bits > 32768) { 10630Sstevel@tonic-gate (void) fprintf(stderr, gettext("Bad server key size.\n")); 10640Sstevel@tonic-gate exit(1); 10650Sstevel@tonic-gate } 10660Sstevel@tonic-gate /* 10670Sstevel@tonic-gate * Check that server and host key lengths differ sufficiently. This 10680Sstevel@tonic-gate * is necessary to make double encryption work with rsaref. Oh, I 10690Sstevel@tonic-gate * hate software patents. I dont know if this can go? Niels 10700Sstevel@tonic-gate */ 10710Sstevel@tonic-gate if (options.server_key_bits > 10720Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) - 10730Sstevel@tonic-gate SSH_KEY_BITS_RESERVED && options.server_key_bits < 10740Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + 10750Sstevel@tonic-gate SSH_KEY_BITS_RESERVED) { 10760Sstevel@tonic-gate options.server_key_bits = 10770Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + 10780Sstevel@tonic-gate SSH_KEY_BITS_RESERVED; 10790Sstevel@tonic-gate debug("Forcing server key to %d bits to make it differ from host key.", 10800Sstevel@tonic-gate options.server_key_bits); 10810Sstevel@tonic-gate } 10820Sstevel@tonic-gate } 10830Sstevel@tonic-gate 10840Sstevel@tonic-gate /* Configuration looks good, so exit if in test mode. */ 10850Sstevel@tonic-gate if (test_flag) 10860Sstevel@tonic-gate exit(0); 10870Sstevel@tonic-gate 10880Sstevel@tonic-gate /* 10890Sstevel@tonic-gate * Clear out any supplemental groups we may have inherited. This 10900Sstevel@tonic-gate * prevents inadvertent creation of files with bad modes (in the 10910Sstevel@tonic-gate * portable version at least, it's certainly possible for PAM 10920Sstevel@tonic-gate * to create a file, and we can't control the code in every 10930Sstevel@tonic-gate * module which might be used). 10940Sstevel@tonic-gate */ 10950Sstevel@tonic-gate if (setgroups(0, NULL) < 0) 10960Sstevel@tonic-gate debug("setgroups() failed: %.200s", strerror(errno)); 10970Sstevel@tonic-gate 10980Sstevel@tonic-gate /* Initialize the log (it is reinitialized below in case we forked). */ 10990Sstevel@tonic-gate if (debug_flag && !inetd_flag) 11000Sstevel@tonic-gate log_stderr = 1; 11010Sstevel@tonic-gate log_init(__progname, options.log_level, options.log_facility, log_stderr); 11020Sstevel@tonic-gate 11038658SJan.Pechanec@Sun.COM /* 11048658SJan.Pechanec@Sun.COM * Solaris 9 and systems upgraded from it may have the Ciphers option 11058658SJan.Pechanec@Sun.COM * explicitly set to "aes128-cbc,blowfish-cbc,3des-cbc" in the 11068658SJan.Pechanec@Sun.COM * sshd_config. Since the default server cipher list completely changed 11078658SJan.Pechanec@Sun.COM * since then we rather notify the administator on startup. We do this 11088658SJan.Pechanec@Sun.COM * check after log_init() so that the message goes to syslogd and not to 11098658SJan.Pechanec@Sun.COM * stderr (unless the server is in the debug mode). Note that since 11108658SJan.Pechanec@Sun.COM * Solaris 10 we no longer ship sshd_config with explicit settings for 11118658SJan.Pechanec@Sun.COM * Ciphers or MACs. Do not try to augment the cipher list here since 11128658SJan.Pechanec@Sun.COM * that might end up in a very confusing situation. 11138658SJan.Pechanec@Sun.COM */ 11148658SJan.Pechanec@Sun.COM #define OLD_DEFAULT_CIPHERS_LIST "aes128-cbc,blowfish-cbc,3des-cbc" 11158658SJan.Pechanec@Sun.COM if (options.ciphers != NULL && 11168658SJan.Pechanec@Sun.COM strcmp(options.ciphers, OLD_DEFAULT_CIPHERS_LIST) == 0) { 11178658SJan.Pechanec@Sun.COM notice("Old default value \"%s\" for the \"Ciphers\" " 11188658SJan.Pechanec@Sun.COM "option found in use. In general it is prudent to let " 11198658SJan.Pechanec@Sun.COM "the server choose the defaults unless your environment " 11208658SJan.Pechanec@Sun.COM "specifically needs an explicit setting. See " 11218658SJan.Pechanec@Sun.COM "sshd_config(4) for more information.", 11228658SJan.Pechanec@Sun.COM OLD_DEFAULT_CIPHERS_LIST); 11238658SJan.Pechanec@Sun.COM } 11248658SJan.Pechanec@Sun.COM 11250Sstevel@tonic-gate #ifdef HAVE_BSM 11260Sstevel@tonic-gate (void) setauid(&auid); 11270Sstevel@tonic-gate #endif /* HAVE_BSM */ 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate /* 11300Sstevel@tonic-gate * If not in debugging mode, and not started from inetd, disconnect 11310Sstevel@tonic-gate * from the controlling terminal, and fork. The original process 11320Sstevel@tonic-gate * exits. 11330Sstevel@tonic-gate */ 11340Sstevel@tonic-gate if (!(debug_flag || inetd_flag || no_daemon_flag)) { 11350Sstevel@tonic-gate #ifdef TIOCNOTTY 11360Sstevel@tonic-gate int fd; 11370Sstevel@tonic-gate #endif /* TIOCNOTTY */ 11380Sstevel@tonic-gate if (daemon(0, 0) < 0) 11390Sstevel@tonic-gate fatal("daemon() failed: %.200s", strerror(errno)); 11400Sstevel@tonic-gate 11410Sstevel@tonic-gate /* Disconnect from the controlling tty. */ 11420Sstevel@tonic-gate #ifdef TIOCNOTTY 11430Sstevel@tonic-gate fd = open(_PATH_TTY, O_RDWR | O_NOCTTY); 11440Sstevel@tonic-gate if (fd >= 0) { 11450Sstevel@tonic-gate (void) ioctl(fd, TIOCNOTTY, NULL); 11460Sstevel@tonic-gate (void) close(fd); 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate #endif /* TIOCNOTTY */ 11490Sstevel@tonic-gate } 11500Sstevel@tonic-gate /* Reinitialize the log (because of the fork above). */ 11510Sstevel@tonic-gate log_init(__progname, options.log_level, options.log_facility, log_stderr); 11520Sstevel@tonic-gate 11530Sstevel@tonic-gate /* Initialize the random number generator. */ 11540Sstevel@tonic-gate arc4random_stir(); 11550Sstevel@tonic-gate 11560Sstevel@tonic-gate /* Chdir to the root directory so that the current disk can be 11570Sstevel@tonic-gate unmounted if desired. */ 11580Sstevel@tonic-gate (void) chdir("/"); 11590Sstevel@tonic-gate 11600Sstevel@tonic-gate /* ignore SIGPIPE */ 11610Sstevel@tonic-gate (void) signal(SIGPIPE, SIG_IGN); 11620Sstevel@tonic-gate 11630Sstevel@tonic-gate /* Start listening for a socket, unless started from inetd. */ 11640Sstevel@tonic-gate if (inetd_flag) { 11650Sstevel@tonic-gate int s1; 11660Sstevel@tonic-gate s1 = dup(0); /* Make sure descriptors 0, 1, and 2 are in use. */ 11670Sstevel@tonic-gate (void) dup(s1); 11680Sstevel@tonic-gate sock_in = dup(0); 11690Sstevel@tonic-gate sock_out = dup(1); 11700Sstevel@tonic-gate startup_pipe = -1; 11717574SJan.Pechanec@Sun.COM /* we need this later for setting audit context */ 11726481Spaulson newsock = sock_in; 11730Sstevel@tonic-gate /* 11740Sstevel@tonic-gate * We intentionally do not close the descriptors 0, 1, and 2 11750Sstevel@tonic-gate * as our code for setting the descriptors won\'t work if 11760Sstevel@tonic-gate * ttyfd happens to be one of those. 11770Sstevel@tonic-gate */ 11780Sstevel@tonic-gate debug("inetd sockets after dupping: %d, %d", sock_in, sock_out); 11790Sstevel@tonic-gate if (options.protocol & SSH_PROTO_1) 11800Sstevel@tonic-gate generate_ephemeral_server_key(); 11810Sstevel@tonic-gate } else { 11820Sstevel@tonic-gate for (ai = options.listen_addrs; ai; ai = ai->ai_next) { 11830Sstevel@tonic-gate if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6) 11840Sstevel@tonic-gate continue; 11850Sstevel@tonic-gate if (num_listen_socks >= MAX_LISTEN_SOCKS) 11860Sstevel@tonic-gate fatal("Too many listen sockets. " 11870Sstevel@tonic-gate "Enlarge MAX_LISTEN_SOCKS"); 11880Sstevel@tonic-gate if (getnameinfo(ai->ai_addr, ai->ai_addrlen, 11890Sstevel@tonic-gate ntop, sizeof(ntop), strport, sizeof(strport), 11900Sstevel@tonic-gate NI_NUMERICHOST|NI_NUMERICSERV) != 0) { 11910Sstevel@tonic-gate error("getnameinfo failed"); 11920Sstevel@tonic-gate continue; 11930Sstevel@tonic-gate } 11940Sstevel@tonic-gate /* Create socket for listening. */ 11950Sstevel@tonic-gate listen_sock = socket(ai->ai_family, SOCK_STREAM, 0); 11960Sstevel@tonic-gate if (listen_sock < 0) { 11970Sstevel@tonic-gate /* kernel may not support ipv6 */ 11980Sstevel@tonic-gate verbose("socket: %.100s", strerror(errno)); 11990Sstevel@tonic-gate continue; 12000Sstevel@tonic-gate } 12010Sstevel@tonic-gate if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) { 12020Sstevel@tonic-gate error("listen_sock O_NONBLOCK: %s", strerror(errno)); 12030Sstevel@tonic-gate (void) close(listen_sock); 12040Sstevel@tonic-gate continue; 12050Sstevel@tonic-gate } 12060Sstevel@tonic-gate /* 12070Sstevel@tonic-gate * Set socket options. 12080Sstevel@tonic-gate * Allow local port reuse in TIME_WAIT. 12090Sstevel@tonic-gate */ 12100Sstevel@tonic-gate if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, 12110Sstevel@tonic-gate &on, sizeof(on)) == -1) 12120Sstevel@tonic-gate error("setsockopt SO_REUSEADDR: %s", strerror(errno)); 12130Sstevel@tonic-gate 12140Sstevel@tonic-gate debug("Bind to port %s on %s.", strport, ntop); 12150Sstevel@tonic-gate 12160Sstevel@tonic-gate /* Bind the socket to the desired port. */ 12170Sstevel@tonic-gate if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) { 12180Sstevel@tonic-gate if (!ai->ai_next) 12190Sstevel@tonic-gate error("Bind to port %s on %s failed: %.200s.", 12200Sstevel@tonic-gate strport, ntop, strerror(errno)); 12210Sstevel@tonic-gate (void) close(listen_sock); 12220Sstevel@tonic-gate continue; 12230Sstevel@tonic-gate } 12240Sstevel@tonic-gate listen_socks[num_listen_socks] = listen_sock; 12250Sstevel@tonic-gate num_listen_socks++; 12260Sstevel@tonic-gate 12270Sstevel@tonic-gate /* Start listening on the port. */ 12280Sstevel@tonic-gate log("Server listening on %s port %s.", ntop, strport); 12290Sstevel@tonic-gate if (listen(listen_sock, 5) < 0) 12300Sstevel@tonic-gate fatal("listen: %.100s", strerror(errno)); 12310Sstevel@tonic-gate 12320Sstevel@tonic-gate } 12330Sstevel@tonic-gate freeaddrinfo(options.listen_addrs); 12340Sstevel@tonic-gate 12350Sstevel@tonic-gate if (!num_listen_socks) 12360Sstevel@tonic-gate fatal("Cannot bind any address."); 12370Sstevel@tonic-gate 12380Sstevel@tonic-gate if (options.protocol & SSH_PROTO_1) 12390Sstevel@tonic-gate generate_ephemeral_server_key(); 12400Sstevel@tonic-gate 12410Sstevel@tonic-gate /* 12420Sstevel@tonic-gate * Arrange to restart on SIGHUP. The handler needs 12430Sstevel@tonic-gate * listen_sock. 12440Sstevel@tonic-gate */ 12450Sstevel@tonic-gate (void) signal(SIGHUP, sighup_handler); 12460Sstevel@tonic-gate 12470Sstevel@tonic-gate (void) signal(SIGTERM, sigterm_handler); 12480Sstevel@tonic-gate (void) signal(SIGQUIT, sigterm_handler); 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate /* Arrange SIGCHLD to be caught. */ 12510Sstevel@tonic-gate (void) signal(SIGCHLD, main_sigchld_handler); 12520Sstevel@tonic-gate 12530Sstevel@tonic-gate /* Write out the pid file after the sigterm handler is setup */ 12540Sstevel@tonic-gate if (!debug_flag) { 12550Sstevel@tonic-gate /* 12560Sstevel@tonic-gate * Record our pid in /var/run/sshd.pid to make it 12570Sstevel@tonic-gate * easier to kill the correct sshd. We don't want to 12580Sstevel@tonic-gate * do this before the bind above because the bind will 12590Sstevel@tonic-gate * fail if there already is a daemon, and this will 12600Sstevel@tonic-gate * overwrite any old pid in the file. 12610Sstevel@tonic-gate */ 12620Sstevel@tonic-gate f = fopen(options.pid_file, "wb"); 12630Sstevel@tonic-gate if (f) { 12640Sstevel@tonic-gate (void) fprintf(f, "%ld\n", (long) getpid()); 12650Sstevel@tonic-gate (void) fclose(f); 12660Sstevel@tonic-gate } 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate 12690Sstevel@tonic-gate /* setup fd set for listen */ 12700Sstevel@tonic-gate fdset = NULL; 12710Sstevel@tonic-gate maxfd = 0; 12720Sstevel@tonic-gate for (i = 0; i < num_listen_socks; i++) 12730Sstevel@tonic-gate if (listen_socks[i] > maxfd) 12740Sstevel@tonic-gate maxfd = listen_socks[i]; 12750Sstevel@tonic-gate /* pipes connected to unauthenticated childs */ 12760Sstevel@tonic-gate startup_pipes = xmalloc(options.max_startups * sizeof(int)); 12770Sstevel@tonic-gate for (i = 0; i < options.max_startups; i++) 12780Sstevel@tonic-gate startup_pipes[i] = -1; 12790Sstevel@tonic-gate 12800Sstevel@tonic-gate /* 12810Sstevel@tonic-gate * Stay listening for connections until the system crashes or 12820Sstevel@tonic-gate * the daemon is killed with a signal. 12830Sstevel@tonic-gate */ 12840Sstevel@tonic-gate for (;;) { 12850Sstevel@tonic-gate if (received_sighup) 12860Sstevel@tonic-gate sighup_restart(); 12870Sstevel@tonic-gate if (fdset != NULL) 12880Sstevel@tonic-gate xfree(fdset); 12890Sstevel@tonic-gate fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask); 12900Sstevel@tonic-gate fdset = (fd_set *)xmalloc(fdsetsz); 12910Sstevel@tonic-gate (void) memset(fdset, 0, fdsetsz); 12920Sstevel@tonic-gate 12930Sstevel@tonic-gate for (i = 0; i < num_listen_socks; i++) 12940Sstevel@tonic-gate FD_SET(listen_socks[i], fdset); 12950Sstevel@tonic-gate for (i = 0; i < options.max_startups; i++) 12960Sstevel@tonic-gate if (startup_pipes[i] != -1) 12970Sstevel@tonic-gate FD_SET(startup_pipes[i], fdset); 12980Sstevel@tonic-gate 12990Sstevel@tonic-gate /* Wait in select until there is a connection. */ 13000Sstevel@tonic-gate ret = select(maxfd+1, fdset, NULL, NULL, NULL); 13010Sstevel@tonic-gate if (ret < 0 && errno != EINTR) 13020Sstevel@tonic-gate error("select: %.100s", strerror(errno)); 13030Sstevel@tonic-gate if (received_sigterm) { 13040Sstevel@tonic-gate log("Received signal %d; terminating.", 13050Sstevel@tonic-gate (int) received_sigterm); 13060Sstevel@tonic-gate close_listen_socks(); 13070Sstevel@tonic-gate (void) unlink(options.pid_file); 13080Sstevel@tonic-gate exit(255); 13090Sstevel@tonic-gate } 13100Sstevel@tonic-gate if (key_used && key_do_regen) { 13110Sstevel@tonic-gate generate_ephemeral_server_key(); 13120Sstevel@tonic-gate key_used = 0; 13130Sstevel@tonic-gate key_do_regen = 0; 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate if (ret < 0) 13160Sstevel@tonic-gate continue; 13170Sstevel@tonic-gate 13180Sstevel@tonic-gate for (i = 0; i < options.max_startups; i++) 13190Sstevel@tonic-gate if (startup_pipes[i] != -1 && 13200Sstevel@tonic-gate FD_ISSET(startup_pipes[i], fdset)) { 13210Sstevel@tonic-gate /* 13220Sstevel@tonic-gate * the read end of the pipe is ready 13230Sstevel@tonic-gate * if the child has closed the pipe 13240Sstevel@tonic-gate * after successful authentication 13250Sstevel@tonic-gate * or if the child has died 13260Sstevel@tonic-gate */ 13270Sstevel@tonic-gate (void) close(startup_pipes[i]); 13280Sstevel@tonic-gate startup_pipes[i] = -1; 13290Sstevel@tonic-gate startups--; 13300Sstevel@tonic-gate } 13310Sstevel@tonic-gate for (i = 0; i < num_listen_socks; i++) { 13320Sstevel@tonic-gate if (!FD_ISSET(listen_socks[i], fdset)) 13330Sstevel@tonic-gate continue; 13340Sstevel@tonic-gate fromlen = sizeof(from); 13350Sstevel@tonic-gate newsock = accept(listen_socks[i], (struct sockaddr *)&from, 13360Sstevel@tonic-gate &fromlen); 13370Sstevel@tonic-gate if (newsock < 0) { 13380Sstevel@tonic-gate if (errno != EINTR && errno != EWOULDBLOCK) 13390Sstevel@tonic-gate error("accept: %.100s", strerror(errno)); 13400Sstevel@tonic-gate continue; 13410Sstevel@tonic-gate } 13420Sstevel@tonic-gate if (fcntl(newsock, F_SETFL, 0) < 0) { 13430Sstevel@tonic-gate error("newsock del O_NONBLOCK: %s", strerror(errno)); 13440Sstevel@tonic-gate (void) close(newsock); 13450Sstevel@tonic-gate continue; 13460Sstevel@tonic-gate } 13470Sstevel@tonic-gate if (drop_connection(startups) == 1) { 13480Sstevel@tonic-gate debug("drop connection #%d", startups); 13490Sstevel@tonic-gate (void) close(newsock); 13500Sstevel@tonic-gate continue; 13510Sstevel@tonic-gate } 13520Sstevel@tonic-gate if (pipe(startup_p) == -1) { 13530Sstevel@tonic-gate (void) close(newsock); 13540Sstevel@tonic-gate continue; 13550Sstevel@tonic-gate } 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate for (j = 0; j < options.max_startups; j++) 13580Sstevel@tonic-gate if (startup_pipes[j] == -1) { 13590Sstevel@tonic-gate startup_pipes[j] = startup_p[0]; 13600Sstevel@tonic-gate if (maxfd < startup_p[0]) 13610Sstevel@tonic-gate maxfd = startup_p[0]; 13620Sstevel@tonic-gate startups++; 13630Sstevel@tonic-gate break; 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate /* 13670Sstevel@tonic-gate * Got connection. Fork a child to handle it, unless 13680Sstevel@tonic-gate * we are in debugging mode. 13690Sstevel@tonic-gate */ 13700Sstevel@tonic-gate if (debug_flag) { 13710Sstevel@tonic-gate /* 13720Sstevel@tonic-gate * In debugging mode. Close the listening 13730Sstevel@tonic-gate * socket, and start processing the 13740Sstevel@tonic-gate * connection without forking. 13750Sstevel@tonic-gate */ 13760Sstevel@tonic-gate debug("Server will not fork when running in debugging mode."); 13770Sstevel@tonic-gate close_listen_socks(); 13780Sstevel@tonic-gate sock_in = newsock; 13790Sstevel@tonic-gate sock_out = newsock; 13800Sstevel@tonic-gate startup_pipe = -1; 13810Sstevel@tonic-gate pid = getpid(); 13820Sstevel@tonic-gate break; 13830Sstevel@tonic-gate } else { 13840Sstevel@tonic-gate /* 13850Sstevel@tonic-gate * Normal production daemon. Fork, and have 13860Sstevel@tonic-gate * the child process the connection. The 13870Sstevel@tonic-gate * parent continues listening. 13880Sstevel@tonic-gate */ 13890Sstevel@tonic-gate #ifdef HAVE_SOLARIS_CONTRACTS 13900Sstevel@tonic-gate /* 13910Sstevel@tonic-gate * Setup Solaris contract template so 13920Sstevel@tonic-gate * the child process is in a different 13930Sstevel@tonic-gate * process contract than the parent; 13940Sstevel@tonic-gate * prevents established connections from 13950Sstevel@tonic-gate * being killed when the sshd master 13960Sstevel@tonic-gate * listener service is stopped. 13970Sstevel@tonic-gate */ 13980Sstevel@tonic-gate contracts_pre_fork(); 13990Sstevel@tonic-gate #endif /* HAVE_SOLARIS_CONTRACTS */ 14000Sstevel@tonic-gate if ((pid = fork()) == 0) { 14010Sstevel@tonic-gate /* 14020Sstevel@tonic-gate * Child. Close the listening and max_startup 14030Sstevel@tonic-gate * sockets. Start using the accepted socket. 14040Sstevel@tonic-gate * Reinitialize logging (since our pid has 14050Sstevel@tonic-gate * changed). We break out of the loop to handle 14060Sstevel@tonic-gate * the connection. 14070Sstevel@tonic-gate */ 14080Sstevel@tonic-gate #ifdef HAVE_SOLARIS_CONTRACTS 14090Sstevel@tonic-gate contracts_post_fork_child(); 14100Sstevel@tonic-gate #endif /* HAVE_SOLARIS_CONTRACTS */ 14115562Sjp161948 xfree(fdset); 14120Sstevel@tonic-gate startup_pipe = startup_p[1]; 14130Sstevel@tonic-gate close_startup_pipes(); 14140Sstevel@tonic-gate close_listen_socks(); 14150Sstevel@tonic-gate sock_in = newsock; 14160Sstevel@tonic-gate sock_out = newsock; 14170Sstevel@tonic-gate log_init(__progname, options.log_level, options.log_facility, log_stderr); 14180Sstevel@tonic-gate break; 14190Sstevel@tonic-gate } 14200Sstevel@tonic-gate 14210Sstevel@tonic-gate #ifdef HAVE_SOLARIS_CONTRACTS 14220Sstevel@tonic-gate contracts_post_fork_parent((pid > 0)); 14230Sstevel@tonic-gate #endif /* HAVE_SOLARIS_CONTRACTS */ 14240Sstevel@tonic-gate } 14250Sstevel@tonic-gate 14260Sstevel@tonic-gate /* Parent. Stay in the loop. */ 14270Sstevel@tonic-gate if (pid < 0) 14280Sstevel@tonic-gate error("fork: %.100s", strerror(errno)); 14290Sstevel@tonic-gate else 14300Sstevel@tonic-gate debug("Forked child %ld.", (long)pid); 14310Sstevel@tonic-gate 14320Sstevel@tonic-gate (void) close(startup_p[1]); 14330Sstevel@tonic-gate 14340Sstevel@tonic-gate /* Mark that the key has been used (it was "given" to the child). */ 14350Sstevel@tonic-gate if ((options.protocol & SSH_PROTO_1) && 14360Sstevel@tonic-gate key_used == 0) { 14370Sstevel@tonic-gate /* Schedule server key regeneration alarm. */ 14380Sstevel@tonic-gate (void) signal(SIGALRM, key_regeneration_alarm); 14390Sstevel@tonic-gate (void) alarm(options.key_regeneration_time); 14400Sstevel@tonic-gate key_used = 1; 14410Sstevel@tonic-gate } 14420Sstevel@tonic-gate 14430Sstevel@tonic-gate arc4random_stir(); 14440Sstevel@tonic-gate 14457574SJan.Pechanec@Sun.COM /* 14467574SJan.Pechanec@Sun.COM * Close the accepted socket since the child 14477574SJan.Pechanec@Sun.COM * will now take care of the new connection. 14487574SJan.Pechanec@Sun.COM */ 14490Sstevel@tonic-gate (void) close(newsock); 14500Sstevel@tonic-gate } 14510Sstevel@tonic-gate /* child process check (or debug mode) */ 14520Sstevel@tonic-gate if (num_listen_socks < 0) 14530Sstevel@tonic-gate break; 14540Sstevel@tonic-gate } 14550Sstevel@tonic-gate } 14560Sstevel@tonic-gate 14577574SJan.Pechanec@Sun.COM /* 14587574SJan.Pechanec@Sun.COM * This is the child processing a new connection, the SSH master process 14597574SJan.Pechanec@Sun.COM * stays in the ( ; ; ) loop above. 14607574SJan.Pechanec@Sun.COM */ 14610Sstevel@tonic-gate #ifdef HAVE_BSM 14620Sstevel@tonic-gate audit_sshd_settid(newsock); 14630Sstevel@tonic-gate #endif 14640Sstevel@tonic-gate /* 14650Sstevel@tonic-gate * Create a new session and process group since the 4.4BSD 14660Sstevel@tonic-gate * setlogin() affects the entire process group. We don't 14670Sstevel@tonic-gate * want the child to be able to affect the parent. 14680Sstevel@tonic-gate */ 14690Sstevel@tonic-gate #if 0 14700Sstevel@tonic-gate /* XXX: this breaks Solaris */ 14710Sstevel@tonic-gate if (!debug_flag && !inetd_flag && setsid() < 0) 14720Sstevel@tonic-gate error("setsid: %.100s", strerror(errno)); 14730Sstevel@tonic-gate #endif 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate /* 14760Sstevel@tonic-gate * Disable the key regeneration alarm. We will not regenerate the 14770Sstevel@tonic-gate * key since we are no longer in a position to give it to anyone. We 14780Sstevel@tonic-gate * will not restart on SIGHUP since it no longer makes sense. 14790Sstevel@tonic-gate */ 14800Sstevel@tonic-gate (void) alarm(0); 14810Sstevel@tonic-gate (void) signal(SIGALRM, SIG_DFL); 14820Sstevel@tonic-gate (void) signal(SIGHUP, SIG_DFL); 14830Sstevel@tonic-gate (void) signal(SIGTERM, SIG_DFL); 14840Sstevel@tonic-gate (void) signal(SIGQUIT, SIG_DFL); 14850Sstevel@tonic-gate (void) signal(SIGCHLD, SIG_DFL); 14860Sstevel@tonic-gate (void) signal(SIGINT, SIG_DFL); 14870Sstevel@tonic-gate 14880Sstevel@tonic-gate /* Set keepalives if requested. */ 14890Sstevel@tonic-gate if (options.keepalives && 14900Sstevel@tonic-gate setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on, 14910Sstevel@tonic-gate sizeof(on)) < 0) 14920Sstevel@tonic-gate debug2("setsockopt SO_KEEPALIVE: %.100s", strerror(errno)); 14930Sstevel@tonic-gate 14940Sstevel@tonic-gate /* 14950Sstevel@tonic-gate * Register our connection. This turns encryption off because we do 14960Sstevel@tonic-gate * not have a key. 14970Sstevel@tonic-gate */ 14980Sstevel@tonic-gate packet_set_connection(sock_in, sock_out); 14990Sstevel@tonic-gate 15000Sstevel@tonic-gate remote_port = get_remote_port(); 15010Sstevel@tonic-gate remote_ip = get_remote_ipaddr(); 15020Sstevel@tonic-gate 15030Sstevel@tonic-gate #ifdef LIBWRAP 15040Sstevel@tonic-gate /* Check whether logins are denied from this host. */ 15050Sstevel@tonic-gate { 15060Sstevel@tonic-gate struct request_info req; 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate (void) request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0); 15090Sstevel@tonic-gate fromhost(&req); 15100Sstevel@tonic-gate 15110Sstevel@tonic-gate if (!hosts_access(&req)) { 15120Sstevel@tonic-gate debug("Connection refused by tcp wrapper"); 15130Sstevel@tonic-gate refuse(&req); 15140Sstevel@tonic-gate /* NOTREACHED */ 15150Sstevel@tonic-gate fatal("libwrap refuse returns"); 15160Sstevel@tonic-gate } 15170Sstevel@tonic-gate } 15180Sstevel@tonic-gate #endif /* LIBWRAP */ 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate /* Log the connection. */ 15210Sstevel@tonic-gate verbose("Connection from %.500s port %d", remote_ip, remote_port); 15220Sstevel@tonic-gate 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * We don\'t want to listen forever unless the other side 15250Sstevel@tonic-gate * successfully authenticates itself. So we set up an alarm which is 15260Sstevel@tonic-gate * cleared after successful authentication. A limit of zero 15270Sstevel@tonic-gate * indicates no limit. Note that we don\'t set the alarm in debugging 15280Sstevel@tonic-gate * mode; it is just annoying to have the server exit just when you 15290Sstevel@tonic-gate * are about to discover the bug. 15300Sstevel@tonic-gate */ 15310Sstevel@tonic-gate (void) signal(SIGALRM, grace_alarm_handler); 15320Sstevel@tonic-gate if (!debug_flag) 15330Sstevel@tonic-gate (void) alarm(options.login_grace_time); 15340Sstevel@tonic-gate 15350Sstevel@tonic-gate sshd_exchange_identification(sock_in, sock_out); 15360Sstevel@tonic-gate /* 15370Sstevel@tonic-gate * Check that the connection comes from a privileged port. 15380Sstevel@tonic-gate * Rhosts-Authentication only makes sense from privileged 15390Sstevel@tonic-gate * programs. Of course, if the intruder has root access on his local 15400Sstevel@tonic-gate * machine, he can connect from any port. So do not use these 15410Sstevel@tonic-gate * authentication methods from machines that you do not trust. 15420Sstevel@tonic-gate */ 15430Sstevel@tonic-gate if (options.rhosts_authentication && 15440Sstevel@tonic-gate (remote_port >= IPPORT_RESERVED || 15450Sstevel@tonic-gate remote_port < IPPORT_RESERVED / 2)) { 15460Sstevel@tonic-gate debug("Rhosts Authentication disabled, " 15470Sstevel@tonic-gate "originating port %d not trusted.", remote_port); 15480Sstevel@tonic-gate options.rhosts_authentication = 0; 15490Sstevel@tonic-gate } 15500Sstevel@tonic-gate #if defined(KRB4) && !defined(KRB5) 15510Sstevel@tonic-gate if (!packet_connection_is_ipv4() && 15520Sstevel@tonic-gate options.kerberos_authentication) { 15530Sstevel@tonic-gate debug("Kerberos Authentication disabled, only available for IPv4."); 15540Sstevel@tonic-gate options.kerberos_authentication = 0; 15550Sstevel@tonic-gate } 15560Sstevel@tonic-gate #endif /* KRB4 && !KRB5 */ 15570Sstevel@tonic-gate #ifdef AFS 15580Sstevel@tonic-gate /* If machine has AFS, set process authentication group. */ 15590Sstevel@tonic-gate if (k_hasafs()) { 15600Sstevel@tonic-gate k_setpag(); 15610Sstevel@tonic-gate k_unlog(); 15620Sstevel@tonic-gate } 15630Sstevel@tonic-gate #endif /* AFS */ 15640Sstevel@tonic-gate 15650Sstevel@tonic-gate packet_set_nonblocking(); 15660Sstevel@tonic-gate 15677574SJan.Pechanec@Sun.COM /* 15687574SJan.Pechanec@Sun.COM * Start the monitor. That way both processes will have their own 15697574SJan.Pechanec@Sun.COM * PKCS#11 sessions. See the PKCS#11 standard for more information on 15707574SJan.Pechanec@Sun.COM * fork safety and packet.c for information about forking with the 15717574SJan.Pechanec@Sun.COM * engine. 15727574SJan.Pechanec@Sun.COM */ 15737574SJan.Pechanec@Sun.COM altprivsep_start_and_do_monitor(options.use_openssl_engine, 15747574SJan.Pechanec@Sun.COM inetd_flag, newsock, startup_pipe); 15757574SJan.Pechanec@Sun.COM 15767574SJan.Pechanec@Sun.COM /* 15777574SJan.Pechanec@Sun.COM * The child is about to start the first key exchange while the monitor 15787574SJan.Pechanec@Sun.COM * stays in altprivsep_start_and_do_monitor() function. 15797574SJan.Pechanec@Sun.COM */ 15807574SJan.Pechanec@Sun.COM (void) pkcs11_engine_load(options.use_openssl_engine); 15817574SJan.Pechanec@Sun.COM 15820Sstevel@tonic-gate /* perform the key exchange */ 15830Sstevel@tonic-gate /* authenticate user and start session */ 15840Sstevel@tonic-gate if (compat20) { 15850Sstevel@tonic-gate do_ssh2_kex(); 15860Sstevel@tonic-gate authctxt = do_authentication2(); 15870Sstevel@tonic-gate } else { 15880Sstevel@tonic-gate do_ssh1_kex(); 15890Sstevel@tonic-gate authctxt = do_authentication(); 15900Sstevel@tonic-gate } 15910Sstevel@tonic-gate 15920Sstevel@tonic-gate authenticated: 15930Sstevel@tonic-gate /* Authentication complete */ 15940Sstevel@tonic-gate (void) alarm(0); 15957574SJan.Pechanec@Sun.COM /* we no longer need an alarm handler */ 15967574SJan.Pechanec@Sun.COM (void) signal(SIGALRM, SIG_DFL); 15970Sstevel@tonic-gate 15980Sstevel@tonic-gate if (startup_pipe != -1) { 15990Sstevel@tonic-gate (void) close(startup_pipe); 16000Sstevel@tonic-gate startup_pipe = -1; 16010Sstevel@tonic-gate } 16020Sstevel@tonic-gate 16037574SJan.Pechanec@Sun.COM /* ALTPRIVSEP Child */ 16040Sstevel@tonic-gate 16057574SJan.Pechanec@Sun.COM /* 16067574SJan.Pechanec@Sun.COM * Drop privileges, access to privileged resources. 16077574SJan.Pechanec@Sun.COM * 16087574SJan.Pechanec@Sun.COM * Destroy private host keys, if any. 16097574SJan.Pechanec@Sun.COM * 16107574SJan.Pechanec@Sun.COM * No need to release any GSS credentials -- sshd only acquires 16117574SJan.Pechanec@Sun.COM * creds to determine what mechs it can negotiate then releases 16127574SJan.Pechanec@Sun.COM * them right away and uses GSS_C_NO_CREDENTIAL to accept 16137574SJan.Pechanec@Sun.COM * contexts. 16147574SJan.Pechanec@Sun.COM */ 16157574SJan.Pechanec@Sun.COM debug2("Unprivileged server process dropping privileges"); 1616*9139SJan.Pechanec@Sun.COM permanently_set_uid(authctxt->pw, options.chroot_directory); 16177574SJan.Pechanec@Sun.COM destroy_sensitive_data(); 1618*9139SJan.Pechanec@Sun.COM 1619*9139SJan.Pechanec@Sun.COM /* Just another safety check. */ 1620*9139SJan.Pechanec@Sun.COM if (getuid() != authctxt->pw->pw_uid || 1621*9139SJan.Pechanec@Sun.COM geteuid() != authctxt->pw->pw_uid) { 1622*9139SJan.Pechanec@Sun.COM fatal("Failed to set uids to %u.", (u_int)authctxt->pw->pw_uid); 1623*9139SJan.Pechanec@Sun.COM } 1624*9139SJan.Pechanec@Sun.COM 16257574SJan.Pechanec@Sun.COM ssh_gssapi_server_mechs(NULL); /* release cached mechs list */ 16267574SJan.Pechanec@Sun.COM packet_set_server(); 16270Sstevel@tonic-gate 16287574SJan.Pechanec@Sun.COM /* now send the authentication context to the monitor */ 16297574SJan.Pechanec@Sun.COM altprivsep_send_auth_context(authctxt); 16307574SJan.Pechanec@Sun.COM 16317574SJan.Pechanec@Sun.COM mpipe = altprivsep_get_pipe_fd(); 16327574SJan.Pechanec@Sun.COM if (fcntl(mpipe, F_SETFL, O_NONBLOCK) < 0) 16337574SJan.Pechanec@Sun.COM error("fcntl O_NONBLOCK: %.100s", strerror(errno)); 16340Sstevel@tonic-gate 16350Sstevel@tonic-gate #ifdef HAVE_BSM 16367574SJan.Pechanec@Sun.COM fatal_remove_cleanup( 16377574SJan.Pechanec@Sun.COM (void (*)(void *))audit_failed_login_cleanup, 16387574SJan.Pechanec@Sun.COM (void *)authctxt); 16390Sstevel@tonic-gate #endif /* HAVE_BSM */ 16400Sstevel@tonic-gate 16417574SJan.Pechanec@Sun.COM if (compat20) { 16427574SJan.Pechanec@Sun.COM debug3("setting handler to forward re-key packets to the monitor"); 16437574SJan.Pechanec@Sun.COM dispatch_range(SSH2_MSG_KEXINIT, SSH2_MSG_TRANSPORT_MAX, 16447574SJan.Pechanec@Sun.COM &altprivsep_rekey); 16457574SJan.Pechanec@Sun.COM } 16460Sstevel@tonic-gate 16477574SJan.Pechanec@Sun.COM /* Logged-in session. */ 16487574SJan.Pechanec@Sun.COM do_authenticated(authctxt); 16490Sstevel@tonic-gate 16507574SJan.Pechanec@Sun.COM /* The connection has been terminated. */ 16517574SJan.Pechanec@Sun.COM verbose("Closing connection to %.100s", remote_ip); 16520Sstevel@tonic-gate 16537574SJan.Pechanec@Sun.COM packet_close(); 16540Sstevel@tonic-gate 16550Sstevel@tonic-gate #ifdef USE_PAM 16567574SJan.Pechanec@Sun.COM finish_pam(authctxt); 16570Sstevel@tonic-gate #endif /* USE_PAM */ 16580Sstevel@tonic-gate 16597574SJan.Pechanec@Sun.COM return (0); 16600Sstevel@tonic-gate } 16610Sstevel@tonic-gate 16620Sstevel@tonic-gate /* 16630Sstevel@tonic-gate * Decrypt session_key_int using our private server key and private host key 16640Sstevel@tonic-gate * (key with larger modulus first). 16650Sstevel@tonic-gate */ 16660Sstevel@tonic-gate int 16670Sstevel@tonic-gate ssh1_session_key(BIGNUM *session_key_int) 16680Sstevel@tonic-gate { 16690Sstevel@tonic-gate int rsafail = 0; 16700Sstevel@tonic-gate 16710Sstevel@tonic-gate if (BN_cmp(sensitive_data.server_key->rsa->n, sensitive_data.ssh1_host_key->rsa->n) > 0) { 16720Sstevel@tonic-gate /* Server key has bigger modulus. */ 16730Sstevel@tonic-gate if (BN_num_bits(sensitive_data.server_key->rsa->n) < 16740Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) + SSH_KEY_BITS_RESERVED) { 16750Sstevel@tonic-gate fatal("do_connection: %s: server_key %d < host_key %d + SSH_KEY_BITS_RESERVED %d", 16760Sstevel@tonic-gate get_remote_ipaddr(), 16770Sstevel@tonic-gate BN_num_bits(sensitive_data.server_key->rsa->n), 16780Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), 16790Sstevel@tonic-gate SSH_KEY_BITS_RESERVED); 16800Sstevel@tonic-gate } 16810Sstevel@tonic-gate if (rsa_private_decrypt(session_key_int, session_key_int, 16820Sstevel@tonic-gate sensitive_data.server_key->rsa) <= 0) 16830Sstevel@tonic-gate rsafail++; 16840Sstevel@tonic-gate if (rsa_private_decrypt(session_key_int, session_key_int, 16850Sstevel@tonic-gate sensitive_data.ssh1_host_key->rsa) <= 0) 16860Sstevel@tonic-gate rsafail++; 16870Sstevel@tonic-gate } else { 16880Sstevel@tonic-gate /* Host key has bigger modulus (or they are equal). */ 16890Sstevel@tonic-gate if (BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) < 16900Sstevel@tonic-gate BN_num_bits(sensitive_data.server_key->rsa->n) + SSH_KEY_BITS_RESERVED) { 16910Sstevel@tonic-gate fatal("do_connection: %s: host_key %d < server_key %d + SSH_KEY_BITS_RESERVED %d", 16920Sstevel@tonic-gate get_remote_ipaddr(), 16930Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n), 16940Sstevel@tonic-gate BN_num_bits(sensitive_data.server_key->rsa->n), 16950Sstevel@tonic-gate SSH_KEY_BITS_RESERVED); 16960Sstevel@tonic-gate } 16970Sstevel@tonic-gate if (rsa_private_decrypt(session_key_int, session_key_int, 16980Sstevel@tonic-gate sensitive_data.ssh1_host_key->rsa) < 0) 16990Sstevel@tonic-gate rsafail++; 17000Sstevel@tonic-gate if (rsa_private_decrypt(session_key_int, session_key_int, 17010Sstevel@tonic-gate sensitive_data.server_key->rsa) < 0) 17020Sstevel@tonic-gate rsafail++; 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate return (rsafail); 17050Sstevel@tonic-gate } 17060Sstevel@tonic-gate /* 17070Sstevel@tonic-gate * SSH1 key exchange 17080Sstevel@tonic-gate */ 17090Sstevel@tonic-gate static void 17100Sstevel@tonic-gate do_ssh1_kex(void) 17110Sstevel@tonic-gate { 17120Sstevel@tonic-gate int i, len; 17130Sstevel@tonic-gate int rsafail = 0; 17140Sstevel@tonic-gate BIGNUM *session_key_int; 17150Sstevel@tonic-gate u_char session_key[SSH_SESSION_KEY_LENGTH]; 17160Sstevel@tonic-gate u_char cookie[8]; 17170Sstevel@tonic-gate u_int cipher_type, auth_mask, protocol_flags; 17180Sstevel@tonic-gate u_int32_t rnd = 0; 17190Sstevel@tonic-gate 17200Sstevel@tonic-gate /* 17210Sstevel@tonic-gate * Generate check bytes that the client must send back in the user 17220Sstevel@tonic-gate * packet in order for it to be accepted; this is used to defy ip 17230Sstevel@tonic-gate * spoofing attacks. Note that this only works against somebody 17240Sstevel@tonic-gate * doing IP spoofing from a remote machine; any machine on the local 17250Sstevel@tonic-gate * network can still see outgoing packets and catch the random 17260Sstevel@tonic-gate * cookie. This only affects rhosts authentication, and this is one 17270Sstevel@tonic-gate * of the reasons why it is inherently insecure. 17280Sstevel@tonic-gate */ 17290Sstevel@tonic-gate for (i = 0; i < 8; i++) { 17300Sstevel@tonic-gate if (i % 4 == 0) 17310Sstevel@tonic-gate rnd = arc4random(); 17320Sstevel@tonic-gate cookie[i] = rnd & 0xff; 17330Sstevel@tonic-gate rnd >>= 8; 17340Sstevel@tonic-gate } 17350Sstevel@tonic-gate 17360Sstevel@tonic-gate /* 17370Sstevel@tonic-gate * Send our public key. We include in the packet 64 bits of random 17380Sstevel@tonic-gate * data that must be matched in the reply in order to prevent IP 17390Sstevel@tonic-gate * spoofing. 17400Sstevel@tonic-gate */ 17410Sstevel@tonic-gate packet_start(SSH_SMSG_PUBLIC_KEY); 17420Sstevel@tonic-gate for (i = 0; i < 8; i++) 17430Sstevel@tonic-gate packet_put_char(cookie[i]); 17440Sstevel@tonic-gate 17450Sstevel@tonic-gate /* Store our public server RSA key. */ 17460Sstevel@tonic-gate packet_put_int(BN_num_bits(sensitive_data.server_key->rsa->n)); 17470Sstevel@tonic-gate packet_put_bignum(sensitive_data.server_key->rsa->e); 17480Sstevel@tonic-gate packet_put_bignum(sensitive_data.server_key->rsa->n); 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate /* Store our public host RSA key. */ 17510Sstevel@tonic-gate packet_put_int(BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); 17520Sstevel@tonic-gate packet_put_bignum(sensitive_data.ssh1_host_key->rsa->e); 17530Sstevel@tonic-gate packet_put_bignum(sensitive_data.ssh1_host_key->rsa->n); 17540Sstevel@tonic-gate 17550Sstevel@tonic-gate /* Put protocol flags. */ 17560Sstevel@tonic-gate packet_put_int(SSH_PROTOFLAG_HOST_IN_FWD_OPEN); 17570Sstevel@tonic-gate 17580Sstevel@tonic-gate /* Declare which ciphers we support. */ 17590Sstevel@tonic-gate packet_put_int(cipher_mask_ssh1(0)); 17600Sstevel@tonic-gate 17610Sstevel@tonic-gate /* Declare supported authentication types. */ 17620Sstevel@tonic-gate auth_mask = 0; 17630Sstevel@tonic-gate if (options.rhosts_authentication) 17640Sstevel@tonic-gate auth_mask |= 1 << SSH_AUTH_RHOSTS; 17650Sstevel@tonic-gate if (options.rhosts_rsa_authentication) 17660Sstevel@tonic-gate auth_mask |= 1 << SSH_AUTH_RHOSTS_RSA; 17670Sstevel@tonic-gate if (options.rsa_authentication) 17680Sstevel@tonic-gate auth_mask |= 1 << SSH_AUTH_RSA; 17690Sstevel@tonic-gate #if defined(KRB4) || defined(KRB5) 17700Sstevel@tonic-gate if (options.kerberos_authentication) 17710Sstevel@tonic-gate auth_mask |= 1 << SSH_AUTH_KERBEROS; 17720Sstevel@tonic-gate #endif 17730Sstevel@tonic-gate #if defined(AFS) || defined(KRB5) 17740Sstevel@tonic-gate if (options.kerberos_tgt_passing) 17750Sstevel@tonic-gate auth_mask |= 1 << SSH_PASS_KERBEROS_TGT; 17760Sstevel@tonic-gate #endif 17770Sstevel@tonic-gate #ifdef AFS 17780Sstevel@tonic-gate if (options.afs_token_passing) 17790Sstevel@tonic-gate auth_mask |= 1 << SSH_PASS_AFS_TOKEN; 17800Sstevel@tonic-gate #endif 17810Sstevel@tonic-gate if (options.challenge_response_authentication == 1) 17820Sstevel@tonic-gate auth_mask |= 1 << SSH_AUTH_TIS; 17830Sstevel@tonic-gate if (options.password_authentication) 17840Sstevel@tonic-gate auth_mask |= 1 << SSH_AUTH_PASSWORD; 17850Sstevel@tonic-gate packet_put_int(auth_mask); 17860Sstevel@tonic-gate 17870Sstevel@tonic-gate /* Send the packet and wait for it to be sent. */ 17880Sstevel@tonic-gate packet_send(); 17890Sstevel@tonic-gate packet_write_wait(); 17900Sstevel@tonic-gate 17910Sstevel@tonic-gate debug("Sent %d bit server key and %d bit host key.", 17920Sstevel@tonic-gate BN_num_bits(sensitive_data.server_key->rsa->n), 17930Sstevel@tonic-gate BN_num_bits(sensitive_data.ssh1_host_key->rsa->n)); 17940Sstevel@tonic-gate 17950Sstevel@tonic-gate /* Read clients reply (cipher type and session key). */ 17960Sstevel@tonic-gate packet_read_expect(SSH_CMSG_SESSION_KEY); 17970Sstevel@tonic-gate 17980Sstevel@tonic-gate /* Get cipher type and check whether we accept this. */ 17990Sstevel@tonic-gate cipher_type = packet_get_char(); 18000Sstevel@tonic-gate 18010Sstevel@tonic-gate if (!(cipher_mask_ssh1(0) & (1 << cipher_type))) { 18020Sstevel@tonic-gate packet_disconnect("Warning: client selects unsupported cipher."); 18030Sstevel@tonic-gate } 18040Sstevel@tonic-gate 18050Sstevel@tonic-gate /* Get check bytes from the packet. These must match those we 18060Sstevel@tonic-gate sent earlier with the public key packet. */ 18070Sstevel@tonic-gate for (i = 0; i < 8; i++) { 18080Sstevel@tonic-gate if (cookie[i] != packet_get_char()) { 18090Sstevel@tonic-gate packet_disconnect("IP Spoofing check bytes do not match."); 18100Sstevel@tonic-gate } 18110Sstevel@tonic-gate } 18120Sstevel@tonic-gate 18130Sstevel@tonic-gate debug("Encryption type: %.200s", cipher_name(cipher_type)); 18140Sstevel@tonic-gate 18150Sstevel@tonic-gate /* Get the encrypted integer. */ 18160Sstevel@tonic-gate if ((session_key_int = BN_new()) == NULL) 18170Sstevel@tonic-gate fatal("do_ssh1_kex: BN_new failed"); 18180Sstevel@tonic-gate packet_get_bignum(session_key_int); 18190Sstevel@tonic-gate 18200Sstevel@tonic-gate protocol_flags = packet_get_int(); 18210Sstevel@tonic-gate packet_set_protocol_flags(protocol_flags); 18220Sstevel@tonic-gate packet_check_eom(); 18230Sstevel@tonic-gate 18240Sstevel@tonic-gate /* Decrypt session_key_int using host/server keys */ 18255562Sjp161948 rsafail = ssh1_session_key(session_key_int); 18260Sstevel@tonic-gate 18270Sstevel@tonic-gate /* 18280Sstevel@tonic-gate * Extract session key from the decrypted integer. The key is in the 18290Sstevel@tonic-gate * least significant 256 bits of the integer; the first byte of the 18300Sstevel@tonic-gate * key is in the highest bits. 18310Sstevel@tonic-gate */ 18320Sstevel@tonic-gate if (!rsafail) { 18330Sstevel@tonic-gate (void) BN_mask_bits(session_key_int, sizeof(session_key) * 8); 18340Sstevel@tonic-gate len = BN_num_bytes(session_key_int); 18350Sstevel@tonic-gate if (len < 0 || len > sizeof(session_key)) { 18360Sstevel@tonic-gate error("do_connection: bad session key len from %s: " 18370Sstevel@tonic-gate "session_key_int %d > sizeof(session_key) %lu", 18380Sstevel@tonic-gate get_remote_ipaddr(), len, (u_long)sizeof(session_key)); 18390Sstevel@tonic-gate rsafail++; 18400Sstevel@tonic-gate } else { 18410Sstevel@tonic-gate (void) memset(session_key, 0, sizeof(session_key)); 18420Sstevel@tonic-gate (void) BN_bn2bin(session_key_int, 18430Sstevel@tonic-gate session_key + sizeof(session_key) - len); 18440Sstevel@tonic-gate 18450Sstevel@tonic-gate compute_session_id(session_id, cookie, 18460Sstevel@tonic-gate sensitive_data.ssh1_host_key->rsa->n, 18470Sstevel@tonic-gate sensitive_data.server_key->rsa->n); 18480Sstevel@tonic-gate /* 18490Sstevel@tonic-gate * Xor the first 16 bytes of the session key with the 18500Sstevel@tonic-gate * session id. 18510Sstevel@tonic-gate */ 18520Sstevel@tonic-gate for (i = 0; i < 16; i++) 18530Sstevel@tonic-gate session_key[i] ^= session_id[i]; 18540Sstevel@tonic-gate } 18550Sstevel@tonic-gate } 18560Sstevel@tonic-gate if (rsafail) { 18570Sstevel@tonic-gate int bytes = BN_num_bytes(session_key_int); 18580Sstevel@tonic-gate u_char *buf = xmalloc(bytes); 18590Sstevel@tonic-gate MD5_CTX md; 18600Sstevel@tonic-gate 18610Sstevel@tonic-gate log("do_connection: generating a fake encryption key"); 18620Sstevel@tonic-gate (void) BN_bn2bin(session_key_int, buf); 18630Sstevel@tonic-gate MD5_Init(&md); 18640Sstevel@tonic-gate MD5_Update(&md, buf, bytes); 18650Sstevel@tonic-gate MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); 18660Sstevel@tonic-gate MD5_Final(session_key, &md); 18670Sstevel@tonic-gate MD5_Init(&md); 18680Sstevel@tonic-gate MD5_Update(&md, session_key, 16); 18690Sstevel@tonic-gate MD5_Update(&md, buf, bytes); 18700Sstevel@tonic-gate MD5_Update(&md, sensitive_data.ssh1_cookie, SSH_SESSION_KEY_LENGTH); 18710Sstevel@tonic-gate MD5_Final(session_key + 16, &md); 18720Sstevel@tonic-gate (void) memset(buf, 0, bytes); 18730Sstevel@tonic-gate xfree(buf); 18740Sstevel@tonic-gate for (i = 0; i < 16; i++) 18750Sstevel@tonic-gate session_id[i] = session_key[i] ^ session_key[i + 16]; 18760Sstevel@tonic-gate } 18770Sstevel@tonic-gate /* Destroy the private and public keys. No longer. */ 18780Sstevel@tonic-gate destroy_sensitive_data(); 18790Sstevel@tonic-gate 18800Sstevel@tonic-gate /* Destroy the decrypted integer. It is no longer needed. */ 18810Sstevel@tonic-gate BN_clear_free(session_key_int); 18820Sstevel@tonic-gate 18830Sstevel@tonic-gate /* Set the session key. From this on all communications will be encrypted. */ 18840Sstevel@tonic-gate packet_set_encryption_key(session_key, SSH_SESSION_KEY_LENGTH, cipher_type); 18850Sstevel@tonic-gate 18860Sstevel@tonic-gate /* Destroy our copy of the session key. It is no longer needed. */ 18870Sstevel@tonic-gate (void) memset(session_key, 0, sizeof(session_key)); 18880Sstevel@tonic-gate 18890Sstevel@tonic-gate debug("Received session key; encryption turned on."); 18900Sstevel@tonic-gate 18910Sstevel@tonic-gate /* Send an acknowledgment packet. Note that this packet is sent encrypted. */ 18920Sstevel@tonic-gate packet_start(SSH_SMSG_SUCCESS); 18930Sstevel@tonic-gate packet_send(); 18940Sstevel@tonic-gate packet_write_wait(); 18950Sstevel@tonic-gate } 18960Sstevel@tonic-gate 18970Sstevel@tonic-gate /* 18987574SJan.Pechanec@Sun.COM * Prepare for SSH2 key exchange. 18990Sstevel@tonic-gate */ 19007574SJan.Pechanec@Sun.COM Kex * 19017574SJan.Pechanec@Sun.COM prepare_for_ssh2_kex(void) 19020Sstevel@tonic-gate { 19030Sstevel@tonic-gate Kex *kex; 19040Sstevel@tonic-gate Kex_hook_func kex_hook = NULL; 19050Sstevel@tonic-gate char **locales; 19068658SJan.Pechanec@Sun.COM static char **myproposal; 19078658SJan.Pechanec@Sun.COM 19088658SJan.Pechanec@Sun.COM myproposal = my_srv_proposal; 19090Sstevel@tonic-gate 19100Sstevel@tonic-gate if (options.ciphers != NULL) { 19110Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_CTOS] = 19120Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_STOC] = options.ciphers; 19130Sstevel@tonic-gate } 19140Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_CTOS] = 19150Sstevel@tonic-gate compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_CTOS]); 19160Sstevel@tonic-gate myproposal[PROPOSAL_ENC_ALGS_STOC] = 19170Sstevel@tonic-gate compat_cipher_proposal(myproposal[PROPOSAL_ENC_ALGS_STOC]); 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate if (options.macs != NULL) { 19200Sstevel@tonic-gate myproposal[PROPOSAL_MAC_ALGS_CTOS] = 19210Sstevel@tonic-gate myproposal[PROPOSAL_MAC_ALGS_STOC] = options.macs; 19220Sstevel@tonic-gate } 19230Sstevel@tonic-gate if (!options.compression) { 19240Sstevel@tonic-gate myproposal[PROPOSAL_COMP_ALGS_CTOS] = 19250Sstevel@tonic-gate myproposal[PROPOSAL_COMP_ALGS_STOC] = "none"; 19260Sstevel@tonic-gate } 19270Sstevel@tonic-gate 19280Sstevel@tonic-gate /* 19290Sstevel@tonic-gate * Prepare kex algs / hostkey algs (excluding GSS, which is 19300Sstevel@tonic-gate * handled in the kex hook. 19310Sstevel@tonic-gate * 19320Sstevel@tonic-gate * XXX This should probably move to the kex hook as well, where 19330Sstevel@tonic-gate * all non-constant kex offer material belongs. 19340Sstevel@tonic-gate */ 19350Sstevel@tonic-gate myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = list_hostkey_types(); 19360Sstevel@tonic-gate 19370Sstevel@tonic-gate /* If we have no host key algs we can't offer KEXDH/KEX_DH_GEX */ 19380Sstevel@tonic-gate if (myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] == NULL || 19390Sstevel@tonic-gate *myproposal[PROPOSAL_SERVER_HOST_KEY_ALGS] == '\0') 19400Sstevel@tonic-gate myproposal[PROPOSAL_KEX_ALGS] = ""; 19410Sstevel@tonic-gate 19420Sstevel@tonic-gate if ((locales = g11n_getlocales()) != NULL) { 19430Sstevel@tonic-gate /* Solaris 9 SSH expects a list of locales */ 19440Sstevel@tonic-gate if (datafellows & SSH_BUG_LOCALES_NOT_LANGTAGS) 19450Sstevel@tonic-gate myproposal[PROPOSAL_LANG_STOC] = xjoin(locales, ','); 19460Sstevel@tonic-gate else 19470Sstevel@tonic-gate myproposal[PROPOSAL_LANG_STOC] = 19480Sstevel@tonic-gate g11n_locales2langs(locales); 19490Sstevel@tonic-gate } 19500Sstevel@tonic-gate 19515562Sjp161948 if (locales != NULL) 19525562Sjp161948 g11n_freelist(locales); 19535562Sjp161948 19540Sstevel@tonic-gate if ((myproposal[PROPOSAL_LANG_STOC] != NULL) || 19550Sstevel@tonic-gate (strcmp(myproposal[PROPOSAL_LANG_STOC], "")) != 0) 19560Sstevel@tonic-gate myproposal[PROPOSAL_LANG_CTOS] = 19570Sstevel@tonic-gate xstrdup(myproposal[PROPOSAL_LANG_STOC]); 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate #ifdef GSSAPI 19600Sstevel@tonic-gate if (options.gss_keyex) 19610Sstevel@tonic-gate kex_hook = ssh_gssapi_server_kex_hook; 19620Sstevel@tonic-gate #endif /* GSSAPI */ 19630Sstevel@tonic-gate 19640Sstevel@tonic-gate kex = kex_setup(NULL, myproposal, kex_hook); 19655562Sjp161948 19665562Sjp161948 if (myproposal[PROPOSAL_LANG_STOC] != NULL) 19675562Sjp161948 xfree(myproposal[PROPOSAL_LANG_STOC]); 19685562Sjp161948 if (myproposal[PROPOSAL_LANG_CTOS] != NULL) 19695562Sjp161948 xfree(myproposal[PROPOSAL_LANG_CTOS]); 19705562Sjp161948 19710Sstevel@tonic-gate kex->kex[KEX_DH_GRP1_SHA1] = kexdh_server; 19720Sstevel@tonic-gate kex->kex[KEX_DH_GEX_SHA1] = kexgex_server; 19730Sstevel@tonic-gate #ifdef GSSAPI 19740Sstevel@tonic-gate kex->kex[KEX_GSS_GRP1_SHA1] = kexgss_server; 19750Sstevel@tonic-gate #endif /* GSSAPI */ 19760Sstevel@tonic-gate kex->server = 1; 19777574SJan.Pechanec@Sun.COM kex->client_version_string = client_version_string; 19787574SJan.Pechanec@Sun.COM kex->server_version_string = server_version_string; 19797574SJan.Pechanec@Sun.COM kex->load_host_key = &get_hostkey_by_type; 19807574SJan.Pechanec@Sun.COM kex->host_key_index = &get_hostkey_index; 19810Sstevel@tonic-gate 19820Sstevel@tonic-gate xxx_kex = kex; 19837574SJan.Pechanec@Sun.COM return (kex); 19847574SJan.Pechanec@Sun.COM } 19857574SJan.Pechanec@Sun.COM 19867574SJan.Pechanec@Sun.COM /* 19877574SJan.Pechanec@Sun.COM * Do SSH2 key exchange. 19887574SJan.Pechanec@Sun.COM */ 19897574SJan.Pechanec@Sun.COM static void 19907574SJan.Pechanec@Sun.COM do_ssh2_kex(void) 19917574SJan.Pechanec@Sun.COM { 19927574SJan.Pechanec@Sun.COM Kex *kex; 19937574SJan.Pechanec@Sun.COM 19947574SJan.Pechanec@Sun.COM kex = prepare_for_ssh2_kex(); 19957574SJan.Pechanec@Sun.COM kex_start(kex); 19960Sstevel@tonic-gate 19970Sstevel@tonic-gate dispatch_run(DISPATCH_BLOCK, &kex->done, kex); 19980Sstevel@tonic-gate 19990Sstevel@tonic-gate if (kex->name) { 20000Sstevel@tonic-gate xfree(kex->name); 20010Sstevel@tonic-gate kex->name = NULL; 20020Sstevel@tonic-gate } 20030Sstevel@tonic-gate session_id2 = kex->session_id; 20040Sstevel@tonic-gate session_id2_len = kex->session_id_len; 20050Sstevel@tonic-gate 20060Sstevel@tonic-gate #ifdef DEBUG_KEXDH 20070Sstevel@tonic-gate /* send 1st encrypted/maced/compressed message */ 20080Sstevel@tonic-gate packet_start(SSH2_MSG_IGNORE); 20090Sstevel@tonic-gate packet_put_cstring("markus"); 20100Sstevel@tonic-gate packet_send(); 20110Sstevel@tonic-gate packet_write_wait(); 20120Sstevel@tonic-gate #endif 20130Sstevel@tonic-gate debug("KEX done"); 20140Sstevel@tonic-gate } 2015