if (options.server_key_bits > BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED && options.server_key_bits < BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) { options.server_key_bits = BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED; debug("Forcing server key to %d bits to make it differ from host key.", options.server_key_bits); }
main(int ac, char **av){	extern char *optarg;	extern int optind;	int opt, sock_in = 0, sock_out = 0, newsock, i, fdsetsz, on = 1;	pid_t pid;	socklen_t fromlen;	int silentrsa = 0;	fd_set *fdset;	struct sockaddr_storage from;	const char *remote_ip;	int remote_port;	char *comment;	FILE *f;	struct linger linger;	struct addrinfo *ai;	char ntop[NI_MAXHOST], strport[NI_MAXSERV];	int listen_sock, maxfd;	/* Save argv[0]. */	saved_argv = av;	if (strchr(av[0], '/'))		av0 = strrchr(av[0], '/') + 1;	else		av0 = av[0];	/* Initialize configuration options to their default values. */	initialize_server_options(&options);	/* Parse command-line arguments. */	while ((opt = getopt(ac, av, "f:p:b:k:h:g:V:diqQ46")) != EOF) {		switch (opt) {		case '4':			IPv4or6 = AF_INET;			break;		case '6':			IPv4or6 = AF_INET6;			break;		case 'f':			config_file_name = optarg;			break;		case 'd':			debug_flag = 1;			options.log_level = SYSLOG_LEVEL_DEBUG;			break;		case 'i':			inetd_flag = 1;			break;		case 'Q':			silentrsa = 1;			break;		case 'q':			options.log_level = SYSLOG_LEVEL_QUIET;			break;		case 'b':			options.server_key_bits = atoi(optarg);			break;		case 'p':			options.ports_from_cmdline = 1;			if (options.num_ports >= MAX_PORTS)				fatal("too many ports.\n");			options.ports[options.num_ports++] = atoi(optarg);			break;		case 'g':			options.login_grace_time = atoi(optarg);			break;		case 'k':			options.key_regeneration_time = atoi(optarg);			break;		case 'h':			options.host_key_file = optarg;			break;		case 'V':			client_version_string = optarg;			/* only makes sense with inetd_flag, i.e. no listen() */			inetd_flag = 1;			break;		case '?':		default:			fprintf(stderr, "sshd version %s\n", SSH_VERSION);			fprintf(stderr, "Usage: %s [options]\n", av0);			fprintf(stderr, "Options:\n");			fprintf(stderr, "  -f file    Configuration file (default %s)\n", SERVER_CONFIG_FILE);			fprintf(stderr, "  -d         Debugging mode\n");			fprintf(stderr, "  -i         Started from inetd\n");			fprintf(stderr, "  -q         Quiet (no logging)\n");			fprintf(stderr, "  -p port    Listen on the specified port (default: 22)\n");			fprintf(stderr, "  -k seconds Regenerate server key every this many seconds (default: 3600)\n");			fprintf(stderr, "  -g seconds Grace period for authentication (default: 300)\n");			fprintf(stderr, "  -b bits    Size of server RSA key (default: 768 bits)\n");			fprintf(stderr, "  -h file    File from which to read host key (default: %s)\n",			    HOST_KEY_FILE);			fprintf(stderr, "  -4         Use IPv4 only\n");			fprintf(stderr, "  -6         Use IPv6 only\n");			exit(1);		}	}	/*	 * Force logging to stderr until we have loaded the private host	 * key (unless started from inetd)	 */	log_init(av0,	    options.log_level == -1 ? SYSLOG_LEVEL_INFO : options.log_level,	    options.log_facility == -1 ? SYSLOG_FACILITY_AUTH : options.log_facility,	    !inetd_flag);	/* check if RSA support exists */	if (rsa_alive() == 0) {		if (silentrsa == 0)			printf("sshd: no RSA support in libssl and libcrypto -- exiting.  See ssl(8)\n");		log("no RSA support in libssl and libcrypto -- exiting.  See ssl(8)");		exit(1);	}	/* Read server configuration options from the configuration file. */	read_server_config(&options, config_file_name);	/* Fill in default values for those options not explicitly set. */	fill_default_server_options(&options);	/* Check certain values for sanity. */	if (options.server_key_bits < 512 ||	    options.server_key_bits > 32768) {		fprintf(stderr, "Bad server key size.\n");		exit(1);	}	/* Check that there are no remaining arguments. */	if (optind < ac) {		fprintf(stderr, "Extra argument %s.\n", av[optind]);		exit(1);	}	debug("sshd version %.100s", SSH_VERSION);	sensitive_data.host_key = RSA_new();	errno = 0;	/* Load the host key.  It must have empty passphrase. */	if (!load_private_key(options.host_key_file, "",			      sensitive_data.host_key, &comment)) {		error("Could not load host key: %.200s: %.100s",		      options.host_key_file, strerror(errno));		exit(1);	}	xfree(comment);	/* Initialize the log (it is reinitialized below in case we	   forked). */	if (debug_flag && !inetd_flag)		log_stderr = 1;	log_init(av0, options.log_level, options.log_facility, log_stderr);	/* If not in debugging mode, and not started from inetd,	   disconnect from the controlling terminal, and fork.  The	   original process exits. */	if (!debug_flag && !inetd_flag) {#ifdef TIOCNOTTY		int fd;#endif /* TIOCNOTTY */		if (daemon(0, 0) < 0)			fatal("daemon() failed: %.200s", strerror(errno));		/* Disconnect from the controlling tty. */#ifdef TIOCNOTTY		fd = open("/dev/tty", O_RDWR | O_NOCTTY);		if (fd >= 0) {			(void) ioctl(fd, TIOCNOTTY, NULL);			close(fd);		}#endif /* TIOCNOTTY */	}	/* Reinitialize the log (because of the fork above). */	log_init(av0, options.log_level, options.log_facility, log_stderr);	/* Check that server and host key lengths differ sufficiently.	   This is necessary to make double encryption work with rsaref.	   Oh, I hate software patents. I dont know if this can go? Niels */	if (options.server_key_bits >	BN_num_bits(sensitive_data.host_key->n) - SSH_KEY_BITS_RESERVED &&	    options.server_key_bits <	BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED) {		options.server_key_bits =			BN_num_bits(sensitive_data.host_key->n) + SSH_KEY_BITS_RESERVED;		debug("Forcing server key to %d bits to make it differ from host key.",		      options.server_key_bits);	}	/* Do not display messages to stdout in RSA code. */	rsa_set_verbose(0);	/* Initialize the random number generator. */	arc4random_stir();	/* Chdir to the root directory so that the current disk can be	   unmounted if desired. */	chdir("/");	/* Start listening for a socket, unless started from inetd. */	if (inetd_flag) {		int s1, s2;		s1 = dup(0);	/* Make sure descriptors 0, 1, and 2 are in use. */		s2 = dup(s1);		sock_in = dup(0);		sock_out = dup(1);		/* We intentionally do not close the descriptors 0, 1, and 2		   as our code for setting the descriptors won\'t work		   if ttyfd happens to be one of those. */		debug("inetd sockets after dupping: %d, %d", sock_in, sock_out);		public_key = RSA_new();		sensitive_data.private_key = RSA_new();		/* XXX check options.protocol */		log("Generating %d bit RSA key.", options.server_key_bits);		rsa_generate_key(sensitive_data.private_key, public_key,				 options.server_key_bits);		arc4random_stir();		log("RSA key generation complete.");	} else {		for (ai = options.listen_addrs; ai; ai = ai->ai_next) {			if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)				continue;			if (num_listen_socks >= MAX_LISTEN_SOCKS)				fatal("Too many listen sockets. "				    "Enlarge MAX_LISTEN_SOCKS");			if (getnameinfo(ai->ai_addr, ai->ai_addrlen,			    ntop, sizeof(ntop), strport, sizeof(strport),			    NI_NUMERICHOST|NI_NUMERICSERV) != 0) {				error("getnameinfo failed");				continue;			}			/* Create socket for listening. */			listen_sock = socket(ai->ai_family, SOCK_STREAM, 0);			if (listen_sock < 0) {				/* kernel may not support ipv6 */				verbose("socket: %.100s", strerror(errno));				continue;			}			if (fcntl(listen_sock, F_SETFL, O_NONBLOCK) < 0) {				error("listen_sock O_NONBLOCK: %s", strerror(errno));				close(listen_sock);				continue;			}			/*			 * Set socket options.  We try to make the port			 * reusable and have it close as fast as possible			 * without waiting in unnecessary wait states on			 * close.			 */			setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,			    (void *) &on, sizeof(on));			linger.l_onoff = 1;			linger.l_linger = 5;			setsockopt(listen_sock, SOL_SOCKET, SO_LINGER,			    (void *) &linger, sizeof(linger));			debug("Bind to port %s on %s.", strport, ntop);			/* Bind the socket to the desired port. */			if (bind(listen_sock, ai->ai_addr, ai->ai_addrlen) < 0) {				error("Bind to port %s on %s failed: %.200s.",				    strport, ntop, strerror(errno));				close(listen_sock);				continue;			}			listen_socks[num_listen_socks] = listen_sock;			num_listen_socks++;			/* Start listening on the port. */			log("Server listening on %s port %s.", ntop, strport);			if (listen(listen_sock, 5) < 0)				fatal("listen: %.100s", strerror(errno));		}		freeaddrinfo(options.listen_addrs);		if (!num_listen_socks)			fatal("Cannot bind any address.");		if (!debug_flag) {			/*			 * Record our pid in /etc/sshd_pid to make it easier			 * to kill the correct sshd.  We don\'t want to do			 * this before the bind above because the bind will			 * fail if there already is a daemon, and this will			 * overwrite any old pid in the file.			 */			f = fopen(SSH_DAEMON_PID_FILE, "w");			if (f) {				fprintf(f, "%u\n", (unsigned int) getpid());				fclose(f);			}		}		public_key = RSA_new();		sensitive_data.private_key = RSA_new();		log("Generating %d bit RSA key.", options.server_key_bits);		rsa_generate_key(sensitive_data.private_key, public_key,				 options.server_key_bits);		arc4random_stir();		log("RSA key generation complete.");		/* Schedule server key regeneration alarm. */		signal(SIGALRM, key_regeneration_alarm);		alarm(options.key_regeneration_time);		/* Arrange to restart on SIGHUP.  The handler needs listen_sock. */		signal(SIGHUP, sighup_handler);		signal(SIGTERM, sigterm_handler);		signal(SIGQUIT, sigterm_handler);		/* Arrange SIGCHLD to be caught. */		signal(SIGCHLD, main_sigchld_handler);		/* setup fd set for listen */		maxfd = 0;		for (i = 0; i < num_listen_socks; i++)			if (listen_socks[i] > maxfd)				maxfd = listen_socks[i];		fdsetsz = howmany(maxfd, NFDBITS) * sizeof(fd_mask);		fdset = (fd_set *)xmalloc(fdsetsz);		/*		 * Stay listening for connections until the system crashes or		 * the daemon is killed with a signal.		 */		for (;;) {			if (received_sighup)				sighup_restart();			/* Wait in select until there is a connection. */			memset(fdset, 0, fdsetsz);			for (i = 0; i < num_listen_socks; i++)				FD_SET(listen_socks[i], fdset);			if (select(maxfd + 1, fdset, NULL, NULL, NULL) < 0) {				if (errno != EINTR)					error("select: %.100s", strerror(errno));				continue;			}			for (i = 0; i < num_listen_socks; i++) {				if (!FD_ISSET(listen_socks[i], fdset))					continue;			fromlen = sizeof(from);			newsock = accept(listen_socks[i], (struct sockaddr *)&from,			    &fromlen);			if (newsock < 0) {				if (errno != EINTR && errno != EWOULDBLOCK)					error("accept: %.100s", strerror(errno));				continue;			}			if (fcntl(newsock, F_SETFL, 0) < 0) {				error("newsock del O_NONBLOCK: %s", strerror(errno));				continue;			}			/*			 * Got connection.  Fork a child to handle it, unless			 * we are in debugging mode.			 */			if (debug_flag) {				/*				 * In debugging mode.  Close the listening				 * socket, and start processing the				 * connection without forking.				 */				debug("Server will not fork when running in debugging mode.");				close_listen_socks();				sock_in = newsock;				sock_out = newsock;				pid = getpid();				break;			} else {				/*				 * Normal production daemon.  Fork, and have				 * the child process the connection. The				 * parent continues listening.				 */				if ((pid = fork()) == 0) {					/*					 * Child.  Close the listening socket, and start using the					 * accepted socket.  Reinitialize logging (since our pid has					 * changed).  We break out of the loop to handle the connection.					 */					close_listen_socks();					sock_in = newsock;					sock_out = newsock;					log_init(av0, options.log_level, options.log_facility, log_stderr);					break;				}			}			/* Parent.  Stay in the loop. */			if (pid < 0)				error("fork: %.100s", strerror(errno));			else				debug("Forked child %d.", pid);			/* Mark that the key has been used (it was "given" to the child). */			key_used = 1;			arc4random_stir();			/* Close the new socket (the child is now taking care of it). */			close(newsock);			} /* for (i = 0; i < num_listen_socks; i++) */			/* child process check (or debug mode) */			if (num_listen_socks < 0)				break;		}	}	/* This is the child processing a new connection. */	/*	 * Disable the key regeneration alarm.  We will not regenerate the	 * key since we are no longer in a position to give it to anyone. We	 * will not restart on SIGHUP since it no longer makes sense.	 */	alarm(0);	signal(SIGALRM, SIG_DFL);	signal(SIGHUP, SIG_DFL);	signal(SIGTERM, SIG_DFL);	signal(SIGQUIT, SIG_DFL);	signal(SIGCHLD, SIG_DFL);	/*	 * Set socket options for the connection.  We want the socket to	 * close as fast as possible without waiting for anything.  If the	 * connection is not a socket, these will do nothing.	 */	/* setsockopt(sock_in, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); */	linger.l_onoff = 1;	linger.l_linger = 5;	setsockopt(sock_in, SOL_SOCKET, SO_LINGER, (void *) &linger, sizeof(linger));	/*	 * Register our connection.  This turns encryption off because we do	 * not have a key.	 */	packet_set_connection(sock_in, sock_out);	remote_port = get_remote_port();	remote_ip = get_remote_ipaddr();	/* Check whether logins are denied from this host. */#ifdef LIBWRAP	/* XXX LIBWRAP noes not know about IPv6 */	{		struct request_info req;		request_init(&req, RQ_DAEMON, av0, RQ_FILE, sock_in, NULL);		fromhost(&req);		if (!hosts_access(&req)) {			close(sock_in);			close(sock_out);			refuse(&req);		}/*XXX IPv6 verbose("Connection from %.500s port %d", eval_client(&req), remote_port); */	}#endif /* LIBWRAP */	/* Log the connection. */	verbose("Connection from %.500s port %d", remote_ip, remote_port);	/*	 * We don\'t want to listen forever unless the other side	 * successfully authenticates itself.  So we set up an alarm which is	 * cleared after successful authentication.  A limit of zero	 * indicates no limit. Note that we don\'t set the alarm in debugging	 * mode; it is just annoying to have the server exit just when you	 * are about to discover the bug.	 */	signal(SIGALRM, grace_alarm_handler);	if (!debug_flag)		alarm(options.login_grace_time);	sshd_exchange_identification(sock_in, sock_out);	/*	 * Check that the connection comes from a privileged port.  Rhosts-	 * and Rhosts-RSA-Authentication only make sense from priviledged	 * programs.  Of course, if the intruder has root access on his local	 * machine, he can connect from any port.  So do not use these	 * authentication methods from machines that you do not trust.	 */	if (remote_port >= IPPORT_RESERVED ||	    remote_port < IPPORT_RESERVED / 2) {		options.rhosts_authentication = 0;		options.rhosts_rsa_authentication = 0;	}#ifdef KRB4	if (!packet_connection_is_ipv4() &&	    options.kerberos_authentication) {		debug("Kerberos Authentication disabled, only available for IPv4.");		options.kerberos_authentication = 0;	}#endif /* KRB4 */	packet_set_nonblocking();	/* perform the key exchange */	/* authenticate user and start session */	if (compat20) {		do_ssh2_kex();		do_authentication2();	} else {		do_ssh1_kex();		do_authentication();	}#ifdef KRB4	/* Cleanup user's ticket cache file. */	if (options.kerberos_ticket_cleanup)		(void) dest_tkt();#endif /* KRB4 */	/* The connection has been terminated. */	verbose("Closing connection to %.100s", remote_ip);	packet_close();	exit(0);}