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

📄 session.c

📁 OpenSSH 是 SSH (Secure SHell) 协议的免费开源实现。它用安全、加密的网络连接工具代替了 telnet、ftp、 rlogin、rsh 和 rcp 工具。OpenSSH 支持
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland *                    All rights reserved * * As far as I am concerned, the code I have written for this software * can be used freely for any purpose.  Any derived versions of this * software must be clearly marked as such, and if the derived work is * incompatible with the protocol description in the RFC file, it must be * called by a name other than "ssh" or "Secure Shell". * * SSH2 support by Markus Friedl. * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright *    notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright *    notice, this list of conditions and the following disclaimer in the *    documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */#include "includes.h"RCSID("$OpenBSD: session.c,v 1.181 2004/12/23 17:35:48 markus Exp $");#include "ssh.h"#include "ssh1.h"#include "ssh2.h"#include "xmalloc.h"#include "sshpty.h"#include "packet.h"#include "buffer.h"#include "match.h"#include "uidswap.h"#include "compat.h"#include "channels.h"#include "bufaux.h"#include "auth.h"#include "auth-options.h"#include "pathnames.h"#include "log.h"#include "servconf.h"#include "sshlogin.h"#include "serverloop.h"#include "canohost.h"#include "session.h"#include "monitor_wrap.h"#if defined(KRB5) && defined(USE_AFS)#include <kafs.h>#endif#ifdef GSSAPI#include "ssh-gss.h"#endif/* func */Session *session_new(void);void	session_set_fds(Session *, int, int, int);void	session_pty_cleanup(Session *);void	session_proctitle(Session *);int	session_setup_x11fwd(Session *);void	do_exec_pty(Session *, const char *);void	do_exec_no_pty(Session *, const char *);void	do_exec(Session *, const char *);void	do_login(Session *, const char *);#ifdef LOGIN_NEEDS_UTMPXstatic void	do_pre_login(Session *s);#endifvoid	do_child(Session *, const char *);void	do_motd(void);int	check_quietlogin(Session *, const char *);static void do_authenticated1(Authctxt *);static void do_authenticated2(Authctxt *);static int session_pty_req(Session *);/* import */extern ServerOptions options;extern char *__progname;extern int log_stderr;extern int debug_flag;extern u_int utmp_len;extern int startup_pipe;extern void destroy_sensitive_data(void);extern Buffer loginmsg;/* original command from peer. */const char *original_command = NULL;/* data */#define MAX_SESSIONS 10Session	sessions[MAX_SESSIONS];#ifdef HAVE_LOGIN_CAPlogin_cap_t *lc;#endifstatic int is_child = 0;/* Name and directory of socket for authentication agent forwarding. */static char *auth_sock_name = NULL;static char *auth_sock_dir = NULL;/* removes the agent forwarding socket */static voidauth_sock_cleanup_proc(struct passwd *pw){	if (auth_sock_name != NULL) {		temporarily_use_uid(pw);		unlink(auth_sock_name);		rmdir(auth_sock_dir);		auth_sock_name = NULL;		restore_uid();	}}static intauth_input_request_forwarding(struct passwd * pw){	Channel *nc;	int sock;	struct sockaddr_un sunaddr;	if (auth_sock_name != NULL) {		error("authentication forwarding requested twice.");		return 0;	}	/* Temporarily drop privileged uid for mkdir/bind. */	temporarily_use_uid(pw);	/* Allocate a buffer for the socket name, and format the name. */	auth_sock_name = xmalloc(MAXPATHLEN);	auth_sock_dir = xmalloc(MAXPATHLEN);	strlcpy(auth_sock_dir, "/tmp/ssh-XXXXXXXXXX", MAXPATHLEN);	/* Create private directory for socket */	if (mkdtemp(auth_sock_dir) == NULL) {		packet_send_debug("Agent forwarding disabled: "		    "mkdtemp() failed: %.100s", strerror(errno));		restore_uid();		xfree(auth_sock_name);		xfree(auth_sock_dir);		auth_sock_name = NULL;		auth_sock_dir = NULL;		return 0;	}	snprintf(auth_sock_name, MAXPATHLEN, "%s/agent.%ld",		 auth_sock_dir, (long) getpid());	/* Create the socket. */	sock = socket(AF_UNIX, SOCK_STREAM, 0);	if (sock < 0)		packet_disconnect("socket: %.100s", strerror(errno));	/* Bind it to the name. */	memset(&sunaddr, 0, sizeof(sunaddr));	sunaddr.sun_family = AF_UNIX;	strlcpy(sunaddr.sun_path, auth_sock_name, sizeof(sunaddr.sun_path));	if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0)		packet_disconnect("bind: %.100s", strerror(errno));	/* Restore the privileged uid. */	restore_uid();	/* Start listening on the socket. */	if (listen(sock, SSH_LISTEN_BACKLOG) < 0)		packet_disconnect("listen: %.100s", strerror(errno));	/* Allocate a channel for the authentication agent socket. */	nc = channel_new("auth socket",	    SSH_CHANNEL_AUTH_SOCKET, sock, sock, -1,	    CHAN_X11_WINDOW_DEFAULT, CHAN_X11_PACKET_DEFAULT,	    0, "auth socket", 1);	strlcpy(nc->path, auth_sock_name, sizeof(nc->path));	return 1;}static voiddisplay_loginmsg(void){        if (buffer_len(&loginmsg) > 0) {                buffer_append(&loginmsg, "\0", 1);                printf("%s", (char *)buffer_ptr(&loginmsg));                buffer_clear(&loginmsg);        }}voiddo_authenticated(Authctxt *authctxt){	setproctitle("%s", authctxt->pw->pw_name);	/*	 * Cancel the alarm we set to limit the time taken for	 * authentication.	 */	alarm(0);	if (startup_pipe != -1) {		close(startup_pipe);		startup_pipe = -1;	}	/* setup the channel layer */	if (!no_port_forwarding_flag && options.allow_tcp_forwarding)		channel_permit_all_opens();	if (compat20)		do_authenticated2(authctxt);	else		do_authenticated1(authctxt);	do_cleanup(authctxt);}/* * Prepares for an interactive session.  This is called after the user has * been successfully authenticated.  During this message exchange, pseudo * terminals are allocated, X11, TCP/IP, and authentication agent forwardings * are requested, etc. */static voiddo_authenticated1(Authctxt *authctxt){	Session *s;	char *command;	int success, type, screen_flag;	int enable_compression_after_reply = 0;	u_int proto_len, data_len, dlen, compression_level = 0;	s = session_new();	if (s == NULL) {		error("no more sessions");		return;	}	s->authctxt = authctxt;	s->pw = authctxt->pw;	/*	 * We stay in this loop until the client requests to execute a shell	 * or a command.	 */	for (;;) {		success = 0;		/* Get a packet from the client. */		type = packet_read();		/* Process the packet. */		switch (type) {		case SSH_CMSG_REQUEST_COMPRESSION:			compression_level = packet_get_int();			packet_check_eom();			if (compression_level < 1 || compression_level > 9) {				packet_send_debug("Received invalid compression level %d.",				    compression_level);				break;			}			if (!options.compression) {				debug2("compression disabled");				break;			}			/* Enable compression after we have responded with SUCCESS. */			enable_compression_after_reply = 1;			success = 1;			break;		case SSH_CMSG_REQUEST_PTY:			success = session_pty_req(s);			break;		case SSH_CMSG_X11_REQUEST_FORWARDING:			s->auth_proto = packet_get_string(&proto_len);			s->auth_data = packet_get_string(&data_len);			screen_flag = packet_get_protocol_flags() &			    SSH_PROTOFLAG_SCREEN_NUMBER;			debug2("SSH_PROTOFLAG_SCREEN_NUMBER: %d", screen_flag);			if (packet_remaining() == 4) {				if (!screen_flag)					debug2("Buggy client: "					    "X11 screen flag missing");				s->screen = packet_get_int();			} else {				s->screen = 0;			}			packet_check_eom();			success = session_setup_x11fwd(s);			if (!success) {				xfree(s->auth_proto);				xfree(s->auth_data);				s->auth_proto = NULL;				s->auth_data = NULL;			}			break;		case SSH_CMSG_AGENT_REQUEST_FORWARDING:			if (no_agent_forwarding_flag || compat13) {				debug("Authentication agent forwarding not permitted for this authentication.");				break;			}			debug("Received authentication agent forwarding request.");			success = auth_input_request_forwarding(s->pw);			break;		case SSH_CMSG_PORT_FORWARD_REQUEST:			if (no_port_forwarding_flag) {				debug("Port forwarding not permitted for this authentication.");				break;			}			if (!options.allow_tcp_forwarding) {				debug("Port forwarding not permitted.");				break;			}			debug("Received TCP/IP port forwarding request.");			channel_input_port_forward_request(s->pw->pw_uid == 0, options.gateway_ports);			success = 1;			break;		case SSH_CMSG_MAX_PACKET_SIZE:			if (packet_set_maxsize(packet_get_int()) > 0)				success = 1;			break;		case SSH_CMSG_EXEC_SHELL:		case SSH_CMSG_EXEC_CMD:			if (type == SSH_CMSG_EXEC_CMD) {				command = packet_get_string(&dlen);				debug("Exec command '%.500s'", command);				do_exec(s, command);				xfree(command);			} else {				do_exec(s, NULL);			}			packet_check_eom();			session_close(s);			return;		default:			/*			 * Any unknown messages in this phase are ignored,			 * and a failure message is returned.			 */			logit("Unknown packet type received after authentication: %d", type);		}		packet_start(success ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);		packet_send();		packet_write_wait();		/* Enable compression now that we have replied if appropriate. */		if (enable_compression_after_reply) {			enable_compression_after_reply = 0;			packet_start_compression(compression_level);		}	}}/* * This is called to fork and execute a command when we have no tty.  This * will call do_child from the child, and server_loop from the parent after * setting up file descriptors and such. */voiddo_exec_no_pty(Session *s, const char *command){	pid_t pid;#ifdef USE_PIPES	int pin[2], pout[2], perr[2];	/* Allocate pipes for communicating with the program. */	if (pipe(pin) < 0 || pipe(pout) < 0 || pipe(perr) < 0)		packet_disconnect("Could not create pipes: %.100s",				  strerror(errno));#else /* USE_PIPES */	int inout[2], err[2];	/* Uses socket pairs to communicate with the program. */	if (socketpair(AF_UNIX, SOCK_STREAM, 0, inout) < 0 ||	    socketpair(AF_UNIX, SOCK_STREAM, 0, err) < 0)		packet_disconnect("Could not create socket pairs: %.100s",				  strerror(errno));#endif /* USE_PIPES */	if (s == NULL)		fatal("do_exec_no_pty: no session");	session_proctitle(s);#if defined(USE_PAM)	if (options.use_pam && !use_privsep)		do_pam_setcred(1);#endif /* USE_PAM */	/* Fork the child. */	if ((pid = fork()) == 0) {		is_child = 1;		/* Child.  Reinitialize the log since the pid has changed. */		log_init(__progname, options.log_level, options.log_facility, log_stderr);		/*		 * Create a new session and process group since the 4.4BSD		 * setlogin() affects the entire process group.		 */		if (setsid() < 0)			error("setsid failed: %.100s", strerror(errno));#ifdef USE_PIPES		/*		 * Redirect stdin.  We close the parent side of the socket		 * pair, and make the child side the standard input.		 */		close(pin[1]);		if (dup2(pin[0], 0) < 0)			perror("dup2 stdin");		close(pin[0]);		/* Redirect stdout. */		close(pout[0]);		if (dup2(pout[1], 1) < 0)			perror("dup2 stdout");		close(pout[1]);		/* Redirect stderr. */		close(perr[0]);		if (dup2(perr[1], 2) < 0)			perror("dup2 stderr");		close(perr[1]);#else /* USE_PIPES */		/*		 * Redirect stdin, stdout, and stderr.  Stdin and stdout will		 * use the same socket, as some programs (particularly rdist)		 * seem to depend on it.		 */		close(inout[1]);		close(err[1]);		if (dup2(inout[0], 0) < 0)	/* stdin */			perror("dup2 stdin");		if (dup2(inout[0], 1) < 0)	/* stdout.  Note: same socket as stdin. */			perror("dup2 stdout");		if (dup2(err[0], 2) < 0)	/* stderr */			perror("dup2 stderr");#endif /* USE_PIPES */#ifdef _UNICOS		cray_init_job(s->pw); /* set up cray jid and tmpdir */#endif		/* Do processing for the child (exec command etc). */		do_child(s, command);		/* NOTREACHED */	}#ifdef _UNICOS	signal(WJSIGNAL, cray_job_termination_handler);#endif /* _UNICOS */#ifdef HAVE_CYGWIN	if (is_winnt)		cygwin_set_impersonation_token(INVALID_HANDLE_VALUE);#endif	if (pid < 0)		packet_disconnect("fork failed: %.100s", strerror(errno));	s->pid = pid;	/* Set interactive/non-interactive mode. */	packet_set_interactive(s->display != NULL);#ifdef USE_PIPES	/* We are the parent.  Close the child sides of the pipes. */	close(pin[0]);	close(pout[1]);	close(perr[1]);	if (compat20) {		if (s->is_subsystem) {			close(perr[0]);			perr[0] = -1;		}		session_set_fds(s, pin[1], pout[0], perr[0]);	} else {		/* Enter the interactive session. */		server_loop(pid, pin[1], pout[0], perr[0]);		/* server_loop has closed pin[1], pout[0], and perr[0]. */	}#else /* USE_PIPES */	/* We are the parent.  Close the child sides of the socket pairs. */	close(inout[0]);	close(err[0]);	/*	 * Clear loginmsg, since it's the child's responsibility to display	 * it to the user, otherwise multiple sessions may accumulate	 * multiple copies of the login messages.	 */	buffer_clear(&loginmsg);	/*	 * Enter the interactive session.  Note: server_loop must be able to	 * handle the case that fdin and fdout are the same.	 */	if (compat20) {		session_set_fds(s, inout[1], inout[1], s->is_subsystem ? -1 : err[1]);	} else {		server_loop(pid, inout[1], inout[1], err[1]);		/* server_loop has closed inout[1] and err[1]. */	}#endif /* USE_PIPES */}/* * This is called to fork and execute a command when we have a tty.  This * will call do_child from the child, and server_loop from the parent after * setting up file descriptors, controlling tty, updating wtmp, utmp, * lastlog, and other such operations. */voiddo_exec_pty(Session *s, const char *command){	int fdout, ptyfd, ttyfd, ptymaster;	pid_t pid;	if (s == NULL)		fatal("do_exec_pty: no session");	ptyfd = s->ptyfd;	ttyfd = s->ttyfd;#if defined(USE_PAM)	if (options.use_pam) {		do_pam_set_tty(s->tty);		if (!use_privsep)			do_pam_setcred(1);	}#endif	/* Fork the child. */	if ((pid = fork()) == 0) {		is_child = 1;		/* Child.  Reinitialize the log because the pid has changed. */		log_init(__progname, options.log_level, options.log_facility, log_stderr);		/* Close the master side of the pseudo tty. */		close(ptyfd);		/* Make the pseudo tty our controlling tty. */		pty_make_controlling_tty(&ttyfd, s->tty);		/* Redirect stdin/stdout/stderr from the pseudo tty. */		if (dup2(ttyfd, 0) < 0)			error("dup2 stdin: %s", strerror(errno));		if (dup2(ttyfd, 1) < 0)			error("dup2 stdout: %s", strerror(errno));		if (dup2(ttyfd, 2) < 0)			error("dup2 stderr: %s", strerror(errno));		/* Close the extra descriptor for the pseudo tty. */		close(ttyfd);		/* record login, etc. similar to login(1) */#ifndef HAVE_OSF_SIA		if (!(options.use_login && command == NULL)) {#ifdef _UNICOS			cray_init_job(s->pw); /* set up cray jid and tmpdir */#endif /* _UNICOS */			do_login(s, command);		}# ifdef LOGIN_NEEDS_UTMPX		else			do_pre_login(s);# endif#endif		/* Do common processing for the child, such as execing the command. */		do_child(s, command);		/* NOTREACHED */	}#ifdef _UNICOS	signal(WJSIGNAL, cray_job_termination_handler);#endif /* _UNICOS */

⌨️ 快捷键说明

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