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

📄 session.c

📁 OpenSSL Source code for SFTP, SSH, and many others
💻 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.138 2002/06/20 23:05:55 markus Exp $");#include "ssh.h"#include "ssh1.h"#include "ssh2.h"#include "xmalloc.h"#include "sshpty.h"#include "packet.h"#include "buffer.h"#include "mpaux.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"#ifdef HAVE_CYGWIN#include <windows.h>#include <sys/cygwin.h>#define is_winnt       (GetVersion() < 0x80000000)#endif/* func */Session *session_new(void);void	session_set_fds(Session *, int, int, int);void	session_pty_cleanup(void *);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);/* original command from peer. */const char *original_command = NULL;/* data */#define MAX_SESSIONS 10Session	sessions[MAX_SESSIONS];#ifdef WITH_AIXAUTHENTICATEchar *aixloginmsg;#endif /* WITH_AIXAUTHENTICATE */#ifdef HAVE_LOGIN_CAPlogin_cap_t *lc;#endif/* 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(void *_pw){	struct passwd *pw = _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-XXXXXXXX", 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());	/* delete agent socket on fatal() */	fatal_add_cleanup(auth_sock_cleanup_proc, pw);	/* 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, 5) < 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, xstrdup("auth socket"), 1);	strlcpy(nc->path, auth_sock_name, sizeof(nc->path));	return 1;}voiddo_authenticated(Authctxt *authctxt){	/*	 * Cancel the alarm we set to limit the time taken for	 * authentication.	 */	alarm(0);	if (startup_pipe != -1) {		close(startup_pipe);		startup_pipe = -1;	}#ifdef WITH_AIXAUTHENTICATE	/* We don't have a pty yet, so just label the line as "ssh" */	if (loginsuccess(authctxt->user,	    get_canonical_hostname(options.verify_reverse_mapping),	    "ssh", &aixloginmsg) < 0)		aixloginmsg = NULL;#endif /* WITH_AIXAUTHENTICATE */	/* 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);	/* remove agent socket */	if (auth_sock_name != NULL)		auth_sock_cleanup_proc(authctxt->pw);#ifdef KRB4	if (options.kerberos_ticket_cleanup)		krb4_cleanup_proc(authctxt);#endif#ifdef KRB5	if (options.kerberos_ticket_cleanup)		krb5_cleanup_proc(authctxt);#endif}/* * 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 compression_level = 0, enable_compression_after_reply = 0;	u_int proto_len, data_len, dlen;	s = session_new();	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 illegal 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;#if defined(AFS) || defined(KRB5)		case SSH_CMSG_HAVE_KERBEROS_TGT:			if (!options.kerberos_tgt_passing) {				verbose("Kerberos TGT passing disabled.");			} else {				char *kdata = packet_get_string(&dlen);				packet_check_eom();				/* XXX - 0x41, see creds_to_radix version */				if (kdata[0] != 0x41) {#ifdef KRB5					krb5_data tgt;					tgt.data = kdata;					tgt.length = dlen;					if (auth_krb5_tgt(s->authctxt, &tgt))						success = 1;					else						verbose("Kerberos v5 TGT refused for %.100s", s->authctxt->user);#endif /* KRB5 */				} else {#ifdef AFS					if (auth_krb4_tgt(s->authctxt, kdata))						success = 1;					else						verbose("Kerberos v4 TGT refused for %.100s", s->authctxt->user);#endif /* AFS */				}				xfree(kdata);			}			break;#endif /* AFS || KRB5 */#ifdef AFS		case SSH_CMSG_HAVE_AFS_TOKEN:			if (!options.afs_token_passing || !k_hasafs()) {				verbose("AFS token passing disabled.");			} else {				/* Accept AFS token. */				char *token = packet_get_string(&dlen);				packet_check_eom();				if (auth_afs_token(s->authctxt, token))					success = 1;				else					verbose("AFS token refused for %.100s",					    s->authctxt->user);				xfree(token);			}			break;#endif /* AFS */		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.			 */			log("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)	do_pam_session(s->pw->pw_name, NULL);	do_pam_setcred(1);	if (is_pam_password_change_required())		packet_disconnect("Password change required but no "		    "TTY available");#endif /* USE_PAM */	/* Fork the child. */	if ((pid = fork()) == 0) {		/* 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)

⌨️ 快捷键说明

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