⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sshd.c

📁 C++编写
💻 C
📖 第 1 页 / 共 4 页
字号:
			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("%s must be owned by root and not group or "			    "world-writable.", _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)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -