fatal("Bad owner or mode for %s", _PATH_PRIVSEP_CHROOT_DIR);
fatal("%s must be owned by root and not group or " "world-writable.", _PATH_PRIVSEP_CHROOT_DIR);
main(int ac, char **av){	extern char *optarg;	extern int optind;	int opt, sock_in = 0, sock_out = 0, newsock, j, i, fdsetsz, on = 1;	pid_t pid;	socklen_t fromlen;	fd_set *fdset;	struct sockaddr_storage from;	const char *remote_ip;	int remote_port;	FILE *f;	struct addrinfo *ai;	char ntop[NI_MAXHOST], strport[NI_MAXSERV];	int listen_sock, maxfd;	int startup_p[2];	int startups = 0;	Authctxt *authctxt;	Key *key;	int ret, key_used = 0;	/* Save argv. */	saved_argv = av;	/* 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:u:o:dDeiqtQ46")) != -1) {		switch (opt) {		case '4':			IPv4or6 = AF_INET;			break;		case '6':			IPv4or6 = AF_INET6;			break;		case 'f':			config_file_name = optarg;			break;		case 'd':			if (0 == debug_flag) {				debug_flag = 1;				options.log_level = SYSLOG_LEVEL_DEBUG1;			} else if (options.log_level < SYSLOG_LEVEL_DEBUG3) {				options.log_level++;			} else {				fprintf(stderr, "Too high debugging level.\n");				exit(1);			}			break;		case 'D':			no_daemon_flag = 1;			break;		case 'e':			log_stderr = 1;			break;		case 'i':			inetd_flag = 1;			break;		case 'Q':			/* ignored */			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) {				fprintf(stderr, "too many ports.\n");				exit(1);			}			options.ports[options.num_ports++] = a2port(optarg);			if (options.ports[options.num_ports-1] == 0) {				fprintf(stderr, "Bad port number.\n");				exit(1);			}			break;		case 'g':			if ((options.login_grace_time = convtime(optarg)) == -1) {				fprintf(stderr, "Invalid login grace time.\n");				exit(1);			}			break;		case 'k':			if ((options.key_regeneration_time = convtime(optarg)) == -1) {				fprintf(stderr, "Invalid key regeneration interval.\n");				exit(1);			}			break;		case 'h':			if (options.num_host_key_files >= MAX_HOSTKEYS) {				fprintf(stderr, "too many host keys.\n");				exit(1);			}			options.host_key_files[options.num_host_key_files++] = optarg;			break;		case 'V':			client_version_string = optarg;			/* only makes sense with inetd_flag, i.e. no listen() */			inetd_flag = 1;			break;		case 't':			test_flag = 1;			break;		case 'u':			utmp_len = atoi(optarg);			if (utmp_len > MAXHOSTNAMELEN) {				fprintf(stderr, "Invalid utmp length.\n");				exit(1);			}			break;		case 'o':			if (process_server_config_line(&options, optarg,			    "command-line", 0) != 0)				exit(1);			break;		case '?':		default:			usage();			break;		}	}	SSLeay_add_all_algorithms();	channel_set_af(IPv4or6);	/*	 * Force logging to stderr until we have loaded the private host	 * key (unless started from inetd)	 */	log_init(__progname,	    options.log_level == SYSLOG_LEVEL_NOT_SET ?	    SYSLOG_LEVEL_INFO : options.log_level,	    options.log_facility == SYSLOG_FACILITY_NOT_SET ?	    SYSLOG_FACILITY_AUTH : options.log_facility,	    log_stderr || !inetd_flag);	/* 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 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);	/* load private host keys */	sensitive_data.host_keys = xmalloc(options.num_host_key_files *	    sizeof(Key *));	for (i = 0; i < options.num_host_key_files; i++)		sensitive_data.host_keys[i] = NULL;	sensitive_data.server_key = NULL;	sensitive_data.ssh1_host_key = NULL;	sensitive_data.have_ssh1_key = 0;	sensitive_data.have_ssh2_key = 0;	for (i = 0; i < options.num_host_key_files; i++) {		key = key_load_private(options.host_key_files[i], "", NULL);		sensitive_data.host_keys[i] = key;		if (key == NULL) {			error("Could not load host key: %s",			    options.host_key_files[i]);			sensitive_data.host_keys[i] = NULL;			continue;		}		switch (key->type) {		case KEY_RSA1:			sensitive_data.ssh1_host_key = key;			sensitive_data.have_ssh1_key = 1;			break;		case KEY_RSA:		case KEY_DSA:			sensitive_data.have_ssh2_key = 1;			break;		}		debug("private host key: #%d type %d %s", i, key->type,		    key_type(key));	}	if ((options.protocol & SSH_PROTO_1) && !sensitive_data.have_ssh1_key) {		log("Disabling protocol version 1. Could not load host key");		options.protocol &= ~SSH_PROTO_1;	}	if ((options.protocol & SSH_PROTO_2) && !sensitive_data.have_ssh2_key) {		log("Disabling protocol version 2. Could not load host key");		options.protocol &= ~SSH_PROTO_2;	}	if (!(options.protocol & (SSH_PROTO_1|SSH_PROTO_2))) {		log("sshd: no hostkeys available -- exiting.");		exit(1);	}	/* Check certain values for sanity. */	if (options.protocol & SSH_PROTO_1) {		if (options.server_key_bits < 512 ||		    options.server_key_bits > 32768) {			fprintf(stderr, "Bad server key size.\n");			exit(1);		}		/*		 * 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.ssh1_host_key->rsa->n) -		    SSH_KEY_BITS_RESERVED && options.server_key_bits <		    BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) +		    SSH_KEY_BITS_RESERVED) {			options.server_key_bits =			    BN_num_bits(sensitive_data.ssh1_host_key->rsa->n) +			    SSH_KEY_BITS_RESERVED;			debug("Forcing server key to %d bits to make it differ from host key.",			    options.server_key_bits);		}	}	if (use_privsep) {		struct passwd *pw;		struct stat st;		if ((pw = getpwnam(SSH_PRIVSEP_USER)) == NULL)			fatal("Privilege separation user %s does not exist",			    SSH_PRIVSEP_USER);		if ((stat(_PATH_PRIVSEP_CHROOT_DIR, &st) == -1) ||		    (S_ISDIR(st.st_mode) == 0))			fatal("Missing privilege separation directory: %s",			    _PATH_PRIVSEP_CHROOT_DIR);		if (st.st_uid != 0 || (st.st_mode & (S_IWGRP|S_IWOTH)) != 0)			fatal("Bad owner or mode for %s",			    _PATH_PRIVSEP_CHROOT_DIR);	}	/* Configuration looks good, so exit if in test mode. */	if (test_flag)		exit(0);	/* Initialize the log (it is reinitialized below in case we forked). */	if (debug_flag && !inetd_flag)		log_stderr = 1;	log_init(__progname, 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 || no_daemon_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(_PATH_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(__progname, options.log_level, options.log_facility, log_stderr);	/* Initialize the random number generator. */	arc4random_stir();	/* Chdir to the root directory so that the current disk can be	   unmounted if desired. */	chdir("/");	/* ignore SIGPIPE */	signal(SIGPIPE, SIG_IGN);	/* Start listening for a socket, unless started from inetd. */	if (inetd_flag) {		int s1;		s1 = dup(0);	/* Make sure descriptors 0, 1, and 2 are in use. */		dup(s1);		sock_in = dup(0);		sock_out = dup(1);		startup_pipe = -1;		/*		 * 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);		if (options.protocol & SSH_PROTO_1)			generate_ephemeral_server_key();	} 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.			 * Allow local port reuse in TIME_WAIT.			 */			if (setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR,			    &on, sizeof(on)) == -1)				error("setsockopt SO_REUSEADDR: %s", strerror(errno));			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 (options.protocol & SSH_PROTO_1)			generate_ephemeral_server_key();		/*		 * 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);		/* Write out the pid file after the sigterm handler is setup */		if (!debug_flag) {			/*			 * Record our pid in /var/run/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(options.pid_file, "w");			if (f) {				fprintf(f, "%ld\n", (long) getpid());				fclose(f);			}		}		/* setup fd set for listen */		fdset = NULL;		maxfd = 0;		for (i = 0; i < num_listen_socks; i++)			if (listen_socks[i] > maxfd)				maxfd = listen_socks[i];		/* pipes connected to unauthenticated childs */		startup_pipes = xmalloc(options.max_startups * sizeof(int));		for (i = 0; i < options.max_startups; i++)			startup_pipes[i] = -1;		/*		 * Stay listening for connections until the system crashes or		 * the daemon is killed with a signal.		 */		for (;;) {			if (received_sighup)				sighup_restart();			if (fdset != NULL)				xfree(fdset);			fdsetsz = howmany(maxfd+1, NFDBITS) * sizeof(fd_mask);			fdset = (fd_set *)xmalloc(fdsetsz);			memset(fdset, 0, fdsetsz);			for (i = 0; i < num_listen_socks; i++)				FD_SET(listen_socks[i], fdset);			for (i = 0; i < options.max_startups; i++)				if (startup_pipes[i] != -1)					FD_SET(startup_pipes[i], fdset);			/* Wait in select until there is a connection. */			ret = select(maxfd+1, fdset, NULL, NULL, NULL);			if (ret < 0 && errno != EINTR)				error("select: %.100s", strerror(errno));			if (received_sigterm) {				log("Received signal %d; terminating.",				    (int) received_sigterm);				close_listen_socks();				unlink(options.pid_file);				exit(255);			}			if (key_used && key_do_regen) {				generate_ephemeral_server_key();				key_used = 0;				key_do_regen = 0;			}			if (ret < 0)				continue;			for (i = 0; i < options.max_startups; i++)				if (startup_pipes[i] != -1 &&				    FD_ISSET(startup_pipes[i], fdset)) {					/*					 * the read end of the pipe is ready					 * if the child has closed the pipe					 * after successful authentication					 * or if the child has died					 */					close(startup_pipes[i]);					startup_pipes[i] = -1;					startups--;				}			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));					close(newsock);					continue;				}				if (drop_connection(startups) == 1) {					debug("drop connection #%d", startups);					close(newsock);					continue;				}				if (pipe(startup_p) == -1) {					close(newsock);					continue;				}				for (j = 0; j < options.max_startups; j++)					if (startup_pipes[j] == -1) {						startup_pipes[j] = startup_p[0];						if (maxfd < startup_p[0])							maxfd = startup_p[0];						startups++;						break;					}				/*				 * 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;					startup_pipe = -1;					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 and max_startup						 * sockets.  Start using the accepted socket.						 * Reinitialize logging (since our pid has						 * changed).  We break out of the loop to handle						 * the connection.						 */						startup_pipe = startup_p[1];						close_startup_pipes();						close_listen_socks();						sock_in = newsock;						sock_out = newsock;						log_init(__progname, 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 %ld.", (long)pid);				close(startup_p[1]);				/* Mark that the key has been used (it was "given" to the child). */				if ((options.protocol & SSH_PROTO_1) &&				    key_used == 0) {					/* Schedule server key regeneration alarm. */					signal(SIGALRM, key_regeneration_alarm);					alarm(options.key_regeneration_time);					key_used = 1;				}				arc4random_stir();				/* Close the new socket (the child is now taking care of it). */				close(newsock);			}			/* child process check (or debug mode) */			if (num_listen_socks < 0)				break;		}	}	/* This is the child processing a new connection. */	/*	 * Create a new session and process group since the 4.4BSD	 * setlogin() affects the entire process group.  We don't	 * want the child to be able to affect the parent.	 */	if (!debug_flag && !inetd_flag && setsid() < 0)		error("setsid: %.100s", strerror(errno));	/*	 * Disable the key regeneration alarm.  We will not regenerate the	 * key since we are no longer in a position to give it to anyone. We	 * will not restart on SIGHUP since it no longer makes sense.	 */	alarm(0);	signal(SIGALRM, SIG_DFL);	signal(SIGHUP, SIG_DFL);	signal(SIGTERM, SIG_DFL);	signal(SIGQUIT, SIG_DFL);	signal(SIGCHLD, SIG_DFL);	/* Set keepalives if requested. */	if (options.keepalives &&	    setsockopt(sock_in, SOL_SOCKET, SO_KEEPALIVE, &on,	    sizeof(on)) < 0)		error("setsockopt SO_KEEPALIVE: %.100s", strerror(errno));	/*	 * 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();#ifdef LIBWRAP	/* Check whether logins are denied from this host. */	{		struct request_info req;		request_init(&req, RQ_DAEMON, __progname, RQ_FILE, sock_in, 0);		fromhost(&req);		if (!hosts_access(&req)) {			debug("Connection refused by tcp wrapper");			refuse(&req);			/* NOTREACHED */			fatal("libwrap refuse returns");		}	}#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-Authentication only makes sense from privileged	 * 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 (options.rhosts_authentication &&	    (remote_port >= IPPORT_RESERVED ||	    remote_port < IPPORT_RESERVED / 2)) {		debug("Rhosts Authentication disabled, "		    "originating port %d not trusted.", remote_port);		options.rhosts_authentication = 0;	}#if defined(KRB4) && !defined(KRB5)	if (!packet_connection_is_ipv4() &&	    options.kerberos_authentication) {		debug("Kerberos Authentication disabled, only available for IPv4.");		options.kerberos_authentication = 0;	}#endif /* KRB4 && !KRB5 */#ifdef AFS	/* If machine has AFS, set process authentication group. */	if (k_hasafs()) {		k_setpag();		k_unlog();	}#endif /* AFS */	packet_set_nonblocking();	if (use_privsep)		if ((authctxt = privsep_preauth()) != NULL)			goto authenticated;	/* perform the key exchange */	/* authenticate user and start session */	if (compat20) {		do_ssh2_kex();		authctxt = do_authentication2();	} else {		do_ssh1_kex();		authctxt = do_authentication();	}	/*	 * If we use privilege separation, the unprivileged child transfers	 * the current keystate and exits	 */	if (use_privsep) {		mm_send_keystate(pmonitor);		exit(0);	} authenticated:	/*	 * In privilege separation, we fork another child and prepare	 * file descriptor passing.	 */	if (use_privsep) {		privsep_postauth(authctxt);		/* the monitor process [priv] will not return */		if (!compat20)			destroy_sensitive_data();	}	/* Perform session preparation. */	do_authenticated(authctxt);	/* The connection has been terminated. */	verbose("Closing connection to %.100s", remote_ip);	packet_close();	if (use_privsep)		mm_terminate();	exit(0);}