version 1.147, 2001/10/08 19:05:05 |
version 1.147.2.3, 2002/05/17 00:03:24 |
|
|
* called by a name other than "ssh" or "Secure Shell". |
* called by a name other than "ssh" or "Secure Shell". |
* |
* |
* Copyright (c) 1999 Niels Provos. All rights reserved. |
* Copyright (c) 1999 Niels Provos. All rights reserved. |
|
* Copyright (c) 2000, 2001, 2002 Markus Friedl. All rights reserved. |
* |
* |
* Modified to work with SSL by Niels Provos <provos@citi.umich.edu> |
* Modified to work with SSL by Niels Provos <provos@citi.umich.edu> |
* in Canada (German citizen). |
* in Canada (German citizen). |
|
|
#include "sshtty.h" |
#include "sshtty.h" |
|
|
#ifdef SMARTCARD |
#ifdef SMARTCARD |
#include <openssl/engine.h> |
|
#include "scard.h" |
#include "scard.h" |
#endif |
#endif |
|
|
|
|
/* socket address the host resolves to */ |
/* socket address the host resolves to */ |
struct sockaddr_storage hostaddr; |
struct sockaddr_storage hostaddr; |
|
|
/* |
|
* Flag to indicate that we have received a window change signal which has |
|
* not yet been processed. This will cause a message indicating the new |
|
* window size to be sent to the server a little later. This is volatile |
|
* because this is updated in a signal handler. |
|
*/ |
|
volatile int received_window_change_signal = 0; |
|
|
|
/* Private host keys. */ |
/* Private host keys. */ |
struct { |
struct { |
Key **keys; |
Key **keys; |
|
|
/* Should we execute a command or invoke a subsystem? */ |
/* Should we execute a command or invoke a subsystem? */ |
int subsystem_flag = 0; |
int subsystem_flag = 0; |
|
|
|
/* # of replies received for global requests */ |
|
static int client_global_request_id = 0; |
|
|
/* Prints a help message to the user. This function never returns. */ |
/* Prints a help message to the user. This function never returns. */ |
|
|
static void |
static void |
|
|
/* NOTREACHED */ |
/* NOTREACHED */ |
} |
} |
if ((fwd_port = a2port(sfwd_port)) == 0 || |
if ((fwd_port = a2port(sfwd_port)) == 0 || |
(fwd_host_port = a2port(sfwd_host_port)) == 0) { |
(fwd_host_port = a2port(sfwd_host_port)) == 0) { |
fprintf(stderr, |
fprintf(stderr, |
"Bad forwarding port(s) '%s'\n", optarg); |
"Bad forwarding port(s) '%s'\n", optarg); |
exit(1); |
exit(1); |
|
|
fwd_host_port); |
fwd_host_port); |
else if (opt == 'R') |
else if (opt == 'R') |
add_remote_forward(&options, fwd_port, buf, |
add_remote_forward(&options, fwd_port, buf, |
fwd_host_port); |
fwd_host_port); |
break; |
break; |
|
|
case 'D': |
case 'D': |
|
|
options.user_hostfile2 = |
options.user_hostfile2 = |
tilde_expand_filename(options.user_hostfile2, original_real_uid); |
tilde_expand_filename(options.user_hostfile2, original_real_uid); |
|
|
|
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ |
|
|
/* Log into the remote system. This never returns if the login fails. */ |
/* Log into the remote system. This never returns if the login fails. */ |
ssh_login(sensitive_data.keys, sensitive_data.nkeys, |
ssh_login(sensitive_data.keys, sensitive_data.nkeys, |
host, (struct sockaddr *)&hostaddr, pw); |
host, (struct sockaddr *)&hostaddr, pw); |
|
|
} |
} |
|
|
static void |
static void |
x11_get_proto(char *proto, int proto_len, char *data, int data_len) |
x11_get_proto(char **_proto, char **_data) |
{ |
{ |
char line[512]; |
char line[512]; |
|
static char proto[512], data[512]; |
FILE *f; |
FILE *f; |
int got_data = 0, i; |
int got_data = 0, i; |
|
char *display; |
|
|
if (options.xauth_location) { |
*_proto = proto; |
|
*_data = data; |
|
proto[0] = data[0] = '\0'; |
|
if (options.xauth_location && (display = getenv("DISPLAY"))) { |
/* Try to get Xauthority information for the display. */ |
/* Try to get Xauthority information for the display. */ |
snprintf(line, sizeof line, "%.100s list %.200s 2>" _PATH_DEVNULL, |
if (strncmp(display, "localhost:", 10) == 0) |
options.xauth_location, getenv("DISPLAY")); |
/* |
|
* Handle FamilyLocal case where $DISPLAY does |
|
* not match an authorization entry. For this we |
|
* just try "xauth list unix:displaynum.screennum". |
|
* XXX: "localhost" match to determine FamilyLocal |
|
* is not perfect. |
|
*/ |
|
snprintf(line, sizeof line, "%.100s list unix:%s 2>" |
|
_PATH_DEVNULL, options.xauth_location, display+10); |
|
else |
|
snprintf(line, sizeof line, "%.100s list %.200s 2>" |
|
_PATH_DEVNULL, options.xauth_location, display); |
|
debug2("x11_get_proto %s", line); |
f = popen(line, "r"); |
f = popen(line, "r"); |
if (f && fgets(line, sizeof(line), f) && |
if (f && fgets(line, sizeof(line), f) && |
sscanf(line, "%*s %s %s", proto, data) == 2) |
sscanf(line, "%*s %511s %511s", proto, data) == 2) |
got_data = 1; |
got_data = 1; |
if (f) |
if (f) |
pclose(f); |
pclose(f); |
|
|
if (!got_data) { |
if (!got_data) { |
u_int32_t rand = 0; |
u_int32_t rand = 0; |
|
|
strlcpy(proto, "MIT-MAGIC-COOKIE-1", proto_len); |
strlcpy(proto, "MIT-MAGIC-COOKIE-1", sizeof proto); |
for (i = 0; i < 16; i++) { |
for (i = 0; i < 16; i++) { |
if (i % 4 == 0) |
if (i % 4 == 0) |
rand = arc4random(); |
rand = arc4random(); |
snprintf(data + 2 * i, data_len - 2 * i, "%02x", rand & 0xff); |
snprintf(data + 2 * i, sizeof data - 2 * i, "%02x", rand & 0xff); |
rand >>= 8; |
rand >>= 8; |
} |
} |
} |
} |
|
|
options.local_forwards[i].port, |
options.local_forwards[i].port, |
options.local_forwards[i].host, |
options.local_forwards[i].host, |
options.local_forwards[i].host_port); |
options.local_forwards[i].host_port); |
success += channel_request_local_forwarding( |
success += channel_setup_local_fwd_listener( |
options.local_forwards[i].port, |
options.local_forwards[i].port, |
options.local_forwards[i].host, |
options.local_forwards[i].host, |
options.local_forwards[i].host_port, |
options.local_forwards[i].host_port, |
|
|
ssh_session(void) |
ssh_session(void) |
{ |
{ |
int type; |
int type; |
int plen; |
|
int interactive = 0; |
int interactive = 0; |
int have_tty = 0; |
int have_tty = 0; |
struct winsize ws; |
struct winsize ws; |
|
|
packet_put_int(options.compression_level); |
packet_put_int(options.compression_level); |
packet_send(); |
packet_send(); |
packet_write_wait(); |
packet_write_wait(); |
type = packet_read(&plen); |
type = packet_read(); |
if (type == SSH_SMSG_SUCCESS) |
if (type == SSH_SMSG_SUCCESS) |
packet_start_compression(options.compression_level); |
packet_start_compression(options.compression_level); |
else if (type == SSH_SMSG_FAILURE) |
else if (type == SSH_SMSG_FAILURE) |
|
|
packet_write_wait(); |
packet_write_wait(); |
|
|
/* Read response from the server. */ |
/* Read response from the server. */ |
type = packet_read(&plen); |
type = packet_read(); |
if (type == SSH_SMSG_SUCCESS) { |
if (type == SSH_SMSG_SUCCESS) { |
interactive = 1; |
interactive = 1; |
have_tty = 1; |
have_tty = 1; |
|
|
} |
} |
/* Request X11 forwarding if enabled and DISPLAY is set. */ |
/* Request X11 forwarding if enabled and DISPLAY is set. */ |
if (options.forward_x11 && getenv("DISPLAY") != NULL) { |
if (options.forward_x11 && getenv("DISPLAY") != NULL) { |
char proto[512], data[512]; |
char *proto, *data; |
/* Get reasonable local authentication information. */ |
/* Get reasonable local authentication information. */ |
x11_get_proto(proto, sizeof proto, data, sizeof data); |
x11_get_proto(&proto, &data); |
/* Request forwarding with authentication spoofing. */ |
/* Request forwarding with authentication spoofing. */ |
debug("Requesting X11 forwarding with authentication spoofing."); |
debug("Requesting X11 forwarding with authentication spoofing."); |
x11_request_forwarding_with_spoofing(0, proto, data); |
x11_request_forwarding_with_spoofing(0, proto, data); |
|
|
/* Read response from the server. */ |
/* Read response from the server. */ |
type = packet_read(&plen); |
type = packet_read(); |
if (type == SSH_SMSG_SUCCESS) { |
if (type == SSH_SMSG_SUCCESS) { |
interactive = 1; |
interactive = 1; |
} else if (type == SSH_SMSG_FAILURE) { |
} else if (type == SSH_SMSG_FAILURE) { |
|
|
auth_request_forwarding(); |
auth_request_forwarding(); |
|
|
/* Read response from the server. */ |
/* Read response from the server. */ |
type = packet_read(&plen); |
type = packet_read(); |
packet_integrity_check(plen, 0, type); |
packet_check_eom(); |
if (type != SSH_SMSG_SUCCESS) |
if (type != SSH_SMSG_SUCCESS) |
log("Warning: Remote host denied authentication agent forwarding."); |
log("Warning: Remote host denied authentication agent forwarding."); |
} |
} |
|
|
int len = buffer_len(&command); |
int len = buffer_len(&command); |
if (len > 900) |
if (len > 900) |
len = 900; |
len = 900; |
debug("Sending command: %.*s", len, buffer_ptr(&command)); |
debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); |
packet_start(SSH_CMSG_EXEC_CMD); |
packet_start(SSH_CMSG_EXEC_CMD); |
packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
packet_send(); |
packet_send(); |
|
|
} |
} |
|
|
static void |
static void |
client_subsystem_reply(int type, int plen, void *ctxt) |
client_subsystem_reply(int type, u_int32_t seq, void *ctxt) |
{ |
{ |
int id, len; |
int id, len; |
|
|
|
|
len = buffer_len(&command); |
len = buffer_len(&command); |
if (len > 900) |
if (len > 900) |
len = 900; |
len = 900; |
packet_done(); |
packet_check_eom(); |
if (type == SSH2_MSG_CHANNEL_FAILURE) |
if (type == SSH2_MSG_CHANNEL_FAILURE) |
fatal("Request for subsystem '%.*s' failed on channel %d", |
fatal("Request for subsystem '%.*s' failed on channel %d", |
len, buffer_ptr(&command), id); |
len, (u_char *)buffer_ptr(&command), id); |
} |
} |
|
|
|
void |
|
client_global_request_reply(int type, u_int32_t seq, void *ctxt) |
|
{ |
|
int i; |
|
|
|
i = client_global_request_id++; |
|
if (i >= options.num_remote_forwards) { |
|
debug("client_global_request_reply: too many replies %d > %d", |
|
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].port, |
|
options.remote_forwards[i].host, |
|
options.remote_forwards[i].host_port); |
|
if (type == SSH2_MSG_REQUEST_FAILURE) |
|
log("Warning: remote port forwarding failed for listen port %d", |
|
options.remote_forwards[i].port); |
|
} |
|
|
/* request pty/x11/agent/tcpfwd/shell for channel */ |
/* request pty/x11/agent/tcpfwd/shell for channel */ |
static void |
static void |
ssh_session2_setup(int id, void *arg) |
ssh_session2_setup(int id, void *arg) |
|
|
} |
} |
if (options.forward_x11 && |
if (options.forward_x11 && |
getenv("DISPLAY") != NULL) { |
getenv("DISPLAY") != NULL) { |
char proto[512], data[512]; |
char *proto, *data; |
/* Get reasonable local authentication information. */ |
/* Get reasonable local authentication information. */ |
x11_get_proto(proto, sizeof proto, data, sizeof data); |
x11_get_proto(&proto, &data); |
/* Request forwarding with authentication spoofing. */ |
/* Request forwarding with authentication spoofing. */ |
debug("Requesting X11 forwarding with authentication spoofing."); |
debug("Requesting X11 forwarding with authentication spoofing."); |
x11_request_forwarding_with_spoofing(id, proto, data); |
x11_request_forwarding_with_spoofing(id, proto, data); |
|
|
if (len > 900) |
if (len > 900) |
len = 900; |
len = 900; |
if (subsystem_flag) { |
if (subsystem_flag) { |
debug("Sending subsystem: %.*s", len, buffer_ptr(&command)); |
debug("Sending subsystem: %.*s", len, (u_char *)buffer_ptr(&command)); |
channel_request_start(id, "subsystem", /*want reply*/ 1); |
channel_request_start(id, "subsystem", /*want reply*/ 1); |
/* register callback for reply */ |
/* register callback for reply */ |
/* XXX we asume that client_loop has already been called */ |
/* XXX we asume that client_loop has already been called */ |
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply); |
dispatch_set(SSH2_MSG_CHANNEL_FAILURE, &client_subsystem_reply); |
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply); |
dispatch_set(SSH2_MSG_CHANNEL_SUCCESS, &client_subsystem_reply); |
} else { |
} else { |
debug("Sending command: %.*s", len, buffer_ptr(&command)); |
debug("Sending command: %.*s", len, (u_char *)buffer_ptr(&command)); |
channel_request_start(id, "exec", 0); |
channel_request_start(id, "exec", 0); |
} |
} |
packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
packet_put_string(buffer_ptr(&command), buffer_len(&command)); |
packet_send(); |
packet_send(); |
} else { |
} else { |
channel_request(id, "shell", 0); |
channel_request_start(id, "shell", 0); |
|
packet_send(); |
} |
} |
/* channel_callback(id, SSH2_MSG_OPEN_CONFIGMATION, client_init, 0); */ |
|
|
|
/* register different callback, etc. XXX */ |
|
packet_set_interactive(interactive); |
packet_set_interactive(interactive); |
} |
} |
|
|
|
|
|
|
window = CHAN_SES_WINDOW_DEFAULT; |
window = CHAN_SES_WINDOW_DEFAULT; |
packetmax = CHAN_SES_PACKET_DEFAULT; |
packetmax = CHAN_SES_PACKET_DEFAULT; |
if (!tty_flag) { |
if (tty_flag) { |
window *= 2; |
window >>= 1; |
packetmax *=2; |
packetmax >>= 1; |
} |
} |
c = channel_new( |
c = channel_new( |
"session", SSH_CHANNEL_OPENING, in, out, err, |
"session", SSH_CHANNEL_OPENING, in, out, err, |
window, packetmax, CHAN_EXTENDED_WRITE, |
window, packetmax, CHAN_EXTENDED_WRITE, |
xstrdup("client-session"), /*nonblock*/0); |
xstrdup("client-session"), /*nonblock*/0); |
if (c == NULL) |
|
fatal("ssh_session2_open: channel_new failed"); |
|
|
|
debug3("ssh_session2_open: channel_new: %d", c->self); |
debug3("ssh_session2_open: channel_new: %d", c->self); |
|
|
channel_send_open(c->self); |
channel_send_open(c->self); |
if (!no_shell_flag) |
if (!no_shell_flag) |
channel_register_callback(c->self, |
channel_register_confirm(c->self, ssh_session2_setup); |
SSH2_MSG_CHANNEL_OPEN_CONFIRMATION, |
|
ssh_session2_setup, (void *)0); |
|
|
|
return c->self; |
return c->self; |
} |
} |
|
|
load_public_identity_files(void) |
load_public_identity_files(void) |
{ |
{ |
char *filename; |
char *filename; |
Key *public; |
|
int i = 0; |
int i = 0; |
|
Key *public; |
#ifdef SMARTCARD |
#ifdef SMARTCARD |
if (options.smartcard_device != NULL && |
Key **keys; |
options.num_identity_files + 1 < SSH_MAX_IDENTITY_FILES && |
|
(public = sc_get_key(options.smartcard_device)) != NULL ) { |
|
Key *new; |
|
|
|
if (options.num_identity_files + 2 > SSH_MAX_IDENTITY_FILES) |
if (options.smartcard_device != NULL && |
options.num_identity_files = SSH_MAX_IDENTITY_FILES - 2; |
options.num_identity_files < SSH_MAX_IDENTITY_FILES && |
memmove(&options.identity_files[2], &options.identity_files[0], |
(keys = sc_get_keys(options.smartcard_device, NULL)) != NULL ) { |
sizeof(char *) * options.num_identity_files); |
int count = 0; |
options.num_identity_files += 2; |
for (i = 0; keys[i] != NULL; i++) { |
i = 2; |
count++; |
|
memmove(&options.identity_files[1], &options.identity_files[0], |
/* XXX ssh1 vs ssh2 */ |
sizeof(char *) * (SSH_MAX_IDENTITY_FILES - 1)); |
new = key_new(KEY_RSA); |
memmove(&options.identity_keys[1], &options.identity_keys[0], |
new->flags = KEY_FLAG_EXT; |
sizeof(Key *) * (SSH_MAX_IDENTITY_FILES - 1)); |
BN_copy(new->rsa->n, public->rsa->n); |
options.num_identity_files++; |
BN_copy(new->rsa->e, public->rsa->e); |
options.identity_keys[0] = keys[i]; |
RSA_set_method(new->rsa, sc_get_engine()); |
options.identity_files[0] = xstrdup("smartcard key");; |
options.identity_keys[0] = new; |
} |
options.identity_files[0] = xstrdup("smartcard rsa key");; |
if (options.num_identity_files > SSH_MAX_IDENTITY_FILES) |
|
options.num_identity_files = SSH_MAX_IDENTITY_FILES; |
new = key_new(KEY_RSA1); |
i = count; |
new->flags = KEY_FLAG_EXT; |
xfree(keys); |
BN_copy(new->rsa->n, public->rsa->n); |
|
BN_copy(new->rsa->e, public->rsa->e); |
|
RSA_set_method(new->rsa, sc_get_engine()); |
|
options.identity_keys[1] = new; |
|
options.identity_files[1] = xstrdup("smartcard rsa1 key"); |
|
|
|
key_free(public); |
|
} |
} |
#endif /* SMARTCARD */ |
#endif /* SMARTCARD */ |
for (; i < options.num_identity_files; i++) { |
for (; i < options.num_identity_files; i++) { |