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