ssh.c

来自「OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它」· C语言 代码 · 共 1,431 行 · 第 1/3 页

C
1,431
字号
		/* Send the packet, and wait for it to leave. */		packet_send();		packet_write_wait();		/* Read response from the server. */		type = packet_read();		if (type == SSH_SMSG_SUCCESS) {			interactive = 1;			have_tty = 1;		} else if (type == SSH_SMSG_FAILURE)			logit("Warning: Remote host failed or refused to allocate a pseudo tty.");		else			packet_disconnect("Protocol error waiting for pty request response.");	}	/* Request X11 forwarding if enabled and DISPLAY is set. */	if (options.forward_x11 && getenv("DISPLAY") != NULL) {		char *proto, *data;		/* Get reasonable local authentication information. */		x11_get_proto(&proto, &data);		/* Request forwarding with authentication spoofing. */		debug("Requesting X11 forwarding with authentication spoofing.");		x11_request_forwarding_with_spoofing(0, proto, data);		/* Read response from the server. */		type = packet_read();		if (type == SSH_SMSG_SUCCESS) {			interactive = 1;		} else if (type == SSH_SMSG_FAILURE) {			logit("Warning: Remote host denied X11 forwarding.");		} else {			packet_disconnect("Protocol error waiting for X11 forwarding");		}	}	/* Tell the packet module whether this is an interactive session. */	packet_set_interactive(interactive);	/* Request authentication agent forwarding if appropriate. */	check_agent_present();	if (options.forward_agent) {		debug("Requesting authentication agent forwarding.");		auth_request_forwarding();		/* Read response from the server. */		type = packet_read();		packet_check_eom();		if (type != SSH_SMSG_SUCCESS)			logit("Warning: Remote host denied authentication agent forwarding.");	}	/* Initiate port forwardings. */	ssh_init_forwarding();	/* If requested, let ssh continue in the background. */	if (fork_after_authentication_flag)		if (daemon(1, 1) < 0)			fatal("daemon() failed: %.200s", strerror(errno));	/*	 * If a command was specified on the command line, execute the	 * command now. Otherwise request the server to start a shell.	 */	if (buffer_len(&command) > 0) {		int len = buffer_len(&command);		if (len > 900)			len = 900;		debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command));		packet_start(SSH_CMSG_EXEC_CMD);		packet_put_string(buffer_ptr(&command), buffer_len(&command));		packet_send();		packet_write_wait();	} else {		debug("Requesting shell.");		packet_start(SSH_CMSG_EXEC_SHELL);		packet_send();		packet_write_wait();	}	/* Enter the interactive session. */	return client_loop(have_tty, tty_flag ?	    options.escape_char : SSH_ESCAPECHAR_NONE, 0);}static voidssh_subsystem_reply(int type, u_int32_t seq, void *ctxt){	int id, len;	id = packet_get_int();	len = buffer_len(&command);	if (len > 900)		len = 900;	packet_check_eom();	if (type == SSH2_MSG_CHANNEL_FAILURE)		fatal("Request for subsystem '%.*s' failed on channel %d",		    len, (u_char *)buffer_ptr(&command), id);}voidclient_global_request_reply_fwd(int type, u_int32_t seq, void *ctxt){	int i;	i = client_global_request_id++;	if (i >= options.num_remote_forwards)		return;	debug("remote forward %s for: listen %d, connect %s:%d",	    type == SSH2_MSG_REQUEST_SUCCESS ? "success" : "failure",	    options.remote_forwards[i].listen_port,	    options.remote_forwards[i].connect_host,	    options.remote_forwards[i].connect_port);	if (type == SSH2_MSG_REQUEST_FAILURE)		logit("Warning: remote port forwarding failed for listen "		    "port %d", options.remote_forwards[i].listen_port);}static voidssh_control_listener(void){	struct sockaddr_un addr;	mode_t old_umask;	int addr_len;	if (options.control_path == NULL || options.control_master <= 0)		return;	memset(&addr, '\0', sizeof(addr));	addr.sun_family = AF_UNIX;	addr_len = offsetof(struct sockaddr_un, sun_path) +	    strlen(options.control_path) + 1;	if (strlcpy(addr.sun_path, options.control_path,	    sizeof(addr.sun_path)) >= sizeof(addr.sun_path))		fatal("ControlPath too long");	if ((control_fd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)		fatal("%s socket(): %s\n", __func__, strerror(errno));	old_umask = umask(0177);	if (bind(control_fd, (struct sockaddr*)&addr, addr_len) == -1) {		control_fd = -1;		if (errno == EINVAL)			fatal("ControlSocket %s already exists",			    options.control_path);		else			fatal("%s bind(): %s\n", __func__, strerror(errno));	}	umask(old_umask);	if (listen(control_fd, 64) == -1)		fatal("%s listen(): %s\n", __func__, strerror(errno));	set_nonblock(control_fd);}/* request pty/x11/agent/tcpfwd/shell for channel */static voidssh_session2_setup(int id, void *arg){	extern char **environ;	int interactive = tty_flag;	if (options.forward_x11 && getenv("DISPLAY") != NULL) {		char *proto, *data;		/* Get reasonable local authentication information. */		x11_get_proto(&proto, &data);		/* Request forwarding with authentication spoofing. */		debug("Requesting X11 forwarding with authentication spoofing.");		x11_request_forwarding_with_spoofing(id, proto, data);		interactive = 1;		/* XXX wait for reply */	}	check_agent_present();	if (options.forward_agent) {		debug("Requesting authentication agent forwarding.");		channel_request_start(id, "auth-agent-req@openssh.com", 0);		packet_send();	}	client_session2_setup(id, tty_flag, subsystem_flag, getenv("TERM"),	    NULL, fileno(stdin), &command, environ, &ssh_subsystem_reply);	packet_set_interactive(interactive);}/* open new channel for a session */static intssh_session2_open(void){	Channel *c;	int window, packetmax, in, out, err;	if (stdin_null_flag) {		in = open(_PATH_DEVNULL, O_RDONLY);	} else {		in = dup(STDIN_FILENO);	}	out = dup(STDOUT_FILENO);	err = dup(STDERR_FILENO);	if (in < 0 || out < 0 || err < 0)		fatal("dup() in/out/err failed");	/* enable nonblocking unless tty */	if (!isatty(in))		set_nonblock(in);	if (!isatty(out))		set_nonblock(out);	if (!isatty(err))		set_nonblock(err);	window = CHAN_SES_WINDOW_DEFAULT;	packetmax = CHAN_SES_PACKET_DEFAULT;	if (tty_flag) {		window >>= 1;		packetmax >>= 1;	}	c = channel_new(	    "session", SSH_CHANNEL_OPENING, in, out, err,	    window, packetmax, CHAN_EXTENDED_WRITE,	    "client-session", /*nonblock*/0);	debug3("ssh_session2_open: channel_new: %d", c->self);	channel_send_open(c->self);	if (!no_shell_flag)		channel_register_confirm(c->self, ssh_session2_setup, NULL);	return c->self;}static intssh_session2(void){	int id = -1;	/* XXX should be pre-session */	ssh_init_forwarding();	ssh_control_listener();	if (!no_shell_flag || (datafellows & SSH_BUG_DUMMYCHAN))		id = ssh_session2_open();	/* If requested, let ssh continue in the background. */	if (fork_after_authentication_flag)		if (daemon(1, 1) < 0)			fatal("daemon() failed: %.200s", strerror(errno));	return client_loop(tty_flag, tty_flag ?	    options.escape_char : SSH_ESCAPECHAR_NONE, id);}static voidload_public_identity_files(void){	char *filename;	int i = 0;	Key *public;#ifdef SMARTCARD	Key **keys;	if (options.smartcard_device != NULL &&	    options.num_identity_files < SSH_MAX_IDENTITY_FILES &&	    (keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) {		int count = 0;		for (i = 0; keys[i] != NULL; i++) {			count++;			memmove(&options.identity_files[1], &options.identity_files[0],			    sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1));			memmove(&options.identity_keys[1], &options.identity_keys[0],			    sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1));			options.num_identity_files++;			options.identity_keys[0] = keys[i];			options.identity_files[0] = sc_get_key_label(keys[i]);		}		if (options.num_identity_files > SSH_MAX_IDENTITY_FILES)			options.num_identity_files = SSH_MAX_IDENTITY_FILES;		i = count;		xfree(keys);	}#endif /* SMARTCARD */	for (; i < options.num_identity_files; i++) {		filename = tilde_expand_filename(options.identity_files[i],		    original_real_uid);		public = key_load_public(filename, NULL);		debug("identity file %s type %d", filename,		    public ? public->type : -1);		xfree(options.identity_files[i]);		options.identity_files[i] = filename;		options.identity_keys[i] = public;	}}static voidcontrol_client_sighandler(int signo){	control_client_terminate = signo;}static voidcontrol_client_sigrelay(int signo){	if (control_server_pid > 1)		kill(control_server_pid, signo);}static intenv_permitted(char *env){	int i;	char name[1024], *cp;	strlcpy(name, env, sizeof(name));	if ((cp = strchr(name, '=')) == NULL)		return (0);	*cp = '\0';	for (i = 0; i < options.num_send_env; i++)		if (match_pattern(name, options.send_env[i]))			return (1);	return (0);}static voidcontrol_client(const char *path){	struct sockaddr_un addr;	int i, r, fd, sock, exitval, num_env, addr_len;	Buffer m;	char *term;	extern char **environ;	u_int  flags;	if (stdin_null_flag) {		if ((fd = open(_PATH_DEVNULL, O_RDONLY)) == -1)			fatal("open(/dev/null): %s", strerror(errno));		if (dup2(fd, STDIN_FILENO) == -1)			fatal("dup2: %s", strerror(errno));		if (fd > STDERR_FILENO)			close(fd);	}	memset(&addr, '\0', sizeof(addr));	addr.sun_family = AF_UNIX;	addr_len = offsetof(struct sockaddr_un, sun_path) +	    strlen(path) + 1;	if (strlcpy(addr.sun_path, path,	    sizeof(addr.sun_path)) >= sizeof(addr.sun_path))		fatal("ControlPath too long");	if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0)		fatal("%s socket(): %s", __func__, strerror(errno));	if (connect(sock, (struct sockaddr*)&addr, addr_len) == -1)		fatal("Couldn't connect to %s: %s", path, strerror(errno));	if ((term = getenv("TERM")) == NULL)		term = "";	flags = 0;	if (tty_flag)		flags |= SSHMUX_FLAG_TTY;	if (subsystem_flag)		flags |= SSHMUX_FLAG_SUBSYS;	buffer_init(&m);	/* Send our command to server */	buffer_put_int(&m, mux_command);	buffer_put_int(&m, flags);	if (ssh_msg_send(sock, /* version */1, &m) == -1)		fatal("%s: msg_send", __func__);	buffer_clear(&m);	/* Get authorisation status and PID of controlee */	if (ssh_msg_recv(sock, &m) == -1)		fatal("%s: msg_recv", __func__);	if (buffer_get_char(&m) != 1)		fatal("%s: wrong version", __func__);	if (buffer_get_int(&m) != 1)		fatal("Connection to master denied");	control_server_pid = buffer_get_int(&m);	buffer_clear(&m);	switch (mux_command) {	case SSHMUX_COMMAND_ALIVE_CHECK:		fprintf(stderr, "Master running (pid=%d)\r\n", 		    control_server_pid);		exit(0);	case SSHMUX_COMMAND_TERMINATE:		fprintf(stderr, "Exit request sent.\r\n");		exit(0);	case SSHMUX_COMMAND_OPEN:		/* continue below */		break;	default:		fatal("silly mux_command %d", mux_command);	}	/* SSHMUX_COMMAND_OPEN */	buffer_put_cstring(&m, term);	buffer_append(&command, "\0", 1);	buffer_put_cstring(&m, buffer_ptr(&command));	if (options.num_send_env == 0 || environ == NULL) {		buffer_put_int(&m, 0);	} else {		/* Pass environment */		num_env = 0;		for (i = 0; environ[i] != NULL; i++)			if (env_permitted(environ[i]))				num_env++; /* Count */		buffer_put_int(&m, num_env);		for (i = 0; environ[i] != NULL && num_env >= 0; i++)			if (env_permitted(environ[i])) {				num_env--;				buffer_put_cstring(&m, environ[i]);			}	}	if (ssh_msg_send(sock, /* version */1, &m) == -1)		fatal("%s: msg_send", __func__);	mm_send_fd(sock, STDIN_FILENO);	mm_send_fd(sock, STDOUT_FILENO);	mm_send_fd(sock, STDERR_FILENO);	/* Wait for reply, so master has a chance to gather ttymodes */	buffer_clear(&m);	if (ssh_msg_recv(sock, &m) == -1)		fatal("%s: msg_recv", __func__);	if (buffer_get_char(&m) != 1)		fatal("%s: wrong version", __func__);	buffer_free(&m);	signal(SIGHUP, control_client_sighandler);	signal(SIGINT, control_client_sighandler);	signal(SIGTERM, control_client_sighandler);	signal(SIGWINCH, control_client_sigrelay);	if (tty_flag)		enter_raw_mode();	/* Stick around until the controlee closes the client_fd */	exitval = 0;	for (;!control_client_terminate;) {		r = read(sock, &exitval, sizeof(exitval));		if (r == 0) {			debug2("Received EOF from master");			break;		}		if (r > 0)			debug2("Received exit status from master %d", exitval);		if (r == -1 && errno != EINTR)			fatal("%s: read %s", __func__, strerror(errno));	}	if (control_client_terminate)		debug2("Exiting on signal %d", control_client_terminate);	close(sock);	leave_raw_mode();	if (tty_flag && options.log_level != SYSLOG_LEVEL_QUIET)		fprintf(stderr, "Connection to master closed.\r\n");	exit(exitval);}

⌨️ 快捷键说明

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