version 1.147.2.3, 2002/05/17 00:03:24 |
version 1.147.2.4, 2002/06/22 07:23:18 |
|
|
#include "xmalloc.h" |
#include "xmalloc.h" |
#include "packet.h" |
#include "packet.h" |
#include "buffer.h" |
#include "buffer.h" |
#include "uidswap.h" |
|
#include "channels.h" |
#include "channels.h" |
#include "key.h" |
#include "key.h" |
#include "authfd.h" |
#include "authfd.h" |
|
|
|
|
/* |
/* |
* Flag indicating that ssh should fork after authentication. This is useful |
* Flag indicating that ssh should fork after authentication. This is useful |
* so that the pasphrase can be entered manually, and then ssh goes to the |
* so that the passphrase can be entered manually, and then ssh goes to the |
* background. |
* background. |
*/ |
*/ |
int fork_after_authentication_flag = 0; |
int fork_after_authentication_flag = 0; |
|
|
struct sockaddr_storage hostaddr; |
struct sockaddr_storage hostaddr; |
|
|
/* Private host keys. */ |
/* Private host keys. */ |
struct { |
Sensitive sensitive_data; |
Key **keys; |
|
int nkeys; |
|
} sensitive_data; |
|
|
|
/* Original real UID. */ |
/* Original real UID. */ |
uid_t original_real_uid; |
uid_t original_real_uid; |
|
uid_t original_effective_uid; |
|
|
/* command to be executed */ |
/* command to be executed */ |
Buffer command; |
Buffer command; |
|
|
exit(1); |
exit(1); |
} |
} |
|
|
/* |
|
* Connects to the given host using rsh (or prints an error message and exits |
|
* if rsh is not available). This function never returns. |
|
*/ |
|
static void |
|
rsh_connect(char *host, char *user, Buffer * command) |
|
{ |
|
char *args[10]; |
|
int i; |
|
|
|
log("Using rsh. WARNING: Connection will not be encrypted."); |
|
/* Build argument list for rsh. */ |
|
i = 0; |
|
args[i++] = _PATH_RSH; |
|
/* host may have to come after user on some systems */ |
|
args[i++] = host; |
|
if (user) { |
|
args[i++] = "-l"; |
|
args[i++] = user; |
|
} |
|
if (buffer_len(command) > 0) { |
|
buffer_append(command, "\0", 1); |
|
args[i++] = buffer_ptr(command); |
|
} |
|
args[i++] = NULL; |
|
if (debug_flag) { |
|
for (i = 0; args[i]; i++) { |
|
if (i != 0) |
|
fprintf(stderr, " "); |
|
fprintf(stderr, "%s", args[i]); |
|
} |
|
fprintf(stderr, "\n"); |
|
} |
|
execv(_PATH_RSH, args); |
|
perror(_PATH_RSH); |
|
exit(1); |
|
} |
|
|
|
static int ssh_session(void); |
static int ssh_session(void); |
static int ssh_session2(void); |
static int ssh_session2(void); |
static void load_public_identity_files(void); |
static void load_public_identity_files(void); |
|
|
int |
int |
main(int ac, char **av) |
main(int ac, char **av) |
{ |
{ |
int i, opt, exit_status, cerr; |
int i, opt, exit_status; |
u_short fwd_port, fwd_host_port; |
u_short fwd_port, fwd_host_port; |
char sfwd_port[6], sfwd_host_port[6]; |
char sfwd_port[6], sfwd_host_port[6]; |
char *p, *cp, buf[256]; |
char *p, *cp, buf[256]; |
struct stat st; |
struct stat st; |
struct passwd *pw; |
struct passwd *pw; |
int dummy; |
int dummy; |
uid_t original_effective_uid; |
|
extern int optind, optreset; |
extern int optind, optreset; |
extern char *optarg; |
extern char *optarg; |
|
|
|
|
* them when the port has been created (actually, when the connection |
* them when the port has been created (actually, when the connection |
* has been made, as we may need to create the port several times). |
* has been made, as we may need to create the port several times). |
*/ |
*/ |
temporarily_use_uid(pw); |
PRIV_END; |
|
|
/* |
/* |
* Set our umask to something reasonable, as some files are created |
* Set our umask to something reasonable, as some files are created |
|
|
"originating port will not be trusted."); |
"originating port will not be trusted."); |
options.rhosts_authentication = 0; |
options.rhosts_authentication = 0; |
} |
} |
/* |
|
* If using rsh has been selected, exec it now (without trying |
|
* anything else). Note that we must release privileges first. |
|
*/ |
|
if (options.use_rsh) { |
|
/* |
|
* Restore our superuser privileges. This must be done |
|
* before permanently setting the uid. |
|
*/ |
|
restore_uid(); |
|
|
|
/* Switch to the original uid permanently. */ |
|
permanently_set_uid(pw); |
|
|
|
/* Execute rsh. */ |
|
rsh_connect(host, options.user, &command); |
|
fatal("rsh_connect returned"); |
|
} |
|
/* Restore our superuser privileges. */ |
|
restore_uid(); |
|
|
|
/* Open a connection to the remote host. */ |
/* Open a connection to the remote host. */ |
|
|
cerr = ssh_connect(host, &hostaddr, options.port, IPv4or6, |
if (ssh_connect(host, &hostaddr, options.port, IPv4or6, |
options.connection_attempts, |
options.connection_attempts, |
original_effective_uid != 0 || !options.use_privileged_port, |
original_effective_uid == 0 && options.use_privileged_port, |
pw, options.proxy_command); |
options.proxy_command) != 0) |
|
exit(1); |
|
|
/* |
/* |
* If we successfully made the connection, load the host private key |
* If we successfully made the connection, load the host private key |
* in case we will need it later for combined rsa-rhosts |
* in case we will need it later for combined rsa-rhosts |
* authentication. This must be done before releasing extra |
* authentication. This must be done before releasing extra |
* privileges, because the file is only readable by root. |
* privileges, because the file is only readable by root. |
|
* If we cannot access the private keys, load the public keys |
|
* instead and try to execute the ssh-keysign helper instead. |
*/ |
*/ |
sensitive_data.nkeys = 0; |
sensitive_data.nkeys = 0; |
sensitive_data.keys = NULL; |
sensitive_data.keys = NULL; |
if (!cerr && (options.rhosts_rsa_authentication || |
sensitive_data.external_keysign = 0; |
options.hostbased_authentication)) { |
if (options.rhosts_rsa_authentication || |
|
options.hostbased_authentication) { |
sensitive_data.nkeys = 3; |
sensitive_data.nkeys = 3; |
sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key)); |
sensitive_data.keys = xmalloc(sensitive_data.nkeys*sizeof(Key)); |
|
|
|
PRIV_START; |
sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, |
sensitive_data.keys[0] = key_load_private_type(KEY_RSA1, |
_PATH_HOST_KEY_FILE, "", NULL); |
_PATH_HOST_KEY_FILE, "", NULL); |
sensitive_data.keys[1] = key_load_private_type(KEY_DSA, |
sensitive_data.keys[1] = key_load_private_type(KEY_DSA, |
_PATH_HOST_DSA_KEY_FILE, "", NULL); |
_PATH_HOST_DSA_KEY_FILE, "", NULL); |
sensitive_data.keys[2] = key_load_private_type(KEY_RSA, |
sensitive_data.keys[2] = key_load_private_type(KEY_RSA, |
_PATH_HOST_RSA_KEY_FILE, "", NULL); |
_PATH_HOST_RSA_KEY_FILE, "", NULL); |
|
PRIV_END; |
|
|
|
if (sensitive_data.keys[0] == NULL && |
|
sensitive_data.keys[1] == NULL && |
|
sensitive_data.keys[2] == NULL) { |
|
sensitive_data.keys[1] = key_load_public( |
|
_PATH_HOST_DSA_KEY_FILE, NULL); |
|
sensitive_data.keys[2] = key_load_public( |
|
_PATH_HOST_RSA_KEY_FILE, NULL); |
|
sensitive_data.external_keysign = 1; |
|
} |
} |
} |
/* |
/* |
* Get rid of any extra privileges that we may have. We will no |
* Get rid of any extra privileges that we may have. We will no |
|
|
* user's home directory if it happens to be on a NFS volume where |
* user's home directory if it happens to be on a NFS volume where |
* root is mapped to nobody. |
* root is mapped to nobody. |
*/ |
*/ |
|
seteuid(original_real_uid); |
|
setuid(original_real_uid); |
|
|
/* |
/* |
* Note that some legacy systems need to postpone the following call |
|
* to permanently_set_uid() until the private hostkey is destroyed |
|
* with RSA_free(). Otherwise the calling user could ptrace() the |
|
* process, read the private hostkey and impersonate the host. |
|
* OpenBSD does not allow ptracing of setuid processes. |
|
*/ |
|
permanently_set_uid(pw); |
|
|
|
/* |
|
* Now that we are back to our own permissions, create ~/.ssh |
* Now that we are back to our own permissions, create ~/.ssh |
* directory if it doesn\'t already exist. |
* directory if it doesn\'t already exist. |
*/ |
*/ |
|
|
if (mkdir(buf, 0700) < 0) |
if (mkdir(buf, 0700) < 0) |
error("Could not create directory '%.200s'.", buf); |
error("Could not create directory '%.200s'.", buf); |
|
|
/* Check if the connection failed, and try "rsh" if appropriate. */ |
|
if (cerr) { |
|
if (!options.fallback_to_rsh) |
|
exit(1); |
|
if (options.port != 0) |
|
log("Secure connection to %.100s on port %hu refused; " |
|
"reverting to insecure method", |
|
host, options.port); |
|
else |
|
log("Secure connection to %.100s refused; " |
|
"reverting to insecure method.", host); |
|
|
|
rsh_connect(host, options.user, &command); |
|
fatal("rsh_connect returned"); |
|
} |
|
/* load options.identity_files */ |
/* load options.identity_files */ |
load_public_identity_files(); |
load_public_identity_files(); |
|
|
|
|
signal(SIGPIPE, SIG_IGN); /* ignore SIGPIPE early */ |
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, host, (struct sockaddr *)&hostaddr, pw); |
host, (struct sockaddr *)&hostaddr, pw); |
|
|
|
/* We no longer need the private host keys. Clear them now. */ |
/* We no longer need the private host keys. Clear them now. */ |
if (sensitive_data.nkeys != 0) { |
if (sensitive_data.nkeys != 0) { |
|
|
* XXX: "localhost" match to determine FamilyLocal |
* XXX: "localhost" match to determine FamilyLocal |
* is not perfect. |
* is not perfect. |
*/ |
*/ |
snprintf(line, sizeof line, "%.100s list unix:%s 2>" |
snprintf(line, sizeof line, "%s list unix:%s 2>" |
_PATH_DEVNULL, options.xauth_location, display+10); |
_PATH_DEVNULL, options.xauth_location, display+10); |
else |
else |
snprintf(line, sizeof line, "%.100s list %.200s 2>" |
snprintf(line, sizeof line, "%s list %.200s 2>" |
_PATH_DEVNULL, options.xauth_location, display); |
_PATH_DEVNULL, options.xauth_location, display); |
debug2("x11_get_proto %s", line); |
debug2("x11_get_proto %s", line); |
f = popen(line, "r"); |
f = popen(line, "r"); |
|
|
debug("Sending subsystem: %.*s", len, (u_char *)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 assume 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 { |