version 1.282, 2016/03/10 11:47:57 |
version 1.283, 2016/08/13 17:47:41 |
|
|
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "ssh.h" |
#include "ssh.h" |
#include "ssh1.h" |
|
#include "ssh2.h" |
#include "ssh2.h" |
#include "sshpty.h" |
#include "sshpty.h" |
#include "packet.h" |
#include "packet.h" |
|
|
void do_motd(void); |
void do_motd(void); |
int check_quietlogin(Session *, const char *); |
int check_quietlogin(Session *, const char *); |
|
|
static void do_authenticated1(Authctxt *); |
|
static void do_authenticated2(Authctxt *); |
static void do_authenticated2(Authctxt *); |
|
|
static int session_pty_req(Session *); |
static int session_pty_req(Session *); |
|
|
|
|
auth_debug_send(); |
auth_debug_send(); |
|
|
if (compat20) |
do_authenticated2(authctxt); |
do_authenticated2(authctxt); |
|
else |
|
do_authenticated1(authctxt); |
|
|
|
do_cleanup(authctxt); |
do_cleanup(authctxt); |
} |
} |
|
|
|
|
return 1; |
return 1; |
} |
} |
|
|
/* |
|
* 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 void |
|
do_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 == COMP_NONE) { |
|
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(); |
|
if (xauth_valid_string(s->auth_proto) && |
|
xauth_valid_string(s->auth_data)) |
|
success = session_setup_x11fwd(s); |
|
else { |
|
success = 0; |
|
error("Invalid X11 forwarding data"); |
|
} |
|
if (!success) { |
|
free(s->auth_proto); |
|
free(s->auth_data); |
|
s->auth_proto = NULL; |
|
s->auth_data = NULL; |
|
} |
|
break; |
|
|
|
case SSH_CMSG_AGENT_REQUEST_FORWARDING: |
|
if (!options.allow_agent_forwarding || |
|
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 & FORWARD_REMOTE)) { |
|
debug("Port forwarding not permitted."); |
|
break; |
|
} |
|
debug("Received TCP/IP port forwarding request."); |
|
if (channel_input_port_forward_request(s->pw->pw_uid == 0, |
|
&options.fwd_opts) < 0) { |
|
debug("Port forwarding failed."); |
|
break; |
|
} |
|
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); |
|
if (do_exec(s, command) != 0) |
|
packet_disconnect( |
|
"command execution failed"); |
|
free(command); |
|
} else { |
|
if (do_exec(s, NULL) != 0) |
|
packet_disconnect( |
|
"shell execution failed"); |
|
} |
|
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); |
|
} |
|
} |
|
} |
|
|
|
#define USE_PIPES 1 |
#define USE_PIPES 1 |
/* |
/* |
* This is called to fork and execute a command when we have no tty. This |
* This is called to fork and execute a command when we have no tty. This |
|
|
close(pout[1]); |
close(pout[1]); |
close(perr[1]); |
close(perr[1]); |
|
|
if (compat20) { |
session_set_fds(s, pin[1], pout[0], perr[0], |
session_set_fds(s, pin[1], pout[0], perr[0], |
s->is_subsystem, 0); |
s->is_subsystem, 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 |
#else |
/* We are the parent. Close the child sides of the socket pairs. */ |
/* We are the parent. Close the child sides of the socket pairs. */ |
close(inout[0]); |
close(inout[0]); |
|
|
* Enter the interactive session. Note: server_loop must be able to |
* Enter the interactive session. Note: server_loop must be able to |
* handle the case that fdin and fdout are the same. |
* handle the case that fdin and fdout are the same. |
*/ |
*/ |
if (compat20) { |
session_set_fds(s, inout[1], inout[1], err[1], |
session_set_fds(s, inout[1], inout[1], err[1], |
s->is_subsystem, 0); |
s->is_subsystem, 0); |
|
} else { |
|
server_loop(pid, inout[1], inout[1], err[1]); |
|
/* server_loop has closed inout[1] and err[1]. */ |
|
} |
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
|
|
s->ptymaster = ptymaster; |
s->ptymaster = ptymaster; |
packet_set_interactive(1, |
packet_set_interactive(1, |
options.ip_qos_interactive, options.ip_qos_bulk); |
options.ip_qos_interactive, options.ip_qos_bulk); |
if (compat20) { |
session_set_fds(s, ptyfd, fdout, -1, 1, 1); |
session_set_fds(s, ptyfd, fdout, -1, 1, 1); |
|
} else { |
|
server_loop(pid, ptyfd, fdout, -1); |
|
/* server_loop _has_ closed ptyfd and fdout. */ |
|
} |
|
return 0; |
return 0; |
} |
} |
|
|
|
|
} |
} |
|
|
s->term = packet_get_string(&len); |
s->term = packet_get_string(&len); |
|
s->col = packet_get_int(); |
if (compat20) { |
s->row = packet_get_int(); |
s->col = packet_get_int(); |
|
s->row = packet_get_int(); |
|
} else { |
|
s->row = packet_get_int(); |
|
s->col = packet_get_int(); |
|
} |
|
s->xpixel = packet_get_int(); |
s->xpixel = packet_get_int(); |
s->ypixel = packet_get_int(); |
s->ypixel = packet_get_int(); |
|
|
|
|
} |
} |
debug("session_pty_req: session %d alloc %s", s->self, s->tty); |
debug("session_pty_req: session %d alloc %s", s->self, s->tty); |
|
|
/* for SSH1 the tty modes length is not given */ |
n_bytes = packet_remaining(); |
if (!compat20) |
|
n_bytes = packet_remaining(); |
|
tty_parse_modes(s->ttyfd, &n_bytes); |
tty_parse_modes(s->ttyfd, &n_bytes); |
|
|
if (!use_privsep) |
if (!use_privsep) |
|
|
session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, |
session_set_fds(Session *s, int fdin, int fdout, int fderr, int ignore_fderr, |
int is_tty) |
int is_tty) |
{ |
{ |
if (!compat20) |
|
fatal("session_set_fds: called for proto != 2.0"); |
|
/* |
/* |
* now that have a child and a pipe to the child, |
* now that have a child and a pipe to the child, |
* we can activate our channel and register the fd's |
* we can activate our channel and register the fd's |
|
|
#endif |
#endif |
|
|
#ifdef GSSAPI |
#ifdef GSSAPI |
if (compat20 && options.gss_cleanup_creds) |
if (options.gss_cleanup_creds) |
ssh_gssapi_cleanup_creds(); |
ssh_gssapi_cleanup_creds(); |
#endif |
#endif |
|
|